예제 #1
0
        private void LoadBlueprint()
        {
            Debug.Log(Debug.BlueprintTransfer, "Loading blueprint at path {0}", snapshotName);

            string deflatedName = snapshotName;

            if (Path.GetExtension(snapshotName).Equals(".bp"))
            {
                deflatedName = snapshotName + ".xml";
                if (!File.Exists(deflatedName))
                {
                    string data = Compressor.UnzipFile(snapshotName);
                    File.WriteAllText(deflatedName, data);
                }
            }

            XmlDocument snapshot = new XmlDocument();

            snapshot.Load(deflatedName);

            XmlNodeList elemList         = snapshot.GetElementsByTagName("cell");
            int         blueprintWidth   = int.Parse(snapshot.FirstChild.Attributes["width"].Value);
            int         blueprintHeight  = int.Parse(snapshot.FirstChild.Attributes["height"].Value);
            Version     blueprintVersion = new Version(snapshot.FirstChild?.Attributes["version"]?.Value ?? "0.0.0.0");

            blueprint = new Blueprint(blueprintWidth, blueprintHeight, blueprintVersion);

            //Snapshot year is an in-game year when snapshot was taken. Thus, all corpse ages, death times, art events and so on are in between of 5500 and [snapshotYear]
            blueprint.snapshotYear = int.Parse(snapshot.FirstChild.Attributes["inGameYear"]?.Value ?? "5600");
            //To prevent artifacts from future we need to shift all dates by some number to the past by _at_least_ (snaphotYear - 5500) years


            int itemNodes    = 0;
            int terrainNodes = 0;

            foreach (XmlNode cellNode in elemList)
            {
                int x = int.Parse(cellNode.Attributes["x"].Value);
                int z = int.Parse(cellNode.Attributes["z"].Value);
                blueprint.itemsMap[x, z] = new List <ItemTile>();

                foreach (XmlNode cellElement in cellNode.ChildNodes)
                {
                    try {
                        if (cellElement.Name.Equals("terrain"))
                        {
                            terrainNodes++;
                            TerrainTile terrain = new TerrainTile(cellElement);
                            terrain.location           = new IntVec3(x, 0, z);
                            blueprint.terrainMap[x, z] = terrain;
                        }
                        else if (cellElement.Name.Equals("item"))
                        {
                            itemNodes++;
                            ItemTile tile = new ItemTile(cellElement);

                            //replace all collapsed rocks with walls
                            if (tile.defName == ThingDefOf.CollapsedRocks.defName)
                            {
                                tile = ItemTile.WallReplacementItemTile(tile.location);
                            }

                            if (tile.defName == ThingDefOf.MinifiedThing.defName && (tile.innerItems?.Count() ?? 0) == 0)
                            {
                                continue; //skip minified things with no inner items
                            }

                            //Trying to load corresponding definition to check if the object is accessible
                            ThingDef thingDef = DefDatabase <ThingDef> .GetNamed(tile.defName, false);

                            if (thingDef != null)
                            {
                                if (thingDef.fillPercent == 1.0f || tile.isWall || tile.isDoor)
                                {
                                    blueprint.wallMap[x, z] = -1;                                 //place wall
                                }
                                tile.stackCount = Math.Min(thingDef.stackLimit, tile.stackCount); //limit stack to max stack size to correctly calculate weight and cost later
                                tile.location   = new IntVec3(x, 0, z);
                                blueprint.itemsMap[x, z].Add(tile);                               //save item if it's def is valid.
                            }
                            else
                            {
                                if (tile.isDoor)   //replacing unavailable door with abstract default door
                                {
                                    tile.defName  = ThingDefOf.Door.defName;
                                    tile.location = new IntVec3(x, 0, z);
                                    blueprint.itemsMap[x, z].Add(tile);                          //replacement door is ok
                                }
                                else if (tile.isWall || tile.defName.ToLower().Contains("wall")) //replacing unavailable impassable 100% filling block (which was likely a wall) with a wall
                                {
                                    tile.defName  = ThingDefOf.Wall.defName;
                                    tile.location = new IntVec3(x, 0, z);
                                    blueprint.itemsMap[x, z].Add(tile); //now it's a wall
                                }
                                else if (tile.defName == "Corpse")
                                {
                                    tile.location = new IntVec3(x, 0, z);
                                    blueprint.itemsMap[x, z].Add(tile); // corpse is ok
                                }
                            }
                        }
                        else if (cellElement.Name.Equals("roof"))
                        {
                            blueprint.roofMap[x, z] = true;
                        }
                    } catch (Exception) {
                        //ignore invalid or unloadable cells
                    }
                }
            }
        }
