Jump to content

Recommended Posts

Hi,

 

I have this code in modmain

 


AddComponentPostInit("talker", function(Talker, inst)

  Taler.old_Say = Talker.Say

  function Talker:Say(script, time, noanim, force, nobroadcast, colour)

    --how to filter only for mychar?

    script = "That's all I can say"

    return Talker:old_Say(script, time, noanim, force, nobroadcast, colour)

  end

end)


 

This works but it affects all (I haven't tested). How do I change it so it only affects mychar?

(Yes mychar can only say "That's all I can say" to ANYthing. Lol.

 

Thanks for help.

@SenL, try this:

AddComponentPostInit("talker", function(self)  local old_Say = self.Say  function self:Say(script, ...)    if self.inst.prefab = "mychar" then        script = "That's all I can say, after all, I'm "..self.inst.prefab    end    return old_Say(self, script, ...)  endend)

- When using AddComponentPostInit, the function gets the component as an argument (here, self).

- self.inst is the player who has the talker component attached to it.

- The "..." basically contains all the arguments passed down to the Say function that are not needed here. Shortens the code a bit.

- When calling old_Say, you have to give self as an argument, because it's not called from the component.

@SenL, What Jjmarco said, but as a side note, it's better to use the "local old_Say" type of construct instead of attaching old_Say to Talker. The point of modifying a function like that is to make it compatible with other mods (otherwise you could just replace the whole function), but if you attach it to Talker.old_Say, then another mod doing the same thing would overwrite Talker.old_Say.

It works!!

Wow quite a lesson there. Thank you sir!

 

Edit:

I was copying the code I found on a thread where the char does not chop effectively

 

In it:

AddComponentPostInit("workable", function(Workable, inst)
  Workable.old_WorkedBy = Workable.WorkedBy
  function Workable:WorkedBy(worker, numworks)
    if worker.prefab == "mychar" and Workable.action == GLOBAL.ACTIONS.CHOP then
      numworks = numworks/2 or 0.5
    end
    return Workable:old_WorkedBy(worker, numworks)
  end
end)
 
Should I change this one too?
Edited by SenL

Changed it to below

AddComponentPostInit("workable", function(self)
  local old_WorkedBy = self.WorkedBy
  function self:WorkedBy(worker, numworks)
    if worker.prefab == "mychar" and self.action == GLOBAL.ACTIONS.CHOP then
      numworks = numworks/2 or 0.5
    end
    return old_WorkedBy(self, worker, numworks)
  end
end)
 
It seems to work.
Does it look good?

1)

How do I lengthen the duration of the text being shown?

It seems to disappear after 2 seconds (I need it to stay for 3-4).

 

Edit: inst.components.talker:Say("blabla", 4) seems to work.

 

2)

How do I change the color of the text...

The function has this parameter but I don't know what value to pass...

 

function Talker:Say(script, time, noanim, force, nobroadcast, colour)

 

Thanks.

Edited by SenL

The talker is fine but it has a bug.

 

My code is:

AddComponentPostInit("talker", function(self)
  local old_Say = self.Say
  function self:Say(script, ...)
    if self.inst.prefab == "mychar" then
      if script and type(script) == "string" then
        if string.sub(script, 1, 2) == "$$" then
          script = string.sub(script, 3)
        else
          script = "Hi"
        end
      end
    end
    return old_Say(self, script, ...)
  end
end)
 
When I play and gain exp, I pass in "$$Exp " .. inst.exp etc etc so that it would say "Exp: 50" for example instead of just "Hi".
However, when a client joins (also as mychar), and he gains exp, his mychar only says "Hi" (should say Exp: #).
How do I fix?
 
Thanks.

@SenL, There's a better way of checking if a string starts with a specific word/character. The find or the match functions of string:

if script:find("^%$%$") thenor if script:match("^%$%$") then

Match and find are pretty similar, but the first returns the start and end indexes, then the matched string, while the other only returns the matched string.

 

They both use regular expressions for finding strings, and '$' is a reserved character, so you have to prepend it with '%' so these functions can match it as a litteral character.

'^' means "match at the start of the string, while '$' means "match at the end of the string".

So "^%$%$" means "match two '$' at the start of the string".

 

You can rewrite your code like so:

if script:find("^%$%$") then -- if two '$' are found at start of string    script = script:match("^%$%$(.*)$") -- script now contains everything after themelse    script = "Hi"end

or even more compact:

script = script:match("^%$%$(.*)$") or "Hi" 

script:match("^%$%$(.*)$") will return the string that's after the two '$', and will return nil if it finds nothing.

'.' means "match any character" while '*' means "match the previous character zero or more times, as many times as possible".

The parenthesis '()' are a capturing group, which will make the match function return only the text matched in between them (in this case, all the text right after the $$).

 

More information about Lua's string matching functions here.

 

This might not be necessary for what you are trying to accomplish here, but it's always useful information for the future!

 

Also, the issue might be that script doesn't contain "$$Exp..." at all for some reason, because your code should work like this. You could put a "print(script)" somewhere and look at the console?

@Jjmarco

Thanks for the tip, I will study that and change.

 

I'm not sure what but it works for the host.

Maybe for client the string or talker is handled differently?

 

I will try the print()

 

Edit:

Maybe I'll move away from using $$ but using something else that's not reserved... hmm... **? ##? ::?

Edited by SenL

The script on the client doesn't contain $$ at all for some reason.

 

Code inside mychar.lua

local function applyupgrades(inst)

  --snip

  inst.components.talker:Say("$$Level " .. inst.level)

end

 

Other code is the same.

 

Not sure how to fix it.

Alternatives would be: a) widget to show level (I have no idea still how to do this), b) some kind of item that says what level when examined.

@Jjmarco The applyupgrades() is being called by

  1. entitydeathfn(), which is being called by master_postinit

    inst:ListenForEvent("entity_death", function(world, data) entitydeathfn(inst, data) end, TheWorld)

  2. oneat(), which is being called also by master_postinit

    inst.components.eater:SetOnEatFn(oneat)

  3. onpreload(), which is being called also by master_postinit

    inst.OnPreLoad = onpreload

  4. onbecomingalive(), which is being called also by master_postinit

    inst:ListenForEvent("ms_respawnedfromghost", onbecomingalive)

 

So I guess master_postinit for all.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
  • Create New...