YakumoYukari

  • Content count

    80
  • Joined

  • Last visited

Community Reputation

90 Excellent

About YakumoYukari

  • Rank
    Junior Member

Recent Profile Visitors

333 profile views
  1. need help with crash

    This code would work fine local FAIL_CHANCE = 1 local function Fail_Craft(inst) local _Dobuild = inst.components.builder.DoBuild function inst.components.builder.DoBuild(self, recname, pt, rotation, skin) if math.random() <= FAIL_CHANCE then local recipe = GetValidRecipe(recname) if self.buffered_builds[recname] ~= nil then -- is bufferable? return _Dobuild(self, recname, pt, rotation, skin) end self:RemoveIngredients(self:GetIngredients(recname), recipe) -- or Remove its ingredients local item = SpawnPrefab(recipe.product, recipe.chooseskin or skin, nil, self.inst.userid) or nil if item == nil then return end item.Transform:SetPosition(inst.Transform:GetWorldPosition()) if not item.components.lootdropper then item:AddComponent("lootdropper") end if item.components.stackable ~= nil then item.components.stackable:SetStackSize(recipe.numtogive) end self.inst:PushEvent("refreshcrafting") inst.components.talker:Say("Oops!") item.components.lootdropper:DropLoot() item:Remove() return true -- to prevent action fail speech. else return _Dobuild(self, recname, pt, rotation, skin) end end end
  2. Let me help you. I have implemented the code what you're trying to do. Here's the code first. In master_postinit() ScienceAura(inst) and local functions(put this code in your character.lua where isn't belong to any other functions) local AuraRadius = 5 local function AddScienceBonusRemovalHandler(inst) if inst.ScienceAuraRangeCheck ~= nil then return end inst.ScienceAuraRangeCheck = inst:DoPeriodicTask(10 * FRAMES, function(inst) if FindEntity(inst, AuraRadius, nil, {"scienceprovider"}) == nil then inst:RemoveTag("scienceaura") local bonus = inst.components.builder.science_bonus inst.components.builder.science_bonus = bonus - 1 inst.ScienceAuraRangeCheck:Cancel() inst.ScienceAuraRangeCheck = nil end end) end local function ScienceAura(inst) inst:AddTag("scienceprovider") inst.components.builder.science_bonus = 1 inst:DoPeriodicTask(10 * FRAMES, function(inst) local x, y, z = inst.Transform:GetWorldPosition() local ents = TheSim:FindEntities(x, y, z, AuraRadius, {"player"}, {"scienceaura", "playerghost", "scienceprovider"}) -- Added tag check to prevent perk vanishing that increases tech bonus(like Wickerbottom or other modded characters) if ents ~= nil then for k, player in pairs(ents) do player:AddTag("scienceaura") local bonus = player.components.builder.science_bonus -- Rename it if you want. -- Available tech trees : science, magic, ancient, shadow player.components.builder.science_bonus = bonus + 1 AddScienceBonusRemovalHandler(player) end end end) end My first approach to implement the 'aura' was playerprox components. However, I soon realized that this is not the one for the entity who came close to your character. That component was focused on the subject rather than the approximated. It can set a 'target' to do something but only one at a time. Even it can't do anything to the approximated. So I have made a new function. ScienceAura() is the implement of the perk. It grants your character to have one science bonus. And trying to give science bonus to the player where is in range of 5 around your character every 10 frames(0.33 seconds). If someone gets the perk, it will have the tag "scienceaura" which means the player has the bonus of the perk. By the must & excluding tags, ..., {"player"}, {"scienceaura", "playerghost", "scienceprovider"}) you know which one should have the effect without overlapping issue. AddScienceBonusRemovalHandler() is to remove the effect when they're out of the range of the aura. It simply checks nearby "scienceprovider" is exist and if not, removes the effect every 10 frames. You don't need to think about how to sync with the client. Because builder component checks the bonus every tick. Read comments and fix and tweak it as you want. Also, codes I have implemented for other forum users including this are uploaded to here. So the other can see it.
  3. Extensive Prefab List?

    Do you mean prefablist.lua? -- Generated by exportprefabs.lua PREFABFILES = { "abigail", "abigail_flower", "acorn", "adventure_portal", "altar_prototyper", "amulet", "animal_track", "antlion", "antlion_sinkhole", "antlion_spawner", "antliontrinket", "armor_dragonfly", "armor_grass", "armor_lavaarena", "armor_marble", "armor_ruins", "armor_sanity", "armor_skeleton", "armor_slurper", "armor_snurtleshell", "armor_wood", "arrowsign", "ash", "atrium_fence", "atrium_gate", "atrium_gate_activatedfx", "atrium_gate_pulsesfx", "atrium_key", "atrium_light", "atrium_overgrowth", "atrium_pillar", "atrium_rubble", "atrium_statue", "attunable_classified", ....
  4. inst.HUD only exist in the client So it should be accessed in client-side.
  5. 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.
  6. Weapon spread on equip

    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.
  7. 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.
  8. need help with crash

    I didn't even assume such a typical case. My bad. I added some code that consumes the recipe ingredient correctly. if self.buffered_builds[recname] ~= nil then -- is bufferable? self.buffered_builds[recname] = nil self.inst.replica.builder:SetIsBuildBuffered(recname, false) -- turn the buffer off else self:RemoveIngredients(self:GetIngredients(recname), recipe) -- or Remove its ingredients end it comes from DoBuild(). So the full code would be this. local FAIL_CHANCE = 1 local function Fail_Craft(inst) local _Dobuild = inst.components.builder.DoBuild function inst.components.builder.DoBuild(self, recname, ...) if math.random() <= FAIL_CHANCE then local recipe = GetValidRecipe(recname) if self.buffered_builds[recname] ~= nil then self.buffered_builds[recname] = nil self.inst.replica.builder:SetIsBuildBuffered(recname, false) else self:RemoveIngredients(self:GetIngredients(recname), recipe) end local item = SpawnPrefab(recipe.product) if item == nil then return end item.Transform:SetPosition(inst.Transform:GetWorldPosition()) if not item.components.lootdropper then item:AddComponent("lootdropper") end if item.components.stackable ~= nil then item.components.stackable:SetStackSize(recipe.numtogive) end inst.components.talker:Say("Oops!") item.components.lootdropper:DropLoot() item:Remove() return true -- to prevent action fail speech. else return _Dobuild(self, recname, ...) end end end
  9. Ink Trail and Ink Damage Perk

    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..)
  10. 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.
  11. For me, I wrote the line as the directory name. Example
  12. Small help with tags

    Has the entity size increased? I thought it was 31 because I tested it about two or three months ago.
  13. 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
  14. I believe there's no GetClock or TheClock things in DST. You have to approach it by problem-specific. What exactly trying to do?
  15. I think this is what you're looking for. x,y,z = inst.Transform:GetWorldPosition()