• Content Count

  • Joined

  • Last visited

Community Reputation

151 Excellent


About YakumoYukari

  • Rank

Recent Profile Visitors

1056 profile views
  1. I'll say there are three popular ways to override prefabs(or components if you want). I've been seen some mod files that modify existing files, and all these ways have their properties. If you enough understand with these options, all three methods are legit. The first one is to use post init functions in the mod environment. It is written in modutil.lua, InsertPostInitFunction I have explained this in the last post(Mod Load Order Priority). Because of the post init functions run in the order listed in postinit table, It is the best-easy, and I think you will probably use this one. For prefabs, there are AddPrefabPostInitAny, AddPlayerPostInit, AddPrefabPostInit. AddPrefabPostInitAny and AddPlayerPostInit are used when you need to override multiple prefabs at once. But you need to think about some performance issues as its comment. And if you want pigmans overridden, do something like this. AddPrefabPostInit("pigman", function(inst) -- do something with inst end) And for the pigman prefab specifically, your PIF will run after the local function, normal. However, you can't override local function in there, like if you're trying to tweak some lines in SetNormalPig which you can't access in PIF scope, you need to re-define the whole local function that works correctly(or copy-paste it then tweaks) or use another method. The second one is to override the existing file, that the way you don't want to do though. If a mod file is at the directory where the original file and the name are the exact same, you can override the whole file. It removes the information of the original file which means the game update will no longer affect that file. So if you don't update your mod frequently, it might cause the crash more easily and soon your mod will be deprecated. But this can be useful when you do a huge scale mod project(that may have unique dependency) or when you need to patch a lot of things. Since prefab files are easily bound to local functions, this can be better than you may concern. But not for components, as it avoids using local functions. Lastly, you can use UpvalueHacker made by Rezecib. This is a tool to access the local variable using Lua's debug functions. It is very powerful but also the toughest to use. Because you need to get a reference by going through the function
  2. Your assumption of the load order is correct. Higher priority loads earlier. Every mod is zero priority given by default. If same, it will load in lexicographical order. And, yes. It affects modutil functions. It would be helpful if you look at the code in modutil. Especially InsertPostInitFunctions. Every PostInit functions are inserted by table.insert() into an environment table, named postinitfns. It is executed in runtime, including the main loads(for the client mods mostly), worldgen and the world loading. Since every element in the game environment(prefabs, stategraphs, actions...) is being variable and separated, it has its own time to appear. And if any post functions exist on that element, the function runs, in the load order. And I do believe that all workshop mods are written in lua which doesn't compile. But executes everything in runtime, line by line. The only matter on the load priority is, how to use it. If you made a prefab post init function that overrides everything about inst, for example, will lose most load order data applied previously. In this case, you need to set your mod priority to the lowest, -2147483648 and rename your mod name start with.. something beyond the 'z' in lexicographical order of the lua sorting algorithm in order to fully apply your code. To avoid this, you can always think about the other mods and use various skills like chain-function. It is always the best to make your mod not to inflict with mods made by other people. Also, you can freely assume the data range of the integer of Lua 5.2 is the int32's.
  3. inst.HUD only exist in the client So it should be accessed in client-side.
  4. There's a various way of setting loot tables. But if you want to tweak birds loots, You can access its loot table by inst.components.lootdropper.randomloot So, let's say we already know the substantial drop table of crow already. It is 50%(feather) and 50%(smallmeat). And we will prove this by iterating crow's randomloot. Since it is a table, you can iterate it by using pairs as you know. And below are pseudo-command-result lines. for k, v in pairs(CROW.components.lootdropper.randomloot) do print(k, v) end) So first, we can just look randomloot directly. The result would 1 table: 0CF356C0 2 table: 0CF35530 like this. Which means, CROW.components.lootdropper.randomloot[1] references table: 0CF356C0 CROW.components.lootdropper.randomloot[2] references table: 0CF35530 and surely you can iterate each randomloot's elements by iterating tables again. Like for k, v in pairs(CROW.components.lootdropper.randomloot[1]) do print(k, v) end) this. But well, I'll use this one to see all of those at once. for k, v in pairs(CROW.components.lootdropper.randomloot) do for k2, v2 in pairs(v) do print(k2, v2) end print() end And the result would like this. prefab feather_crow weight 1 prefab smallmeat weight 1 It means, CROW.components.lootdropper.randomloot[1]["prefab"] is "feater_crow" CROW.components.lootdropper.randomloot[1]["weight"]is 1 CROW.components.lootdropper.randomloot[2]["prefab"] is "smallmeat" CROW.components.lootdropper.randomloot[2]["weight"]is 1 And this intuitively gives us the information about what loots inside and it seems weight one is the chance thing. Right? So we can test by changing each weight you want to prove. AddPrefabPostInit("crow", function(inst) if not GLOBAL.TheWorld.ismastersim then return end inst.components.lootdropper.randomloot[2]["weight"] = 0 end) So this would make smallmeat not to be dropped. But after murdering some crows, soon will know there's a chance to have given nothing that was smallmeat. Then we can change the weight to 0.25 After genociding some, crows, we'll know that there still could be a chance to give nothing but you can obtain smallmeat quite rarely. That and some more tests will give you proof that substantial loot table of the above case is 50%(feather) 12.5%(smallmeat) 37.5%(nothing). Then how to code for birds? Here's the code. But I have to sleep now so no explain. local BIRDS = {"crow", "robin", "robin_winter", "canary"} local FEATHER_CHANCE_INCREASE_MODIFIER = 5 -- 1 means 33.33% of meat will drop, 2 -> 25%, ..., n -> 1/(2+n) (n must natural) for _, v in pairs(BIRDS) do AddPrefabPostInit(v, function(inst) if not GLOBAL.TheWorld.ismastersim then return end for k, v in pairs(inst.components.lootdropper.randomloot) do if v["prefab"] == "smallmeat" then for i = 1, FEATHER_CHANCE_INCREASE_MODIFIER do inst.components.lootdropper:AddRandomLoot("feather_"..inst.prefab, 1) end end end end) end Please read it and re-code it and test it to tune as you want.
  5. The reason you can't AOE(the meaning of your "weapon spread") attack via owner.components.combat:SetAreaDamage(20, 1) is because the player's ATTACK action does target only one they're trying to attack. While AOE attacked will only exist when the attacker's attack can have multiple targets, and the attacked has not been attacked by the direct hit(this includes case evading DH but still in AOE range). So I think the best easy way to do is to let the weapon itself cause the attacker does AOE. Here's the code. In your weapon.lua: Put this in your fn() inst.components.weapon:SetOnAttack(OnAttack) And these in anywhere where is not belong to any local functions. local AOE_RADIUS = 20 local AREA_EXCLUDE_TAGS = { "INLIMBO", "notarget", "noattack", "flight", "invisible", "playerghost", "companion", "wall" } local function IsPreemitive(ent) return (TheNet:GetPVPEnabled() and ent:HasTag("player")) or (ent.components.combat ~= nil and ent.components.combat.target ~= nil) end local function DoAOEAttack(inst, attacker, target) attacker.components.combat:DoAreaAttack(target, AOE_RADIUS, inst, IsPreemitive, nil, AREA_EXCLUDE_TAGS) end local function OnAttack(inst, attacker, target) DoAOEAttack(inst, attacker, target) end If the attacker attacks target by your weapon, OnAttack() calls and it calls DoAOEAttack(). If you need to make a condition to raise AOE, if-case it. And DoAOEAttack() cause AOE only targets enemies that is about to attack you and players when PVP is on. If you don't want this condition, modify IsPreemitive() and AREA_EXCLUDE_TAGS as you wish. And the amount of AOE damage can be edited by inst.components.combat.areahitdamagepercent = 1 in fn() of your character.lua But the damage itself will not decrease or dynamically calculated by distance. - Only the static amount of damage will be taken. If you want to implement any kind of these, you need to make your AOE functions.
  6. My mod character has a similar feature like what you're trying to. Equipping a hat will act like the goggle. So "terrible" screen appeared to me. I solved this by just patching HUD not to show the goggle screen. You can see it right here. But this will be hard to apply it to yours in just copy-pasting. Because I made my character's classified and call the patching function into that. Instead, try this code. This will prevent the goggle screen to appear unless your character equips the goggle. But before, enable the screen and the ability to walk freely in sandstorm by inst.components.playervision.forcegogglevision = true in master_postinit. And put this function somewhere in your charcter.lua. local function PatchHUD(inst) if inst.HUD ~= nil then -- if this line run in the client(because HUD only exist in the client) inst.HUD.gogglesover.ToggleGoggles = function(self, show) local owner = self.owner local shouldshow = true if owner ~= nil then shouldshow = owner.replica.inventory:EquipHasTag("goggles") end if show then if not self.shown and shouldshow then self:Show() self:AddChild(self.storm_overlays):MoveToBack() end elseif self.shown then self:Hide() self.storm_root:AddChild(self.storm_overlays) end end end end Then put the function call in common_postinit. PatchHUD(inst) As I mentioned in the comment, inst.HUD only exist in the client. So you should place the function call in the right position. common_postinit is where before the SetPristine() calls which run in both client and server, and master_postinit is after which run only in the server.
  7. Nothing is impossible if you are eager to do something with the desire. I think all the features you want is implementable. Printing the footstep corresponds to the actual step animation is the problem though. Needs some tests. Here are my suggestions. About the first : - You will need to create an 'ink footstep' prefab. So creating, vanishing or counting it becomes possible. - Footsteps should belong to the player prefab. So footsteps can be printed 10 per the mod player. - Each footstep should have information about when is being printed to delete 1st one if 11th one prints. - Footsteps should vanish automatically. So we won't think about player disconnecting or something else. - I can't imagine "the trail of ink". Why don't you draw a picture you imagine it? - Slowing enemies or Vanishing it in rain is just absolutely implementable. I'll add the code later. Second : - Everything Is just possible. Even you can override the entities color slightly blacker. Like this. If you hit an enemy with that sword, it will get DOT damage and slightly be 'reddished'. Here's the code (well the comment is not your language though..)
  8. In DST, clients and servers are separated. Clients don't have most data calculated by the server because they don't need it. So most components like leveluplan, class variables are just not existed. The only exception is when you're the host of the server hosted through the game(not dedicated) without a cave. In this case, the server and the client are the same. That is - you have to change the code from the basics. If this code is not the whole features of the mod, you need to work on re-coding about those. Read Differences chapter more carefully. At least if you want to understand this issue, it is required to understand what replica, RPC, netvars is. Please read the thread before you read below. Let's look at the code from the perspective of problem-solving. As I mentioned above, the client doesn't have information about those GetPlayer().components.leveluplan.levelLan, math.floor(GetPlayer().components.leveluplan.expLan), GetPlayer().components.leveluplan:XPneed(), ((2.2 - 1.003 ^ -GetPlayer().components.leveluplan.levelLan) / 1.2 - 1) * 100 because component leveluplan may not exist in the client. But what can we do? Adding the component in the client too? No. We just need to run it in the server. Because the server has the info. And you can do it by using RPC. Let's make a code sending RPC to the server. The server receives the RPC, and execute the function that let the sender(the player prefab) say the info. The first thing to do is to change AddKeyDownHandler(). A client raises KeyDown Event. So the client will send RPC. G.TheInput:AddKeyDownHandler(INFO_KEY, function() if G.TheFrontEnd:GetActiveScreen() ~= nil and G.TheFrontEnd:GetActiveScreen().name == "HUD" then G.SendModRPCToServer(MOD_RPC["modprettyname"]["getinfo"], ThePlayer) end end) You can freely change MOD_RPC's key. Just ensure "modprettyname" part distinguishable compared to other mods. So if you press the key, the client says to the server: "Execute function in MODRPC.modprettyname.getinfo" And... I won't use GetPlayer() because it will only call in DST code part. Oh and IsPaused() is not used in DST. Instead, if G.TheFrontEnd:GetActiveScreen()~ part will prevent further sequences when any screen is activated. Next is to add an RPC handler. If the server receives an RPC, it will execute the function in matching key(modprettyname.getinfo in this case) in MOD_RPC. Adding the function to MOD_RPC is this. AddModRPCHandler("modprettyname", "getinfo", GetInfo) You will notice that the key should be corresponding. Rename it correctly. After the server received the RPC, it will call GetInfo() in server-side. The server does have the information. However, the server doesn't know who GetPlayer(ThePlayer) is. So don't use it in GetInfo(). Instead, use a parameter passed by the RPC which is the sender's player entity. ..."modprettyname"]["getinfo"], ThePlayer) That parameter is actually ThePlayer, the argument of SendModRPCToServer. Since this ThePlayer was sent by the client, the server can distinguish which player is to start function. local function GetInfo(inst) inst.components.talker:Say( string.format( "Level: %d\nXP: %d/%d\n%.4f speed", inst.components.leveluplan.levelLan, math.floor(inst.components.leveluplan.expLan), inst.components.leveluplan:XPneed(), inst.components.leveluplan.speedupLan ) ) end That will do it. Recode it as you want. Take a look at my character mod's code as well. I've already made the feature similar to yours.
  9. Has the entity size increased? I thought it was 31 because I tested it about two or three months ago.
  10. There're two options. 1. Use WatchWorldState. (Recommended) 2. Get law worldstate data. Seems your case doesn't need to bind to WatchWorldState(). Instead, you can directly get the value of worldstate(isday) by isday = TheWorld.components.worldstate.data.isday The code above will detect daytime overworld only(otherwise it's always false). If you need to detect it also in Cave, isday = TheWorld:HasTag("cave") and TheWorld.components.worldstate.data.iscaveday or TheWorld.components.worldstate.data.isday
  11. I believe there's no GetClock or TheClock things in DST. You have to approach it by problem-specific. What exactly trying to do?
  12. I think this is what you're looking for. x,y,z = inst.Transform:GetWorldPosition()
  13. You can make netvars like this inst.testvar = net_bool(inst.GUID, "ontestvar", "ontestvardirty") inst.testvar:set(false) There're many other sorts of netvars available. You can see it in netvars.lua. Actually, I have made a similar thing like what you're trying to do. https://github.com/HimekaidouHatate/YakumoYukari-DST/tree/master/scripts Look stategraph_yukari.lua and prefab/yukari_classified.lua You can see how I create netvars and use it. But you don't actually need to make your own classified. Just define your netvar at common_poistinit. (if it's not a player character, define it before SetPristine() like this.)