private void StartGame(int tile) { var init = Current.Game.InitData; if (WorldEditor.LoadedTemplate.PawnSelectMode == PawnSelectMode.Standart) { foreach (var scenPart in Find.Scenario.AllParts) { ScenPart_ConfigPage_ConfigureStartingPawns part = scenPart as ScenPart_ConfigPage_ConfigureStartingPawns; if (part != null) { init.startingAndOptionalPawns = new List <Pawn>(part.pawnChoiceCount); init.startingPawnCount = part.pawnCount; for (int i = 0; i < init.startingPawnCount; i++) { Pawn p = PawnGenerator.GeneratePawn(PawnKindDefOf.Colonist, init.playerFaction); init.startingAndOptionalPawns.Add(p); } break; } } } init.startingTile = tile; Find.World.renderer.wantedMode = WorldRenderMode.None; if (WorldEditor.LoadedTemplate.PawnSelectMode == PawnSelectMode.None) { Action preLoadLevelAction = delegate { Find.GameInitData.PrepForMapGen(); Find.GameInitData.startedFromEntry = true; Find.Scenario.PreMapGenerate(); }; LongEventHandler.QueueLongEvent(preLoadLevelAction, "Play", "GeneratingMap", doAsynchronously: true, null); return; } //if (WorldEdit.EdbLoaded) // EdbConfigurator(); var page = new Page_ConfigureStartingPawns(); page.nextAct = nextAct = delegate { Action preLoadLevelAction = delegate { Find.GameInitData.PrepForMapGen(); Find.GameInitData.startedFromEntry = true; Find.Scenario.PreMapGenerate(); }; LongEventHandler.QueueLongEvent(preLoadLevelAction, "Play", "GeneratingMap", doAsynchronously: true, null); }; Find.WindowStack.Add(page); }
public static Scenario GenScenSkeleton(string _name) { // ***************** // // Set Scenario Head // // ***************** // scen = new Scenario(); scen.name = _name; scen.summary = "Test summary"; scen.description = "Test description"; scen.Category = ScenarioCategory.CustomLocal; //Instantiate and inject player faction ScenPart_PlayerFaction f = new ScenPart_PlayerFaction(); Traverse.Create(f).Field("factionDef").SetValue(FactionDefOf.PlayerTribe); Traverse.Create(scen).Field("playerFaction").SetValue(f); // ***************** // // Set Scenario Body // // ***************** // //List for Scenario.parts List <ScenPart> p = new List <ScenPart>(); //Pawn ConfigPage. Pawncount should be 3 already. ScenPart_ConfigPage_ConfigureStartingPawns SPCPCSP = new ScenPart_ConfigPage_ConfigureStartingPawns(); SPCPCSP.def = ScenPartDefOf.ConfigPage_ConfigureStartingPawns; //Pawn Arrival method ScenPart_PlayerPawnsArriveMethod SPPPAM = new ScenPart_PlayerPawnsArriveMethod(); SPPPAM.def = ScenPartDefOf.PlayerPawnsArriveMethod; Traverse.Create(SPPPAM).Field("method").SetValue(PlayerPawnsArriveMethod.Standing); SPPPAM.visible = false; //Add ScenParts into List p.Add(SPCPCSP); p.Add(SPPPAM); //Inject List into Scenario.parts Traverse.Create(scen).Field("parts").SetValue(p); return(scen); }
protected void ReplaceScenarioParts(Scenario actualScenario, Scenario vanillaFriendlyScenario) { // Create a lookup of all of the scenario types that we want to replace. HashSet <string> scenarioPartsToReplace = new HashSet <string>() { typeof(RimWorld.ScenPart_StartingThing_Defined).FullName, typeof(RimWorld.ScenPart_ScatterThingsNearPlayerStart).FullName, typeof(RimWorld.ScenPart_StartingAnimal).FullName }; // Create lists to hold the new scenario parts. List <ScenPart> actualScenarioParts = new List <ScenPart>(); List <ScenPart> vanillaFriendlyScenarioParts = new List <ScenPart>(); // Get the list of parts from the original scenario. The actual scenario and the vanilla-friendly // scenario will both be copies of the original scenario and equivalent at this point, so we only // need to look at the parts in one of them. FieldInfo partsField = typeof(Scenario).GetField("parts", BindingFlags.NonPublic | BindingFlags.Instance); List <ScenPart> originalParts = (List <ScenPart>)partsField.GetValue(actualScenario); // Replace the pawn count in the configure pawns scenario part to reflect the number of // pawns that were selected in Prepare Carefully. foreach (var part in originalParts) { ScenPart_ConfigPage_ConfigureStartingPawns configurePawnPart = part as ScenPart_ConfigPage_ConfigureStartingPawns; if (configurePawnPart == null) { continue; } configurePawnPart.pawnCount = Find.GameInitData.startingPawnCount; } // Fill in each part list with only the scenario parts that we're not going to replace. foreach (var part in originalParts) { if (!scenarioPartsToReplace.Contains(part.GetType().FullName)) { actualScenarioParts.Add(part); vanillaFriendlyScenarioParts.Add(part); } } // Sort the equipment from highest count to lowest so that gear is less likely to get blocked // if there's a bulk item included. If you don't do this, then a large number of an item (meals, // for example) could fill up the spawn area right away and then the rest of the items would have // nowhere to spawn. PrepareCarefully.Instance.Equipment.Sort((EquipmentSelection a, EquipmentSelection b) => { return(a.Count.CompareTo(b.Count)); }); // Create all of the scatter things scenario parts that we need. Make note of the maximum number of stacks // that could be created. We must use a custom scatter scenario part because we need to customize the spawn // radius when there are large numbers of resources. List <ScenPart_CustomScatterThingsNearPlayerStart> scatterParts = new List <ScenPart_CustomScatterThingsNearPlayerStart>(); int scatterStackCount = 0; foreach (var e in PrepareCarefully.Instance.Equipment) { if (e.record.animal) { continue; } if (!PlayerStartsWith(e)) { int stacks = Mathf.CeilToInt((float)e.Count / (float)e.ThingDef.stackLimit); scatterStackCount += stacks; ScenPart_CustomScatterThingsNearPlayerStart part = new ScenPart_CustomScatterThingsNearPlayerStart(); part.ThingDef = e.ThingDef; part.StuffDef = e.StuffDef; part.Count = e.Count; scatterParts.Add(part); ScenPart_ScatterThingsNearPlayerStart vanillaPart = new ScenPart_ScatterThingsNearPlayerStart(); vanillaPart.def = ScenPartDefOf.ScatterThingsNearPlayerStart; vanillaPart.SetPrivateField("thingDef", e.ThingDef); vanillaPart.SetPrivateField("stuff", e.StuffDef); vanillaPart.SetPrivateField("count", e.Count); vanillaFriendlyScenarioParts.Add(vanillaPart); } } // Get the non-public fields that we'll need to set on the new starting thing scenario parts // that we're going to add. FieldInfo thingDefField = typeof(ScenPart_StartingThing_Defined).GetField("thingDef", BindingFlags.Instance | BindingFlags.NonPublic); FieldInfo stuffField = typeof(ScenPart_StartingThing_Defined).GetField("stuff", BindingFlags.Instance | BindingFlags.NonPublic); FieldInfo countField = typeof(ScenPart_StartingThing_Defined).GetField("count", BindingFlags.Instance | BindingFlags.NonPublic); // Go through all of the equipment that's meant to spawn as a starting thing. We'll try to add // a starting thing scenario part for each, but we're keeping track of the overall density of // things that will be spawned into the area (based on stack count and spawn area radius). If // the density is too high, we'll add the things as scattered nearby scenario parts instead. float radius = 7.5f; float area = Mathf.PI * radius * radius; float maxDensity = 0.25f; int maxStacks = Mathf.FloorToInt(maxDensity * area); int stackCount = 0; foreach (var e in PrepareCarefully.Instance.Equipment) { if (e.record.animal) { continue; } if (PlayerStartsWith(e)) { int scatterCount = 0; int nearCount = e.Count; // If the number of stacks added by this part will push us over the density // limit, then we split the stacks into two scenario parts, one that spawns // as a starting thing and the other that scatters nearby. int nearStacks = Mathf.CeilToInt((float)nearCount / (float)e.ThingDef.stackLimit); if (nearStacks + stackCount > maxStacks) { int availableStacks = maxStacks - stackCount; nearCount = availableStacks * e.ThingDef.stackLimit; scatterCount = e.Count - nearCount; } if (nearCount > 0) { stackCount += Mathf.CeilToInt((float)nearCount / (float)e.ThingDef.stackLimit); ScenPart_StartingThing_Defined part = new ScenPart_StartingThing_Defined(); // Be sure to set the def, since that doesn't happen automatically. Failing to do so will // cause null pointer exceptions when trying to sort the scenario parts when creating the // description to display in the "Scenario Summary." part.def = ScenPartDefOf.StartingThing_Defined; thingDefField.SetValue(part, e.ThingDef); stuffField.SetValue(part, e.StuffDef); countField.SetValue(part, nearCount); actualScenarioParts.Add(part); vanillaFriendlyScenarioParts.Add(part); } if (scatterCount > 0) { scatterCount += Mathf.CeilToInt((float)scatterCount / (float)e.ThingDef.stackLimit); ScenPart_CustomScatterThingsNearPlayerStart part = new ScenPart_CustomScatterThingsNearPlayerStart(); part.ThingDef = e.ThingDef; part.StuffDef = e.StuffDef; part.Count = scatterCount; scatterParts.Add(part); ScenPart_ScatterThingsNearPlayerStart vanillaPart = new ScenPart_ScatterThingsNearPlayerStart(); vanillaPart.def = ScenPartDefOf.ScatterThingsNearPlayerStart; vanillaPart.SetPrivateField("thingDef", e.ThingDef); vanillaPart.SetPrivateField("stuff", e.StuffDef); vanillaPart.SetPrivateField("count", scatterCount); vanillaFriendlyScenarioParts.Add(vanillaPart); } } } // Create parts to spawn the animals. We can't use the default starting animal scenario part, // because it doesn't allow us to choose a gender. Dictionary <PawnKindDef, int> animalKindCounts = new Dictionary <PawnKindDef, int>(); foreach (var e in PrepareCarefully.Instance.Equipment) { if (e.record.animal) { PawnKindDef animalKindDef = (from td in DefDatabase <PawnKindDef> .AllDefs where td.race == e.ThingDef select td).FirstOrDefault(); ScenPart_CustomAnimal part = new ScenPart_CustomAnimal(); part.Count = e.count; part.Gender = e.Gender; part.KindDef = animalKindDef; actualScenarioParts.Add(part); if (animalKindCounts.ContainsKey(animalKindDef)) { int count = animalKindCounts[animalKindDef]; animalKindCounts[animalKindDef] = count + e.count; } else { animalKindCounts.Add(animalKindDef, e.count); } } } // The vanilla starting animal part does not distinguish between genders, so we combine // the custom parts into a single vanilla part for each animal kind. foreach (var animalKindDef in animalKindCounts.Keys) { ScenPart_StartingAnimal vanillaPart = new ScenPart_StartingAnimal(); vanillaPart.def = ScenPartDefOf.StartingAnimal; vanillaPart.SetPrivateField("animalKind", animalKindDef); vanillaPart.SetPrivateField("count", animalKindCounts[animalKindDef]); vanillaFriendlyScenarioParts.Add(vanillaPart); } // We figure out how dense the spawn area will be after spawning all of the scattered things. // We'll target a maximum density and increase the spawn radius if we're over that density. stackCount += scatterStackCount; float originalRadius = 12f; radius = originalRadius; maxDensity = 0.35f; bool evaluate = true; while (evaluate) { float density = GetSpawnAreaDensity(radius, stackCount); if (density > maxDensity) { radius += 1f; } else { evaluate = false; } } int addedRadius = (int)(radius - originalRadius); // For each scatter part, we set our custom radius before adding the part to the scenario. foreach (var part in scatterParts) { part.Radius = addedRadius; actualScenarioParts.Add(part); } // Set the new part lists on the two scenarios. actualScenario.SetPrivateField("parts", actualScenarioParts); vanillaFriendlyScenario.SetPrivateField("parts", vanillaFriendlyScenarioParts); }