Exemple #1
0
        static public ItemTile DefaultDoorItemTile(IntVec3 location)
        {
            ItemTile tile = new ItemTile();

            tile.defName    = ThingDefOf.Door.defName;
            tile.stuffDef   = ThingDefOf.WoodLog.defName;
            tile.isDoor     = true;
            tile.isWall     = false;
            tile.location   = location;
            tile.stackCount = 1;
            tile.rot        = 0;
            tile.cost       = 0;
            tile.weight     = 1.0f;

            return(tile);
        }
Exemple #2
0
        public static ItemTile WallReplacementItemTile(IntVec3 location)
        {
            ItemTile tile = new ItemTile {
                defName    = ThingDefOf.Wall.defName,
                stuffDef   = ThingDefOf.BlocksGranite.defName,
                isDoor     = false,
                isWall     = true,
                stackCount = 1,
                rot        = 0,
                cost       = 0,
                weight     = 1.0f,
                location   = location
            };

            return(tile);
        }
        private void ProcessTile(ItemTile itemTile, IntVec3 pos)
        {
            ThingDef itemDef = DefDatabase <ThingDef> .GetNamed(itemTile.defName, false);

            if (itemDef == null)
            {
                return;
            }

            ItemStatRecord stats = null;

            if (itemStats.ContainsKey(itemTile.defName))
            {
                stats = itemStats[itemTile.defName];
            }
            else
            {
                stats = new ItemStatRecord();
                itemStats[itemTile.defName] = stats;
            }

            stats.stacksCount++;
            stats.totalCount += itemTile.stackCount;
            stats.cost       += itemTile.cost;

            result.totalItemsCost += itemTile.cost;
            result.occupiedTilesCount++;
            result.itemsCount += itemTile.stackCount;

            if (itemTile.isWall)
            {
                result.wallLength++;
            }

            var message = itemTile.defName + " ";

            if (itemDef.alwaysHaulable)
            {
                message += "is haulable ";
                result.haulableStacksCount++;
                result.haulableItemsCount += itemTile.stackCount;
                result.haulableItemsCost  += itemTile.cost;
            }

            string lowerName = itemTile.defName.ToLower();

            if (itemDef.IsShell || itemDef.IsRangedWeapon || lowerName.Contains("turret") || lowerName.Contains("cannon") || lowerName.Contains("gun")
                /* || lowerName.Contains("laser") || lowerName.Contains("marauder") and obelisk and punisher when RimAtomics will add faction split*/)
            {
                result.militaryItemsCount++;
                message += "military ";
                if (itemDef.building != null)
                {
                    message += "non-nul building ";
                    result.defensiveItemsCount++;
                    if (itemDef.building.IsTurret)
                    {
                        message += "turret ";
                    }
                }
            }

            if (itemDef.HasComp(typeof(CompMannable)))
            {
                result.mannableCount++;
            }

            if (itemDef.IsWorkTable)
            {
                message += "worktable ";
                result.productionItemsCount++;
            }

            if (itemDef.IsBed)
            {
                message += "bed ";
                result.bedsCount++;
            }

            if (blueprint.wallMap[pos.x, pos.z] > 1 || blueprint.roofMap[pos.x, pos.z] == true)
            {
                result.itemsInside++;
            }


            if (!itemTile.isWall && !itemTile.isDoor && itemTile.cost > 100)
            {
                // Debug.Message(message);
            }
        }
        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
                    }
                }
            }
        }
