Expeditions rework (#18960)
This commit is contained in:
@@ -4,6 +4,7 @@ using Content.Client.Stylesheets;
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Parallax.Biomes;
|
||||
using Content.Shared.Procedural;
|
||||
using Content.Shared.Salvage;
|
||||
using Content.Shared.Salvage.Expeditions;
|
||||
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++)
|
||||
{
|
||||
var missionParams = state.Missions[i];
|
||||
var config = missionParams.MissionType;
|
||||
var mission = _salvage.GetMission(missionParams.MissionType, missionParams.Difficulty, missionParams.Seed);
|
||||
var difficultyId = "Moderate";
|
||||
var difficultyProto = _prototype.Index<SalvageDifficultyPrototype>(difficultyId);
|
||||
// TODO: Selectable difficulty soon.
|
||||
var mission = _salvage.GetMission(difficultyProto, missionParams.Seed);
|
||||
|
||||
// Mission title
|
||||
var missionStripe = new StripeBack()
|
||||
@@ -64,7 +67,7 @@ public sealed partial class SalvageExpeditionWindow : FancyWindow,
|
||||
|
||||
missionStripe.AddChild(new Label()
|
||||
{
|
||||
Text = Loc.GetString($"salvage-expedition-type-{config.ToString()}"),
|
||||
Text = Loc.GetString($"salvage-expedition-type"),
|
||||
HorizontalAlignment = HAlignment.Center,
|
||||
Margin = new Thickness(0f, 5f, 0f, 5f),
|
||||
});
|
||||
@@ -81,48 +84,25 @@ public sealed partial class SalvageExpeditionWindow : FancyWindow,
|
||||
Text = Loc.GetString("salvage-expedition-window-difficulty")
|
||||
});
|
||||
|
||||
Color difficultyColor;
|
||||
|
||||
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();
|
||||
}
|
||||
var difficultyColor = difficultyProto.Color;
|
||||
|
||||
lBox.AddChild(new Label
|
||||
{
|
||||
Text = Loc.GetString($"salvage-expedition-difficulty-{missionParams.Difficulty.ToString()}"),
|
||||
Text = Loc.GetString("salvage-expedition-difficulty-Moderate"),
|
||||
FontColorOverride = difficultyColor,
|
||||
HorizontalAlignment = HAlignment.Left,
|
||||
Margin = new Thickness(0f, 0f, 0f, 5f),
|
||||
});
|
||||
|
||||
// Details
|
||||
var details = _salvage.GetMissionDescription(mission);
|
||||
|
||||
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
|
||||
{
|
||||
Text = details,
|
||||
Text = difficultyProto.RecommendedPlayers.ToString(),
|
||||
FontColorOverride = StyleNano.NanoGold,
|
||||
HorizontalAlignment = HAlignment.Left,
|
||||
Margin = new Thickness(0f, 0f, 0f, 5f),
|
||||
@@ -168,7 +148,7 @@ public sealed partial class SalvageExpeditionWindow : FancyWindow,
|
||||
|
||||
lBox.AddChild(new Label
|
||||
{
|
||||
Text = Loc.GetString(_prototype.Index<SalvageBiomeMod>(biome).ID),
|
||||
Text = Loc.GetString(_prototype.Index<SalvageBiomeModPrototype>(biome).ID),
|
||||
FontColorOverride = StyleNano.NanoGold,
|
||||
HorizontalAlignment = HAlignment.Left,
|
||||
Margin = new Thickness(0f, 0f, 0f, 5f),
|
||||
@@ -190,29 +170,6 @@ public sealed partial class SalvageExpeditionWindow : FancyWindow,
|
||||
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
|
||||
var claimButton = new Button()
|
||||
{
|
||||
@@ -289,7 +246,7 @@ public sealed partial class SalvageExpeditionWindow : FancyWindow,
|
||||
else
|
||||
{
|
||||
var cooldown = _cooldown
|
||||
? TimeSpan.FromSeconds(_cfgManager.GetCVar(CCVars.SalvageExpeditionFailedCooldown))
|
||||
? TimeSpan.FromSeconds(_cfgManager.GetCVar(CCVars.SalvageExpeditionCooldown))
|
||||
: TimeSpan.FromSeconds(_cfgManager.GetCVar(CCVars.SalvageExpeditionCooldown));
|
||||
|
||||
NextOfferBar.Value = 1f - (float) (remaining / cooldown);
|
||||
|
||||
@@ -83,17 +83,14 @@ public sealed partial class DungeonJob
|
||||
var lastDirection = new Dictionary<Vector2i, Direction>();
|
||||
costSoFar[start] = 0f;
|
||||
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)
|
||||
{
|
||||
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();
|
||||
|
||||
@@ -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),
|
||||
};
|
||||
|
||||
/// <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.Expeditions;
|
||||
|
||||
@@ -18,7 +19,7 @@ public sealed partial class SalvageSystem
|
||||
SpawnMission(missionparams, station.Value);
|
||||
|
||||
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);
|
||||
UpdateConsoles(data);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ using Robust.Shared.CPUJob.JobQueues;
|
||||
using Robust.Shared.CPUJob.JobQueues.Queues;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Content.Shared.Procedural;
|
||||
using Content.Shared.Salvage.Expeditions;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
@@ -26,7 +27,6 @@ public sealed partial class SalvageSystem
|
||||
private const double SalvageJobTime = 0.002;
|
||||
|
||||
private float _cooldown;
|
||||
private float _failedCooldown;
|
||||
|
||||
private void InitializeExpeditions()
|
||||
{
|
||||
@@ -43,9 +43,7 @@ public sealed partial class SalvageSystem
|
||||
SubscribeLocalEvent<SalvageStructureComponent, ExaminedEvent>(OnStructureExamine);
|
||||
|
||||
_cooldown = _configurationManager.GetCVar(CCVars.SalvageExpeditionCooldown);
|
||||
_failedCooldown = _configurationManager.GetCVar(CCVars.SalvageExpeditionFailedCooldown);
|
||||
_configurationManager.OnValueChanged(CCVars.SalvageExpeditionCooldown, SetCooldownChange);
|
||||
_configurationManager.OnValueChanged(CCVars.SalvageExpeditionFailedCooldown, SetFailedCooldownChange);
|
||||
}
|
||||
|
||||
private void OnExpeditionGetState(EntityUid uid, SalvageExpeditionComponent component, ref ComponentGetState args)
|
||||
@@ -59,7 +57,6 @@ public sealed partial class SalvageSystem
|
||||
private void ShutdownExpeditions()
|
||||
{
|
||||
_configurationManager.UnsubValueChanged(CCVars.SalvageExpeditionCooldown, SetCooldownChange);
|
||||
_configurationManager.UnsubValueChanged(CCVars.SalvageExpeditionFailedCooldown, SetFailedCooldownChange);
|
||||
}
|
||||
|
||||
private void SetCooldownChange(float obj)
|
||||
@@ -77,20 +74,6 @@ public sealed partial class SalvageSystem
|
||||
_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)
|
||||
{
|
||||
component.Stream?.Stop();
|
||||
@@ -110,7 +93,7 @@ public sealed partial class SalvageSystem
|
||||
// Finish mission
|
||||
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);
|
||||
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.NextOffer = _timing.CurTime + TimeSpan.FromSeconds(_cooldown);
|
||||
Announce(uid, Loc.GetString("salvage-expedition-mission-completed"));
|
||||
component.ActiveMission = 0;
|
||||
component.Cooldown = true;
|
||||
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)
|
||||
{
|
||||
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++)
|
||||
{
|
||||
_random.Shuffle(configs);
|
||||
var rating = difficulties[i];
|
||||
|
||||
foreach (var config in configs)
|
||||
var mission = new SalvageMissionParams
|
||||
{
|
||||
var mission = new SalvageMissionParams
|
||||
{
|
||||
Index = component.NextIndex,
|
||||
MissionType = config,
|
||||
Seed = _random.Next(),
|
||||
Difficulty = rating,
|
||||
};
|
||||
Index = component.NextIndex,
|
||||
Seed = _random.Next(),
|
||||
Difficulty = "Moderate",
|
||||
};
|
||||
|
||||
component.Missions[component.NextIndex++] = mission;
|
||||
break;
|
||||
}
|
||||
component.Missions[component.NextIndex++] = mission;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -271,13 +174,13 @@ public sealed partial class SalvageSystem
|
||||
SalvageJobTime,
|
||||
EntityManager,
|
||||
_timing,
|
||||
_logManager,
|
||||
_mapManager,
|
||||
_prototypeManager,
|
||||
_anchorable,
|
||||
_biome,
|
||||
_dungeon,
|
||||
_metaData,
|
||||
this,
|
||||
station,
|
||||
missionParams,
|
||||
cancelToken.Token);
|
||||
@@ -290,19 +193,4 @@ public sealed partial class SalvageSystem
|
||||
{
|
||||
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.
|
||||
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)
|
||||
continue;
|
||||
@@ -109,22 +109,11 @@ public sealed partial class SalvageSystem
|
||||
Announce(args.MapUid, Loc.GetString("salvage-expedition-announcement-dungeon", ("direction", component.DungeonLocation.GetDir())));
|
||||
|
||||
component.Stage = ExpeditionStage.Running;
|
||||
Dirty(component);
|
||||
Dirty(args.MapUid, component);
|
||||
}
|
||||
|
||||
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) ||
|
||||
!TryComp<SalvageExpeditionDataComponent>(expedition.Station, out var station))
|
||||
{
|
||||
@@ -169,7 +158,7 @@ public sealed partial class SalvageSystem
|
||||
Dirty(uid, comp);
|
||||
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;
|
||||
Dirty(uid, comp);
|
||||
@@ -210,72 +199,5 @@ public sealed partial class SalvageSystem
|
||||
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 IConfigurationManager _configurationManager = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly ILogManager _logManager = default!;
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly AnchorableSystem _anchorable = default!;
|
||||
[Dependency] private readonly BiomeSystem _biome = default!;
|
||||
[Dependency] private readonly CargoSystem _cargo = default!;
|
||||
[Dependency] private readonly DungeonSystem _dungeon = default!;
|
||||
[Dependency] private readonly MapLoaderSystem _map = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Threading;
|
||||
@@ -19,6 +20,7 @@ using Content.Shared.Parallax.Biomes;
|
||||
using Content.Shared.Physics;
|
||||
using Content.Shared.Procedural;
|
||||
using Content.Shared.Procedural.Loot;
|
||||
using Content.Shared.Random;
|
||||
using Content.Shared.Salvage;
|
||||
using Content.Shared.Salvage.Expeditions;
|
||||
using Content.Shared.Salvage.Expeditions.Modifiers;
|
||||
@@ -29,6 +31,7 @@ using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.Salvage;
|
||||
|
||||
@@ -42,22 +45,23 @@ public sealed class SpawnSalvageMissionJob : Job<bool>
|
||||
private readonly BiomeSystem _biome;
|
||||
private readonly DungeonSystem _dungeon;
|
||||
private readonly MetaDataSystem _metaData;
|
||||
private readonly SalvageSystem _salvage;
|
||||
|
||||
public readonly EntityUid Station;
|
||||
private readonly SalvageMissionParams _missionParams;
|
||||
|
||||
private readonly ISawmill _sawmill;
|
||||
|
||||
public SpawnSalvageMissionJob(
|
||||
double maxTime,
|
||||
IEntityManager entManager,
|
||||
IGameTiming timing,
|
||||
ILogManager logManager,
|
||||
IMapManager mapManager,
|
||||
IPrototypeManager protoManager,
|
||||
AnchorableSystem anchorable,
|
||||
BiomeSystem biome,
|
||||
DungeonSystem dungeon,
|
||||
MetaDataSystem metaData,
|
||||
SalvageSystem salvage,
|
||||
EntityUid station,
|
||||
SalvageMissionParams missionParams,
|
||||
CancellationToken cancellation = default) : base(maxTime, cancellation)
|
||||
@@ -70,15 +74,17 @@ public sealed class SpawnSalvageMissionJob : Job<bool>
|
||||
_biome = biome;
|
||||
_dungeon = dungeon;
|
||||
_metaData = metaData;
|
||||
_salvage = salvage;
|
||||
Station = station;
|
||||
_missionParams = missionParams;
|
||||
_sawmill = logManager.GetSawmill("salvage_job");
|
||||
#if !DEBUG
|
||||
_sawmill.Level = LogLevel.Info;
|
||||
#endif
|
||||
}
|
||||
|
||||
protected override async Task<bool> Process()
|
||||
{
|
||||
Logger.DebugS("salvage", $"Spawning salvage mission with seed {_missionParams.Seed}");
|
||||
var config = _missionParams.MissionType;
|
||||
_sawmill.Debug("salvage", $"Spawning salvage mission with seed {_missionParams.Seed}");
|
||||
var mapId = _mapManager.CreateMap();
|
||||
var mapUid = _mapManager.GetMapEntityId(mapId);
|
||||
_mapManager.AddUninitializedMap(mapId);
|
||||
@@ -88,16 +94,17 @@ public sealed class SpawnSalvageMissionJob : Job<bool>
|
||||
|
||||
// Setup mission configs
|
||||
// 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>()
|
||||
.GetMission(_missionParams.MissionType, _missionParams.Difficulty, _missionParams.Seed);
|
||||
.GetMission(difficultyProto, _missionParams.Seed);
|
||||
|
||||
var missionBiome = _prototypeManager.Index<SalvageBiomeMod>(mission.Biome);
|
||||
BiomeComponent? biome = null;
|
||||
var missionBiome = _prototypeManager.Index<SalvageBiomeModPrototype>(mission.Biome);
|
||||
|
||||
if (missionBiome.BiomePrototype != null)
|
||||
{
|
||||
biome = _entManager.AddComponent<BiomeComponent>(mapUid);
|
||||
var biome = _entManager.AddComponent<BiomeComponent>(mapUid);
|
||||
var biomeSystem = _entManager.System<BiomeSystem>();
|
||||
biomeSystem.SetTemplate(biome, _prototypeManager.Index<BiomeTemplatePrototype>(missionBiome.BiomePrototype));
|
||||
biomeSystem.SetSeed(biome, mission.Seed);
|
||||
@@ -125,7 +132,7 @@ public sealed class SpawnSalvageMissionJob : Job<bool>
|
||||
{
|
||||
var lighting = _entManager.EnsureComponent<MapLightComponent>(mapUid);
|
||||
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.EndTime = _timing.CurTime + mission.Duration;
|
||||
expedition.MissionParams = _missionParams;
|
||||
expedition.Difficulty = _missionParams.Difficulty;
|
||||
expedition.Rewards = mission.Rewards;
|
||||
|
||||
// Don't want consoles to have the incorrect name until refreshed.
|
||||
var ftlUid = _entManager.CreateEntityUninitialized("FTLPoint", new EntityCoordinates(mapUid, grid.TileSizeHalfVector));
|
||||
@@ -151,29 +156,23 @@ public sealed class SpawnSalvageMissionJob : Job<bool>
|
||||
// We'll use the dungeon rotation as the spawn angle
|
||||
var dungeonRotation = _dungeon.GetDungeonRotation(_missionParams.Seed);
|
||||
|
||||
Dungeon dungeon = default!;
|
||||
var maxDungeonOffset = minDungeonOffset + 12;
|
||||
var dungeonOffsetDistance = minDungeonOffset + (maxDungeonOffset - minDungeonOffset) * random.NextFloat();
|
||||
var dungeonOffset = new Vector2(0f, dungeonOffsetDistance);
|
||||
dungeonOffset = dungeonRotation.RotateVec(dungeonOffset);
|
||||
var dungeonMod = _prototypeManager.Index<SalvageDungeonModPrototype>(mission.Dungeon);
|
||||
var dungeonConfig = _prototypeManager.Index<DungeonConfigPrototype>(dungeonMod.Proto);
|
||||
var dungeon = await WaitAsyncTask(_dungeon.GenerateDungeonAsync(dungeonConfig, mapUid, grid, (Vector2i) dungeonOffset,
|
||||
_missionParams.Seed));
|
||||
|
||||
if (config != SalvageMissionType.Mining)
|
||||
// Aborty
|
||||
if (dungeon.Rooms.Count == 0)
|
||||
{
|
||||
var maxDungeonOffset = minDungeonOffset + 12;
|
||||
var dungeonOffsetDistance = minDungeonOffset + (maxDungeonOffset - minDungeonOffset) * random.NextFloat();
|
||||
var dungeonOffset = new Vector2(0f, dungeonOffsetDistance);
|
||||
dungeonOffset = dungeonRotation.RotateVec(dungeonOffset);
|
||||
var dungeonMod = _prototypeManager.Index<SalvageDungeonMod>(mission.Dungeon);
|
||||
var dungeonConfig = _prototypeManager.Index<DungeonConfigPrototype>(dungeonMod.Proto);
|
||||
dungeon =
|
||||
await WaitAsyncTask(_dungeon.GenerateDungeonAsync(dungeonConfig, mapUid, grid, (Vector2i) dungeonOffset,
|
||||
_missionParams.Seed));
|
||||
|
||||
// Aborty
|
||||
if (dungeon.Rooms.Count == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
expedition.DungeonLocation = dungeonOffset;
|
||||
return false;
|
||||
}
|
||||
|
||||
expedition.DungeonLocation = dungeonOffset;
|
||||
|
||||
List<Vector2i> reservedTiles = new();
|
||||
|
||||
foreach (var tile in grid.GetTilesIntersecting(new Circle(Vector2.Zero, landingPadRadius), false))
|
||||
@@ -184,24 +183,14 @@ public sealed class SpawnSalvageMissionJob : Job<bool>
|
||||
reservedTiles.Add(tile.GridIndices);
|
||||
}
|
||||
|
||||
// Mission setup
|
||||
switch (config)
|
||||
{
|
||||
case SalvageMissionType.Mining:
|
||||
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();
|
||||
}
|
||||
var budgetEntries = new List<IBudgetEntry>();
|
||||
|
||||
/*
|
||||
* GUARANTEED LOOT
|
||||
*/
|
||||
|
||||
// Handle loot
|
||||
// We'll always add this loot if possible
|
||||
// mainly used for ore layers.
|
||||
foreach (var lootProto in _prototypeManager.EnumeratePrototypes<SalvageLootPrototype>())
|
||||
{
|
||||
if (!lootProto.Guaranteed)
|
||||
@@ -210,10 +199,104 @@ public sealed class SpawnSalvageMissionJob : Job<bool>
|
||||
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;
|
||||
}
|
||||
|
||||
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++)
|
||||
{
|
||||
@@ -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);
|
||||
|
||||
/// <summary>
|
||||
/// Cooldown for successful missions.
|
||||
/// Duration for missions
|
||||
/// </summary>
|
||||
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>
|
||||
SalvageExpeditionFailedCooldown = CVarDef.Create("salvage.expedition_failed_cooldown", 900f, CVar.REPLICATED);
|
||||
SalvageExpeditionCooldown = CVarDef.Create("salvage.expedition_cooldown", 780f, CVar.REPLICATED);
|
||||
|
||||
/*
|
||||
* 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.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
|
||||
|
||||
namespace Content.Shared.Procedural.Loot;
|
||||
|
||||
@@ -17,14 +15,6 @@ public sealed class SalvageLootPrototype : IPrototype
|
||||
/// </summary>
|
||||
[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>
|
||||
/// All of the loot rules
|
||||
/// </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;
|
||||
|
||||
/// <inheritdoc/>
|
||||
[DataField("biomes", customTypeSerializer: typeof(PrototypeIdListSerializer<SalvageBiomeMod>))]
|
||||
[DataField("biomes", customTypeSerializer: typeof(PrototypeIdListSerializer<SalvageBiomeModPrototype>))]
|
||||
public List<string>? Biomes { get; private set; } = null;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Content.Shared.Salvage.Expeditions.Modifiers;
|
||||
/// Affects the biome to be used for salvage.
|
||||
/// </summary>
|
||||
[Prototype("salvageBiomeMod")]
|
||||
public sealed class SalvageBiomeMod : IPrototype, ISalvageMod
|
||||
public sealed class SalvageBiomeModPrototype : IPrototype, ISalvageMod
|
||||
{
|
||||
[IdDataField] public string ID { get; } = default!;
|
||||
|
||||
@@ -6,7 +6,7 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototy
|
||||
namespace Content.Shared.Salvage.Expeditions.Modifiers;
|
||||
|
||||
[Prototype("salvageDungeonMod")]
|
||||
public sealed class SalvageDungeonMod : IPrototype, IBiomeSpecificMod
|
||||
public sealed class SalvageDungeonModPrototype : IPrototype, IBiomeSpecificMod
|
||||
{
|
||||
[IdDataField] public string ID { get; } = default!;
|
||||
|
||||
@@ -17,7 +17,7 @@ public sealed class SalvageDungeonMod : IPrototype, IBiomeSpecificMod
|
||||
public float Cost { get; private set; } = 0f;
|
||||
|
||||
/// <inheridoc/>
|
||||
[DataField("biomes", customTypeSerializer: typeof(PrototypeIdListSerializer<SalvageBiomeMod>))]
|
||||
[DataField("biomes", customTypeSerializer: typeof(PrototypeIdListSerializer<SalvageBiomeModPrototype>))]
|
||||
public List<string>? Biomes { get; private set; } = null;
|
||||
|
||||
/// <summary>
|
||||
@@ -15,7 +15,7 @@ public sealed class SalvageLightMod : IPrototype, IBiomeSpecificMod
|
||||
public float Cost { get; private set; } = 0f;
|
||||
|
||||
/// <inheritdoc/>
|
||||
[DataField("biomes", customTypeSerializer: typeof(PrototypeIdListSerializer<SalvageBiomeMod>))]
|
||||
[DataField("biomes", customTypeSerializer: typeof(PrototypeIdListSerializer<SalvageBiomeModPrototype>))]
|
||||
public List<string>? Biomes { get; private set; } = null;
|
||||
|
||||
[DataField("color", required: true)] public Color? Color;
|
||||
|
||||
@@ -16,7 +16,7 @@ public sealed class SalvageTemperatureMod : IPrototype, IBiomeSpecificMod
|
||||
public float Cost { get; private set; } = 0f;
|
||||
|
||||
/// <inheritdoc/>
|
||||
[DataField("biomes", customTypeSerializer: typeof(PrototypeIdListSerializer<SalvageBiomeMod>))]
|
||||
[DataField("biomes", customTypeSerializer: typeof(PrototypeIdListSerializer<SalvageBiomeModPrototype>))]
|
||||
public List<string>? Biomes { get; private set; } = null;
|
||||
|
||||
/// <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;
|
||||
|
||||
/// <inheritdoc/>
|
||||
[DataField("biomes", customTypeSerializer: typeof(PrototypeIdListSerializer<SalvageBiomeMod>))]
|
||||
[DataField("biomes", customTypeSerializer: typeof(PrototypeIdListSerializer<SalvageBiomeModPrototype>))]
|
||||
public List<string>? Biomes { get; private set; } = null;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -72,28 +72,14 @@ public sealed partial class SalvageExpeditionDataComponent : Component
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed record SalvageMissionParams : IComparable<SalvageMissionParams>
|
||||
public sealed record SalvageMissionParams
|
||||
{
|
||||
[ViewVariables]
|
||||
public ushort Index;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public SalvageMissionType MissionType;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)] public int Seed;
|
||||
|
||||
/// <summary>
|
||||
/// 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);
|
||||
}
|
||||
public string Difficulty = string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -102,16 +88,13 @@ public sealed record SalvageMissionParams : IComparable<SalvageMissionParams>
|
||||
/// </summary>
|
||||
public sealed record SalvageMission(
|
||||
int Seed,
|
||||
DifficultyRating Difficulty,
|
||||
string Dungeon,
|
||||
string Faction,
|
||||
SalvageMissionType Mission,
|
||||
string Biome,
|
||||
string Air,
|
||||
float Temperature,
|
||||
Color? Color,
|
||||
TimeSpan Duration,
|
||||
List<string> Rewards,
|
||||
List<string> Modifiers)
|
||||
{
|
||||
/// <summary>
|
||||
@@ -120,12 +103,7 @@ public sealed record SalvageMission(
|
||||
public readonly int Seed = Seed;
|
||||
|
||||
/// <summary>
|
||||
/// Difficulty rating.
|
||||
/// </summary>
|
||||
public DifficultyRating Difficulty = Difficulty;
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="SalvageDungeonMod"/> to be used.
|
||||
/// <see cref="SalvageDungeonModPrototype"/> to be used.
|
||||
/// </summary>
|
||||
public readonly string Dungeon = Dungeon;
|
||||
|
||||
@@ -134,11 +112,6 @@ public sealed record SalvageMission(
|
||||
/// </summary>
|
||||
public readonly string Faction = Faction;
|
||||
|
||||
/// <summary>
|
||||
/// Underlying mission params that generated this.
|
||||
/// </summary>
|
||||
public readonly SalvageMissionType Mission = Mission;
|
||||
|
||||
/// <summary>
|
||||
/// Biome to be used for the mission.
|
||||
/// </summary>
|
||||
@@ -164,11 +137,6 @@ public sealed record SalvageMission(
|
||||
/// </summary>
|
||||
public TimeSpan Duration = Duration;
|
||||
|
||||
/// <summary>
|
||||
/// The list of items to order on mission completion.
|
||||
/// </summary>
|
||||
public List<string> Rewards = Rewards;
|
||||
|
||||
/// <summary>
|
||||
/// Modifiers (outside of the above) applied to the mission.
|
||||
/// </summary>
|
||||
|
||||
@@ -5,20 +5,14 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototy
|
||||
namespace Content.Shared.Salvage.Expeditions;
|
||||
|
||||
[Prototype("salvageFaction")]
|
||||
public sealed class SalvageFactionPrototype : IPrototype, ISalvageMod
|
||||
public sealed class SalvageFactionPrototype : IPrototype
|
||||
{
|
||||
[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; } = 0f;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("groups", required: true)]
|
||||
public List<SalvageMobGroup> MobGroups = default!;
|
||||
[ViewVariables(VVAccess.ReadWrite), DataField("entries", required: true)]
|
||||
public List<SalvageMobEntry> MobGroups = new();
|
||||
|
||||
/// <summary>
|
||||
/// 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 Content.Shared.CCVar;
|
||||
using Content.Shared.Dataset;
|
||||
using Content.Shared.Procedural;
|
||||
using Content.Shared.Procedural.Loot;
|
||||
using Content.Shared.Random;
|
||||
using Content.Shared.Random.Helpers;
|
||||
using Content.Shared.Salvage.Expeditions;
|
||||
using Content.Shared.Salvage.Expeditions.Modifiers;
|
||||
using Robust.Shared.Configuration;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Serialization;
|
||||
@@ -13,73 +17,14 @@ namespace Content.Shared.Salvage;
|
||||
|
||||
public abstract class SharedSalvageSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly ILocalizationManager _loc = default!;
|
||||
[Dependency] protected readonly IConfigurationManager CfgManager = 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>
|
||||
/// Gets the amount of structures to destroy.
|
||||
/// Main loot table for salvage expeditions.
|
||||
/// </summary>
|
||||
public int GetStructureCount(DifficultyRating baseRating)
|
||||
{
|
||||
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;
|
||||
}
|
||||
[ValidatePrototypeId<SalvageLootPrototype>]
|
||||
public const string ExpeditionsLootProto = "SalvageLoot";
|
||||
|
||||
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))}";
|
||||
}
|
||||
|
||||
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
|
||||
var rating = (float) GetDifficulty(difficulty);
|
||||
// Don't want easy missions to have any negative modifiers but also want
|
||||
// easy to be a 1 for difficulty.
|
||||
rating -= 1f;
|
||||
var modifierBudget = difficulty.ModifierBudget;
|
||||
var rand = new System.Random(seed);
|
||||
var faction = GetMod<SalvageFactionPrototype>(rand, ref rating);
|
||||
var biome = GetMod<SalvageBiomeMod>(rand, ref rating);
|
||||
var dungeon = GetBiomeMod<SalvageDungeonMod>(biome.ID, rand, ref rating);
|
||||
|
||||
// Run budget in order of priority
|
||||
// - 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 air = GetBiomeMod<SalvageAirMod>(biome.ID, rand, ref rating);
|
||||
if (air.Description != string.Empty)
|
||||
{
|
||||
mods.Add(air.Description);
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
mods.Add(temp.Description);
|
||||
}
|
||||
|
||||
var light = GetBiomeMod<SalvageLightMod>(biome.ID, rand, ref rating);
|
||||
if (light.Description != string.Empty)
|
||||
{
|
||||
mods.Add(light.Description);
|
||||
}
|
||||
|
||||
var time = GetMod<SalvageTimeMod>(rand, ref rating);
|
||||
// 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);
|
||||
var duration = TimeSpan.FromSeconds(CfgManager.GetCVar(CCVars.SalvageExpeditionDuration));
|
||||
|
||||
if (time.Description != string.Empty)
|
||||
{
|
||||
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);
|
||||
return new SalvageMission(seed, dungeon.ID, faction.ID, biome.ID, air.ID, temp.Temperature, light.Color, duration, mods);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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]
|
||||
expedition_cooldown = 30.0
|
||||
expedition_failed_cooldown = 30.0
|
||||
|
||||
[shuttle]
|
||||
grid_fill = false
|
||||
|
||||
@@ -4,8 +4,7 @@ salvage-expedition-structure-remaining = {$count ->
|
||||
*[other] {$count} structures remaining.
|
||||
}
|
||||
|
||||
salvage-expedition-megafauna-remaining = {$count} megafauna remaining.
|
||||
|
||||
salvage-expedition-type = Mission
|
||||
salvage-expedition-window-title = Salvage expeditions
|
||||
salvage-expedition-window-difficulty = Difficulty:
|
||||
salvage-expedition-window-details = Details:
|
||||
@@ -13,31 +12,17 @@ salvage-expedition-window-hostiles = Hostiles:
|
||||
salvage-expedition-window-duration = Duration:
|
||||
salvage-expedition-window-biome = Biome:
|
||||
salvage-expedition-window-modifiers = Modifiers:
|
||||
salvage-expedition-window-rewards = Rewards:
|
||||
salvage-expedition-window-claimed = Claimed
|
||||
salvage-expedition-window-claim = Claim
|
||||
|
||||
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-Hazardous = Hazardous
|
||||
salvage-expedition-difficulty-Extreme = Extreme
|
||||
|
||||
salvage-expedition-difficulty-players = Recommended salvagers:
|
||||
|
||||
# Runner
|
||||
salvage-expedition-not-all-present = Not all salvagers are aboard the shuttle!
|
||||
|
||||
|
||||
@@ -164,7 +164,14 @@
|
||||
parent: MobCarp
|
||||
suffix: Dungeon
|
||||
components:
|
||||
- type: MobThresholds
|
||||
thresholds:
|
||||
0: Alive
|
||||
50: Dead
|
||||
- type: SlowOnDamage
|
||||
speedModifierThresholds:
|
||||
25: 0.7
|
||||
- type: MeleeWeapon
|
||||
damage:
|
||||
types:
|
||||
Slash: 5
|
||||
Slash: 6
|
||||
|
||||
@@ -60,6 +60,9 @@
|
||||
thresholds:
|
||||
0: Alive
|
||||
50: Dead
|
||||
- type: SlowOnDamage
|
||||
speedModifierThresholds:
|
||||
25: 0.5
|
||||
- type: Stamina
|
||||
critThreshold: 200
|
||||
- type: Bloodstream
|
||||
@@ -129,7 +132,7 @@
|
||||
- type: MobThresholds
|
||||
thresholds:
|
||||
0: Alive
|
||||
75: Dead
|
||||
100: Dead
|
||||
- type: Stamina
|
||||
critThreshold: 300
|
||||
- type: SlowOnDamage
|
||||
@@ -162,18 +165,16 @@
|
||||
- type: MobThresholds
|
||||
thresholds:
|
||||
0: Alive
|
||||
150: Dead
|
||||
80: Dead
|
||||
- type: SlowOnDamage
|
||||
speedModifierThresholds:
|
||||
40: 0.7
|
||||
- type: MeleeWeapon
|
||||
damage:
|
||||
groups:
|
||||
Brute: 5
|
||||
Brute: 6
|
||||
- type: MovementSpeedModifier
|
||||
baseWalkSpeed: 2.0
|
||||
baseSprintSpeed: 2.5
|
||||
- type: SlowOnDamage
|
||||
speedModifierThresholds:
|
||||
100: 0.4
|
||||
50: 0.7
|
||||
baseSprintSpeed: 4
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
fix1:
|
||||
@@ -202,20 +203,15 @@
|
||||
thresholds:
|
||||
0: Alive
|
||||
300: Dead
|
||||
- type: Stamina
|
||||
critThreshold: 1500
|
||||
- type: SlowOnDamage
|
||||
speedModifierThresholds:
|
||||
150: 0.7
|
||||
- type: MovementSpeedModifier
|
||||
baseWalkSpeed: 2.8
|
||||
baseSprintSpeed: 3.8
|
||||
- type: MeleeWeapon
|
||||
hidden: true
|
||||
damage:
|
||||
groups:
|
||||
Brute: 20
|
||||
- type: SlowOnDamage
|
||||
speedModifierThresholds:
|
||||
250: 0.4
|
||||
200: 0.7
|
||||
Brute: 12
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
fix1:
|
||||
@@ -246,12 +242,9 @@
|
||||
- type: MobThresholds
|
||||
thresholds:
|
||||
0: Alive
|
||||
200: Dead
|
||||
- type: Stamina
|
||||
critThreshold: 550
|
||||
100: Dead
|
||||
- type: MovementSpeedModifier
|
||||
baseWalkSpeed: 2.3
|
||||
baseSprintSpeed: 4.2
|
||||
baseSprintSpeed: 4
|
||||
- type: MeleeWeapon
|
||||
hidden: true
|
||||
damage:
|
||||
@@ -259,8 +252,7 @@
|
||||
Brute: 10
|
||||
- type: SlowOnDamage
|
||||
speedModifierThresholds:
|
||||
150: 0.5
|
||||
100: 0.7
|
||||
50: 0.7
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
fix1:
|
||||
@@ -285,16 +277,13 @@
|
||||
layers:
|
||||
- map: ["enum.DamageStateVisualLayers.Base"]
|
||||
state: running
|
||||
- type: Stamina
|
||||
critThreshold: 250
|
||||
- type: MovementSpeedModifier
|
||||
baseWalkSpeed: 2.7
|
||||
baseSprintSpeed: 6.0
|
||||
- type: MeleeWeapon
|
||||
hidden: true
|
||||
damage:
|
||||
groups:
|
||||
Brute: 3
|
||||
Brute: 5
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
fix1:
|
||||
@@ -332,12 +321,13 @@
|
||||
- type: MobThresholds
|
||||
thresholds:
|
||||
0: Alive
|
||||
75: Dead
|
||||
50: Dead
|
||||
- type: SlowOnDamage
|
||||
speedModifierThresholds:
|
||||
25: 0.7
|
||||
- type: HTN
|
||||
rootTask:
|
||||
task: SimpleRangedHostileCompound
|
||||
- type: Stamina
|
||||
critThreshold: 300
|
||||
- type: RechargeBasicEntityAmmo
|
||||
rechargeCooldown: 0.75
|
||||
- type: BasicEntityAmmoProvider
|
||||
@@ -351,9 +341,6 @@
|
||||
availableModes:
|
||||
- FullAuto
|
||||
soundGunshot: /Audio/Weapons/Xeno/alien_spitacid.ogg
|
||||
- type: SlowOnDamage
|
||||
speedModifierThresholds:
|
||||
50: 0.4
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
fix1:
|
||||
|
||||
@@ -144,21 +144,22 @@
|
||||
components:
|
||||
- type: GhostRole
|
||||
description: ghost-role-information-space-dragon-dungeon-description
|
||||
# less tanky, no crit
|
||||
- type: SlowOnDamage
|
||||
speedModifierThresholds:
|
||||
100: 0.7
|
||||
- type: MobThresholds
|
||||
thresholds:
|
||||
0: Alive
|
||||
300: Dead
|
||||
200: Dead
|
||||
# less meat spawned since it's a lot easier to kill
|
||||
- type: Butcherable
|
||||
spawned:
|
||||
- id: FoodMeatDragon
|
||||
amount: 1
|
||||
# half damage, spread evenly
|
||||
- type: MeleeWeapon
|
||||
damage:
|
||||
groups:
|
||||
Brute: 15
|
||||
Brute: 12
|
||||
|
||||
- type: entity
|
||||
id: ActionSpawnRift
|
||||
|
||||
@@ -13,16 +13,16 @@
|
||||
- type: ItemCooldown
|
||||
- type: MeleeWeapon
|
||||
damage:
|
||||
groups:
|
||||
Brute: 5
|
||||
types:
|
||||
Blunt: 2.5
|
||||
Piercing: 2.5
|
||||
Structural: 10
|
||||
- type: Wieldable
|
||||
- type: IncreaseDamageOnWield
|
||||
damage:
|
||||
groups:
|
||||
Brute: 10
|
||||
types:
|
||||
Blunt: 5
|
||||
Piercing: 5
|
||||
Structural: 10
|
||||
- type: Item
|
||||
size: 80
|
||||
@@ -44,7 +44,7 @@
|
||||
- type: MeleeWeapon
|
||||
attackRate: 1.5
|
||||
damage:
|
||||
groups:
|
||||
Brute: 10
|
||||
types:
|
||||
Blunt: 5
|
||||
Piercing: 5
|
||||
Structural: 10
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
|
||||
- type: entity
|
||||
id: Thruster
|
||||
name: thruster
|
||||
parent: [ BaseThruster, ConstructibleMachine ]
|
||||
components:
|
||||
- type: Thruster
|
||||
@@ -64,6 +65,15 @@
|
||||
visible: false
|
||||
offset: 0, 1
|
||||
|
||||
- type: entity
|
||||
id: ThrusterUnanchored
|
||||
parent: Thruster
|
||||
components:
|
||||
- type: Transform
|
||||
anchored: false
|
||||
- type: Physics
|
||||
bodyType: Dynamic
|
||||
|
||||
- type: entity
|
||||
id: DebugThruster
|
||||
parent: BaseThruster
|
||||
@@ -91,6 +101,7 @@
|
||||
|
||||
- type: entity
|
||||
id: Gyroscope
|
||||
name: gyroscope
|
||||
parent: [ BaseThruster, ConstructibleMachine ]
|
||||
components:
|
||||
- type: Thruster
|
||||
@@ -133,6 +144,15 @@
|
||||
- type: StaticPrice
|
||||
price: 2000
|
||||
|
||||
- type: entity
|
||||
id: GyroscopeUnanchored
|
||||
parent: Gyroscope
|
||||
components:
|
||||
- type: Transform
|
||||
anchored: false
|
||||
- type: Physics
|
||||
bodyType: Dynamic
|
||||
|
||||
- type: entity
|
||||
id: DebugGyroscope
|
||||
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
|
||||
id: Xenos
|
||||
groups:
|
||||
- entries:
|
||||
- id: MobXeno
|
||||
amount: 2
|
||||
maxAmount: 3
|
||||
- id: MobXenoDrone
|
||||
amount: 1
|
||||
- entries:
|
||||
- id: MobXenoPraetorian
|
||||
amount: 1
|
||||
maxAmount: 2
|
||||
prob: 0.5
|
||||
- entries:
|
||||
- id: MobXenoDrone
|
||||
amount: 0
|
||||
maxAmount: 2
|
||||
prob: 0.25
|
||||
- entries:
|
||||
- id: WeaponTurretXeno
|
||||
amount: 3
|
||||
prob: 0.25
|
||||
- entries:
|
||||
- id: MobXenoSpitter
|
||||
amount: 2
|
||||
prob: 0.25
|
||||
- entries:
|
||||
- id: MobXenoRavager
|
||||
amount: 1
|
||||
prob: 0.1
|
||||
- entries:
|
||||
- id: MobXenoRouny
|
||||
amount: 1
|
||||
prob: 0.001
|
||||
entries:
|
||||
- proto: MobXeno
|
||||
- proto: MobXenoDrone
|
||||
cost: 2
|
||||
- proto: MobXenoPraetorian
|
||||
cost: 5
|
||||
prob: 0.1
|
||||
- proto: MobXenoQueen
|
||||
cost: 10
|
||||
prob: 0.02
|
||||
- proto: MobXenoRavager
|
||||
cost: 5
|
||||
- proto: MobXenoRouny
|
||||
cost: 3
|
||||
prob: 0.02
|
||||
- proto: MobXenoSpitter
|
||||
- proto: WeaponTurretXeno
|
||||
prob: 0.1
|
||||
configs:
|
||||
DefenseStructure: XenoWardingTower
|
||||
Mining: Xenos
|
||||
Megafauna: MobXenoQueen
|
||||
|
||||
- type: salvageFaction
|
||||
id: Carps
|
||||
groups:
|
||||
- entries:
|
||||
- id: MobCarpDungeon
|
||||
amount: 1
|
||||
maxAmount: 4
|
||||
- entries:
|
||||
- id: MobCarpMagic
|
||||
amount: 1
|
||||
maxAmount: 3
|
||||
prob: 0.5
|
||||
- entries:
|
||||
- id: MobCarpHolo
|
||||
amount: 1
|
||||
maxAmount: 2
|
||||
prob: 0.25
|
||||
entries:
|
||||
- proto: MobCarpDungeon
|
||||
# These do too much damage for salvage, need nerfs
|
||||
#- proto: MobCarpHolo
|
||||
# cost: 5
|
||||
# prob: 0.1
|
||||
#- proto: MobCarpMagic
|
||||
# cost: 5
|
||||
# prob: 0.1
|
||||
- proto: MobDragonDungeon
|
||||
cost: 10
|
||||
prob: 0.02
|
||||
configs:
|
||||
DefenseStructure: CarpStatue
|
||||
Mining: Carps
|
||||
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
|
||||
- type: salvageLoot
|
||||
id: OreTin
|
||||
desc: Veins of steel
|
||||
guaranteed: true
|
||||
loots:
|
||||
- !type:BiomeMarkerLoot
|
||||
@@ -14,7 +131,6 @@
|
||||
|
||||
- type: salvageLoot
|
||||
id: OreQuartz
|
||||
desc: Veins of quartz
|
||||
guaranteed: true
|
||||
loots:
|
||||
- !type:BiomeMarkerLoot
|
||||
@@ -27,7 +143,6 @@
|
||||
# - Medium value
|
||||
- type: salvageLoot
|
||||
id: OreGold
|
||||
desc: Veins of gold ore
|
||||
guaranteed: true
|
||||
loots:
|
||||
- !type:BiomeMarkerLoot
|
||||
@@ -39,7 +154,6 @@
|
||||
|
||||
- type: salvageLoot
|
||||
id: OreSilver
|
||||
desc: Veins of silver ore
|
||||
guaranteed: true
|
||||
loots:
|
||||
- !type:BiomeMarkerLoot
|
||||
@@ -52,7 +166,6 @@
|
||||
# - High value
|
||||
- type: salvageLoot
|
||||
id: OrePlasma
|
||||
desc: Veins of plasma ore
|
||||
guaranteed: true
|
||||
loots:
|
||||
- !type:BiomeMarkerLoot
|
||||
@@ -64,7 +177,6 @@
|
||||
|
||||
- type: salvageLoot
|
||||
id: OreUranium
|
||||
desc: Veins of uranium ore
|
||||
guaranteed: true
|
||||
loots:
|
||||
- !type:BiomeMarkerLoot
|
||||
@@ -76,7 +188,6 @@
|
||||
|
||||
- type: salvageLoot
|
||||
id: OreBananium
|
||||
desc: Veins of bananium ore
|
||||
guaranteed: true
|
||||
loots:
|
||||
- !type:BiomeMarkerLoot
|
||||
@@ -88,7 +199,6 @@
|
||||
|
||||
- type: salvageLoot
|
||||
id: OreArtifactFragment
|
||||
desc: artifact fragment-embedded rock
|
||||
guaranteed: true
|
||||
loots:
|
||||
- !type:BiomeMarkerLoot
|
||||
|
||||
@@ -4,58 +4,44 @@
|
||||
parent: FTLPoint
|
||||
|
||||
# Biome mods -> at least 1 required
|
||||
- type: salvageBiomeMod
|
||||
id: Caves
|
||||
biome: Caves
|
||||
|
||||
- type: salvageBiomeMod
|
||||
id: Grasslands
|
||||
biome: Grasslands
|
||||
|
||||
- type: salvageBiomeMod
|
||||
id: Snow
|
||||
cost: 1
|
||||
biome: Snow
|
||||
|
||||
- type: salvageBiomeMod
|
||||
id: Lava
|
||||
cost: 2
|
||||
biome: Lava
|
||||
|
||||
- type: salvageBiomeMod
|
||||
id: Snow
|
||||
biome: Snow
|
||||
|
||||
- type: salvageBiomeMod
|
||||
id: Caves
|
||||
cost: 1
|
||||
biome: Caves
|
||||
|
||||
#- type: salvageBiomeMod
|
||||
# id: Space
|
||||
# cost: 1
|
||||
# weather: false
|
||||
# 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
|
||||
# At some stage with sub-biomes this will probably be moved onto the biome itself
|
||||
- type: salvageLightMod
|
||||
id: Daylight
|
||||
desc: Daylight
|
||||
color: "#D8B059"
|
||||
biomes:
|
||||
- Grasslands
|
||||
- Grasslands
|
||||
|
||||
- type: salvageLightMod
|
||||
id: Lavalight
|
||||
desc: Daylight
|
||||
color: "#A34931"
|
||||
biomes:
|
||||
- Lava
|
||||
- Lava
|
||||
|
||||
- type: salvageLightMod
|
||||
id: Evening
|
||||
@@ -65,24 +51,169 @@
|
||||
- type: salvageLightMod
|
||||
id: Night
|
||||
desc: Night time
|
||||
cost: 2
|
||||
cost: 1
|
||||
color: null
|
||||
|
||||
# Time mods -> at least 1 required
|
||||
- type: salvageTimeMod
|
||||
id: StandardTime
|
||||
# Temperatures
|
||||
- type: salvageTemperatureMod
|
||||
id: RoomTemp
|
||||
cost: 0
|
||||
|
||||
- type: salvageTimeMod
|
||||
id: RushTime
|
||||
desc: Rush
|
||||
minDuration: 420
|
||||
maxDuration: 465
|
||||
- type: salvageTemperatureMod
|
||||
id: Hot
|
||||
cost: 1
|
||||
temperature: 323.15 # 50C
|
||||
biomes:
|
||||
- Caves
|
||||
#- LowDesert
|
||||
- Grasslands
|
||||
- Lava
|
||||
|
||||
# Misc mods
|
||||
- type: salvageMod
|
||||
id: LongDistance
|
||||
desc: Long distance
|
||||
- type: salvageTemperatureMod
|
||||
id: Burning
|
||||
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:
|
||||
- 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
|
||||
- type: salvageAirMod
|
||||
id: Space
|
||||
desc: No atmosphere
|
||||
space: true
|
||||
cost: 2
|
||||
biomes:
|
||||
- Caves
|
||||
- Lava
|
||||
|
||||
- type: salvageAirMod
|
||||
id: Breathable
|
||||
cost: 0
|
||||
gases:
|
||||
- 21.824779 # oxygen
|
||||
- 82.10312 # nitrogen
|
||||
|
||||
- type: salvageAirMod
|
||||
id: Sleepy
|
||||
cost: 1
|
||||
desc: Dangerous atmosphere
|
||||
gases:
|
||||
- 21.824779 # oxygen
|
||||
- 72.10312 # nitrogen
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 10 # nitrous oxide
|
||||
biomes:
|
||||
- Caves
|
||||
#- LowDesert
|
||||
- Snow
|
||||
- Grasslands
|
||||
- Lava
|
||||
|
||||
- type: salvageAirMod
|
||||
id: Poisoned
|
||||
cost: 2
|
||||
desc: Dangerous atmosphere
|
||||
gases:
|
||||
- 21.824779 # oxygen
|
||||
- 77.10312 # nitrogen
|
||||
- 10 # carbon dioxide
|
||||
biomes:
|
||||
- Caves
|
||||
#- LowDesert
|
||||
- Snow
|
||||
- Grasslands
|
||||
- Lava
|
||||
|
||||
- type: salvageAirMod
|
||||
id: Poison
|
||||
cost: 3
|
||||
desc: Toxic atmosphere
|
||||
gases:
|
||||
- 21.824779 # oxygen
|
||||
- 0
|
||||
- 82.10312 # carbon dioxide
|
||||
biomes:
|
||||
- Caves
|
||||
- Snow
|
||||
- Lava
|
||||
|
||||
- type: salvageAirMod
|
||||
id: Plasma
|
||||
cost: 4
|
||||
desc: Toxic atmosphere
|
||||
gases:
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 103.927899 # plasma
|
||||
biomes:
|
||||
- Caves
|
||||
- Lava
|
||||
|
||||
- type: salvageAirMod
|
||||
id: Burnable
|
||||
cost: 5
|
||||
desc: Volatile atmosphere
|
||||
gases:
|
||||
- 21.824779 # oxygen
|
||||
- 0
|
||||
- 0
|
||||
- 82.10312 # plasma
|
||||
biomes:
|
||||
- Caves
|
||||
- Lava
|
||||
|
||||
# Weather mods -> not required
|
||||
#- type: salvageWeatherMod
|
||||
# id: SnowfallHeavy
|
||||
# weather: SnowfallHeavy
|
||||
# cost: 1
|
||||
#
|
||||
#- type: salvageWeatherMod
|
||||
# id: Rain
|
||||
# weather: Rain
|
||||
|
||||
# Dungeons
|
||||
# For now just simple 1-dungeon setups
|
||||
@@ -100,160 +231,3 @@
|
||||
proto: LavaBrig
|
||||
biomes:
|
||||
- Lava
|
||||
|
||||
# Air mixtures
|
||||
- type: salvageAirMod
|
||||
id: Space
|
||||
desc: No atmosphere
|
||||
space: true
|
||||
cost: 1
|
||||
biomes:
|
||||
- Caves
|
||||
- Lava
|
||||
|
||||
- type: salvageAirMod
|
||||
id: Breathable
|
||||
gases:
|
||||
- 21.824779 # oxygen
|
||||
- 82.10312 # nitrogen
|
||||
biomes:
|
||||
- Caves
|
||||
#- LowDesert
|
||||
- Snow
|
||||
- Grasslands
|
||||
|
||||
- type: salvageAirMod
|
||||
id: Sleepy
|
||||
cost: 1
|
||||
desc: Dangerous atmosphere
|
||||
gases:
|
||||
- 21.824779 # oxygen
|
||||
- 72.10312 # nitrogen
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 10 # nitrous oxide
|
||||
biomes:
|
||||
- Caves
|
||||
#- LowDesert
|
||||
- Snow
|
||||
- Grasslands
|
||||
- Lava
|
||||
|
||||
- type: salvageAirMod
|
||||
id: Poisoned
|
||||
cost: 2
|
||||
desc: Dangerous atmosphere
|
||||
gases:
|
||||
- 21.824779 # oxygen
|
||||
- 77.10312 # nitrogen
|
||||
- 10 # carbon dioxide
|
||||
biomes:
|
||||
- Caves
|
||||
#- LowDesert
|
||||
- Snow
|
||||
- Grasslands
|
||||
- Lava
|
||||
|
||||
- type: salvageAirMod
|
||||
id: Poison
|
||||
cost: 3
|
||||
desc: Toxic atmosphere
|
||||
gases:
|
||||
- 21.824779 # oxygen
|
||||
- 0
|
||||
- 82.10312 # carbon dioxide
|
||||
biomes:
|
||||
- Caves
|
||||
- Snow
|
||||
- Lava
|
||||
|
||||
- type: salvageAirMod
|
||||
id: Plasma
|
||||
cost: 4
|
||||
desc: Toxic atmosphere
|
||||
gases:
|
||||
- 0
|
||||
- 0
|
||||
- 0
|
||||
- 103.927899 # plasma
|
||||
biomes:
|
||||
- Caves
|
||||
- Lava
|
||||
|
||||
- type: salvageAirMod
|
||||
id: Burnable
|
||||
cost: 5
|
||||
desc: Volatile atmosphere
|
||||
gases:
|
||||
- 21.824779 # oxygen
|
||||
- 0
|
||||
- 0
|
||||
- 82.10312 # plasma
|
||||
biomes:
|
||||
- Caves
|
||||
- Lava
|
||||
|
||||
# Temperatures
|
||||
|
||||
- type: salvageTemperatureMod
|
||||
id: RoomTemp
|
||||
biomes:
|
||||
- Caves
|
||||
#- LowDesert
|
||||
- Grasslands
|
||||
|
||||
- type: salvageTemperatureMod
|
||||
id: Hot
|
||||
temperature: 323.15 # 50C
|
||||
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:
|
||||
- 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