예제 #2
0
        public void RaidAndScavenge(Blueprint blueprint, ScatterOptions options)
        {
            //remove the most precious things. smash some other things.
            //word is spread, so each next raid is more destructive than the previous ones
            //to make calculations a bit easier we're going to calculate value per cell, not per item.

            this.options   = options;
            this.blueprint = blueprint;

            Debug.active = false;

            float scavengersActivity = Rand.Value * options.scavengingMultiplier + (options.scavengingMultiplier) / 3; //slight variation for scavengers activity for this particular blueprint
            float elapsedTime        = -blueprint.dateShift;

            int totalRemovedTiles    = 0;
            int totalRemovedTerrains = 0;
            int totalReplacedTiles   = 0;
            int processedTiles       = 0;
            int processedTerrains    = 0;

            for (int x = 0; x < blueprint.width; x++)
            {
                for (int z = 0; z < blueprint.height; z++)
                {
                    if (blueprint.terrainMap[x, z] != null)
                    {
                        tilesByCost.Add(blueprint.terrainMap[x, z]);
                        totalCost += blueprint.terrainMap[x, z].cost;
                        processedTerrains++;
                    }

                    foreach (ItemTile item in blueprint.itemsMap[x, z])
                    {
                        tilesByCost.Add(item);
                        totalCost += item.cost;
                        processedTiles++;
                    }
                }
            }

            tilesByCost.Sort(delegate(Tile t1, Tile t2) {
                return((t1.cost / t1.weight).CompareTo(t2.cost / t2.weight));
            });

            int ruinsArea = blueprint.width * blueprint.height;

            //Debug.Message("Scavenging blueprint of area {0}, age {1}, scavengers activity multiplier {2}", ruinsArea, elapsedTime, scavengersActivity);
            //Debug.Message("Enumerated {0} items", tilesByCost.Count());
            //Debug.PrintArray(tilesByCost.ToArray());

            int raidsCount = (int)(Math.Log(elapsedTime / 10 + 1) * scavengersActivity);

            if (raidsCount > 50)
            {
                raidsCount = 50;
            }
            if (options.scavengingMultiplier > 0.9f && raidsCount <= 0)
            {
                raidsCount = 1; //at least one raid for each ruins in case of normal scavenging activity
            }
            float baseRaidCapacity = ruinsArea / 10 * scavengersActivity;

            Debug.Log(Debug.BlueprintTransfer, "Performing {0} raids. Base capacity: {1}", raidsCount, baseRaidCapacity);

            for (int i = 0; i < raidsCount; i++)
            {
                float raidCapacity = baseRaidCapacity * (float)Math.Pow(1.1, i);
                bool  shouldStop   = false;
                Debug.Log(Debug.BlueprintTransfer, "Performing raid {0} of capacity {1}", i, raidCapacity);

                while (tilesByCost.Count > 0 && raidCapacity > 0 && !shouldStop)
                {
                    Tile   topTile = tilesByCost.Pop();
                    String msg     = string.Format("Inspecting tile \"{0}\" of cost {1} and weight {2}. ", topTile.defName, topTile.cost, topTile.weight);

                    if (topTile.cost / topTile.weight < 7)
                    {
                        shouldStop = true; //nothing to do here, everything valueable has already gone
                        msg       += "Too cheap, stopping.";
                    }
                    else
                    {
                        if (Rand.Chance(0.999f))   //there is still chance that even the most expensive thing will be left after raid. ("Big momma said ya shouldn't touch that golden chair, it's cursed")
                        {
                            raidCapacity -= topTile.weight;
                            if (topTile is TerrainTile)
                            {
                                blueprint.terrainMap[topTile.location.x, topTile.location.z] = null;
                                totalRemovedTerrains++;
                                totalCost -= topTile.cost;
                                msg       += "Terrain removed.";
                            }
                            else if (topTile is ItemTile)
                            {
                                ItemTile itemTile = topTile as ItemTile;
                                totalCost -= itemTile.cost;
                                blueprint.itemsMap[topTile.location.x, topTile.location.z].Remove(itemTile);
                                if (itemTile.isDoor)       //if door is removed it should be replaced with another door, raiders are very polite and always replace expensive doors with cheaper ones.
                                {
                                    if (Rand.Chance(0.8f)) //ok, not always.
                                    {
                                        ItemTile replacementTile = ItemTile.DefaultDoorItemTile(itemTile.location);
                                        blueprint.itemsMap[topTile.location.x, topTile.location.z].Add(replacementTile);
                                        msg += "Added " + replacementTile.defName + ", original ";
                                        totalReplacedTiles++;
                                    }
                                    else
                                    {
                                        totalRemovedTiles++;
                                        blueprint.RemoveWall(itemTile.location.x, itemTile.location.z);
                                    }
                                }
                                else if (itemTile.isWall)     //if something like a wall removed (vent or aircon) you usually want to cover the hole to keep wall integrity
                                {
                                    ItemTile replacementTile = ItemTile.WallReplacementItemTile(itemTile.location);
                                    blueprint.itemsMap[topTile.location.x, topTile.location.z].Add(replacementTile);
                                    msg += "Added " + replacementTile.defName + ", original ";
                                    totalReplacedTiles++;
                                }
                                else
                                {
                                    totalRemovedTiles++;
                                }
                                msg += "Tile removed.";
                            }
                        }
                    }
                    Debug.Log(Debug.BlueprintTransfer, msg);
                    if (shouldStop)
                    {
                        break;
                    }
                }
                if (shouldStop)
                {
                    break;
                }
            }

            //Check that there are no "hanging doors" left
            bool HasWallsIn(List <ItemTile> list)
            {
                foreach (ItemTile tile in list)
                {
                    if (tile.isWall)
                    {
                        return(true);
                    }
                }
                return(false);
            }

            for (int z = 1; z < blueprint.height - 1; z++)
            {
                for (int x = 1; x < blueprint.width - 1; x++)
                {
                    ItemTile tileToRemove = null;
                    foreach (ItemTile tile in blueprint.itemsMap[x, z])
                    {
                        if (tile.isDoor)   //check if a particular door tile has both two vertically adjacent walls (or similar) or two horizintally adjacent walls
                        {
                            if (!(HasWallsIn(blueprint.itemsMap[x - 1, z]) && HasWallsIn(blueprint.itemsMap[x + 1, z])) &&
                                !(HasWallsIn(blueprint.itemsMap[x, z - 1]) && HasWallsIn(blueprint.itemsMap[x, z + 1])))
                            {
                                tileToRemove = tile;
                                break;
                            }
                        }
                    }
                    if (tileToRemove != null)
                    {
                        blueprint.itemsMap[x, z].Remove(tileToRemove);
                        totalCost -= tileToRemove.cost;
                        blueprint.RemoveWall(x, z);
                    }
                }
            }
            Debug.active = true;
            //Debug.Message("Scavenging completed. Terrain removed: {0}/{1}, Tiles removed: {2}/{3}, tiles replaced: {4}.", totalRemovedTerrains, processedTerrains, totalRemovedTiles, processedTiles, totalReplacedTiles);

            if (options.costCap > 0)
            {
                LimitCostToCap();
            }
        }