Exemple #5
0
        public ItemTile(XmlNode node)
        {
            defName = node.Attributes["def"].Value;
            itemXml = node.OuterXml;

            XmlAttribute stuffDefAttribute = node.Attributes["stuffDef"];

            if (stuffDefAttribute != null)
            {
                stuffDef = stuffDefAttribute.Value;
            }

            corpseDeathTime = long.Parse(node.Attributes["timeOfDeath"]?.Value ?? "0");

            XmlAttribute stackCountAttribute = node.Attributes["stackCount"];

            if (stackCountAttribute != null)
            {
                stackCount = int.Parse(s: stackCountAttribute.Value);
            }
            else
            {
                stackCount = 1;
            }

            XmlAttribute doorAttribute = node.Attributes["isDoor"];

            if (doorAttribute != null || defName.ToLower().Contains("door"))
            {
                isDoor = true;
            }

            XmlAttribute textAttribute = node.Attributes["text"];

            if (textAttribute != null)
            {
                attachedText = textAttribute.Value;
            }

            XmlAttribute wallAttribute = node.Attributes["actsAsWall"];

            if (wallAttribute != null || defName.ToLower().Contains("wall") || defName.Equals("Cooler") || defName.Equals("Vent"))   //compatibility
            {
                isWall = true;
            }

            XmlAttribute rotAttribute = node.Attributes["rot"];

            if (rotAttribute != null)
            {
                rot = int.Parse(s: rotAttribute.Value);
            }
            else
            {
                rot = 0;
            }

            XmlAttribute artTitleAttribute = node.Attributes["artTitle"];

            if (artTitleAttribute != null)
            {
                if (art == null)
                {
                    art = new ItemArt();
                }
                art.title = Uri.UnescapeDataString(artTitleAttribute.Value);
            }

            XmlAttribute artAuthorAttribute = node.Attributes["artAuthor"];

            if (artAuthorAttribute != null)
            {
                if (art == null)
                {
                    art = new ItemArt();
                }
                art.author = Uri.UnescapeDataString(artAuthorAttribute.Value);
            }

            XmlAttribute artDescriptionAttribute = node.Attributes["artDescription"];

            if (artDescriptionAttribute != null)
            {
                if (art == null)
                {
                    art = new ItemArt();
                }
                art.text = Uri.UnescapeDataString(artDescriptionAttribute.Value);
            }

            if (node.HasChildNodes)
            {
                List <ItemTile> innerItems = new List <ItemTile>();
                foreach (XmlNode childNode in node.ChildNodes)
                {
                    if (childNode.Name.Equals("item"))
                    {
                        ItemTile innerTile = new ItemTile(childNode);
                        innerItems.Add(innerTile);
                    }
                }

                if (innerItems.Count > 0)
                {
                    this.innerItems = innerItems;
                }
            }
        }
