Expeditions rework (#18960)
This commit is contained in:
@@ -4,6 +4,7 @@ using Content.Client.Stylesheets;
|
|||||||
using Content.Client.UserInterface.Controls;
|
using Content.Client.UserInterface.Controls;
|
||||||
using Content.Shared.CCVar;
|
using Content.Shared.CCVar;
|
||||||
using Content.Shared.Parallax.Biomes;
|
using Content.Shared.Parallax.Biomes;
|
||||||
|
using Content.Shared.Procedural;
|
||||||
using Content.Shared.Salvage;
|
using Content.Shared.Salvage;
|
||||||
using Content.Shared.Salvage.Expeditions;
|
using Content.Shared.Salvage.Expeditions;
|
||||||
using Content.Shared.Salvage.Expeditions.Modifiers;
|
using Content.Shared.Salvage.Expeditions.Modifiers;
|
||||||
@@ -53,8 +54,10 @@ public sealed partial class SalvageExpeditionWindow : FancyWindow,
|
|||||||
for (var i = 0; i < state.Missions.Count; i++)
|
for (var i = 0; i < state.Missions.Count; i++)
|
||||||
{
|
{
|
||||||
var missionParams = state.Missions[i];
|
var missionParams = state.Missions[i];
|
||||||
var config = missionParams.MissionType;
|
var difficultyId = "Moderate";
|
||||||
var mission = _salvage.GetMission(missionParams.MissionType, missionParams.Difficulty, missionParams.Seed);
|
var difficultyProto = _prototype.Index<SalvageDifficultyPrototype>(difficultyId);
|
||||||
|
// TODO: Selectable difficulty soon.
|
||||||
|
var mission = _salvage.GetMission(difficultyProto, missionParams.Seed);
|
||||||
|
|
||||||
// Mission title
|
// Mission title
|
||||||
var missionStripe = new StripeBack()
|
var missionStripe = new StripeBack()
|
||||||
@@ -64,7 +67,7 @@ public sealed partial class SalvageExpeditionWindow : FancyWindow,
|
|||||||
|
|
||||||
missionStripe.AddChild(new Label()
|
missionStripe.AddChild(new Label()
|
||||||
{
|
{
|
||||||
Text = Loc.GetString($"salvage-expedition-type-{config.ToString()}"),
|
Text = Loc.GetString($"salvage-expedition-type"),
|
||||||
HorizontalAlignment = HAlignment.Center,
|
HorizontalAlignment = HAlignment.Center,
|
||||||
Margin = new Thickness(0f, 5f, 0f, 5f),
|
Margin = new Thickness(0f, 5f, 0f, 5f),
|
||||||
});
|
});
|
||||||
@@ -81,48 +84,25 @@ public sealed partial class SalvageExpeditionWindow : FancyWindow,
|
|||||||
Text = Loc.GetString("salvage-expedition-window-difficulty")
|
Text = Loc.GetString("salvage-expedition-window-difficulty")
|
||||||
});
|
});
|
||||||
|
|
||||||
Color difficultyColor;
|
var difficultyColor = difficultyProto.Color;
|
||||||
|
|
||||||
switch (missionParams.Difficulty)
|
|
||||||
{
|
|
||||||
case DifficultyRating.Minimal:
|
|
||||||
difficultyColor = Color.FromHex("#52B4E996");
|
|
||||||
break;
|
|
||||||
case DifficultyRating.Minor:
|
|
||||||
difficultyColor = Color.FromHex("#9FED5896");
|
|
||||||
break;
|
|
||||||
case DifficultyRating.Moderate:
|
|
||||||
difficultyColor = Color.FromHex("#EFB34196");
|
|
||||||
break;
|
|
||||||
case DifficultyRating.Hazardous:
|
|
||||||
difficultyColor = Color.FromHex("#DE3A3A96");
|
|
||||||
break;
|
|
||||||
case DifficultyRating.Extreme:
|
|
||||||
difficultyColor = Color.FromHex("#D381C996");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new ArgumentOutOfRangeException();
|
|
||||||
}
|
|
||||||
|
|
||||||
lBox.AddChild(new Label
|
lBox.AddChild(new Label
|
||||||
{
|
{
|
||||||
Text = Loc.GetString($"salvage-expedition-difficulty-{missionParams.Difficulty.ToString()}"),
|
Text = Loc.GetString("salvage-expedition-difficulty-Moderate"),
|
||||||
FontColorOverride = difficultyColor,
|
FontColorOverride = difficultyColor,
|
||||||
HorizontalAlignment = HAlignment.Left,
|
HorizontalAlignment = HAlignment.Left,
|
||||||
Margin = new Thickness(0f, 0f, 0f, 5f),
|
Margin = new Thickness(0f, 0f, 0f, 5f),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Details
|
|
||||||
var details = _salvage.GetMissionDescription(mission);
|
|
||||||
|
|
||||||
lBox.AddChild(new Label
|
lBox.AddChild(new Label
|
||||||
{
|
{
|
||||||
Text = Loc.GetString("salvage-expedition-window-details")
|
Text = Loc.GetString("salvage-expedition-difficulty-players"),
|
||||||
|
HorizontalAlignment = HAlignment.Left,
|
||||||
});
|
});
|
||||||
|
|
||||||
lBox.AddChild(new Label
|
lBox.AddChild(new Label
|
||||||
{
|
{
|
||||||
Text = details,
|
Text = difficultyProto.RecommendedPlayers.ToString(),
|
||||||
FontColorOverride = StyleNano.NanoGold,
|
FontColorOverride = StyleNano.NanoGold,
|
||||||
HorizontalAlignment = HAlignment.Left,
|
HorizontalAlignment = HAlignment.Left,
|
||||||
Margin = new Thickness(0f, 0f, 0f, 5f),
|
Margin = new Thickness(0f, 0f, 0f, 5f),
|
||||||
@@ -168,7 +148,7 @@ public sealed partial class SalvageExpeditionWindow : FancyWindow,
|
|||||||
|
|
||||||
lBox.AddChild(new Label
|
lBox.AddChild(new Label
|
||||||
{
|
{
|
||||||
Text = Loc.GetString(_prototype.Index<SalvageBiomeMod>(biome).ID),
|
Text = Loc.GetString(_prototype.Index<SalvageBiomeModPrototype>(biome).ID),
|
||||||
FontColorOverride = StyleNano.NanoGold,
|
FontColorOverride = StyleNano.NanoGold,
|
||||||
HorizontalAlignment = HAlignment.Left,
|
HorizontalAlignment = HAlignment.Left,
|
||||||
Margin = new Thickness(0f, 0f, 0f, 5f),
|
Margin = new Thickness(0f, 0f, 0f, 5f),
|
||||||
@@ -190,29 +170,6 @@ public sealed partial class SalvageExpeditionWindow : FancyWindow,
|
|||||||
Margin = new Thickness(0f, 0f, 0f, 5f),
|
Margin = new Thickness(0f, 0f, 0f, 5f),
|
||||||
});
|
});
|
||||||
|
|
||||||
lBox.AddChild(new Label()
|
|
||||||
{
|
|
||||||
Text = Loc.GetString("salvage-expedition-window-rewards")
|
|
||||||
});
|
|
||||||
|
|
||||||
var rewards = new Dictionary<string, int>();
|
|
||||||
foreach (var reward in mission.Rewards)
|
|
||||||
{
|
|
||||||
var name = _prototype.Index<EntityPrototype>(reward).Name;
|
|
||||||
var count = rewards.GetOrNew(name);
|
|
||||||
count++;
|
|
||||||
rewards[name] = count;
|
|
||||||
}
|
|
||||||
|
|
||||||
// there will always be 3 or more rewards so no need for 0 check
|
|
||||||
lBox.AddChild(new Label()
|
|
||||||
{
|
|
||||||
Text = string.Join("\n", rewards.Select(o => "- " + o.Key + (o.Value > 1 ? $" x {o.Value}" : ""))).TrimEnd(),
|
|
||||||
FontColorOverride = StyleNano.ConcerningOrangeFore,
|
|
||||||
HorizontalAlignment = HAlignment.Left,
|
|
||||||
Margin = new Thickness(0f, 0f, 0f, 5f)
|
|
||||||
});
|
|
||||||
|
|
||||||
// Claim
|
// Claim
|
||||||
var claimButton = new Button()
|
var claimButton = new Button()
|
||||||
{
|
{
|
||||||
@@ -289,7 +246,7 @@ public sealed partial class SalvageExpeditionWindow : FancyWindow,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
var cooldown = _cooldown
|
var cooldown = _cooldown
|
||||||
? TimeSpan.FromSeconds(_cfgManager.GetCVar(CCVars.SalvageExpeditionFailedCooldown))
|
? TimeSpan.FromSeconds(_cfgManager.GetCVar(CCVars.SalvageExpeditionCooldown))
|
||||||
: TimeSpan.FromSeconds(_cfgManager.GetCVar(CCVars.SalvageExpeditionCooldown));
|
: TimeSpan.FromSeconds(_cfgManager.GetCVar(CCVars.SalvageExpeditionCooldown));
|
||||||
|
|
||||||
NextOfferBar.Value = 1f - (float) (remaining / cooldown);
|
NextOfferBar.Value = 1f - (float) (remaining / cooldown);
|
||||||
|
|||||||
@@ -83,17 +83,14 @@ public sealed partial class DungeonJob
|
|||||||
var lastDirection = new Dictionary<Vector2i, Direction>();
|
var lastDirection = new Dictionary<Vector2i, Direction>();
|
||||||
costSoFar[start] = 0f;
|
costSoFar[start] = 0f;
|
||||||
lastDirection[start] = Direction.Invalid;
|
lastDirection[start] = Direction.Invalid;
|
||||||
var tagQuery = _entManager.GetEntityQuery<TagComponent>();
|
|
||||||
|
|
||||||
// TODO:
|
|
||||||
// Pick a random node to start
|
|
||||||
// Then, dijkstra out from it. Add like +10 if it's a wall or smth
|
|
||||||
// When we hit another cable then mark it as found and iterate cameFrom and add to the thingie.
|
|
||||||
while (remaining.Count > 0)
|
while (remaining.Count > 0)
|
||||||
{
|
{
|
||||||
if (frontier.Count == 0)
|
if (frontier.Count == 0)
|
||||||
{
|
{
|
||||||
frontier.Enqueue(remaining.First(), 0f);
|
var newStart = remaining.First();
|
||||||
|
frontier.Enqueue(newStart, 0f);
|
||||||
|
lastDirection[newStart] = Direction.Invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
var node = frontier.Dequeue();
|
var node = frontier.Dequeue();
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
using Content.Shared.Salvage;
|
|
||||||
|
|
||||||
namespace Content.Server.Salvage.Expeditions.Structure;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tracks expedition data for <see cref="SalvageMissionType.Elimination"/>
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent, Access(typeof(SalvageSystem), typeof(SpawnSalvageMissionJob))]
|
|
||||||
public sealed partial class SalvageEliminationExpeditionComponent : Component
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// List of mobs that need to be killed for the mission to be complete.
|
|
||||||
/// </summary>
|
|
||||||
[DataField("megafauna")]
|
|
||||||
public List<EntityUid> Megafauna = new();
|
|
||||||
}
|
|
||||||
@@ -49,16 +49,4 @@ public sealed partial class SalvageExpeditionComponent : SharedSalvageExpedition
|
|||||||
{
|
{
|
||||||
Params = AudioParams.Default.WithVolume(-5),
|
Params = AudioParams.Default.WithVolume(-5),
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The difficulty this mission had or, in the future, was selected.
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables(VVAccess.ReadWrite), DataField("difficulty")]
|
|
||||||
public DifficultyRating Difficulty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// List of items to order on mission completion
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables(VVAccess.ReadWrite), DataField("rewards", customTypeSerializer: typeof(PrototypeIdListSerializer<EntityPrototype>))]
|
|
||||||
public List<string> Rewards = default!;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
using Content.Shared.Salvage;
|
|
||||||
|
|
||||||
namespace Content.Server.Salvage.Expeditions;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tracks expedition data for <see cref="SalvageMissionType.Mining"/>
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent, Access(typeof(SalvageSystem))]
|
|
||||||
public sealed partial class SalvageMiningExpeditionComponent : Component
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Entities that were present on the shuttle and match the loot tax.
|
|
||||||
/// </summary>
|
|
||||||
[DataField("exemptEntities")]
|
|
||||||
public List<EntityUid> ExemptEntities = new();
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
using Content.Shared.Salvage;
|
|
||||||
|
|
||||||
namespace Content.Server.Salvage.Expeditions.Structure;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tracks expedition data for <see cref="SalvageMissionType.Structure"/>
|
|
||||||
/// </summary>
|
|
||||||
[RegisterComponent, Access(typeof(SalvageSystem), typeof(SpawnSalvageMissionJob))]
|
|
||||||
public sealed partial class SalvageStructureExpeditionComponent : Component
|
|
||||||
{
|
|
||||||
[DataField("structures")]
|
|
||||||
public List<EntityUid> Structures = new();
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using Content.Shared.Procedural;
|
||||||
using Content.Shared.Salvage;
|
using Content.Shared.Salvage;
|
||||||
using Content.Shared.Salvage.Expeditions;
|
using Content.Shared.Salvage.Expeditions;
|
||||||
|
|
||||||
@@ -18,7 +19,7 @@ public sealed partial class SalvageSystem
|
|||||||
SpawnMission(missionparams, station.Value);
|
SpawnMission(missionparams, station.Value);
|
||||||
|
|
||||||
data.ActiveMission = args.Index;
|
data.ActiveMission = args.Index;
|
||||||
var mission = GetMission(missionparams.MissionType, missionparams.Difficulty, missionparams.Seed);
|
var mission = GetMission(_prototypeManager.Index<SalvageDifficultyPrototype>(missionparams.Difficulty), missionparams.Seed);
|
||||||
data.NextOffer = _timing.CurTime + mission.Duration + TimeSpan.FromSeconds(1);
|
data.NextOffer = _timing.CurTime + mission.Duration + TimeSpan.FromSeconds(1);
|
||||||
UpdateConsoles(data);
|
UpdateConsoles(data);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ using Robust.Shared.CPUJob.JobQueues;
|
|||||||
using Robust.Shared.CPUJob.JobQueues.Queues;
|
using Robust.Shared.CPUJob.JobQueues.Queues;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using Content.Shared.Procedural;
|
||||||
using Content.Shared.Salvage.Expeditions;
|
using Content.Shared.Salvage.Expeditions;
|
||||||
using Robust.Shared.GameStates;
|
using Robust.Shared.GameStates;
|
||||||
|
|
||||||
@@ -26,7 +27,6 @@ public sealed partial class SalvageSystem
|
|||||||
private const double SalvageJobTime = 0.002;
|
private const double SalvageJobTime = 0.002;
|
||||||
|
|
||||||
private float _cooldown;
|
private float _cooldown;
|
||||||
private float _failedCooldown;
|
|
||||||
|
|
||||||
private void InitializeExpeditions()
|
private void InitializeExpeditions()
|
||||||
{
|
{
|
||||||
@@ -43,9 +43,7 @@ public sealed partial class SalvageSystem
|
|||||||
SubscribeLocalEvent<SalvageStructureComponent, ExaminedEvent>(OnStructureExamine);
|
SubscribeLocalEvent<SalvageStructureComponent, ExaminedEvent>(OnStructureExamine);
|
||||||
|
|
||||||
_cooldown = _configurationManager.GetCVar(CCVars.SalvageExpeditionCooldown);
|
_cooldown = _configurationManager.GetCVar(CCVars.SalvageExpeditionCooldown);
|
||||||
_failedCooldown = _configurationManager.GetCVar(CCVars.SalvageExpeditionFailedCooldown);
|
|
||||||
_configurationManager.OnValueChanged(CCVars.SalvageExpeditionCooldown, SetCooldownChange);
|
_configurationManager.OnValueChanged(CCVars.SalvageExpeditionCooldown, SetCooldownChange);
|
||||||
_configurationManager.OnValueChanged(CCVars.SalvageExpeditionFailedCooldown, SetFailedCooldownChange);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnExpeditionGetState(EntityUid uid, SalvageExpeditionComponent component, ref ComponentGetState args)
|
private void OnExpeditionGetState(EntityUid uid, SalvageExpeditionComponent component, ref ComponentGetState args)
|
||||||
@@ -59,7 +57,6 @@ public sealed partial class SalvageSystem
|
|||||||
private void ShutdownExpeditions()
|
private void ShutdownExpeditions()
|
||||||
{
|
{
|
||||||
_configurationManager.UnsubValueChanged(CCVars.SalvageExpeditionCooldown, SetCooldownChange);
|
_configurationManager.UnsubValueChanged(CCVars.SalvageExpeditionCooldown, SetCooldownChange);
|
||||||
_configurationManager.UnsubValueChanged(CCVars.SalvageExpeditionFailedCooldown, SetFailedCooldownChange);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetCooldownChange(float obj)
|
private void SetCooldownChange(float obj)
|
||||||
@@ -77,20 +74,6 @@ public sealed partial class SalvageSystem
|
|||||||
_cooldown = obj;
|
_cooldown = obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetFailedCooldownChange(float obj)
|
|
||||||
{
|
|
||||||
var diff = obj - _failedCooldown;
|
|
||||||
|
|
||||||
var query = AllEntityQuery<SalvageExpeditionDataComponent>();
|
|
||||||
|
|
||||||
while (query.MoveNext(out var comp))
|
|
||||||
{
|
|
||||||
comp.NextOffer += TimeSpan.FromSeconds(diff);
|
|
||||||
}
|
|
||||||
|
|
||||||
_failedCooldown = obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnExpeditionShutdown(EntityUid uid, SalvageExpeditionComponent component, ComponentShutdown args)
|
private void OnExpeditionShutdown(EntityUid uid, SalvageExpeditionComponent component, ComponentShutdown args)
|
||||||
{
|
{
|
||||||
component.Stream?.Stop();
|
component.Stream?.Stop();
|
||||||
@@ -110,7 +93,7 @@ public sealed partial class SalvageSystem
|
|||||||
// Finish mission
|
// Finish mission
|
||||||
if (TryComp<SalvageExpeditionDataComponent>(component.Station, out var data))
|
if (TryComp<SalvageExpeditionDataComponent>(component.Station, out var data))
|
||||||
{
|
{
|
||||||
FinishExpedition(data, uid, component, null);
|
FinishExpedition(data, uid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,109 +135,29 @@ public sealed partial class SalvageSystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FinishExpedition(SalvageExpeditionDataComponent component, EntityUid uid, SalvageExpeditionComponent expedition, EntityUid? shuttle)
|
private void FinishExpedition(SalvageExpeditionDataComponent component, EntityUid uid)
|
||||||
{
|
{
|
||||||
// Finish mission cleanup.
|
|
||||||
switch (expedition.MissionParams.MissionType)
|
|
||||||
{
|
|
||||||
// Handles the mining taxation.
|
|
||||||
case SalvageMissionType.Mining:
|
|
||||||
expedition.Completed = true;
|
|
||||||
|
|
||||||
if (shuttle != null && TryComp<SalvageMiningExpeditionComponent>(uid, out var mining))
|
|
||||||
{
|
|
||||||
var xformQuery = GetEntityQuery<TransformComponent>();
|
|
||||||
var entities = new List<EntityUid>();
|
|
||||||
MiningTax(entities, shuttle.Value, mining, xformQuery);
|
|
||||||
|
|
||||||
var tax = GetMiningTax(expedition.MissionParams.Difficulty);
|
|
||||||
_random.Shuffle(entities);
|
|
||||||
|
|
||||||
// TODO: urgh this pr is already taking so long I'll do this later
|
|
||||||
for (var i = 0; i < Math.Ceiling(entities.Count * tax); i++)
|
|
||||||
{
|
|
||||||
// QueueDel(entities[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle payout after expedition has finished
|
|
||||||
if (expedition.Completed)
|
|
||||||
{
|
|
||||||
Log.Debug($"Completed mission {expedition.MissionParams.MissionType} with seed {expedition.MissionParams.Seed}");
|
|
||||||
component.NextOffer = _timing.CurTime + TimeSpan.FromSeconds(_cooldown);
|
component.NextOffer = _timing.CurTime + TimeSpan.FromSeconds(_cooldown);
|
||||||
Announce(uid, Loc.GetString("salvage-expedition-mission-completed"));
|
Announce(uid, Loc.GetString("salvage-expedition-mission-completed"));
|
||||||
GiveRewards(expedition);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Log.Debug($"Failed mission {expedition.MissionParams.MissionType} with seed {expedition.MissionParams.Seed}");
|
|
||||||
component.NextOffer = _timing.CurTime + TimeSpan.FromSeconds(_failedCooldown);
|
|
||||||
Announce(uid, Loc.GetString("salvage-expedition-mission-failed"));
|
|
||||||
}
|
|
||||||
|
|
||||||
component.ActiveMission = 0;
|
component.ActiveMission = 0;
|
||||||
component.Cooldown = true;
|
component.Cooldown = true;
|
||||||
UpdateConsoles(component);
|
UpdateConsoles(component);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Deducts ore tax for mining.
|
|
||||||
/// </summary>
|
|
||||||
private void MiningTax(List<EntityUid> entities, EntityUid entity, SalvageMiningExpeditionComponent mining, EntityQuery<TransformComponent> xformQuery)
|
|
||||||
{
|
|
||||||
if (!mining.ExemptEntities.Contains(entity))
|
|
||||||
{
|
|
||||||
entities.Add(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
var xform = xformQuery.GetComponent(entity);
|
|
||||||
var children = xform.ChildEnumerator;
|
|
||||||
|
|
||||||
while (children.MoveNext(out var child))
|
|
||||||
{
|
|
||||||
MiningTax(entities, child.Value, mining, xformQuery);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void GenerateMissions(SalvageExpeditionDataComponent component)
|
private void GenerateMissions(SalvageExpeditionDataComponent component)
|
||||||
{
|
{
|
||||||
component.Missions.Clear();
|
component.Missions.Clear();
|
||||||
var configs = Enum.GetValues<SalvageMissionType>().ToList();
|
|
||||||
|
|
||||||
// Temporarily removed coz it SUCKS
|
|
||||||
configs.Remove(SalvageMissionType.Mining);
|
|
||||||
|
|
||||||
// this doesn't support having more missions than types of ratings
|
|
||||||
// but the previous system didn't do that either.
|
|
||||||
var allDifficulties = Enum.GetValues<DifficultyRating>();
|
|
||||||
_random.Shuffle(allDifficulties);
|
|
||||||
var difficulties = allDifficulties.Take(MissionLimit).ToList();
|
|
||||||
difficulties.Sort();
|
|
||||||
|
|
||||||
if (configs.Count == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (var i = 0; i < MissionLimit; i++)
|
for (var i = 0; i < MissionLimit; i++)
|
||||||
{
|
|
||||||
_random.Shuffle(configs);
|
|
||||||
var rating = difficulties[i];
|
|
||||||
|
|
||||||
foreach (var config in configs)
|
|
||||||
{
|
{
|
||||||
var mission = new SalvageMissionParams
|
var mission = new SalvageMissionParams
|
||||||
{
|
{
|
||||||
Index = component.NextIndex,
|
Index = component.NextIndex,
|
||||||
MissionType = config,
|
|
||||||
Seed = _random.Next(),
|
Seed = _random.Next(),
|
||||||
Difficulty = rating,
|
Difficulty = "Moderate",
|
||||||
};
|
};
|
||||||
|
|
||||||
component.Missions[component.NextIndex++] = mission;
|
component.Missions[component.NextIndex++] = mission;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,13 +174,13 @@ public sealed partial class SalvageSystem
|
|||||||
SalvageJobTime,
|
SalvageJobTime,
|
||||||
EntityManager,
|
EntityManager,
|
||||||
_timing,
|
_timing,
|
||||||
|
_logManager,
|
||||||
_mapManager,
|
_mapManager,
|
||||||
_prototypeManager,
|
_prototypeManager,
|
||||||
_anchorable,
|
_anchorable,
|
||||||
_biome,
|
_biome,
|
||||||
_dungeon,
|
_dungeon,
|
||||||
_metaData,
|
_metaData,
|
||||||
this,
|
|
||||||
station,
|
station,
|
||||||
missionParams,
|
missionParams,
|
||||||
cancelToken.Token);
|
cancelToken.Token);
|
||||||
@@ -290,19 +193,4 @@ public sealed partial class SalvageSystem
|
|||||||
{
|
{
|
||||||
args.PushMarkup(Loc.GetString("salvage-expedition-structure-examine"));
|
args.PushMarkup(Loc.GetString("salvage-expedition-structure-examine"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GiveRewards(SalvageExpeditionComponent comp)
|
|
||||||
{
|
|
||||||
// send it to cargo, no rewards otherwise.
|
|
||||||
if (!TryComp<StationCargoOrderDatabaseComponent>(comp.Station, out var cargoDb))
|
|
||||||
return;
|
|
||||||
|
|
||||||
foreach (var reward in comp.Rewards)
|
|
||||||
{
|
|
||||||
var sender = Loc.GetString("cargo-gift-default-sender");
|
|
||||||
var desc = Loc.GetString("salvage-expedition-reward-description");
|
|
||||||
var dest = Loc.GetString("cargo-gift-default-dest");
|
|
||||||
_cargo.AddAndApproveOrder(comp.Station, reward, 0, 1, sender, desc, dest, cargoDb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public sealed partial class SalvageSystem
|
|||||||
// TODO: This is terrible but need bluespace harnesses or something.
|
// TODO: This is terrible but need bluespace harnesses or something.
|
||||||
var query = EntityQueryEnumerator<HumanoidAppearanceComponent, MobStateComponent, TransformComponent>();
|
var query = EntityQueryEnumerator<HumanoidAppearanceComponent, MobStateComponent, TransformComponent>();
|
||||||
|
|
||||||
while (query.MoveNext(out var uid, out var _, out var mobState, out var mobXform))
|
while (query.MoveNext(out var uid, out _, out var mobState, out var mobXform))
|
||||||
{
|
{
|
||||||
if (mobXform.MapUid != xform.MapUid)
|
if (mobXform.MapUid != xform.MapUid)
|
||||||
continue;
|
continue;
|
||||||
@@ -109,22 +109,11 @@ public sealed partial class SalvageSystem
|
|||||||
Announce(args.MapUid, Loc.GetString("salvage-expedition-announcement-dungeon", ("direction", component.DungeonLocation.GetDir())));
|
Announce(args.MapUid, Loc.GetString("salvage-expedition-announcement-dungeon", ("direction", component.DungeonLocation.GetDir())));
|
||||||
|
|
||||||
component.Stage = ExpeditionStage.Running;
|
component.Stage = ExpeditionStage.Running;
|
||||||
Dirty(component);
|
Dirty(args.MapUid, component);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnFTLStarted(ref FTLStartedEvent ev)
|
private void OnFTLStarted(ref FTLStartedEvent ev)
|
||||||
{
|
{
|
||||||
// Started a mining mission so work out exempt entities
|
|
||||||
if (TryComp<SalvageMiningExpeditionComponent>(
|
|
||||||
_mapManager.GetMapEntityId(ev.TargetCoordinates.ToMap(EntityManager, _transform).MapId),
|
|
||||||
out var mining))
|
|
||||||
{
|
|
||||||
var ents = new List<EntityUid>();
|
|
||||||
var xformQuery = GetEntityQuery<TransformComponent>();
|
|
||||||
MiningTax(ents, ev.Entity, mining, xformQuery);
|
|
||||||
mining.ExemptEntities = ents;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!TryComp<SalvageExpeditionComponent>(ev.FromMapUid, out var expedition) ||
|
if (!TryComp<SalvageExpeditionComponent>(ev.FromMapUid, out var expedition) ||
|
||||||
!TryComp<SalvageExpeditionDataComponent>(expedition.Station, out var station))
|
!TryComp<SalvageExpeditionDataComponent>(expedition.Station, out var station))
|
||||||
{
|
{
|
||||||
@@ -169,7 +158,7 @@ public sealed partial class SalvageSystem
|
|||||||
Dirty(uid, comp);
|
Dirty(uid, comp);
|
||||||
Announce(uid, Loc.GetString("salvage-expedition-announcement-countdown-minutes", ("duration", TimeSpan.FromMinutes(2).Minutes)));
|
Announce(uid, Loc.GetString("salvage-expedition-announcement-countdown-minutes", ("duration", TimeSpan.FromMinutes(2).Minutes)));
|
||||||
}
|
}
|
||||||
else if (comp.Stage < ExpeditionStage.Countdown && remaining < TimeSpan.FromMinutes(5))
|
else if (comp.Stage < ExpeditionStage.Countdown && remaining < TimeSpan.FromMinutes(4))
|
||||||
{
|
{
|
||||||
comp.Stage = ExpeditionStage.Countdown;
|
comp.Stage = ExpeditionStage.Countdown;
|
||||||
Dirty(uid, comp);
|
Dirty(uid, comp);
|
||||||
@@ -210,72 +199,5 @@ public sealed partial class SalvageSystem
|
|||||||
QueueDel(uid);
|
QueueDel(uid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mining missions: NOOP since it's handled after ftling
|
|
||||||
|
|
||||||
// Structure missions
|
|
||||||
var structureQuery = EntityQueryEnumerator<SalvageStructureExpeditionComponent, SalvageExpeditionComponent>();
|
|
||||||
|
|
||||||
while (structureQuery.MoveNext(out var uid, out var structure, out var comp))
|
|
||||||
{
|
|
||||||
if (comp.Completed)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var structureAnnounce = false;
|
|
||||||
|
|
||||||
for (var i = 0; i < structure.Structures.Count; i++)
|
|
||||||
{
|
|
||||||
var objective = structure.Structures[i];
|
|
||||||
|
|
||||||
if (Deleted(objective))
|
|
||||||
{
|
|
||||||
structure.Structures.RemoveSwap(i);
|
|
||||||
structureAnnounce = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (structureAnnounce)
|
|
||||||
{
|
|
||||||
Announce(uid, Loc.GetString("salvage-expedition-structure-remaining", ("count", structure.Structures.Count)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (structure.Structures.Count == 0)
|
|
||||||
{
|
|
||||||
comp.Completed = true;
|
|
||||||
Announce(uid, Loc.GetString("salvage-expedition-completed"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Elimination missions
|
|
||||||
var eliminationQuery = EntityQueryEnumerator<SalvageEliminationExpeditionComponent, SalvageExpeditionComponent>();
|
|
||||||
while (eliminationQuery.MoveNext(out var uid, out var elimination, out var comp))
|
|
||||||
{
|
|
||||||
if (comp.Completed)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var announce = false;
|
|
||||||
|
|
||||||
for (var i = 0; i < elimination.Megafauna.Count; i++)
|
|
||||||
{
|
|
||||||
var mob = elimination.Megafauna[i];
|
|
||||||
|
|
||||||
if (Deleted(mob) || _mobState.IsDead(mob))
|
|
||||||
{
|
|
||||||
elimination.Megafauna.RemoveSwap(i);
|
|
||||||
announce = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (announce)
|
|
||||||
{
|
|
||||||
Announce(uid, Loc.GetString("salvage-expedition-megafauna-remaining", ("count", elimination.Megafauna.Count)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (elimination.Megafauna.Count == 0)
|
|
||||||
{
|
|
||||||
comp.Completed = true;
|
|
||||||
Announce(uid, Loc.GetString("salvage-expedition-completed"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,12 +37,12 @@ namespace Content.Server.Salvage
|
|||||||
[Dependency] private readonly IChatManager _chat = default!;
|
[Dependency] private readonly IChatManager _chat = default!;
|
||||||
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
|
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
|
||||||
[Dependency] private readonly IGameTiming _timing = default!;
|
[Dependency] private readonly IGameTiming _timing = default!;
|
||||||
|
[Dependency] private readonly ILogManager _logManager = default!;
|
||||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
[Dependency] private readonly AnchorableSystem _anchorable = default!;
|
[Dependency] private readonly AnchorableSystem _anchorable = default!;
|
||||||
[Dependency] private readonly BiomeSystem _biome = default!;
|
[Dependency] private readonly BiomeSystem _biome = default!;
|
||||||
[Dependency] private readonly CargoSystem _cargo = default!;
|
|
||||||
[Dependency] private readonly DungeonSystem _dungeon = default!;
|
[Dependency] private readonly DungeonSystem _dungeon = default!;
|
||||||
[Dependency] private readonly MapLoaderSystem _map = default!;
|
[Dependency] private readonly MapLoaderSystem _map = default!;
|
||||||
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System.Collections;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@@ -19,6 +20,7 @@ using Content.Shared.Parallax.Biomes;
|
|||||||
using Content.Shared.Physics;
|
using Content.Shared.Physics;
|
||||||
using Content.Shared.Procedural;
|
using Content.Shared.Procedural;
|
||||||
using Content.Shared.Procedural.Loot;
|
using Content.Shared.Procedural.Loot;
|
||||||
|
using Content.Shared.Random;
|
||||||
using Content.Shared.Salvage;
|
using Content.Shared.Salvage;
|
||||||
using Content.Shared.Salvage.Expeditions;
|
using Content.Shared.Salvage.Expeditions;
|
||||||
using Content.Shared.Salvage.Expeditions.Modifiers;
|
using Content.Shared.Salvage.Expeditions.Modifiers;
|
||||||
@@ -29,6 +31,7 @@ using Robust.Shared.Map.Components;
|
|||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
using Robust.Shared.Timing;
|
using Robust.Shared.Timing;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
namespace Content.Server.Salvage;
|
namespace Content.Server.Salvage;
|
||||||
|
|
||||||
@@ -42,22 +45,23 @@ public sealed class SpawnSalvageMissionJob : Job<bool>
|
|||||||
private readonly BiomeSystem _biome;
|
private readonly BiomeSystem _biome;
|
||||||
private readonly DungeonSystem _dungeon;
|
private readonly DungeonSystem _dungeon;
|
||||||
private readonly MetaDataSystem _metaData;
|
private readonly MetaDataSystem _metaData;
|
||||||
private readonly SalvageSystem _salvage;
|
|
||||||
|
|
||||||
public readonly EntityUid Station;
|
public readonly EntityUid Station;
|
||||||
private readonly SalvageMissionParams _missionParams;
|
private readonly SalvageMissionParams _missionParams;
|
||||||
|
|
||||||
|
private readonly ISawmill _sawmill;
|
||||||
|
|
||||||
public SpawnSalvageMissionJob(
|
public SpawnSalvageMissionJob(
|
||||||
double maxTime,
|
double maxTime,
|
||||||
IEntityManager entManager,
|
IEntityManager entManager,
|
||||||
IGameTiming timing,
|
IGameTiming timing,
|
||||||
|
ILogManager logManager,
|
||||||
IMapManager mapManager,
|
IMapManager mapManager,
|
||||||
IPrototypeManager protoManager,
|
IPrototypeManager protoManager,
|
||||||
AnchorableSystem anchorable,
|
AnchorableSystem anchorable,
|
||||||
BiomeSystem biome,
|
BiomeSystem biome,
|
||||||
DungeonSystem dungeon,
|
DungeonSystem dungeon,
|
||||||
MetaDataSystem metaData,
|
MetaDataSystem metaData,
|
||||||
SalvageSystem salvage,
|
|
||||||
EntityUid station,
|
EntityUid station,
|
||||||
SalvageMissionParams missionParams,
|
SalvageMissionParams missionParams,
|
||||||
CancellationToken cancellation = default) : base(maxTime, cancellation)
|
CancellationToken cancellation = default) : base(maxTime, cancellation)
|
||||||
@@ -70,15 +74,17 @@ public sealed class SpawnSalvageMissionJob : Job<bool>
|
|||||||
_biome = biome;
|
_biome = biome;
|
||||||
_dungeon = dungeon;
|
_dungeon = dungeon;
|
||||||
_metaData = metaData;
|
_metaData = metaData;
|
||||||
_salvage = salvage;
|
|
||||||
Station = station;
|
Station = station;
|
||||||
_missionParams = missionParams;
|
_missionParams = missionParams;
|
||||||
|
_sawmill = logManager.GetSawmill("salvage_job");
|
||||||
|
#if !DEBUG
|
||||||
|
_sawmill.Level = LogLevel.Info;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task<bool> Process()
|
protected override async Task<bool> Process()
|
||||||
{
|
{
|
||||||
Logger.DebugS("salvage", $"Spawning salvage mission with seed {_missionParams.Seed}");
|
_sawmill.Debug("salvage", $"Spawning salvage mission with seed {_missionParams.Seed}");
|
||||||
var config = _missionParams.MissionType;
|
|
||||||
var mapId = _mapManager.CreateMap();
|
var mapId = _mapManager.CreateMap();
|
||||||
var mapUid = _mapManager.GetMapEntityId(mapId);
|
var mapUid = _mapManager.GetMapEntityId(mapId);
|
||||||
_mapManager.AddUninitializedMap(mapId);
|
_mapManager.AddUninitializedMap(mapId);
|
||||||
@@ -88,16 +94,17 @@ public sealed class SpawnSalvageMissionJob : Job<bool>
|
|||||||
|
|
||||||
// Setup mission configs
|
// Setup mission configs
|
||||||
// As we go through the config the rating will deplete so we'll go for most important to least important.
|
// As we go through the config the rating will deplete so we'll go for most important to least important.
|
||||||
|
var difficultyId = "Moderate";
|
||||||
|
var difficultyProto = _prototypeManager.Index<SalvageDifficultyPrototype>(difficultyId);
|
||||||
|
|
||||||
var mission = _entManager.System<SharedSalvageSystem>()
|
var mission = _entManager.System<SharedSalvageSystem>()
|
||||||
.GetMission(_missionParams.MissionType, _missionParams.Difficulty, _missionParams.Seed);
|
.GetMission(difficultyProto, _missionParams.Seed);
|
||||||
|
|
||||||
var missionBiome = _prototypeManager.Index<SalvageBiomeMod>(mission.Biome);
|
var missionBiome = _prototypeManager.Index<SalvageBiomeModPrototype>(mission.Biome);
|
||||||
BiomeComponent? biome = null;
|
|
||||||
|
|
||||||
if (missionBiome.BiomePrototype != null)
|
if (missionBiome.BiomePrototype != null)
|
||||||
{
|
{
|
||||||
biome = _entManager.AddComponent<BiomeComponent>(mapUid);
|
var biome = _entManager.AddComponent<BiomeComponent>(mapUid);
|
||||||
var biomeSystem = _entManager.System<BiomeSystem>();
|
var biomeSystem = _entManager.System<BiomeSystem>();
|
||||||
biomeSystem.SetTemplate(biome, _prototypeManager.Index<BiomeTemplatePrototype>(missionBiome.BiomePrototype));
|
biomeSystem.SetTemplate(biome, _prototypeManager.Index<BiomeTemplatePrototype>(missionBiome.BiomePrototype));
|
||||||
biomeSystem.SetSeed(biome, mission.Seed);
|
biomeSystem.SetSeed(biome, mission.Seed);
|
||||||
@@ -125,7 +132,7 @@ public sealed class SpawnSalvageMissionJob : Job<bool>
|
|||||||
{
|
{
|
||||||
var lighting = _entManager.EnsureComponent<MapLightComponent>(mapUid);
|
var lighting = _entManager.EnsureComponent<MapLightComponent>(mapUid);
|
||||||
lighting.AmbientLightColor = mission.Color.Value;
|
lighting.AmbientLightColor = mission.Color.Value;
|
||||||
_entManager.Dirty(lighting);
|
_entManager.Dirty(mapUid, lighting);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,8 +144,6 @@ public sealed class SpawnSalvageMissionJob : Job<bool>
|
|||||||
expedition.Station = Station;
|
expedition.Station = Station;
|
||||||
expedition.EndTime = _timing.CurTime + mission.Duration;
|
expedition.EndTime = _timing.CurTime + mission.Duration;
|
||||||
expedition.MissionParams = _missionParams;
|
expedition.MissionParams = _missionParams;
|
||||||
expedition.Difficulty = _missionParams.Difficulty;
|
|
||||||
expedition.Rewards = mission.Rewards;
|
|
||||||
|
|
||||||
// Don't want consoles to have the incorrect name until refreshed.
|
// Don't want consoles to have the incorrect name until refreshed.
|
||||||
var ftlUid = _entManager.CreateEntityUninitialized("FTLPoint", new EntityCoordinates(mapUid, grid.TileSizeHalfVector));
|
var ftlUid = _entManager.CreateEntityUninitialized("FTLPoint", new EntityCoordinates(mapUid, grid.TileSizeHalfVector));
|
||||||
@@ -151,18 +156,13 @@ public sealed class SpawnSalvageMissionJob : Job<bool>
|
|||||||
// We'll use the dungeon rotation as the spawn angle
|
// We'll use the dungeon rotation as the spawn angle
|
||||||
var dungeonRotation = _dungeon.GetDungeonRotation(_missionParams.Seed);
|
var dungeonRotation = _dungeon.GetDungeonRotation(_missionParams.Seed);
|
||||||
|
|
||||||
Dungeon dungeon = default!;
|
|
||||||
|
|
||||||
if (config != SalvageMissionType.Mining)
|
|
||||||
{
|
|
||||||
var maxDungeonOffset = minDungeonOffset + 12;
|
var maxDungeonOffset = minDungeonOffset + 12;
|
||||||
var dungeonOffsetDistance = minDungeonOffset + (maxDungeonOffset - minDungeonOffset) * random.NextFloat();
|
var dungeonOffsetDistance = minDungeonOffset + (maxDungeonOffset - minDungeonOffset) * random.NextFloat();
|
||||||
var dungeonOffset = new Vector2(0f, dungeonOffsetDistance);
|
var dungeonOffset = new Vector2(0f, dungeonOffsetDistance);
|
||||||
dungeonOffset = dungeonRotation.RotateVec(dungeonOffset);
|
dungeonOffset = dungeonRotation.RotateVec(dungeonOffset);
|
||||||
var dungeonMod = _prototypeManager.Index<SalvageDungeonMod>(mission.Dungeon);
|
var dungeonMod = _prototypeManager.Index<SalvageDungeonModPrototype>(mission.Dungeon);
|
||||||
var dungeonConfig = _prototypeManager.Index<DungeonConfigPrototype>(dungeonMod.Proto);
|
var dungeonConfig = _prototypeManager.Index<DungeonConfigPrototype>(dungeonMod.Proto);
|
||||||
dungeon =
|
var dungeon = await WaitAsyncTask(_dungeon.GenerateDungeonAsync(dungeonConfig, mapUid, grid, (Vector2i) dungeonOffset,
|
||||||
await WaitAsyncTask(_dungeon.GenerateDungeonAsync(dungeonConfig, mapUid, grid, (Vector2i) dungeonOffset,
|
|
||||||
_missionParams.Seed));
|
_missionParams.Seed));
|
||||||
|
|
||||||
// Aborty
|
// Aborty
|
||||||
@@ -172,7 +172,6 @@ public sealed class SpawnSalvageMissionJob : Job<bool>
|
|||||||
}
|
}
|
||||||
|
|
||||||
expedition.DungeonLocation = dungeonOffset;
|
expedition.DungeonLocation = dungeonOffset;
|
||||||
}
|
|
||||||
|
|
||||||
List<Vector2i> reservedTiles = new();
|
List<Vector2i> reservedTiles = new();
|
||||||
|
|
||||||
@@ -184,24 +183,14 @@ public sealed class SpawnSalvageMissionJob : Job<bool>
|
|||||||
reservedTiles.Add(tile.GridIndices);
|
reservedTiles.Add(tile.GridIndices);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mission setup
|
var budgetEntries = new List<IBudgetEntry>();
|
||||||
switch (config)
|
|
||||||
{
|
/*
|
||||||
case SalvageMissionType.Mining:
|
* GUARANTEED LOOT
|
||||||
await SetupMining(mission, mapUid);
|
*/
|
||||||
break;
|
|
||||||
case SalvageMissionType.Destruction:
|
|
||||||
await SetupStructure(mission, dungeon, mapUid, grid, random);
|
|
||||||
break;
|
|
||||||
case SalvageMissionType.Elimination:
|
|
||||||
await SetupElimination(mission, dungeon, mapUid, grid, random);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle loot
|
|
||||||
// We'll always add this loot if possible
|
// We'll always add this loot if possible
|
||||||
|
// mainly used for ore layers.
|
||||||
foreach (var lootProto in _prototypeManager.EnumeratePrototypes<SalvageLootPrototype>())
|
foreach (var lootProto in _prototypeManager.EnumeratePrototypes<SalvageLootPrototype>())
|
||||||
{
|
{
|
||||||
if (!lootProto.Guaranteed)
|
if (!lootProto.Guaranteed)
|
||||||
@@ -210,10 +199,104 @@ public sealed class SpawnSalvageMissionJob : Job<bool>
|
|||||||
await SpawnDungeonLoot(dungeon, missionBiome, lootProto, mapUid, grid, random, reservedTiles);
|
await SpawnDungeonLoot(dungeon, missionBiome, lootProto, mapUid, grid, random, reservedTiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle boss loot (when relevant).
|
||||||
|
|
||||||
|
// Handle mob loot.
|
||||||
|
|
||||||
|
// Handle remaining loot
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MOB SPAWNS
|
||||||
|
*/
|
||||||
|
|
||||||
|
var mobBudget = difficultyProto.MobBudget;
|
||||||
|
var faction = _prototypeManager.Index<SalvageFactionPrototype>(mission.Faction);
|
||||||
|
var randomSystem = _entManager.System<RandomSystem>();
|
||||||
|
|
||||||
|
foreach (var entry in faction.MobGroups)
|
||||||
|
{
|
||||||
|
budgetEntries.Add(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
var probSum = budgetEntries.Sum(x => x.Prob);
|
||||||
|
|
||||||
|
while (mobBudget > 0f)
|
||||||
|
{
|
||||||
|
var entry = randomSystem.GetBudgetEntry(ref mobBudget, ref probSum, budgetEntries, random);
|
||||||
|
if (entry == null)
|
||||||
|
break;
|
||||||
|
|
||||||
|
await SpawnRandomEntry(grid, entry, dungeon, random);
|
||||||
|
}
|
||||||
|
|
||||||
|
var allLoot = _prototypeManager.Index<SalvageLootPrototype>(SharedSalvageSystem.ExpeditionsLootProto);
|
||||||
|
var lootBudget = difficultyProto.LootBudget;
|
||||||
|
|
||||||
|
foreach (var rule in allLoot.LootRules)
|
||||||
|
{
|
||||||
|
switch (rule)
|
||||||
|
{
|
||||||
|
case RandomSpawnsLoot randomLoot:
|
||||||
|
budgetEntries.Clear();
|
||||||
|
|
||||||
|
foreach (var entry in randomLoot.Entries)
|
||||||
|
{
|
||||||
|
budgetEntries.Add(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
probSum = budgetEntries.Sum(x => x.Prob);
|
||||||
|
|
||||||
|
while (lootBudget > 0f)
|
||||||
|
{
|
||||||
|
var entry = randomSystem.GetBudgetEntry(ref lootBudget, ref probSum, budgetEntries, random);
|
||||||
|
if (entry == null)
|
||||||
|
break;
|
||||||
|
|
||||||
|
_sawmill.Debug($"Spawning dungeon loot {entry.Proto}");
|
||||||
|
await SpawnRandomEntry(grid, entry, dungeon, random);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SpawnDungeonLoot(Dungeon? dungeon, SalvageBiomeMod biomeMod, SalvageLootPrototype loot, EntityUid gridUid, MapGridComponent grid, Random random, List<Vector2i> reservedTiles)
|
private async Task SpawnRandomEntry(MapGridComponent grid, IBudgetEntry entry, Dungeon dungeon, Random random)
|
||||||
|
{
|
||||||
|
await SuspendIfOutOfTime();
|
||||||
|
|
||||||
|
var availableRooms = new ValueList<DungeonRoom>(dungeon.Rooms);
|
||||||
|
var availableTiles = new List<Vector2i>();
|
||||||
|
|
||||||
|
while (availableRooms.Count > 0)
|
||||||
|
{
|
||||||
|
availableTiles.Clear();
|
||||||
|
var roomIndex = random.Next(availableRooms.Count);
|
||||||
|
var room = availableRooms.RemoveSwap(roomIndex);
|
||||||
|
availableTiles.AddRange(room.Tiles);
|
||||||
|
|
||||||
|
while (availableTiles.Count > 0)
|
||||||
|
{
|
||||||
|
var tile = availableTiles.RemoveSwap(random.Next(availableTiles.Count));
|
||||||
|
|
||||||
|
if (!_anchorable.TileFree(grid, tile, (int) CollisionGroup.MachineLayer,
|
||||||
|
(int) CollisionGroup.MachineLayer))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
_entManager.SpawnAtPosition(entry.Proto, grid.GridTileToLocal(tile));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// oh noooooooooooo
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SpawnDungeonLoot(Dungeon dungeon, SalvageBiomeModPrototype biomeMod, SalvageLootPrototype loot, EntityUid gridUid, MapGridComponent grid, Random random, List<Vector2i> reservedTiles)
|
||||||
{
|
{
|
||||||
for (var i = 0; i < loot.LootRules.Count; i++)
|
for (var i = 0; i < loot.LootRules.Count; i++)
|
||||||
{
|
{
|
||||||
@@ -241,150 +324,4 @@ public sealed class SpawnSalvageMissionJob : Job<bool>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Mission Specific
|
|
||||||
|
|
||||||
private async Task SetupMining(
|
|
||||||
SalvageMission mission,
|
|
||||||
EntityUid gridUid)
|
|
||||||
{
|
|
||||||
var faction = _prototypeManager.Index<SalvageFactionPrototype>(mission.Faction);
|
|
||||||
|
|
||||||
if (_entManager.TryGetComponent<BiomeComponent>(gridUid, out var biome))
|
|
||||||
{
|
|
||||||
// TODO: Better
|
|
||||||
for (var i = 0; i < _salvage.GetDifficulty(mission.Difficulty); i++)
|
|
||||||
{
|
|
||||||
_biome.AddMarkerLayer(biome, faction.Configs["Mining"]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task SetupStructure(
|
|
||||||
SalvageMission mission,
|
|
||||||
Dungeon dungeon,
|
|
||||||
EntityUid gridUid,
|
|
||||||
MapGridComponent grid,
|
|
||||||
Random random)
|
|
||||||
{
|
|
||||||
var structureComp = _entManager.EnsureComponent<SalvageStructureExpeditionComponent>(gridUid);
|
|
||||||
var availableRooms = dungeon.Rooms.ToList();
|
|
||||||
var faction = _prototypeManager.Index<SalvageFactionPrototype>(mission.Faction);
|
|
||||||
await SpawnMobsRandomRooms(mission, dungeon, faction, grid, random);
|
|
||||||
|
|
||||||
var structureCount = _salvage.GetStructureCount(mission.Difficulty);
|
|
||||||
var shaggy = faction.Configs["DefenseStructure"];
|
|
||||||
var validSpawns = new List<Vector2i>();
|
|
||||||
|
|
||||||
// Spawn the objectives
|
|
||||||
for (var i = 0; i < structureCount; i++)
|
|
||||||
{
|
|
||||||
var structureRoom = availableRooms[random.Next(availableRooms.Count)];
|
|
||||||
validSpawns.Clear();
|
|
||||||
validSpawns.AddRange(structureRoom.Tiles);
|
|
||||||
random.Shuffle(validSpawns);
|
|
||||||
|
|
||||||
while (validSpawns.Count > 0)
|
|
||||||
{
|
|
||||||
var spawnTile = validSpawns[^1];
|
|
||||||
validSpawns.RemoveAt(validSpawns.Count - 1);
|
|
||||||
|
|
||||||
if (!_anchorable.TileFree(grid, spawnTile, (int) CollisionGroup.MachineLayer,
|
|
||||||
(int) CollisionGroup.MachineLayer))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var spawnPosition = grid.GridTileToLocal(spawnTile);
|
|
||||||
var uid = _entManager.SpawnEntity(shaggy, spawnPosition);
|
|
||||||
_entManager.AddComponent<SalvageStructureComponent>(uid);
|
|
||||||
structureComp.Structures.Add(uid);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task SetupElimination(
|
|
||||||
SalvageMission mission,
|
|
||||||
Dungeon dungeon,
|
|
||||||
EntityUid gridUid,
|
|
||||||
MapGridComponent grid,
|
|
||||||
Random random)
|
|
||||||
{
|
|
||||||
// spawn megafauna in a random place
|
|
||||||
var roomIndex = random.Next(dungeon.Rooms.Count);
|
|
||||||
var room = dungeon.Rooms[roomIndex];
|
|
||||||
var tile = room.Tiles.ElementAt(random.Next(room.Tiles.Count));
|
|
||||||
var position = grid.GridTileToLocal(tile);
|
|
||||||
|
|
||||||
var faction = _prototypeManager.Index<SalvageFactionPrototype>(mission.Faction);
|
|
||||||
var prototype = faction.Configs["Megafauna"];
|
|
||||||
var uid = _entManager.SpawnEntity(prototype, position);
|
|
||||||
// not removing ghost role since its 1 megafauna, expect that you won't be able to cheese it.
|
|
||||||
var eliminationComp = _entManager.EnsureComponent<SalvageEliminationExpeditionComponent>(gridUid);
|
|
||||||
eliminationComp.Megafauna.Add(uid);
|
|
||||||
|
|
||||||
// spawn less mobs than usual since there's megafauna to deal with too
|
|
||||||
await SpawnMobsRandomRooms(mission, dungeon, faction, grid, random, 0.5f);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task SpawnMobsRandomRooms(SalvageMission mission, Dungeon dungeon, SalvageFactionPrototype faction, MapGridComponent grid, Random random, float scale = 1f)
|
|
||||||
{
|
|
||||||
// scale affects how many groups are spawned, not the size of the groups themselves
|
|
||||||
var groupSpawns = _salvage.GetSpawnCount(mission.Difficulty) * scale;
|
|
||||||
var groupSum = faction.MobGroups.Sum(o => o.Prob);
|
|
||||||
var validSpawns = new List<Vector2i>();
|
|
||||||
|
|
||||||
for (var i = 0; i < groupSpawns; i++)
|
|
||||||
{
|
|
||||||
var roll = random.NextFloat() * groupSum;
|
|
||||||
var value = 0f;
|
|
||||||
|
|
||||||
foreach (var group in faction.MobGroups)
|
|
||||||
{
|
|
||||||
value += group.Prob;
|
|
||||||
|
|
||||||
if (value < roll)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var mobGroupIndex = random.Next(faction.MobGroups.Count);
|
|
||||||
var mobGroup = faction.MobGroups[mobGroupIndex];
|
|
||||||
|
|
||||||
var spawnRoomIndex = random.Next(dungeon.Rooms.Count);
|
|
||||||
var spawnRoom = dungeon.Rooms[spawnRoomIndex];
|
|
||||||
validSpawns.Clear();
|
|
||||||
validSpawns.AddRange(spawnRoom.Tiles);
|
|
||||||
random.Shuffle(validSpawns);
|
|
||||||
|
|
||||||
foreach (var entry in EntitySpawnCollection.GetSpawns(mobGroup.Entries, random))
|
|
||||||
{
|
|
||||||
while (validSpawns.Count > 0)
|
|
||||||
{
|
|
||||||
var spawnTile = validSpawns[^1];
|
|
||||||
validSpawns.RemoveAt(validSpawns.Count - 1);
|
|
||||||
|
|
||||||
if (!_anchorable.TileFree(grid, spawnTile, (int) CollisionGroup.MachineLayer,
|
|
||||||
(int) CollisionGroup.MachineLayer))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var spawnPosition = grid.GridTileToLocal(spawnTile);
|
|
||||||
|
|
||||||
var uid = _entManager.CreateEntityUninitialized(entry, spawnPosition);
|
|
||||||
_entManager.RemoveComponent<GhostTakeoverAvailableComponent>(uid);
|
|
||||||
_entManager.RemoveComponent<GhostRoleComponent>(uid);
|
|
||||||
_entManager.InitializeAndStartEntity(uid);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await SuspendIfOutOfTime();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1500,13 +1500,16 @@ namespace Content.Shared.CCVar
|
|||||||
SalvageForced = CVarDef.Create("salvage.forced", "", CVar.SERVERONLY);
|
SalvageForced = CVarDef.Create("salvage.forced", "", CVar.SERVERONLY);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Cooldown for successful missions.
|
/// Duration for missions
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly CVarDef<float>
|
public static readonly CVarDef<float>
|
||||||
SalvageExpeditionCooldown = CVarDef.Create("salvage.expedition_cooldown", 300f, CVar.REPLICATED);
|
SalvageExpeditionDuration = CVarDef.Create("salvage.expedition_duration", 420f, CVar.REPLICATED);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cooldown for missions.
|
||||||
|
/// </summary>
|
||||||
public static readonly CVarDef<float>
|
public static readonly CVarDef<float>
|
||||||
SalvageExpeditionFailedCooldown = CVarDef.Create("salvage.expedition_failed_cooldown", 900f, CVar.REPLICATED);
|
SalvageExpeditionCooldown = CVarDef.Create("salvage.expedition_cooldown", 780f, CVar.REPLICATED);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Flavor
|
* Flavor
|
||||||
|
|||||||
33
Content.Shared/Procedural/Loot/RandomSpawnsLoot.cs
Normal file
33
Content.Shared/Procedural/Loot/RandomSpawnsLoot.cs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
using Content.Shared.Random;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||||
|
|
||||||
|
namespace Content.Shared.Procedural.Loot;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Randomly places loot in free areas inside the dungeon.
|
||||||
|
/// </summary>
|
||||||
|
public sealed partial class RandomSpawnsLoot : IDungeonLoot
|
||||||
|
{
|
||||||
|
[ViewVariables(VVAccess.ReadWrite), DataField("entries", required: true)]
|
||||||
|
public List<RandomSpawnLootEntry> Entries = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataDefinition]
|
||||||
|
public partial record struct RandomSpawnLootEntry : IBudgetEntry
|
||||||
|
{
|
||||||
|
[ViewVariables(VVAccess.ReadWrite), DataField("proto", required: true, customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))]
|
||||||
|
public string Proto { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cost for this loot to spawn.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite), DataField("cost")]
|
||||||
|
public float Cost { get; set; } = 1f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unit probability for this entry. Weighted against the entire table.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite), DataField("prob")]
|
||||||
|
public float Prob { get; set; } = 1f;
|
||||||
|
}
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
using Content.Shared.Salvage;
|
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
|
|
||||||
|
|
||||||
namespace Content.Shared.Procedural.Loot;
|
namespace Content.Shared.Procedural.Loot;
|
||||||
|
|
||||||
@@ -17,14 +15,6 @@ public sealed class SalvageLootPrototype : IPrototype
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("guaranteed")] public bool Guaranteed;
|
[DataField("guaranteed")] public bool Guaranteed;
|
||||||
|
|
||||||
[DataField("desc")] public string Description = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Mission types this loot is not allowed to spawn for
|
|
||||||
/// </summary>
|
|
||||||
[DataField("blacklist")]
|
|
||||||
public List<SalvageMissionType> Blacklist = new();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// All of the loot rules
|
/// All of the loot rules
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
36
Content.Shared/Procedural/SalvageDifficultyPrototype.cs
Normal file
36
Content.Shared/Procedural/SalvageDifficultyPrototype.cs
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
|
namespace Content.Shared.Procedural;
|
||||||
|
|
||||||
|
[Prototype("salvageDifficulty")]
|
||||||
|
public sealed class SalvageDifficultyPrototype : IPrototype
|
||||||
|
{
|
||||||
|
[IdDataField] public string ID { get; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Color to be used in UI.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite), DataField("color")]
|
||||||
|
public Color Color = Color.White;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// How much loot this difficulty is allowed to spawn.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("lootBudget", required : true)]
|
||||||
|
public float LootBudget;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// How many mobs this difficulty is allowed to spawn.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("mobBudget", required : true)]
|
||||||
|
public float MobBudget;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Budget allowed for mission modifiers like no light, etc.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("modifierBudget")]
|
||||||
|
public float ModifierBudget;
|
||||||
|
|
||||||
|
[DataField("recommendedPlayers", required: true)]
|
||||||
|
public int RecommendedPlayers;
|
||||||
|
}
|
||||||
20
Content.Shared/Random/IBudgetEntry.cs
Normal file
20
Content.Shared/Random/IBudgetEntry.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
namespace Content.Shared.Random;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Budgeted random spawn entry.
|
||||||
|
/// </summary>
|
||||||
|
public interface IBudgetEntry : IProbEntry
|
||||||
|
{
|
||||||
|
float Cost { get; set; }
|
||||||
|
|
||||||
|
string Proto { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Random entry that has a prob. See <see cref="RandomSystem"/>
|
||||||
|
/// </summary>
|
||||||
|
public interface IProbEntry
|
||||||
|
{
|
||||||
|
float Prob { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
58
Content.Shared/Random/RandomSystem.cs
Normal file
58
Content.Shared/Random/RandomSystem.cs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
using Robust.Shared.Random;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
|
namespace Content.Shared.Random;
|
||||||
|
|
||||||
|
public sealed class RandomSystem : EntitySystem
|
||||||
|
{
|
||||||
|
public IBudgetEntry? GetBudgetEntry(ref float budget, ref float probSum, IList<IBudgetEntry> entries, System.Random random)
|
||||||
|
{
|
||||||
|
DebugTools.Assert(budget > 0f);
|
||||||
|
|
||||||
|
if (entries.Count == 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// - Pick an entry
|
||||||
|
// - Remove the cost from budget
|
||||||
|
// - If our remaining budget is under maxCost then start pruning unavailable entries.
|
||||||
|
random.Shuffle(entries);
|
||||||
|
var budgetEntry = (IBudgetEntry) GetProbEntry(entries, probSum, random);
|
||||||
|
|
||||||
|
budget -= budgetEntry.Cost;
|
||||||
|
|
||||||
|
// Prune invalid entries.
|
||||||
|
for (var i = 0; i < entries.Count; i++)
|
||||||
|
{
|
||||||
|
var entry = entries[i];
|
||||||
|
|
||||||
|
if (entry.Cost < budget)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
entries.RemoveSwap(i);
|
||||||
|
i--;
|
||||||
|
probSum -= entry.Prob;
|
||||||
|
}
|
||||||
|
|
||||||
|
return budgetEntry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a random entry based on each entry having a different probability.
|
||||||
|
/// </summary>
|
||||||
|
public IProbEntry GetProbEntry(IEnumerable<IProbEntry> entries, float probSum, System.Random random)
|
||||||
|
{
|
||||||
|
var value = random.NextFloat() * probSum;
|
||||||
|
|
||||||
|
foreach (var entry in entries)
|
||||||
|
{
|
||||||
|
value -= entry.Prob;
|
||||||
|
|
||||||
|
if (value < 0f)
|
||||||
|
{
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,7 +24,7 @@ public sealed class SalvageAirMod : IPrototype, IBiomeSpecificMod
|
|||||||
public float Cost { get; private set; } = 0f;
|
public float Cost { get; private set; } = 0f;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
[DataField("biomes", customTypeSerializer: typeof(PrototypeIdListSerializer<SalvageBiomeMod>))]
|
[DataField("biomes", customTypeSerializer: typeof(PrototypeIdListSerializer<SalvageBiomeModPrototype>))]
|
||||||
public List<string>? Biomes { get; private set; } = null;
|
public List<string>? Biomes { get; private set; } = null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ namespace Content.Shared.Salvage.Expeditions.Modifiers;
|
|||||||
/// Affects the biome to be used for salvage.
|
/// Affects the biome to be used for salvage.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Prototype("salvageBiomeMod")]
|
[Prototype("salvageBiomeMod")]
|
||||||
public sealed class SalvageBiomeMod : IPrototype, ISalvageMod
|
public sealed class SalvageBiomeModPrototype : IPrototype, ISalvageMod
|
||||||
{
|
{
|
||||||
[IdDataField] public string ID { get; } = default!;
|
[IdDataField] public string ID { get; } = default!;
|
||||||
|
|
||||||
@@ -6,7 +6,7 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototy
|
|||||||
namespace Content.Shared.Salvage.Expeditions.Modifiers;
|
namespace Content.Shared.Salvage.Expeditions.Modifiers;
|
||||||
|
|
||||||
[Prototype("salvageDungeonMod")]
|
[Prototype("salvageDungeonMod")]
|
||||||
public sealed class SalvageDungeonMod : IPrototype, IBiomeSpecificMod
|
public sealed class SalvageDungeonModPrototype : IPrototype, IBiomeSpecificMod
|
||||||
{
|
{
|
||||||
[IdDataField] public string ID { get; } = default!;
|
[IdDataField] public string ID { get; } = default!;
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ public sealed class SalvageDungeonMod : IPrototype, IBiomeSpecificMod
|
|||||||
public float Cost { get; private set; } = 0f;
|
public float Cost { get; private set; } = 0f;
|
||||||
|
|
||||||
/// <inheridoc/>
|
/// <inheridoc/>
|
||||||
[DataField("biomes", customTypeSerializer: typeof(PrototypeIdListSerializer<SalvageBiomeMod>))]
|
[DataField("biomes", customTypeSerializer: typeof(PrototypeIdListSerializer<SalvageBiomeModPrototype>))]
|
||||||
public List<string>? Biomes { get; private set; } = null;
|
public List<string>? Biomes { get; private set; } = null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -15,7 +15,7 @@ public sealed class SalvageLightMod : IPrototype, IBiomeSpecificMod
|
|||||||
public float Cost { get; private set; } = 0f;
|
public float Cost { get; private set; } = 0f;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
[DataField("biomes", customTypeSerializer: typeof(PrototypeIdListSerializer<SalvageBiomeMod>))]
|
[DataField("biomes", customTypeSerializer: typeof(PrototypeIdListSerializer<SalvageBiomeModPrototype>))]
|
||||||
public List<string>? Biomes { get; private set; } = null;
|
public List<string>? Biomes { get; private set; } = null;
|
||||||
|
|
||||||
[DataField("color", required: true)] public Color? Color;
|
[DataField("color", required: true)] public Color? Color;
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ public sealed class SalvageTemperatureMod : IPrototype, IBiomeSpecificMod
|
|||||||
public float Cost { get; private set; } = 0f;
|
public float Cost { get; private set; } = 0f;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
[DataField("biomes", customTypeSerializer: typeof(PrototypeIdListSerializer<SalvageBiomeMod>))]
|
[DataField("biomes", customTypeSerializer: typeof(PrototypeIdListSerializer<SalvageBiomeModPrototype>))]
|
||||||
public List<string>? Biomes { get; private set; } = null;
|
public List<string>? Biomes { get; private set; } = null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
using Robust.Shared.Prototypes;
|
|
||||||
|
|
||||||
namespace Content.Shared.Salvage.Expeditions.Modifiers;
|
|
||||||
|
|
||||||
[Prototype("salvageTimeMod")]
|
|
||||||
public sealed class SalvageTimeMod : IPrototype, ISalvageMod
|
|
||||||
{
|
|
||||||
[IdDataField] public string ID { get; } = default!;
|
|
||||||
|
|
||||||
[DataField("desc")] public string Description { get; private set; } = string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Cost for difficulty modifiers.
|
|
||||||
/// </summary>
|
|
||||||
[DataField("cost")]
|
|
||||||
public float Cost { get; private set; }
|
|
||||||
|
|
||||||
[DataField("minDuration")]
|
|
||||||
public int MinDuration = 630;
|
|
||||||
|
|
||||||
[DataField("maxDuration")]
|
|
||||||
public int MaxDuration = 570;
|
|
||||||
}
|
|
||||||
@@ -17,7 +17,7 @@ public sealed class SalvageWeatherMod : IPrototype, IBiomeSpecificMod
|
|||||||
public float Cost { get; private set; } = 0f;
|
public float Cost { get; private set; } = 0f;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
[DataField("biomes", customTypeSerializer: typeof(PrototypeIdListSerializer<SalvageBiomeMod>))]
|
[DataField("biomes", customTypeSerializer: typeof(PrototypeIdListSerializer<SalvageBiomeModPrototype>))]
|
||||||
public List<string>? Biomes { get; private set; } = null;
|
public List<string>? Biomes { get; private set; } = null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -72,28 +72,14 @@ public sealed partial class SalvageExpeditionDataComponent : Component
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
public sealed record SalvageMissionParams : IComparable<SalvageMissionParams>
|
public sealed record SalvageMissionParams
|
||||||
{
|
{
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
public ushort Index;
|
public ushort Index;
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
|
||||||
public SalvageMissionType MissionType;
|
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)] public int Seed;
|
[ViewVariables(VVAccess.ReadWrite)] public int Seed;
|
||||||
|
|
||||||
/// <summary>
|
public string Difficulty = string.Empty;
|
||||||
/// Base difficulty for this mission.
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)] public DifficultyRating Difficulty;
|
|
||||||
|
|
||||||
public int CompareTo(SalvageMissionParams? other)
|
|
||||||
{
|
|
||||||
if (other == null)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
return Difficulty.CompareTo(other.Difficulty);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -102,16 +88,13 @@ public sealed record SalvageMissionParams : IComparable<SalvageMissionParams>
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed record SalvageMission(
|
public sealed record SalvageMission(
|
||||||
int Seed,
|
int Seed,
|
||||||
DifficultyRating Difficulty,
|
|
||||||
string Dungeon,
|
string Dungeon,
|
||||||
string Faction,
|
string Faction,
|
||||||
SalvageMissionType Mission,
|
|
||||||
string Biome,
|
string Biome,
|
||||||
string Air,
|
string Air,
|
||||||
float Temperature,
|
float Temperature,
|
||||||
Color? Color,
|
Color? Color,
|
||||||
TimeSpan Duration,
|
TimeSpan Duration,
|
||||||
List<string> Rewards,
|
|
||||||
List<string> Modifiers)
|
List<string> Modifiers)
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -120,12 +103,7 @@ public sealed record SalvageMission(
|
|||||||
public readonly int Seed = Seed;
|
public readonly int Seed = Seed;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Difficulty rating.
|
/// <see cref="SalvageDungeonModPrototype"/> to be used.
|
||||||
/// </summary>
|
|
||||||
public DifficultyRating Difficulty = Difficulty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// <see cref="SalvageDungeonMod"/> to be used.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly string Dungeon = Dungeon;
|
public readonly string Dungeon = Dungeon;
|
||||||
|
|
||||||
@@ -134,11 +112,6 @@ public sealed record SalvageMission(
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly string Faction = Faction;
|
public readonly string Faction = Faction;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Underlying mission params that generated this.
|
|
||||||
/// </summary>
|
|
||||||
public readonly SalvageMissionType Mission = Mission;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Biome to be used for the mission.
|
/// Biome to be used for the mission.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -164,11 +137,6 @@ public sealed record SalvageMission(
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public TimeSpan Duration = Duration;
|
public TimeSpan Duration = Duration;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The list of items to order on mission completion.
|
|
||||||
/// </summary>
|
|
||||||
public List<string> Rewards = Rewards;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Modifiers (outside of the above) applied to the mission.
|
/// Modifiers (outside of the above) applied to the mission.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -5,20 +5,14 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototy
|
|||||||
namespace Content.Shared.Salvage.Expeditions;
|
namespace Content.Shared.Salvage.Expeditions;
|
||||||
|
|
||||||
[Prototype("salvageFaction")]
|
[Prototype("salvageFaction")]
|
||||||
public sealed class SalvageFactionPrototype : IPrototype, ISalvageMod
|
public sealed class SalvageFactionPrototype : IPrototype
|
||||||
{
|
{
|
||||||
[IdDataField] public string ID { get; } = default!;
|
[IdDataField] public string ID { get; } = default!;
|
||||||
|
|
||||||
[DataField("desc")] public string Description { get; private set; } = string.Empty;
|
[DataField("desc")] public string Description { get; private set; } = string.Empty;
|
||||||
|
|
||||||
/// <summary>
|
[ViewVariables(VVAccess.ReadWrite), DataField("entries", required: true)]
|
||||||
/// Cost for difficulty modifiers.
|
public List<SalvageMobEntry> MobGroups = new();
|
||||||
/// </summary>
|
|
||||||
[DataField("cost")]
|
|
||||||
public float Cost { get; private set; } = 0f;
|
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite), DataField("groups", required: true)]
|
|
||||||
public List<SalvageMobGroup> MobGroups = default!;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Miscellaneous data for factions.
|
/// Miscellaneous data for factions.
|
||||||
|
|||||||
24
Content.Shared/Salvage/Expeditions/SalvageMobEntry.cs
Normal file
24
Content.Shared/Salvage/Expeditions/SalvageMobEntry.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
using Content.Shared.Random;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||||
|
|
||||||
|
namespace Content.Shared.Salvage.Expeditions;
|
||||||
|
|
||||||
|
[DataDefinition]
|
||||||
|
public partial record struct SalvageMobEntry() : IBudgetEntry
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Cost for this mob in a budget.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite), DataField("cost")]
|
||||||
|
public float Cost { get; set; } = 1f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Probability to spawn this mob. Summed with everything else for the faction.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables(VVAccess.ReadWrite), DataField("prob")]
|
||||||
|
public float Prob { get; set; } = 1f;
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite), DataField("proto", required: true, customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))]
|
||||||
|
public string Proto { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
using Content.Shared.Storage;
|
|
||||||
|
|
||||||
namespace Content.Shared.Salvage.Expeditions;
|
|
||||||
|
|
||||||
[DataDefinition]
|
|
||||||
public partial record struct SalvageMobGroup()
|
|
||||||
{
|
|
||||||
// A mob may be cheap but rare or expensive but frequent.
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Probability to spawn this group. Summed with everything else for the faction.
|
|
||||||
/// </summary>
|
|
||||||
[ViewVariables(VVAccess.ReadWrite), DataField("prob")]
|
|
||||||
public float Prob = 1f;
|
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite), DataField("entries", required: true)]
|
|
||||||
public List<EntitySpawnEntry> Entries = new();
|
|
||||||
}
|
|
||||||
@@ -1,9 +1,13 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Content.Shared.CCVar;
|
||||||
using Content.Shared.Dataset;
|
using Content.Shared.Dataset;
|
||||||
|
using Content.Shared.Procedural;
|
||||||
|
using Content.Shared.Procedural.Loot;
|
||||||
using Content.Shared.Random;
|
using Content.Shared.Random;
|
||||||
using Content.Shared.Random.Helpers;
|
using Content.Shared.Random.Helpers;
|
||||||
using Content.Shared.Salvage.Expeditions;
|
using Content.Shared.Salvage.Expeditions;
|
||||||
using Content.Shared.Salvage.Expeditions.Modifiers;
|
using Content.Shared.Salvage.Expeditions.Modifiers;
|
||||||
|
using Robust.Shared.Configuration;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
@@ -13,73 +17,14 @@ namespace Content.Shared.Salvage;
|
|||||||
|
|
||||||
public abstract class SharedSalvageSystem : EntitySystem
|
public abstract class SharedSalvageSystem : EntitySystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly ILocalizationManager _loc = default!;
|
[Dependency] protected readonly IConfigurationManager CfgManager = default!;
|
||||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||||
|
|
||||||
#region Descriptions
|
|
||||||
|
|
||||||
public string GetMissionDescription(SalvageMission mission)
|
|
||||||
{
|
|
||||||
// Hardcoded in coooooz it's dynamic based on difficulty and I'm lazy.
|
|
||||||
switch (mission.Mission)
|
|
||||||
{
|
|
||||||
case SalvageMissionType.Mining:
|
|
||||||
// Taxation: , ("tax", $"{GetMiningTax(mission.Difficulty) * 100f:0}")
|
|
||||||
return Loc.GetString("salvage-expedition-desc-mining");
|
|
||||||
case SalvageMissionType.Destruction:
|
|
||||||
var proto = _proto.Index<SalvageFactionPrototype>(mission.Faction).Configs["DefenseStructure"];
|
|
||||||
|
|
||||||
return Loc.GetString("salvage-expedition-desc-structure",
|
|
||||||
("count", GetStructureCount(mission.Difficulty)),
|
|
||||||
("structure", _loc.GetEntityData(proto).Name));
|
|
||||||
case SalvageMissionType.Elimination:
|
|
||||||
return Loc.GetString("salvage-expedition-desc-elimination");
|
|
||||||
default:
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public float GetMiningTax(DifficultyRating baseRating)
|
|
||||||
{
|
|
||||||
return 0.6f + (int) baseRating * 0.05f;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the amount of structures to destroy.
|
/// Main loot table for salvage expeditions.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int GetStructureCount(DifficultyRating baseRating)
|
[ValidatePrototypeId<SalvageLootPrototype>]
|
||||||
{
|
public const string ExpeditionsLootProto = "SalvageLoot";
|
||||||
return 1 + (int) baseRating * 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
public int GetDifficulty(DifficultyRating rating)
|
|
||||||
{
|
|
||||||
switch (rating)
|
|
||||||
{
|
|
||||||
case DifficultyRating.Minimal:
|
|
||||||
return 1;
|
|
||||||
case DifficultyRating.Minor:
|
|
||||||
return 2;
|
|
||||||
case DifficultyRating.Moderate:
|
|
||||||
return 4;
|
|
||||||
case DifficultyRating.Hazardous:
|
|
||||||
return 8;
|
|
||||||
case DifficultyRating.Extreme:
|
|
||||||
return 16;
|
|
||||||
default:
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(rating), rating, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// How many groups of mobs to spawn for a mission.
|
|
||||||
/// </summary>
|
|
||||||
public float GetSpawnCount(DifficultyRating difficulty)
|
|
||||||
{
|
|
||||||
return (int) difficulty * 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GetFTLName(DatasetPrototype dataset, int seed)
|
public static string GetFTLName(DatasetPrototype dataset, int seed)
|
||||||
{
|
{
|
||||||
@@ -87,51 +32,45 @@ public abstract class SharedSalvageSystem : EntitySystem
|
|||||||
return $"{dataset.Values[random.Next(dataset.Values.Count)]}-{random.Next(10, 100)}-{(char) (65 + random.Next(26))}";
|
return $"{dataset.Values[random.Next(dataset.Values.Count)]}-{random.Next(10, 100)}-{(char) (65 + random.Next(26))}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public SalvageMission GetMission(SalvageMissionType config, DifficultyRating difficulty, int seed)
|
public SalvageMission GetMission(SalvageDifficultyPrototype difficulty, int seed)
|
||||||
{
|
{
|
||||||
// This is on shared to ensure the client display for missions and what the server generates are consistent
|
// This is on shared to ensure the client display for missions and what the server generates are consistent
|
||||||
var rating = (float) GetDifficulty(difficulty);
|
var modifierBudget = difficulty.ModifierBudget;
|
||||||
// Don't want easy missions to have any negative modifiers but also want
|
|
||||||
// easy to be a 1 for difficulty.
|
|
||||||
rating -= 1f;
|
|
||||||
var rand = new System.Random(seed);
|
var rand = new System.Random(seed);
|
||||||
var faction = GetMod<SalvageFactionPrototype>(rand, ref rating);
|
|
||||||
var biome = GetMod<SalvageBiomeMod>(rand, ref rating);
|
// Run budget in order of priority
|
||||||
var dungeon = GetBiomeMod<SalvageDungeonMod>(biome.ID, rand, ref rating);
|
// - Biome
|
||||||
|
// - Lighting
|
||||||
|
// - Atmos
|
||||||
|
var biome = GetMod<SalvageBiomeModPrototype>(rand, ref modifierBudget);
|
||||||
|
var light = GetBiomeMod<SalvageLightMod>(biome.ID, rand, ref modifierBudget);
|
||||||
|
var temp = GetBiomeMod<SalvageTemperatureMod>(biome.ID, rand, ref modifierBudget);
|
||||||
|
var air = GetBiomeMod<SalvageAirMod>(biome.ID, rand, ref modifierBudget);
|
||||||
|
var dungeon = GetBiomeMod<SalvageDungeonModPrototype>(biome.ID, rand, ref modifierBudget);
|
||||||
|
var factionProtos = _proto.EnumeratePrototypes<SalvageFactionPrototype>().ToList();
|
||||||
|
var faction = factionProtos[rand.Next(factionProtos.Count)];
|
||||||
|
|
||||||
var mods = new List<string>();
|
var mods = new List<string>();
|
||||||
|
|
||||||
var air = GetBiomeMod<SalvageAirMod>(biome.ID, rand, ref rating);
|
|
||||||
if (air.Description != string.Empty)
|
if (air.Description != string.Empty)
|
||||||
{
|
{
|
||||||
mods.Add(air.Description);
|
mods.Add(air.Description);
|
||||||
}
|
}
|
||||||
|
|
||||||
// only show the description if there is an atmosphere since wont matter otherwise
|
// only show the description if there is an atmosphere since wont matter otherwise
|
||||||
var temp = GetBiomeMod<SalvageTemperatureMod>(biome.ID, rand, ref rating);
|
|
||||||
if (temp.Description != string.Empty && !air.Space)
|
if (temp.Description != string.Empty && !air.Space)
|
||||||
{
|
{
|
||||||
mods.Add(temp.Description);
|
mods.Add(temp.Description);
|
||||||
}
|
}
|
||||||
|
|
||||||
var light = GetBiomeMod<SalvageLightMod>(biome.ID, rand, ref rating);
|
|
||||||
if (light.Description != string.Empty)
|
if (light.Description != string.Empty)
|
||||||
{
|
{
|
||||||
mods.Add(light.Description);
|
mods.Add(light.Description);
|
||||||
}
|
}
|
||||||
|
|
||||||
var time = GetMod<SalvageTimeMod>(rand, ref rating);
|
var duration = TimeSpan.FromSeconds(CfgManager.GetCVar(CCVars.SalvageExpeditionDuration));
|
||||||
// Round the duration to nearest 15 seconds.
|
|
||||||
var exactDuration = MathHelper.Lerp(time.MinDuration, time.MaxDuration, rand.NextFloat());
|
|
||||||
exactDuration = MathF.Round(exactDuration / 15f) * 15f;
|
|
||||||
var duration = TimeSpan.FromSeconds(exactDuration);
|
|
||||||
|
|
||||||
if (time.Description != string.Empty)
|
return new SalvageMission(seed, dungeon.ID, faction.ID, biome.ID, air.ID, temp.Temperature, light.Color, duration, mods);
|
||||||
{
|
|
||||||
mods.Add(time.Description);
|
|
||||||
}
|
|
||||||
|
|
||||||
var rewards = GetRewards(difficulty, rand);
|
|
||||||
return new SalvageMission(seed, difficulty, dungeon.ID, faction.ID, config, biome.ID, air.ID, temp.Temperature, light.Color, duration, rewards, mods);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public T GetBiomeMod<T>(string biome, System.Random rand, ref float rating) where T : class, IPrototype, IBiomeSpecificMod
|
public T GetBiomeMod<T>(string biome, System.Random rand, ref float rating) where T : class, IPrototype, IBiomeSpecificMod
|
||||||
@@ -171,72 +110,5 @@ public abstract class SharedSalvageSystem : EntitySystem
|
|||||||
|
|
||||||
throw new InvalidOperationException();
|
throw new InvalidOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<string> GetRewards(DifficultyRating difficulty, System.Random rand)
|
|
||||||
{
|
|
||||||
var rewards = new List<string>(3);
|
|
||||||
var ids = RewardsForDifficulty(difficulty);
|
|
||||||
foreach (var id in ids)
|
|
||||||
{
|
|
||||||
// pick a random reward to give
|
|
||||||
var weights = _proto.Index<WeightedRandomEntityPrototype>(id);
|
|
||||||
rewards.Add(weights.Pick(rand));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return rewards;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get a list of WeightedRandomEntityPrototype IDs with the rewards for a certain difficulty.
|
|
||||||
/// </summary>
|
|
||||||
private string[] RewardsForDifficulty(DifficultyRating rating)
|
|
||||||
{
|
|
||||||
var common = "SalvageRewardCommon";
|
|
||||||
var rare = "SalvageRewardRare";
|
|
||||||
var epic = "SalvageRewardEpic";
|
|
||||||
switch (rating)
|
|
||||||
{
|
|
||||||
case DifficultyRating.Minimal:
|
|
||||||
return new string[] { common, common, common };
|
|
||||||
case DifficultyRating.Minor:
|
|
||||||
return new string[] { common, common, rare };
|
|
||||||
case DifficultyRating.Moderate:
|
|
||||||
return new string[] { common, rare, rare };
|
|
||||||
case DifficultyRating.Hazardous:
|
|
||||||
return new string[] { rare, rare, rare, epic };
|
|
||||||
case DifficultyRating.Extreme:
|
|
||||||
return new string[] { rare, rare, epic, epic, epic };
|
|
||||||
default:
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public enum SalvageMissionType : byte
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// No dungeon, just ore loot and random mob spawns.
|
|
||||||
/// </summary>
|
|
||||||
Mining,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Destroy the specified structures in a dungeon.
|
|
||||||
/// </summary>
|
|
||||||
Destruction,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Kill a large creature in a dungeon.
|
|
||||||
/// </summary>
|
|
||||||
Elimination,
|
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public enum DifficultyRating : byte
|
|
||||||
{
|
|
||||||
Minimal,
|
|
||||||
Minor,
|
|
||||||
Moderate,
|
|
||||||
Hazardous,
|
|
||||||
Extreme,
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ preload = false
|
|||||||
|
|
||||||
[salvage]
|
[salvage]
|
||||||
expedition_cooldown = 30.0
|
expedition_cooldown = 30.0
|
||||||
expedition_failed_cooldown = 30.0
|
|
||||||
|
|
||||||
[shuttle]
|
[shuttle]
|
||||||
grid_fill = false
|
grid_fill = false
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ salvage-expedition-structure-remaining = {$count ->
|
|||||||
*[other] {$count} structures remaining.
|
*[other] {$count} structures remaining.
|
||||||
}
|
}
|
||||||
|
|
||||||
salvage-expedition-megafauna-remaining = {$count} megafauna remaining.
|
salvage-expedition-type = Mission
|
||||||
|
|
||||||
salvage-expedition-window-title = Salvage expeditions
|
salvage-expedition-window-title = Salvage expeditions
|
||||||
salvage-expedition-window-difficulty = Difficulty:
|
salvage-expedition-window-difficulty = Difficulty:
|
||||||
salvage-expedition-window-details = Details:
|
salvage-expedition-window-details = Details:
|
||||||
@@ -13,31 +12,17 @@ salvage-expedition-window-hostiles = Hostiles:
|
|||||||
salvage-expedition-window-duration = Duration:
|
salvage-expedition-window-duration = Duration:
|
||||||
salvage-expedition-window-biome = Biome:
|
salvage-expedition-window-biome = Biome:
|
||||||
salvage-expedition-window-modifiers = Modifiers:
|
salvage-expedition-window-modifiers = Modifiers:
|
||||||
salvage-expedition-window-rewards = Rewards:
|
|
||||||
salvage-expedition-window-claimed = Claimed
|
salvage-expedition-window-claimed = Claimed
|
||||||
salvage-expedition-window-claim = Claim
|
salvage-expedition-window-claim = Claim
|
||||||
|
|
||||||
salvage-expedition-window-next = Next offer
|
salvage-expedition-window-next = Next offer
|
||||||
|
|
||||||
# Expedition descriptions
|
|
||||||
salvage-expedition-desc-mining = Collect resources inside the area.
|
|
||||||
# You will be taxed {$tax}% of the resources collected.
|
|
||||||
salvage-expedition-desc-structure = {$count ->
|
|
||||||
[one] Destroy {$count} {$structure} inside the area.
|
|
||||||
*[other] Destroy {$count} {$structure}s inside the area.
|
|
||||||
}
|
|
||||||
salvage-expedition-desc-elimination = Kill a large and dangerous creature inside the area.
|
|
||||||
|
|
||||||
salvage-expedition-type-Mining = Mining
|
|
||||||
salvage-expedition-type-Destruction = Destruction
|
|
||||||
salvage-expedition-type-Elimination = Elimination
|
|
||||||
|
|
||||||
salvage-expedition-difficulty-Minimal = Minimal
|
|
||||||
salvage-expedition-difficulty-Minor = Minor
|
|
||||||
salvage-expedition-difficulty-Moderate = Moderate
|
salvage-expedition-difficulty-Moderate = Moderate
|
||||||
salvage-expedition-difficulty-Hazardous = Hazardous
|
salvage-expedition-difficulty-Hazardous = Hazardous
|
||||||
salvage-expedition-difficulty-Extreme = Extreme
|
salvage-expedition-difficulty-Extreme = Extreme
|
||||||
|
|
||||||
|
salvage-expedition-difficulty-players = Recommended salvagers:
|
||||||
|
|
||||||
# Runner
|
# Runner
|
||||||
salvage-expedition-not-all-present = Not all salvagers are aboard the shuttle!
|
salvage-expedition-not-all-present = Not all salvagers are aboard the shuttle!
|
||||||
|
|
||||||
|
|||||||
@@ -164,7 +164,14 @@
|
|||||||
parent: MobCarp
|
parent: MobCarp
|
||||||
suffix: Dungeon
|
suffix: Dungeon
|
||||||
components:
|
components:
|
||||||
|
- type: MobThresholds
|
||||||
|
thresholds:
|
||||||
|
0: Alive
|
||||||
|
50: Dead
|
||||||
|
- type: SlowOnDamage
|
||||||
|
speedModifierThresholds:
|
||||||
|
25: 0.7
|
||||||
- type: MeleeWeapon
|
- type: MeleeWeapon
|
||||||
damage:
|
damage:
|
||||||
types:
|
types:
|
||||||
Slash: 5
|
Slash: 6
|
||||||
|
|||||||
@@ -60,6 +60,9 @@
|
|||||||
thresholds:
|
thresholds:
|
||||||
0: Alive
|
0: Alive
|
||||||
50: Dead
|
50: Dead
|
||||||
|
- type: SlowOnDamage
|
||||||
|
speedModifierThresholds:
|
||||||
|
25: 0.5
|
||||||
- type: Stamina
|
- type: Stamina
|
||||||
critThreshold: 200
|
critThreshold: 200
|
||||||
- type: Bloodstream
|
- type: Bloodstream
|
||||||
@@ -129,7 +132,7 @@
|
|||||||
- type: MobThresholds
|
- type: MobThresholds
|
||||||
thresholds:
|
thresholds:
|
||||||
0: Alive
|
0: Alive
|
||||||
75: Dead
|
100: Dead
|
||||||
- type: Stamina
|
- type: Stamina
|
||||||
critThreshold: 300
|
critThreshold: 300
|
||||||
- type: SlowOnDamage
|
- type: SlowOnDamage
|
||||||
@@ -162,18 +165,16 @@
|
|||||||
- type: MobThresholds
|
- type: MobThresholds
|
||||||
thresholds:
|
thresholds:
|
||||||
0: Alive
|
0: Alive
|
||||||
150: Dead
|
80: Dead
|
||||||
|
- type: SlowOnDamage
|
||||||
|
speedModifierThresholds:
|
||||||
|
40: 0.7
|
||||||
- type: MeleeWeapon
|
- type: MeleeWeapon
|
||||||
damage:
|
damage:
|
||||||
groups:
|
groups:
|
||||||
Brute: 5
|
Brute: 6
|
||||||
- type: MovementSpeedModifier
|
- type: MovementSpeedModifier
|
||||||
baseWalkSpeed: 2.0
|
baseSprintSpeed: 4
|
||||||
baseSprintSpeed: 2.5
|
|
||||||
- type: SlowOnDamage
|
|
||||||
speedModifierThresholds:
|
|
||||||
100: 0.4
|
|
||||||
50: 0.7
|
|
||||||
- type: Fixtures
|
- type: Fixtures
|
||||||
fixtures:
|
fixtures:
|
||||||
fix1:
|
fix1:
|
||||||
@@ -202,20 +203,15 @@
|
|||||||
thresholds:
|
thresholds:
|
||||||
0: Alive
|
0: Alive
|
||||||
300: Dead
|
300: Dead
|
||||||
- type: Stamina
|
- type: SlowOnDamage
|
||||||
critThreshold: 1500
|
speedModifierThresholds:
|
||||||
|
150: 0.7
|
||||||
- type: MovementSpeedModifier
|
- type: MovementSpeedModifier
|
||||||
baseWalkSpeed: 2.8
|
|
||||||
baseSprintSpeed: 3.8
|
|
||||||
- type: MeleeWeapon
|
- type: MeleeWeapon
|
||||||
hidden: true
|
hidden: true
|
||||||
damage:
|
damage:
|
||||||
groups:
|
groups:
|
||||||
Brute: 20
|
Brute: 12
|
||||||
- type: SlowOnDamage
|
|
||||||
speedModifierThresholds:
|
|
||||||
250: 0.4
|
|
||||||
200: 0.7
|
|
||||||
- type: Fixtures
|
- type: Fixtures
|
||||||
fixtures:
|
fixtures:
|
||||||
fix1:
|
fix1:
|
||||||
@@ -246,12 +242,9 @@
|
|||||||
- type: MobThresholds
|
- type: MobThresholds
|
||||||
thresholds:
|
thresholds:
|
||||||
0: Alive
|
0: Alive
|
||||||
200: Dead
|
100: Dead
|
||||||
- type: Stamina
|
|
||||||
critThreshold: 550
|
|
||||||
- type: MovementSpeedModifier
|
- type: MovementSpeedModifier
|
||||||
baseWalkSpeed: 2.3
|
baseSprintSpeed: 4
|
||||||
baseSprintSpeed: 4.2
|
|
||||||
- type: MeleeWeapon
|
- type: MeleeWeapon
|
||||||
hidden: true
|
hidden: true
|
||||||
damage:
|
damage:
|
||||||
@@ -259,8 +252,7 @@
|
|||||||
Brute: 10
|
Brute: 10
|
||||||
- type: SlowOnDamage
|
- type: SlowOnDamage
|
||||||
speedModifierThresholds:
|
speedModifierThresholds:
|
||||||
150: 0.5
|
50: 0.7
|
||||||
100: 0.7
|
|
||||||
- type: Fixtures
|
- type: Fixtures
|
||||||
fixtures:
|
fixtures:
|
||||||
fix1:
|
fix1:
|
||||||
@@ -285,16 +277,13 @@
|
|||||||
layers:
|
layers:
|
||||||
- map: ["enum.DamageStateVisualLayers.Base"]
|
- map: ["enum.DamageStateVisualLayers.Base"]
|
||||||
state: running
|
state: running
|
||||||
- type: Stamina
|
|
||||||
critThreshold: 250
|
|
||||||
- type: MovementSpeedModifier
|
- type: MovementSpeedModifier
|
||||||
baseWalkSpeed: 2.7
|
|
||||||
baseSprintSpeed: 6.0
|
baseSprintSpeed: 6.0
|
||||||
- type: MeleeWeapon
|
- type: MeleeWeapon
|
||||||
hidden: true
|
hidden: true
|
||||||
damage:
|
damage:
|
||||||
groups:
|
groups:
|
||||||
Brute: 3
|
Brute: 5
|
||||||
- type: Fixtures
|
- type: Fixtures
|
||||||
fixtures:
|
fixtures:
|
||||||
fix1:
|
fix1:
|
||||||
@@ -332,12 +321,13 @@
|
|||||||
- type: MobThresholds
|
- type: MobThresholds
|
||||||
thresholds:
|
thresholds:
|
||||||
0: Alive
|
0: Alive
|
||||||
75: Dead
|
50: Dead
|
||||||
|
- type: SlowOnDamage
|
||||||
|
speedModifierThresholds:
|
||||||
|
25: 0.7
|
||||||
- type: HTN
|
- type: HTN
|
||||||
rootTask:
|
rootTask:
|
||||||
task: SimpleRangedHostileCompound
|
task: SimpleRangedHostileCompound
|
||||||
- type: Stamina
|
|
||||||
critThreshold: 300
|
|
||||||
- type: RechargeBasicEntityAmmo
|
- type: RechargeBasicEntityAmmo
|
||||||
rechargeCooldown: 0.75
|
rechargeCooldown: 0.75
|
||||||
- type: BasicEntityAmmoProvider
|
- type: BasicEntityAmmoProvider
|
||||||
@@ -351,9 +341,6 @@
|
|||||||
availableModes:
|
availableModes:
|
||||||
- FullAuto
|
- FullAuto
|
||||||
soundGunshot: /Audio/Weapons/Xeno/alien_spitacid.ogg
|
soundGunshot: /Audio/Weapons/Xeno/alien_spitacid.ogg
|
||||||
- type: SlowOnDamage
|
|
||||||
speedModifierThresholds:
|
|
||||||
50: 0.4
|
|
||||||
- type: Fixtures
|
- type: Fixtures
|
||||||
fixtures:
|
fixtures:
|
||||||
fix1:
|
fix1:
|
||||||
|
|||||||
@@ -144,21 +144,22 @@
|
|||||||
components:
|
components:
|
||||||
- type: GhostRole
|
- type: GhostRole
|
||||||
description: ghost-role-information-space-dragon-dungeon-description
|
description: ghost-role-information-space-dragon-dungeon-description
|
||||||
# less tanky, no crit
|
- type: SlowOnDamage
|
||||||
|
speedModifierThresholds:
|
||||||
|
100: 0.7
|
||||||
- type: MobThresholds
|
- type: MobThresholds
|
||||||
thresholds:
|
thresholds:
|
||||||
0: Alive
|
0: Alive
|
||||||
300: Dead
|
200: Dead
|
||||||
# less meat spawned since it's a lot easier to kill
|
# less meat spawned since it's a lot easier to kill
|
||||||
- type: Butcherable
|
- type: Butcherable
|
||||||
spawned:
|
spawned:
|
||||||
- id: FoodMeatDragon
|
- id: FoodMeatDragon
|
||||||
amount: 1
|
amount: 1
|
||||||
# half damage, spread evenly
|
|
||||||
- type: MeleeWeapon
|
- type: MeleeWeapon
|
||||||
damage:
|
damage:
|
||||||
groups:
|
groups:
|
||||||
Brute: 15
|
Brute: 12
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: ActionSpawnRift
|
id: ActionSpawnRift
|
||||||
|
|||||||
@@ -13,16 +13,16 @@
|
|||||||
- type: ItemCooldown
|
- type: ItemCooldown
|
||||||
- type: MeleeWeapon
|
- type: MeleeWeapon
|
||||||
damage:
|
damage:
|
||||||
|
groups:
|
||||||
|
Brute: 5
|
||||||
types:
|
types:
|
||||||
Blunt: 2.5
|
|
||||||
Piercing: 2.5
|
|
||||||
Structural: 10
|
Structural: 10
|
||||||
- type: Wieldable
|
- type: Wieldable
|
||||||
- type: IncreaseDamageOnWield
|
- type: IncreaseDamageOnWield
|
||||||
damage:
|
damage:
|
||||||
|
groups:
|
||||||
|
Brute: 10
|
||||||
types:
|
types:
|
||||||
Blunt: 5
|
|
||||||
Piercing: 5
|
|
||||||
Structural: 10
|
Structural: 10
|
||||||
- type: Item
|
- type: Item
|
||||||
size: 80
|
size: 80
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
- type: MeleeWeapon
|
- type: MeleeWeapon
|
||||||
attackRate: 1.5
|
attackRate: 1.5
|
||||||
damage:
|
damage:
|
||||||
|
groups:
|
||||||
|
Brute: 10
|
||||||
types:
|
types:
|
||||||
Blunt: 5
|
|
||||||
Piercing: 5
|
|
||||||
Structural: 10
|
Structural: 10
|
||||||
|
|||||||
@@ -44,6 +44,7 @@
|
|||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: Thruster
|
id: Thruster
|
||||||
|
name: thruster
|
||||||
parent: [ BaseThruster, ConstructibleMachine ]
|
parent: [ BaseThruster, ConstructibleMachine ]
|
||||||
components:
|
components:
|
||||||
- type: Thruster
|
- type: Thruster
|
||||||
@@ -64,6 +65,15 @@
|
|||||||
visible: false
|
visible: false
|
||||||
offset: 0, 1
|
offset: 0, 1
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: ThrusterUnanchored
|
||||||
|
parent: Thruster
|
||||||
|
components:
|
||||||
|
- type: Transform
|
||||||
|
anchored: false
|
||||||
|
- type: Physics
|
||||||
|
bodyType: Dynamic
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: DebugThruster
|
id: DebugThruster
|
||||||
parent: BaseThruster
|
parent: BaseThruster
|
||||||
@@ -91,6 +101,7 @@
|
|||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: Gyroscope
|
id: Gyroscope
|
||||||
|
name: gyroscope
|
||||||
parent: [ BaseThruster, ConstructibleMachine ]
|
parent: [ BaseThruster, ConstructibleMachine ]
|
||||||
components:
|
components:
|
||||||
- type: Thruster
|
- type: Thruster
|
||||||
@@ -133,6 +144,15 @@
|
|||||||
- type: StaticPrice
|
- type: StaticPrice
|
||||||
price: 2000
|
price: 2000
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
id: GyroscopeUnanchored
|
||||||
|
parent: Gyroscope
|
||||||
|
components:
|
||||||
|
- type: Transform
|
||||||
|
anchored: false
|
||||||
|
- type: Physics
|
||||||
|
bodyType: Dynamic
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
id: DebugGyroscope
|
id: DebugGyroscope
|
||||||
parent: BaseThruster
|
parent: BaseThruster
|
||||||
|
|||||||
12
Resources/Prototypes/Procedural/salvage_difficulties.yml
Normal file
12
Resources/Prototypes/Procedural/salvage_difficulties.yml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
- type: salvageDifficulty
|
||||||
|
id: Moderate
|
||||||
|
lootBudget: 30
|
||||||
|
mobBudget: 25
|
||||||
|
modifierBudget: 2
|
||||||
|
color: "#52B4E996"
|
||||||
|
recommendedPlayers: 2
|
||||||
|
|
||||||
|
#9FED5896
|
||||||
|
#EFB34196
|
||||||
|
#DE3A3A96
|
||||||
|
#D381C996
|
||||||
@@ -1,61 +1,41 @@
|
|||||||
- type: salvageFaction
|
- type: salvageFaction
|
||||||
id: Xenos
|
id: Xenos
|
||||||
groups:
|
entries:
|
||||||
- entries:
|
- proto: MobXeno
|
||||||
- id: MobXeno
|
- proto: MobXenoDrone
|
||||||
amount: 2
|
cost: 2
|
||||||
maxAmount: 3
|
- proto: MobXenoPraetorian
|
||||||
- id: MobXenoDrone
|
cost: 5
|
||||||
amount: 1
|
prob: 0.1
|
||||||
- entries:
|
- proto: MobXenoQueen
|
||||||
- id: MobXenoPraetorian
|
cost: 10
|
||||||
amount: 1
|
prob: 0.02
|
||||||
maxAmount: 2
|
- proto: MobXenoRavager
|
||||||
prob: 0.5
|
cost: 5
|
||||||
- entries:
|
- proto: MobXenoRouny
|
||||||
- id: MobXenoDrone
|
cost: 3
|
||||||
amount: 0
|
prob: 0.02
|
||||||
maxAmount: 2
|
- proto: MobXenoSpitter
|
||||||
prob: 0.25
|
- proto: WeaponTurretXeno
|
||||||
- entries:
|
|
||||||
- id: WeaponTurretXeno
|
|
||||||
amount: 3
|
|
||||||
prob: 0.25
|
|
||||||
- entries:
|
|
||||||
- id: MobXenoSpitter
|
|
||||||
amount: 2
|
|
||||||
prob: 0.25
|
|
||||||
- entries:
|
|
||||||
- id: MobXenoRavager
|
|
||||||
amount: 1
|
|
||||||
prob: 0.1
|
prob: 0.1
|
||||||
- entries:
|
|
||||||
- id: MobXenoRouny
|
|
||||||
amount: 1
|
|
||||||
prob: 0.001
|
|
||||||
configs:
|
configs:
|
||||||
DefenseStructure: XenoWardingTower
|
DefenseStructure: XenoWardingTower
|
||||||
Mining: Xenos
|
|
||||||
Megafauna: MobXenoQueen
|
Megafauna: MobXenoQueen
|
||||||
|
|
||||||
- type: salvageFaction
|
- type: salvageFaction
|
||||||
id: Carps
|
id: Carps
|
||||||
groups:
|
entries:
|
||||||
- entries:
|
- proto: MobCarpDungeon
|
||||||
- id: MobCarpDungeon
|
# These do too much damage for salvage, need nerfs
|
||||||
amount: 1
|
#- proto: MobCarpHolo
|
||||||
maxAmount: 4
|
# cost: 5
|
||||||
- entries:
|
# prob: 0.1
|
||||||
- id: MobCarpMagic
|
#- proto: MobCarpMagic
|
||||||
amount: 1
|
# cost: 5
|
||||||
maxAmount: 3
|
# prob: 0.1
|
||||||
prob: 0.5
|
- proto: MobDragonDungeon
|
||||||
- entries:
|
cost: 10
|
||||||
- id: MobCarpHolo
|
prob: 0.02
|
||||||
amount: 1
|
|
||||||
maxAmount: 2
|
|
||||||
prob: 0.25
|
|
||||||
configs:
|
configs:
|
||||||
DefenseStructure: CarpStatue
|
DefenseStructure: CarpStatue
|
||||||
Mining: Carps
|
|
||||||
Megafauna: MobDragonDungeon
|
Megafauna: MobDragonDungeon
|
||||||
|
|||||||
@@ -1,8 +1,125 @@
|
|||||||
# Ores
|
# Loot table
|
||||||
|
# Main loot table for random spawns
|
||||||
|
- type: salvageLoot
|
||||||
|
id: SalvageLoot
|
||||||
|
loots:
|
||||||
|
- !type:RandomSpawnsLoot
|
||||||
|
entries:
|
||||||
|
- proto: AdvMopItem
|
||||||
|
prob: 0.5
|
||||||
|
- proto: AmmoTechFabCircuitboard
|
||||||
|
cost: 2
|
||||||
|
- proto: AutolatheMachineCircuitboard
|
||||||
|
cost: 2
|
||||||
|
- proto: BiomassReclaimerMachineCircuitboard
|
||||||
|
cost: 2
|
||||||
|
- proto: BluespaceBeaker
|
||||||
|
cost: 2
|
||||||
|
- proto: CyborgEndoskeleton
|
||||||
|
cost: 3
|
||||||
|
prob: 0.5
|
||||||
|
- proto: ChemDispenserMachineCircuitboard
|
||||||
|
cost: 2
|
||||||
|
- proto: CircuitImprinter
|
||||||
|
cost: 2
|
||||||
|
- proto: CloningConsoleComputerCircuitboard
|
||||||
|
cost: 2
|
||||||
|
- proto: CloningPodMachineCircuitboard
|
||||||
|
cost: 2
|
||||||
|
- proto: CognizineChemistryBottle
|
||||||
|
- proto: CratePartsT3
|
||||||
|
cost: 2
|
||||||
|
prob: 0.5
|
||||||
|
- proto: CratePartsT3T4
|
||||||
|
cost: 5
|
||||||
|
prob: 0.5
|
||||||
|
- proto: CratePartsT4
|
||||||
|
cost: 5
|
||||||
|
prob: 0.5
|
||||||
|
- proto: CrateSalvageEquipment
|
||||||
|
cost: 3
|
||||||
|
prob: 0.5
|
||||||
|
- proto: GasRecycler
|
||||||
|
cost: 2
|
||||||
|
- proto: GeneratorRTG
|
||||||
|
cost: 5
|
||||||
|
- proto: GravityGeneratorMini
|
||||||
|
cost: 2
|
||||||
|
- proto: GyroscopeUnanchored
|
||||||
|
cost: 2
|
||||||
|
prob: 0.1
|
||||||
|
- proto: MedicalScannerMachineCircuitboard
|
||||||
|
cost: 2
|
||||||
|
- proto: NuclearBombKeg
|
||||||
|
cost: 5
|
||||||
|
- proto: OmnizineChemistryBottle
|
||||||
|
prob: 0.5
|
||||||
|
- proto: PortableGeneratorPacman
|
||||||
|
cost: 2
|
||||||
|
- proto: PortableGeneratorSuperPacman
|
||||||
|
cost: 3
|
||||||
|
- proto: PowerCellAntiqueProto
|
||||||
|
cost: 5
|
||||||
|
prob: 0.5
|
||||||
|
- proto: ProtolatheMachineCircuitboard
|
||||||
|
- proto: RandomArtifactSpawner
|
||||||
|
cost: 2
|
||||||
|
- proto: RandomCargoCorpseSpawner
|
||||||
|
cost: 2
|
||||||
|
prob: 0.5
|
||||||
|
- proto: RandomCommandCorpseSpawner
|
||||||
|
cost: 5
|
||||||
|
prob: 0.5
|
||||||
|
- proto: RandomEngineerCorpseSpawner
|
||||||
|
cost: 2
|
||||||
|
prob: 0.5
|
||||||
|
- proto: RandomMedicCorpseSpawner
|
||||||
|
cost: 2
|
||||||
|
prob: 0.5
|
||||||
|
- proto: RandomScienceCorpseSpawner
|
||||||
|
cost: 2
|
||||||
|
prob: 0.5
|
||||||
|
- proto: RandomSecurityCorpseSpawner
|
||||||
|
cost: 2
|
||||||
|
prob: 0.5
|
||||||
|
- proto: RandomServiceCorpseSpawner
|
||||||
|
cost: 2
|
||||||
|
prob: 0.5
|
||||||
|
- proto: ResearchAndDevelopmentServerMachineCircuitboard
|
||||||
|
cost: 5
|
||||||
|
prob: 0.5
|
||||||
|
- proto: ResearchDisk10000
|
||||||
|
prob: 0.5
|
||||||
|
- proto: ResearchDisk5000
|
||||||
|
prob: 0.5
|
||||||
|
- proto: RipleyHarness
|
||||||
|
cost: 3
|
||||||
|
prob: 0.5
|
||||||
|
- proto: RPED
|
||||||
|
- proto: SpaceCash1000
|
||||||
|
- proto: SpaceCash10000
|
||||||
|
cost: 10
|
||||||
|
- proto: SpaceCash2500
|
||||||
|
cost: 3
|
||||||
|
- proto: SpaceCash5000
|
||||||
|
cost: 5
|
||||||
|
- proto: TechnologyDiskRare
|
||||||
|
cost: 5
|
||||||
|
prob: 0.5
|
||||||
|
- proto: ThrusterUnanchored
|
||||||
|
- proto: WaterTankHighCapacity
|
||||||
|
- proto: WeldingFuelTankHighCapacity
|
||||||
|
cost: 3
|
||||||
|
|
||||||
|
# Mob loot table
|
||||||
|
|
||||||
|
|
||||||
|
# Boss loot table
|
||||||
|
|
||||||
|
# Ores - these are guaranteed
|
||||||
# - Low value
|
# - Low value
|
||||||
- type: salvageLoot
|
- type: salvageLoot
|
||||||
id: OreTin
|
id: OreTin
|
||||||
desc: Veins of steel
|
|
||||||
guaranteed: true
|
guaranteed: true
|
||||||
loots:
|
loots:
|
||||||
- !type:BiomeMarkerLoot
|
- !type:BiomeMarkerLoot
|
||||||
@@ -14,7 +131,6 @@
|
|||||||
|
|
||||||
- type: salvageLoot
|
- type: salvageLoot
|
||||||
id: OreQuartz
|
id: OreQuartz
|
||||||
desc: Veins of quartz
|
|
||||||
guaranteed: true
|
guaranteed: true
|
||||||
loots:
|
loots:
|
||||||
- !type:BiomeMarkerLoot
|
- !type:BiomeMarkerLoot
|
||||||
@@ -27,7 +143,6 @@
|
|||||||
# - Medium value
|
# - Medium value
|
||||||
- type: salvageLoot
|
- type: salvageLoot
|
||||||
id: OreGold
|
id: OreGold
|
||||||
desc: Veins of gold ore
|
|
||||||
guaranteed: true
|
guaranteed: true
|
||||||
loots:
|
loots:
|
||||||
- !type:BiomeMarkerLoot
|
- !type:BiomeMarkerLoot
|
||||||
@@ -39,7 +154,6 @@
|
|||||||
|
|
||||||
- type: salvageLoot
|
- type: salvageLoot
|
||||||
id: OreSilver
|
id: OreSilver
|
||||||
desc: Veins of silver ore
|
|
||||||
guaranteed: true
|
guaranteed: true
|
||||||
loots:
|
loots:
|
||||||
- !type:BiomeMarkerLoot
|
- !type:BiomeMarkerLoot
|
||||||
@@ -52,7 +166,6 @@
|
|||||||
# - High value
|
# - High value
|
||||||
- type: salvageLoot
|
- type: salvageLoot
|
||||||
id: OrePlasma
|
id: OrePlasma
|
||||||
desc: Veins of plasma ore
|
|
||||||
guaranteed: true
|
guaranteed: true
|
||||||
loots:
|
loots:
|
||||||
- !type:BiomeMarkerLoot
|
- !type:BiomeMarkerLoot
|
||||||
@@ -64,7 +177,6 @@
|
|||||||
|
|
||||||
- type: salvageLoot
|
- type: salvageLoot
|
||||||
id: OreUranium
|
id: OreUranium
|
||||||
desc: Veins of uranium ore
|
|
||||||
guaranteed: true
|
guaranteed: true
|
||||||
loots:
|
loots:
|
||||||
- !type:BiomeMarkerLoot
|
- !type:BiomeMarkerLoot
|
||||||
@@ -76,7 +188,6 @@
|
|||||||
|
|
||||||
- type: salvageLoot
|
- type: salvageLoot
|
||||||
id: OreBananium
|
id: OreBananium
|
||||||
desc: Veins of bananium ore
|
|
||||||
guaranteed: true
|
guaranteed: true
|
||||||
loots:
|
loots:
|
||||||
- !type:BiomeMarkerLoot
|
- !type:BiomeMarkerLoot
|
||||||
@@ -88,7 +199,6 @@
|
|||||||
|
|
||||||
- type: salvageLoot
|
- type: salvageLoot
|
||||||
id: OreArtifactFragment
|
id: OreArtifactFragment
|
||||||
desc: artifact fragment-embedded rock
|
|
||||||
guaranteed: true
|
guaranteed: true
|
||||||
loots:
|
loots:
|
||||||
- !type:BiomeMarkerLoot
|
- !type:BiomeMarkerLoot
|
||||||
|
|||||||
@@ -4,45 +4,31 @@
|
|||||||
parent: FTLPoint
|
parent: FTLPoint
|
||||||
|
|
||||||
# Biome mods -> at least 1 required
|
# Biome mods -> at least 1 required
|
||||||
|
- type: salvageBiomeMod
|
||||||
|
id: Caves
|
||||||
|
biome: Caves
|
||||||
|
|
||||||
- type: salvageBiomeMod
|
- type: salvageBiomeMod
|
||||||
id: Grasslands
|
id: Grasslands
|
||||||
biome: Grasslands
|
biome: Grasslands
|
||||||
|
|
||||||
|
- type: salvageBiomeMod
|
||||||
|
id: Snow
|
||||||
|
cost: 1
|
||||||
|
biome: Snow
|
||||||
|
|
||||||
- type: salvageBiomeMod
|
- type: salvageBiomeMod
|
||||||
id: Lava
|
id: Lava
|
||||||
cost: 2
|
cost: 2
|
||||||
biome: Lava
|
biome: Lava
|
||||||
|
|
||||||
- type: salvageBiomeMod
|
|
||||||
id: Snow
|
|
||||||
biome: Snow
|
|
||||||
|
|
||||||
- type: salvageBiomeMod
|
|
||||||
id: Caves
|
|
||||||
cost: 1
|
|
||||||
biome: Caves
|
|
||||||
|
|
||||||
#- type: salvageBiomeMod
|
#- type: salvageBiomeMod
|
||||||
# id: Space
|
# id: Space
|
||||||
# cost: 1
|
# cost: 1
|
||||||
# weather: false
|
# weather: false
|
||||||
# biome: null
|
# biome: null
|
||||||
|
|
||||||
# Temperature mods -> not required
|
|
||||||
# Also whitelist it
|
|
||||||
|
|
||||||
# Weather mods -> not required
|
|
||||||
- type: salvageWeatherMod
|
|
||||||
id: SnowfallHeavy
|
|
||||||
weather: SnowfallHeavy
|
|
||||||
cost: 1
|
|
||||||
|
|
||||||
- type: salvageWeatherMod
|
|
||||||
id: Rain
|
|
||||||
weather: Rain
|
|
||||||
|
|
||||||
# Light mods -> required
|
# Light mods -> required
|
||||||
# At some stage with sub-biomes this will probably be moved onto the biome itself
|
|
||||||
- type: salvageLightMod
|
- type: salvageLightMod
|
||||||
id: Daylight
|
id: Daylight
|
||||||
desc: Daylight
|
desc: Daylight
|
||||||
@@ -65,62 +51,85 @@
|
|||||||
- type: salvageLightMod
|
- type: salvageLightMod
|
||||||
id: Night
|
id: Night
|
||||||
desc: Night time
|
desc: Night time
|
||||||
cost: 2
|
cost: 1
|
||||||
color: null
|
color: null
|
||||||
|
|
||||||
# Time mods -> at least 1 required
|
# Temperatures
|
||||||
- type: salvageTimeMod
|
- type: salvageTemperatureMod
|
||||||
id: StandardTime
|
id: RoomTemp
|
||||||
|
cost: 0
|
||||||
|
|
||||||
- type: salvageTimeMod
|
- type: salvageTemperatureMod
|
||||||
id: RushTime
|
id: Hot
|
||||||
desc: Rush
|
|
||||||
minDuration: 420
|
|
||||||
maxDuration: 465
|
|
||||||
cost: 1
|
cost: 1
|
||||||
|
temperature: 323.15 # 50C
|
||||||
# Misc mods
|
|
||||||
- type: salvageMod
|
|
||||||
id: LongDistance
|
|
||||||
desc: Long distance
|
|
||||||
|
|
||||||
# Dungeons
|
|
||||||
# For now just simple 1-dungeon setups
|
|
||||||
- type: salvageDungeonMod
|
|
||||||
id: Experiment
|
|
||||||
proto: Experiment
|
|
||||||
biomes:
|
biomes:
|
||||||
- Caves
|
- Caves
|
||||||
#- LowDesert
|
#- LowDesert
|
||||||
- Snow
|
|
||||||
- Grasslands
|
- Grasslands
|
||||||
|
- Lava
|
||||||
|
|
||||||
- type: salvageDungeonMod
|
- type: salvageTemperatureMod
|
||||||
id: LavaBrig
|
id: Burning
|
||||||
proto: LavaBrig
|
desc: High temperature
|
||||||
|
cost: 2
|
||||||
|
temperature: 423.15 # 200C
|
||||||
|
biomes:
|
||||||
|
- Caves
|
||||||
|
#- LowDesert
|
||||||
|
- Lava
|
||||||
|
|
||||||
|
- type: salvageTemperatureMod
|
||||||
|
id: Melting
|
||||||
|
desc: Extreme heat
|
||||||
|
cost: 4
|
||||||
|
temperature: 1273.15 # 1000C hot hot hot
|
||||||
biomes:
|
biomes:
|
||||||
- Lava
|
- Lava
|
||||||
|
|
||||||
|
- type: salvageTemperatureMod
|
||||||
|
id: Cold
|
||||||
|
cost: 1
|
||||||
|
temperature: 275.15 # 2C
|
||||||
|
biomes:
|
||||||
|
- Caves
|
||||||
|
#- LowDesert
|
||||||
|
- Grasslands
|
||||||
|
- Snow
|
||||||
|
|
||||||
|
- type: salvageTemperatureMod
|
||||||
|
id: Tundra
|
||||||
|
desc: Low temperature
|
||||||
|
cost: 2
|
||||||
|
temperature: 263.15 # -40C
|
||||||
|
biomes:
|
||||||
|
- Caves
|
||||||
|
- Snow
|
||||||
|
|
||||||
|
- type: salvageTemperatureMod
|
||||||
|
id: Frozen
|
||||||
|
desc: Extreme cold
|
||||||
|
cost: 4
|
||||||
|
temperature: 123.15 # -150C
|
||||||
|
biomes:
|
||||||
|
- Snow
|
||||||
|
|
||||||
# Air mixtures
|
# Air mixtures
|
||||||
- type: salvageAirMod
|
- type: salvageAirMod
|
||||||
id: Space
|
id: Space
|
||||||
desc: No atmosphere
|
desc: No atmosphere
|
||||||
space: true
|
space: true
|
||||||
cost: 1
|
cost: 2
|
||||||
biomes:
|
biomes:
|
||||||
- Caves
|
- Caves
|
||||||
- Lava
|
- Lava
|
||||||
|
|
||||||
- type: salvageAirMod
|
- type: salvageAirMod
|
||||||
id: Breathable
|
id: Breathable
|
||||||
|
cost: 0
|
||||||
gases:
|
gases:
|
||||||
- 21.824779 # oxygen
|
- 21.824779 # oxygen
|
||||||
- 82.10312 # nitrogen
|
- 82.10312 # nitrogen
|
||||||
biomes:
|
|
||||||
- Caves
|
|
||||||
#- LowDesert
|
|
||||||
- Snow
|
|
||||||
- Grasslands
|
|
||||||
|
|
||||||
- type: salvageAirMod
|
- type: salvageAirMod
|
||||||
id: Sleepy
|
id: Sleepy
|
||||||
@@ -196,64 +205,29 @@
|
|||||||
- Caves
|
- Caves
|
||||||
- Lava
|
- Lava
|
||||||
|
|
||||||
# Temperatures
|
# Weather mods -> not required
|
||||||
|
#- type: salvageWeatherMod
|
||||||
|
# id: SnowfallHeavy
|
||||||
|
# weather: SnowfallHeavy
|
||||||
|
# cost: 1
|
||||||
|
#
|
||||||
|
#- type: salvageWeatherMod
|
||||||
|
# id: Rain
|
||||||
|
# weather: Rain
|
||||||
|
|
||||||
- type: salvageTemperatureMod
|
# Dungeons
|
||||||
id: RoomTemp
|
# For now just simple 1-dungeon setups
|
||||||
|
- type: salvageDungeonMod
|
||||||
|
id: Experiment
|
||||||
|
proto: Experiment
|
||||||
biomes:
|
biomes:
|
||||||
- Caves
|
- Caves
|
||||||
#- LowDesert
|
#- LowDesert
|
||||||
|
- Snow
|
||||||
- Grasslands
|
- Grasslands
|
||||||
|
|
||||||
- type: salvageTemperatureMod
|
- type: salvageDungeonMod
|
||||||
id: Hot
|
id: LavaBrig
|
||||||
temperature: 323.15 # 50C
|
proto: LavaBrig
|
||||||
biomes:
|
|
||||||
- Caves
|
|
||||||
#- LowDesert
|
|
||||||
- Grasslands
|
|
||||||
- Lava
|
|
||||||
|
|
||||||
- type: salvageTemperatureMod
|
|
||||||
id: Burning
|
|
||||||
desc: High temperature
|
|
||||||
cost: 1
|
|
||||||
temperature: 423.15 # 200C
|
|
||||||
biomes:
|
|
||||||
- Caves
|
|
||||||
#- LowDesert
|
|
||||||
- Lava
|
|
||||||
|
|
||||||
- type: salvageTemperatureMod
|
|
||||||
id: Melting
|
|
||||||
desc: Extreme heat
|
|
||||||
cost: 4
|
|
||||||
temperature: 1273.15 # 1000C hot hot hot
|
|
||||||
biomes:
|
biomes:
|
||||||
- Lava
|
- Lava
|
||||||
|
|
||||||
- type: salvageTemperatureMod
|
|
||||||
id: Cold
|
|
||||||
temperature: 275.15 # 2C
|
|
||||||
biomes:
|
|
||||||
- Caves
|
|
||||||
#- LowDesert
|
|
||||||
- Grasslands
|
|
||||||
- Snow
|
|
||||||
|
|
||||||
- type: salvageTemperatureMod
|
|
||||||
id: Tundra
|
|
||||||
desc: Low temperature
|
|
||||||
cost: 2
|
|
||||||
temperature: 263.15 # -40C
|
|
||||||
biomes:
|
|
||||||
- Caves
|
|
||||||
- Snow
|
|
||||||
|
|
||||||
- type: salvageTemperatureMod
|
|
||||||
id: Frozen
|
|
||||||
desc: Extreme cold
|
|
||||||
cost: 3
|
|
||||||
temperature: 123.15 # -150C
|
|
||||||
biomes:
|
|
||||||
- Snow
|
|
||||||
|
|||||||
Reference in New Issue
Block a user