-
Posts
68 -
Joined
-
Last visited
Content Type
Profiles
Forums
News
Store
Posts posted by Frepo
-
-
With my current knowledge I think I would be able to get the player to being downed instead of dead at 0 hp. And thats about it
What I would primarily need take a deep dive into is:
- Animation (player crawling)
- Getting some sort custom UI graphics displayed on the screeen (e.g. a revive-meter)
- Restricting player controls
But some day I will make this happen, if noone else already has. -
OMG it was the consumer class! Started working perfectly after changing to MPBase. Just had to copy in the Join-/LeaveNetwork methods, and OnConnected and OnDisConnected actions. What a relief to finally be able to move on from this.
THANK YOU!!!- 2
-
If you take a look in the BlockLantern class, you'll find the method GetLightHsv, which retrieves the light from the lantern.
Spoilerpublic override byte[] GetLightHsv(IBlockAccessor blockAccessor, BlockPos pos, ItemStack stack = null) { if (pos != null) { BELantern be = blockAccessor.GetBlockEntity(pos) as BELantern; if (be != null) { return be.GetLightHsv(); } } if (stack != null) { string lining = stack.Attributes.GetString("lining", null); stack.Attributes.GetString("material", null); int v = (int)(this.LightHsv[2] + ((lining != "plain") ? 2 : 0)); byte[] lightHsv = new byte[] { this.LightHsv[0], this.LightHsv[1], (byte)v }; BELantern.setLightColor(this.LightHsv, lightHsv, stack.Attributes.GetString("glass", null)); return lightHsv; } return base.GetLightHsv(blockAccessor, pos, stack); }
And in this method is a call to it's entity class, BELantern:
BELantern.setLightColor(this.LightHsv, lightHsv, stack.Attributes.GetString("glass", null));
Where the glass attribute is passed in. And as the name implies, this is where the light is set depending on the glass.Spoilerpublic static void setLightColor(byte[] origLightHsv, byte[] lightHsv, string color) { if (color != null) { switch (color.Length) { case 3: if (color == "red") { lightHsv[0] = 0; lightHsv[1] = 4; return; } break; case 4: { char c = color[0]; if (c != 'b') { if (c == 'p') { if (color == "pink") { lightHsv[0] = 54; lightHsv[1] = 4; return; } } } else if (color == "blue") { lightHsv[0] = 42; lightHsv[1] = 4; return; } break; } case 5: { char c = color[0]; if (c != 'b') { if (c == 'g') { if (color == "green") { lightHsv[0] = 20; lightHsv[1] = 4; return; } } } else if (color == "brown") { lightHsv[0] = 5; lightHsv[1] = 4; return; } break; } case 6: { char c = color[0]; if (c != 'v') { if (c == 'y') { if (color == "yellow") { lightHsv[0] = 11; lightHsv[1] = 4; return; } } } else if (color == "violet") { lightHsv[0] = 48; lightHsv[1] = 4; return; } break; } } } lightHsv[1] = origLightHsv[1]; lightHsv[0] = origLightHsv[0]; }
Also in BELantern is where the player sets the color by interaction.
Spoilerinternal bool Interact(IPlayer byPlayer) { ItemSlot slot = byPlayer.InventoryManager.ActiveHotbarSlot; if (slot.Empty) { return false; } CollectibleObject obj = slot.Itemstack.Collectible; if (obj.FirstCodePart(0) == "glass" && obj.Variant.ContainsKey("color")) { if (this.glass != "quartz" && byPlayer.WorldData.CurrentGameMode != EnumGameMode.Creative) { ItemStack stack = new ItemStack(this.Api.World.GetBlock(new AssetLocation("glass-" + this.glass)), 1); if (!byPlayer.InventoryManager.TryGiveItemstack(stack, true)) { this.Api.World.SpawnItemEntity(stack, this.Pos.ToVec3d().Add(0.5, 0.0, 0.5), null); } } this.glass = obj.Variant["color"]; if (byPlayer.WorldData.CurrentGameMode != EnumGameMode.Creative && this.glass != "quartz") { slot.TakeOut(1); } if (this.Api.Side == EnumAppSide.Client) { (byPlayer as IClientPlayer).TriggerFpAnimation(EnumHandInteract.HeldItemInteract); } Vec3d soundpos = this.Pos.ToVec3d().Add(0.5, 0.0, 0.5); this.Api.World.PlaySoundAt(this.Api.World.GetBlock(new AssetLocation("glass-" + this.glass)).Sounds.Place, soundpos.X, soundpos.Y, soundpos.Z, byPlayer, true, 32f, 1f); BELantern.setLightColor(this.origlightHsv, this.lightHsv, this.glass); this.Api.World.BlockAccessor.ExchangeBlock(base.Block.Id, this.Pos); this.MarkDirty(true, null); return true; } if (this.lining == null || (this.lining == "plain" && obj is ItemMetalPlate && (obj.Variant["metal"] == "gold" || obj.Variant["metal"] == "silver"))) { this.lining = obj.Variant["metal"]; if (this.Api.Side == EnumAppSide.Client) { (byPlayer as IClientPlayer).TriggerFpAnimation(EnumHandInteract.HeldItemInteract); } Vec3d soundpos2 = this.Pos.ToVec3d().Add(0.5, 0.0, 0.5); this.Api.World.PlaySoundAt(new AssetLocation("sounds/block/plate"), soundpos2.X, soundpos2.Y, soundpos2.Z, byPlayer, true, 32f, 1f); slot.TakeOut(1); this.MarkDirty(true, null); return true; } return false; }
- 1
- 1
-
@Spear and Fang Have you made any machines that uses behaviors based on the BEBehaviorMPConsumer?
Where the autosifter differ from the toggle is that it's behavior is BEBehaviorMPConsumer, where the toggle is just BEBehaviorMPBase, just like your passthrough axle.
In the Initialize method ( in BEBehaviorMPConsumer) there's a line that caught my eye;
this.Shape = properties["mechPartShape"].AsObject<CompositeShape>(null);
If don't know if this property is set anywhere, can't find anything when I search the word. So I was wondering if you know where this is set, or if I need to set this myself somewhere. -
Thanks guys for you help! I'm completely stuck on this. But, I will not give up! Gotta take a break from it, and come back later with a fresh approach. That usually helps.
-
Wouldn't it be nice if players could revive each other?
- The player enters a state of being downed when hp reaches 0 (or a configurable chance for this happening).
- While downed: You can't do anything except slowly crawl around (no jumping).
- You die after 60 seconds (configurable), if no friend was able to revive you during this window.
- Revival takes a couple of seconds to perform (hold interact button with a bandage or any healing item in hand)
Not a new concept by any means, but I think it would be super nice to get a chance to save your friend when out on long expeditions far far away from home.
Also, it's fun! These situations tend to get quite intense, being on a timer to save your friend. -
Thanks mate! I'll look into that for sure.
-
I'm doing some fixing of the auto-sifter mod, since I love the machine and dev is discontinued, and also to start learning how to mod for the MP-system.
Currently I'm stuck at combining the static shape model with the animated/rotating part. Only the static model shows up in-game.
The code for the wooden toggle is used as basis for this machine, since they both only connect horizontally ("ns", "we"), and don't have inventories and such.
I've split the model into 3 separate models
autosifter-inventory.json is the complete model (left pic), autosifter-stand.json is the static part (middle), and autosifter-moving.json is the rotating part (right)
As far as I understood, the shape is set to the moving one in the json for BlockAutoSifter (at shapeByType)Spoiler{ code: "tieredautosifter", class: "BlockAutoSifter", entityclass: "AutoSifterBlockEntity", behaviors: [{name: "NWOrientable" }], entityBehaviors: [{ name: "MPSifter" }], creativeinventory: { "general": ["*-ns"],"mechanics": ["*-ns"] }, variantgroups: [ { code:"metal", states: ["steel","meteoriciron","iron","blackbronze","bismuthbronze","tinbronze","empty"]}, { code:"orientation", states: ["ns", "we"]}, ], blockmaterial: "Metal", shapeInventory: { base: "block/autosifter-inventory" }, shapeByType: { "*-ns": { base: "block/autosifter-moving", rotateY: 90 }, "*-we": { base: "block/autosifter-moving", rotateY: 0 }, }, textures: { grate: { base: "grate_{metal}" }, lip: { base: "ingot/{metal}"}, metalbase: { base: "metalbase"}, metalalts: { base: "metalalts"}, axle: { base: "game:block/wood/planks/generic" }, }, drops: [ { type: "block", code: "tieredautosifter-{metal}-ns", quantity: { avg: 1 } } ], sidesolid: { all: false }, sideopaque: { all: false }, attributes: { maxblocksByType: { "tieredautosifter-steel-*": 7, "tieredautosifter-meteoriciron-*": 4, "tieredautosifter-iron-*": 3, "tieredautosifter-blackbronze-*": 2, "tieredautosifter-bismuthbronze-*": 1, "tieredautosifter-tinbronze-*": 1 } }, resistance: 3.5, lightAbsorption: 1, maxStackSize: 1, groundTransform: { translation: { x: 0, y: 0, z: 0 }, rotation: { x: -90, y: 0, z: 0 }, origin: { x: 0.5, y: 0.45, z: 0.38 }, scale: 2.7 }, guiTransform: { rotation: { x: -43, y: 45, z: 1 }, scale: 0.96 }, tpHandTransform: { translation: { x: -1.2, y: -0.4, z: -0.6 }, rotation: { x: -90, y: 11, z: -103 }, origin: { x: 0.5, y: 0.25, z: 0.5 }, scale: 0.42 }, collisionSelectionBoxByType: { "*-we": { x1: 0, y1: 0.34375, z1: 0, x2: 1, y2: 1, z2: 1 }, "*-ns": { x1: 0, y1: 0.34375, z1: 0, x2: 1, y2: 1, z2: 1, rotateY: 90 }, }, sounds: { "place": "game:sounds/block/chute", "walk": "game:sounds/walk/stone" } }
Here is the code for BlockAutoSifter, it's basically ripped off the vanilla BlockToggle:
Spoilernamespace fregtech { public class BlockAutoSifter : BlockMPBase { public bool IsOrientedTo(BlockFacing facing) { string dirs = base.LastCodePart(0); return dirs[0] == facing.Code[0] || (dirs.Length > 1 && dirs[1] == facing.Code[0]); } public override bool HasMechPowerConnectorAt(IWorldAccessor world, BlockPos pos, BlockFacing face) { return this.IsOrientedTo(face); } public override bool TryPlaceBlock(IWorldAccessor world, IPlayer byPlayer, ItemStack itemstack, BlockSelection blockSel, ref string failureCode) { if (!this.CanPlaceBlock(world, byPlayer, blockSel, ref failureCode)) { return false; } foreach (BlockFacing face in BlockFacing.HORIZONTALS) { BlockPos pos = blockSel.Position.AddCopy(face); IMechanicalPowerBlock block = world.BlockAccessor.GetBlock(pos) as IMechanicalPowerBlock; if (block != null && block.HasMechPowerConnectorAt(world, pos, face.Opposite)) { AssetLocation loc = new AssetLocation(this.Code.Domain, base.FirstCodePart(0) + "-" + base.FirstCodePart(1) + "-" + face.Opposite.Code[0].ToString() + face.Code[0].ToString()); Block toPlaceBlock = world.GetBlock(loc); if (toPlaceBlock == null) { loc = new AssetLocation(this.Code.Domain, base.FirstCodePart(0) + "-" + base.FirstCodePart(1) + "-" + face.Code[0].ToString() + face.Opposite.Code[0].ToString()); toPlaceBlock = world.GetBlock(loc); } if (toPlaceBlock != null && toPlaceBlock.DoPlaceBlock(world, byPlayer, blockSel, itemstack)) { block.DidConnectAt(world, pos, face.Opposite); this.WasPlaced(world, blockSel.Position, face); return true; } } } if (base.TryPlaceBlock(world, byPlayer, itemstack, blockSel, ref failureCode)) { this.WasPlaced(world, blockSel.Position, null); return true; } return false; } public override void OnNeighbourBlockChange(IWorldAccessor world, BlockPos pos, BlockPos neibpos) { BlockEntity blockEntity = world.BlockAccessor.GetBlockEntity(pos); BEBehaviorMPSifter bempsifter = (blockEntity != null) ? blockEntity.GetBehavior<BEBehaviorMPSifter>() : null; if (bempsifter != null && !bempsifter.IsAttachedToBlock()) { foreach (BlockFacing face in BlockFacing.HORIZONTALS) { BlockPos npos = pos.AddCopy(face); BlockAngledGears blockagears = world.BlockAccessor.GetBlock(npos) as BlockAngledGears; if (blockagears != null && blockagears.Facings.Contains(face.Opposite) && blockagears.Facings.Length == 1) { world.BlockAccessor.BreakBlock(npos, null, 1f); } } } base.OnNeighbourBlockChange(world, pos, neibpos); } public override void DidConnectAt(IWorldAccessor world, BlockPos pos, BlockFacing face) { } } }
Here is the code for the BEBehaviorMPSifter, which is mostly ripped off the BEBehaviorMPToggle. Here in lies the problem, I think, probably in the getStandMesh and/or OnTesselation methods. Instead of adding the autosifter-stand model to the autosifter-moving model, it replaces it. And I have no idea why.
Spoilernamespace fregtech { public class BEBehaviorMPSifter : BEBehaviorMPConsumer { public BEBehaviorMPSifter(BlockEntity blockentity) : base(blockentity) { } public override void Initialize(ICoreAPI api, JsonObject properties) { base.Initialize(api, properties); string domainAndPath = "block/autosifter-stand.json"; AssetLocation code = base.Block.Code; this.sifterStandLoc = AssetLocation.Create(domainAndPath, (code != null) ? code.Domain : "fregtech"); JsonObject attributes = base.Block.Attributes; if (attributes != null && attributes["sifterStandLoc"].Exists) { JsonObject attributes2 = base.Block.Attributes; this.sifterStandLoc = ((attributes2 != null) ? attributes2["sifterStandLoc"].AsObject<AssetLocation>(null) : null); } this.sifterStandLoc.WithPathPrefixOnce("shapes/").WithPathAppendixOnce(".json"); if (api.Side == EnumAppSide.Client) { this.capi = (api as ICoreClientAPI); } this.orientations = this.Block.Variant["orientation"]; string a = this.orientations; if (a == "ns") { this.AxisSign = new int[] { 0, 0, -1 }; this.orients[0] = BlockFacing.NORTH; this.orients[1] = BlockFacing.SOUTH; this.sides[0] = this.Position.AddCopy(BlockFacing.WEST); this.sides[1] = this.Position.AddCopy(BlockFacing.EAST); return; } if (!(a == "we")) { return; } int[] array = new int[3]; array[0] = -1; this.AxisSign = array; this.orients[0] = BlockFacing.WEST; this.orients[1] = BlockFacing.EAST; this.sides[0] = this.Position.AddCopy(BlockFacing.NORTH); this.sides[1] = this.Position.AddCopy(BlockFacing.SOUTH); } public override float GetResistance() { this.Api.World.BlockAccessor.GetBlockEntity(this.Position); float speed = (this.network == null) ? 0f : Math.Abs(this.network.Speed * base.GearedRatio); float speedLimiter = 5f * (float)Math.Exp((double)speed * 2.8 - 5.0); Block blockabove = this.Api.World.BlockAccessor.GetBlock(this.Position.AddCopy(0, 1, 0)); if (blockabove.Attributes != null && blockabove.Attributes.IsTrue("pannable")) { return 0.125f + speedLimiter; } return (0.125f + speedLimiter) * 0.5f; } public override void JoinNetwork(MechanicalNetwork network) { base.JoinNetwork(network); float speed = (network == null) ? 0f : (Math.Abs(network.Speed * base.GearedRatio) * 1.6f); if (speed > 1f) { network.Speed /= speed; network.clientSpeed /= speed; } } public bool IsAttachedToBlock() { return (this.orientations == "ns" || this.orientations == "we") && (this.Api.World.BlockAccessor.IsSideSolid(this.Position.X, this.Position.Y - 1, this.Position.Z, BlockFacing.UP) || this.Api.World.BlockAccessor.IsSideSolid(this.Position.X, this.Position.Y + 1, this.Position.Z, BlockFacing.DOWN)); } private MeshData getStandMesh(string orient) { ICoreAPI api = this.Api; AssetLocation code = base.Block.Code; return ObjectCacheUtil.GetOrCreate<MeshData>(api, ((code != null) ? code.ToString() : null) + "-" + orient + "-stand", delegate { Shape shape = Vintagestory.API.Common.Shape.TryGet(this.capi, this.sifterStandLoc); MeshData mesh; this.capi.Tesselator.TesselateShape(this.Block, shape, out mesh, null, null, null); if (orient == "ns") { mesh.Rotate(new Vec3f(0.5f, 0.5f, 0.5f), 0f, 1.5707964f, 0f); } return mesh; }); } public override bool OnTesselation(ITerrainMeshPool mesher, ITesselatorAPI tesselator) { MeshData mesh = this.getStandMesh(base.Block.Variant["orientation"]); mesher.AddMeshData(mesh, 1); return base.OnTesselation(mesher, tesselator); } protected readonly BlockFacing[] orients = new BlockFacing[2]; protected readonly BlockPos[] sides = new BlockPos[2]; private ICoreClientAPI capi; private string orientations; private AssetLocation sifterStandLoc; } }
So this is the end result... the machine functions as intended (guess the BlockEntity code is OK), but the wooden axle is nowhere to be seen.
-
Me and some friends play with a "hardcore" modpack I put together, I've added some stuff myself, tweaked many of the mods and vanilla mechanics.
If you wan't, you can give me your mail and I'll send you the modpack.
Settings i strongly recommend with this pack:
- Hunger: 125%
- Creature Strength: 150%
- Global deposit spawn rate: 80%
- Worldmap and coordinates: OFF (very important)
- Soil sand and gravel gravity with side-ways instability: ON (very important)
Some notes on what's tweaked and changed:
- When you die; Each item in your inventory (and hotbar and worn) have 50% chance to be deleted
- Food tweaks (red meat nerfed, animal drops nerfed, bread buffed)
- Many recipes changed to "weave together" different mods, but mostly to make stuff more costly
- Raw grass, must be dried before you get dry grass
- Tool tier system changed (stone -> copper -> tin/bismuth bronze -> black bronze -> iron -> steel -> titanium)
- Sleeping made harder, low tier beds can break after use, can't sleep in rain or if it's too cold (make a fire and build better beds to mitigate the cold)
- All rocks have a small chance of coming loose and fall when mining a nearby block, deals quite a bit of damage if it lands on you
- Increased fall damage (+70%!!!), each piece of clothing reduces fall damage by 5%
- Can't break cobblestone with hands anymore
- Can't place water sources with buckets anymore
- Drifters spawn everywhere!
- More dealy wild animals
Notable mods in the pack:
- Primitive Surivial
- Medieval Expansion
- Better Crates
- Better Ruins
- Compass2
- Dungeons and Shafts
- Feverstone Wilds
- Kreatures and Kritters
- Farm To Table (fixed)
- Ranged Weapons
- Titanium Tools
- Lichen
- NoWaterproofInventories (crashes the game since .NET7 update, I might have fixed it, not sure yet, just remove if crashes the game)
+ much much more- 1
-
Structure like this.
E.g. Location of Vanilla file you want to replace:
..\Vintagestory\assets\survival\worldgen\treengenproperties.json
Make a json (copy original) to this location in your mod to use that one instead:
..\MyMod_v1.0\assets\game\worldgen\treengenproperties.json
It's kinda confusing, since the files we are looking to replace are placed in the folder named "survival", one would think we should also name our folder the same, but no, it's "game" for some reason. But I don't question it, it works for me- 1
-
I can't get this recipe to work
{ ingredientPattern: "TP", ingredients: { "T": { type: "block", code: "fregtech:fttrunkmetal-east", attributes: { type: "reinforced" } }, "P": { type: "block", code: "game:woodbucket" }, }, width: 2, height: 1, shapeless: true, attributes: { liquidContainerProps: { requiresContent: { type: "item", code: "game:dye-blue" }, requiresLitres: 1.0 } }, output: { type: "block", code: "fregtech:fttrunkmetal-east", attributes: { type: "reinforcedblue" } } },
Is something written wrong or is it simply not possible to combine several items with attributes in the same recipe?
Coz it works fine like e.g. this:Spoiler{ ingredientPattern: "TP", ingredients: { "T": { type: "block", code: "fregtech:fttrunkmetal-east", attributes: { type: "reinforced" } }, "P": { type: "item", code: "game:leather-blue", quantity: 1 }, }, width: 2, height: 1, shapeless: true, output: { type: "block", code: "fregtech:fttrunkmetal-east", attributes: { type: "reinforcedblue" } } },
-
37 minutes ago, Streetwind said:
You need to update your project, using an internal updater tool:
https://devblogs.microsoft.com/dotnet/upgrade-assistant-now-in-visual-studio/
Thanks man! You're an angel!
-
Re-installed Visual Studio and made sure the .NET desktop development workload is installed as well.
Still same error. I'm not accustomed to visual studio at all, but I noticed that VintagestoryAPI.dll is compiled against an older runtime version of .NET (v4.x).
This must be because VS i targeting a 4.x-framework (4.8 in my case), right? So changing the target framework to 7.x (if I only could) should recompile the assembly against that version instead, right? -
I just got back to modding again after a long time away. I noticed the game is now .NET7-based. After downloading the SDK I started my old project and tried a rebuild, and got this error:
My mod still works fine after I updated the game (no changes whatsoever to the mod). I'm not sure what to make of this error. I realized my project wasn't targeting the .NET7 framework. I guess that must be the cause of the error. Problem is, I can't select the .NET7 framework in my project settings. It simply isn't there!
The SDK seems to be installed and working.
Visual Studio is up to date.
Someone at StackOverflow mentioned you should check the box "Use previews of the .NET SDK"-box, and so I did.
Is there anything else I need to do to make VS find the new framework version?
-
Love the idea of more hazards in the environment. In addition to you venus flytrap I would also like to see a plant that can shoot some sort of projectile at you.
And puffball mushrooms that, when stepped on, releases a poisonous cloud. -
You can patch in your items in survival/itemtypes/meta/stackrandomizer.json.
-
Are there any loot tables (JSONs) for the collapsed chests found underground, where we can add custom loot?
I found the loot tables for the urns in BlockLootVessel. But the collapsed chests are just variants of the standard chest you craft, and there seems to be no loot randomizing in BlockGenericTypedContainer or BlockEntityGenericTypedContainer (nor in their respective sub-classes).
-
Anyone adept in harmony transpiler patches? I want to insert a new tier level between bronze and iron, so the progression goes ... -> tin/bismuth bronze -> black bronze -> iron -> ....
The relevant jsons have been patched (changing miningTiers and toolTiers) and working fine. But I need to add the tier to a list in GetPlacedBlockInfo (in Block class):
so the code becomes ->So I thought it would be nice to accomplish this with a small transpiler patch. But I'm unsure how to go about this. Studying the IL-code for the list
Spoiler/* 0x000001D5 1D */ IL_01D5: ldc.i4.7 /* 0x000001D6 8D???????? */ IL_01D6: newarr [System.Private.CoreLib]System.String /* 0x000001DB 25 */ IL_01DB: dup /* 0x000001DC 16 */ IL_01DC: ldc.i4.0 /* 0x000001DD 72???????? */ IL_01DD: ldstr "tier_hands" /* 0x000001E2 28???????? */ IL_01E2: call !!0[] [System.Private.CoreLib]System.Array::Empty<object>() /* 0x000001E7 286C080006 */ IL_01E7: call string Vintagestory.API.Config.Lang::Get(string, object[]) /* 0x000001EC A2 */ IL_01EC: stelem.ref /* 0x000001ED 25 */ IL_01ED: dup /* 0x000001EE 17 */ IL_01EE: ldc.i4.1 /* 0x000001EF 72???????? */ IL_01EF: ldstr "tier_stone" /* 0x000001F4 28???????? */ IL_01F4: call !!0[] [System.Private.CoreLib]System.Array::Empty<object>() /* 0x000001F9 286C080006 */ IL_01F9: call string Vintagestory.API.Config.Lang::Get(string, object[]) /* 0x000001FE A2 */ IL_01FE: stelem.ref /* 0x000001FF 25 */ IL_01FF: dup /* 0x00000200 18 */ IL_0200: ldc.i4.2 /* 0x00000201 72???????? */ IL_0201: ldstr "tier_copper" /* 0x00000206 28???????? */ IL_0206: call !!0[] [System.Private.CoreLib]System.Array::Empty<object>() /* 0x0000020B 286C080006 */ IL_020B: call string Vintagestory.API.Config.Lang::Get(string, object[]) /* 0x00000210 A2 */ IL_0210: stelem.ref /* 0x00000211 25 */ IL_0211: dup /* 0x00000212 19 */ IL_0212: ldc.i4.3 /* 0x00000213 72???????? */ IL_0213: ldstr "tier_bronze" /* 0x00000218 28???????? */ IL_0218: call !!0[] [System.Private.CoreLib]System.Array::Empty<object>() /* 0x0000021D 286C080006 */ IL_021D: call string Vintagestory.API.Config.Lang::Get(string, object[]) /* 0x00000222 A2 */ IL_0222: stelem.ref /* 0x00000223 25 */ IL_0223: dup /* 0x00000224 1A */ IL_0224: ldc.i4.4 /* 0x00000225 72???????? */ IL_0225: ldstr "tier_iron" /* 0x0000022A 28???????? */ IL_022A: call !!0[] [System.Private.CoreLib]System.Array::Empty<object>() /* 0x0000022F 286C080006 */ IL_022F: call string Vintagestory.API.Config.Lang::Get(string, object[]) /* 0x00000234 A2 */ IL_0234: stelem.ref /* 0x00000235 25 */ IL_0235: dup /* 0x00000236 1B */ IL_0236: ldc.i4.5 /* 0x00000237 72???????? */ IL_0237: ldstr "tier_steel" /* 0x0000023C 28???????? */ IL_023C: call !!0[] [System.Private.CoreLib]System.Array::Empty<object>() /* 0x00000241 286C080006 */ IL_0241: call string Vintagestory.API.Config.Lang::Get(string, object[]) /* 0x00000246 A2 */ IL_0246: stelem.ref /* 0x00000247 25 */ IL_0247: dup /* 0x00000248 1C */ IL_0248: ldc.i4.6 /* 0x00000249 72???????? */ IL_0249: ldstr "tier_titanium" /* 0x0000024E 28???????? */ IL_024E: call !!0[] [System.Private.CoreLib]System.Array::Empty<object>() /* 0x00000253 286C080006 */ IL_0253: call string Vintagestory.API.Config.Lang::Get(string, object[]) /* 0x00000258 A2 */ IL_0258: stelem.ref /* 0x00000259 1307 */ IL_0259: stloc.s tiers
I get the feeling I can't just insert my code before IL_0225: ldstr "tier_iron", since this would mess up the indexing, right? In that case, I would need to replace each subsequent ldc.i4.x instruction with x+1? Or must I replace all the IL-code for the entire list? If so, how do I replace this list? By replacing each instruction with a nop and then adding all the code again, including the new index?
-
1 hour ago, Maelstrom said:
Yes. I have seen chromium and nickel ores generate minable blocks.
Ok, thanks for the confirmation!
-
By "unimplemented" I mean they have no use yet. But do these ores (e.g. uranium and nickel) generate during worldgen? I have never seen them in-game, though I haven't been digging around in the deep depths that much.
-
Yeah it's not supposed to be a game changer by any means, merely a "quality of life" tool.
I would love to have one when firing up my 16 clay ovens, takes like half a minute to light them all with the torch -
-
How about a tinder box? A limited-use tool to instantly ignite stuff.
Crafting
Clay bowl + flint + iron/steel bits + dry grass[EDIT] Oops! Should perhaps have posted this in the suggestions section.
-
Jesus f-ing christ! That looks absolutely GORGEOUS!! And with a gear in the window there! A most excellent touch!
BRAVO- 1
How can I cancel fall damage?
in Mods & Mod Development
Posted
I made it do the opposite (increase fall damage). It's basically a custom made behavior for the player, that extends EntityBehavior and overrides the OnFallToGround method in there. But I'm not quite sure it completely replaces the fall damage mechanic (actually I think my method adds on top of the vanilla method), I wrote that a looong time ago with little experience. But it increased the damage for sure, so I was content and never looked back at it again. Maybe you can find something useful here.
Patch json
My custom behavior class
Maybe you can just write something like this
But again, I'm very unsure that this method completely replaces the vanilla mechanic.