Exemple #6
0
        private Thing MakeThingFromItemTile(ItemTile itemTile, bool enableLogging = false)
        {
            try {
                if (enableLogging)
                {
                    //Debug.Message("Trying to create new inner item {0}", itemTile.defName);
                }

                if (itemTile.defName.ToLower() == "pawn")
                {
                    //Debug.Message("Now need to instantiate pawn");
                    return(MakePawnWithRawXml(itemTile.itemXml));
                }

                if (itemTile.defName.ToLower() == "corpse")
                {
                    if (itemTile.innerItems != null)
                    {
                        //Debug.Message("Creating corpse");
                        Pawn   p      = (Pawn)MakeThingFromItemTile(itemTile.innerItems.First());
                        Corpse corpse = null;
                        if (p.Corpse != null)
                        {
                            corpse = p.Corpse;
                        }
                        else
                        {
                            corpse           = (Corpse)ThingMaker.MakeThing(p.RaceProps.corpseDef);
                            corpse.InnerPawn = p;
                        }
                        corpse.timeOfDeath = (int)(itemTile.corpseDeathTime + (ticksInYear * blueprint.dateShift));

                        CompRottable rottable = corpse.TryGetComp <CompRottable>();
                        if (rottable != null)
                        {
                            rottable.RotProgress = ticksInYear * (-blueprint.dateShift);
                        }
                        return(corpse);
                    }
                    return(null);
                }

                if (itemTile.defName.ToLower().Contains("corpse") || itemTile.defName.ToLower().Contains("minified"))   //should bypass older minified things and corpses
                {
                    if ((!itemTile.innerItems?.Any()) ?? true)
                    {
                        return(null);
                    }
                }

                if (itemTile.defName == "Hive")
                {
                    return(null);                                                              //Ignore hives, probably should add more comprehensive ignore list here.
                }
                ThingDef thingDef = DefDatabase <ThingDef> .GetNamed(itemTile.defName, false); //here thingDef is definitely not null because it was checked earlier

                if (thingDef.category == ThingCategory.Ethereal)
                {
                    return(null);                                        //don't spawn ethereals like drop pod landing sites and so on
                }
                ThingDef stuffDef = null;                                //but stuff can still be null, or can be missing, so we have to check and use default just in case.
                if (itemTile.stuffDef != null && thingDef.MadeFromStuff) //some mods may alter thing and add stuff parameter to it. this will result in a bug on a vanilla, so need to double-check here
                {
                    stuffDef = DefDatabase <ThingDef> .GetNamed(itemTile.stuffDef, false);
                }

                if (stuffDef == null)
                {
                    if (itemTile.isWall && thingDef.MadeFromStuff)
                    {
                        stuffDef = ThingDefOf.BlocksGranite; //walls from modded materials becomes granite walls.
                    }
                    else
                    {
                        stuffDef = GenStuff.DefaultStuffFor(thingDef);
                    }
                }

                Thing thing = ThingMaker.MakeThing(thingDef, stuffDef);


                if (thing != null)
                {
                    if (itemTile.innerItems != null && thing is IThingHolder)
                    {
                        //Debug.Message("Found inners");
                        foreach (ItemTile innerTile in itemTile.innerItems)
                        {
                            Thing innerThing = MakeThingFromItemTile(innerTile, true);
                            if (innerThing != null)
                            {
                                ((IThingHolder)thing).GetDirectlyHeldThings().TryAdd(innerThing);
                            }
                        }
                        if (thing.GetInnerIfMinified() == null)
                        {
                            return(null);
                        }
                    }

                    if (thingDef.CanHaveFaction)
                    {
                        thing.SetFaction(rp.faction);
                    }

                    //Check quality and attach art
                    CompQuality q = thing.TryGetComp <CompQuality>();
                    if (q != null)
                    {
                        byte category = (byte)Math.Abs(Math.Round(Rand.Gaussian(0, 2)));

                        if (itemTile.art != null)
                        {
                            if (category > 6)
                            {
                                category = 6;
                            }
                            q.SetQuality((QualityCategory)category, ArtGenerationContext.Outsider); //setquality resets art, so it should go before actual setting art
                            thing.TryGetComp <CompArt>()?.InitializeArt(itemTile.art.author, itemTile.art.title, itemTile.art.TextWithDatesShiftedBy(blueprint.dateShift));
                        }
                        else
                        {
                            if (category > 6)
                            {
                                category = 6;
                            }
                            q.SetQuality((QualityCategory)category, ArtGenerationContext.Outsider);
                        }
                    }


                    if (itemTile.stackCount > 1)
                    {
                        thing.stackCount = itemTile.stackCount;


                        //Spoil things that can be spoiled. You shouldn't find a fresh meat an the old ruins.
                        CompRottable rottable = thing.TryGetComp <CompRottable>();
                        if (rottable != null)
                        {
                            //if deterioration degree is > 0.5 you definitely won't find any food.
                            //anyway, there is a chance that you also won't get any food even if deterioriation is relatively low. animalr, raiders, you know.
                            if (options.canHaveFood)
                            {
                                rottable.RotProgress = (Rand.Value * 0.5f + options.deteriorationMultiplier) * (rottable.PropsRot.TicksToRotStart);
                            }
                            else
                            {
                                rottable.RotProgress = rottable.PropsRot.TicksToRotStart + 1;
                            }
                        }
                    }

                    if (itemTile.attachedText != null && thing is ThingWithComps)
                    {
                        ThingWithComps thingWithComps = thing as ThingWithComps;
                        Type           CompTextClass  = Type.GetType("SaM.CompText, Signs_and_Memorials");
                        if (CompTextClass != null)
                        {
                            System.Object textComp = null;
                            for (int i = 0; i < thingWithComps.AllComps.Count; i++)
                            {
                                var val = thingWithComps.AllComps[i];
                                if (val.GetType() == CompTextClass)
                                {
                                    textComp = val;
                                }
                            }

                            //var textComp = Activator.CreateInstance(CompTextClass);
                            if (textComp != null)
                            {
                                textComp?.GetType()?.GetField("text").SetValue(textComp, itemTile.attachedText);
                            }
                            //thingWithComps.
                        }
                    }

                    if (thing is UnfinishedThing)
                    {
                        ((UnfinishedThing)thing).workLeft = 10000;
                        ((UnfinishedThing)thing).Creator  = Find.WorldPawns.AllPawnsAliveOrDead.RandomElement();
                    }

                    //Substract some hit points. Most lilkely below 400 (to make really strudy structures stay almost untouched. No more 1% beta poly walls)
                    var maxDeltaHP = 0;
                    if (!options.forceFullHitPoints)
                    {
                        maxDeltaHP = Math.Min(thing.MaxHitPoints - 1, (int)Math.Abs(Rand.Gaussian(0, 200)));
                    }
                    thing.HitPoints = thing.MaxHitPoints - Rand.Range(0, maxDeltaHP);

                    //Forbid haulable stuff
                    if (thing.def.EverHaulable)
                    {
                        thing.SetForbidden(true, false);
                    }

                    if (thing is Building_Storage)
                    {
                        ((Building_Storage)thing).settings.Priority = StoragePriority.Unstored;
                    }
                }
                return(thing);
            } catch (Exception e) {
                Debug.Log(Debug.BlueprintTransfer, "Failed to spawn item {0} because of {1}", itemTile.defName, e);
                return(null);
            }
        }
Exemple #7
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();
            }
        }