Page 3 of 3 FirstFirst 123
Results 21 to 26 of 26

Thread: Multiplayer health via script

  1. #21


    For example, the original devs often did:


    // do stuff

    goto TestThread1

    I mean, it'll work, but I think loops are generally accepted as the best alternative to that:

    while (1)
    // do stuff

  2. #22


    Hmm, at the moment it's not doing much of anything. lol
    I replaced the "heal' thread with your updated version and "session" seems to work but not all and I may have screwed up with the "time" mode.
    Although I'm sure I followed your instructions correctly.
    I think it could come down to trigger size.

    Email sent, with map.

  3. #23


    Yeah, goto is definitely not what you want.

    As discussed before the two lines marked below will never be executed because the thread will move to 'heal' (rather than create a new one there):

    $vb_trig nottriggerable
    $vbcan hide
    wait 1
    $vendor playsound drink
    $vendor moveto shut_vendor
    $vendor time 1
    $vendor move
    wait 10
    goto heal
    $coin_trig triggerable // this will never be executed
    goto belch // this will never be executed

    The labels you pass in are case sensitive, so goto Heal would be the right format. It won't recognised 'heal'. It may be prudent to make my examples lowercase to match the rest of your script though.

    My code also assumes that 'Heal' is the entry point. Your entry point (setthread) in this example is 'takevb', and you have waits before you eventually call 'Heal'. What would happen if a player disconnects or dies during that period of 11 seconds? The server will be spammed with nasty errors. You also need to be sure that we're passing in both player and trigger. Luckily, we are in your example, but that may not always be the case.

    I just thought I'd respond to this example here as it's a real case, and may be useful to others. So yeah, change all 'goto' to 'thread' and make sure the label has the right case.

    As there are many entry points, and as such from my code I can't be sure if a player or trigger still exists when we get there, it's probably best to check this at the beginning of Heal:

    group.player = parm.other
    group.trigger = self

    // make sure the player and trigger exists (and is alive), if they don't then end here
    if !(isAlive group.player && group.trigger && group.player.dmteam != "spectator") end

    // we don't want the player to use healing spot if they already have full health
    // or if they are restricted (temporarily or otherwise)
    if (waitthread Restricted || == group.player.max_health) end

    local.hp = group.trigger.hp // grab the '#hp' property '5' we set on the trigger in Radiant
    local.mode = group.trigger.mode // grab the mode
    local.time = group.trigger.time // grab the time

    // do the heal
    group.player healthonly ( + group.trigger.hp)

    // play sound (comment this out if you don't want health sound, or include your own)
    group.trigger playsound med_kit

    switch (local.mode)
    // if mode is session or timed then restrict this healing spot for this player
    case "session":
    case "timed":
    thread RestrictHealingSpot; break
    case "single":
    group.trigger remove; break // remove the trigger as this is a single use trigger

    You may come across a scenario where a player sets off a trigger and the sound and 'animations' play after they have disconnected or died, so you may need to think about whether that is valid or not.
    Last edited by 1337Smithy; February 13th, 2020 at 10:20 AM.

  4. #24


    1337Smithy: Thanks mate.

    Yeah I noticed the capital "H" in "Heal" of the second script and I meant to change it but forgot to get back to it after disabling the original "heal" thread.

    I think it's best if I only use trigger_multiple.
    As it currently stands with the trigger_use triggers, a player could engage the trigger then run away and it still continues to play the sound effect, perform the scripted animation and gives the heal.
    This was why I was originally using the bind / glue, to keep them still long enough to earn the heal.

    As the player is the entity playing the sound effect, does it mean that only the respective player would hear the sound and it stops if he/she dies or disconnects?
    In some cases (i.e. the photocopiers), if the player moves away from the trigger, I'd like the sound and animation to play through but not the heal.

    edit: I think I need an "If" statement or "while" loop to ensure that the player is still there before calling the "thread heal".
    	while (1)
    	thread heal
    edit: Okay that caused the map to crash "command overflow: possible loop" or words to that effect.
    I guess I need to end the loop. I've only put in two threads.
    If it was more like VB I'd know to end while.
    Last edited by AccadaccA; February 13th, 2020 at 05:52 PM.

  5. #25


    Yes, you'll need a check there, but you wouldn't want to loop over 'heal' because that would be constantly trying to give players the amount of hp defined on the trigger over and over until the loop is told to stop. Remember, loops, as the name implies, cycle through the code inside them.

    On the subject of loops, you will always need a wait in there of some form or else you will get a command overflow, which is why you will often see a 'waitframe' (waits for one server frame - 0.05 seconds by default) at the very least inside a while loop. It's just a form of protection that the developers included. You can wait for a shorter amount of time than that but it may have consequences for server performance, so 'waitframe' is usually the resolution you should use if you just want to iterate over code as quickly as reasonably possible.

    But for what you want, it's probably best to make sure they are within a given distance to the healing spot. Using trigger_multiple won't fix your issue automatically, as a player could just trigger it and walk away, no different to a trigger_use. I'd refrain from binding or gluing them to entities unless you really have to. Artificially taking away player autonomy is generally considered a no-no, unless you really have to. Doing it organically, like being trapped behind a locked door, is usually fine, as it doesn't feel cheap to the player. In your case, and when it comes to multiplayer especially, you don't want a player to be forced to stay in one place while people are trying to kill them, unless of course they know beforehand that would be the trade-off. An example would be getting into a machine that straps them down. That would be considered more organic and thus less jarring for a player than being randomly stuck on the spot next to a photocopier or something.

    You'd be able to do what you want in a script, by checking that players are in the immediate vicinity right before a heal is administered. As with most things MOHAA, there are several ways you can achieve this. One obvious way is to add an invisible block around the location, which becomes the de facto healing area that players need to be inside to successfully heal. Maybe an easier method for you (saves you having to mess around with brushes in Radiant) is to just check distance via simple functions already built into the game.

    Such as:

    local.player = parm.other
    local.trigger = self
    local.trigger playsound pee_bowl
    wait 9
    if (local.player && vector_within local.player local.trigger 96)
    thread heal

    This will check that the player is within 96 units of the trigger (more specifically, the trigger's origin).

    It may be worth actually making it so that if the player isn't next to a trigger (or is dead) like with the photocopiers, that it then checks if any other player is so they can then get the heal. Another thing to ask yourself is if a 9 second wait is really necessary for the toilets? For people playing the map for the first time, it wouldn't be immediately obvious what will happen, and a lot can happen in 9 seconds. Would an instant heal be more appropriate for that example?

    You can make it more dynamic and less dependent on long arbitrary waits by doing something like this:

    local.trigger = self
    local.trigger nottriggerable

    local.player = parm.other
    local.player loopsound pee_bowl

    // the time that the piss will be complete (9 seconds from current game time)
    local.piss_time = level.time + 9

    // number of units that the player has to be within (use whatever number you want)
    local.distance = 96

    // wait for 'waitcheck' to finish
    local.do_heal = waitthread waitcheck local.piss_time local.distance

    // the sound should stop now
    local.player stoploopsound
    local.trigger triggerable

    // do the heal if local.do_heal is true
    if (local.do_heal)
    thread heal

    waitcheck local.time local.distance:

    local.trigger = self
    local.player = parm.other

    // keep waiting until the player either walks away, dies, disconnects, or has stayed for the duration
    while (isAlive local.player && vector_within local.player local.trigger local.distance)
    // each iteration of the loop we check if the right amount of time has passed
    if (local.time <= level.time)
    // player has stuck around for the whole piss!
    // lets get out of here and return true (1)
    end 1
    wait 0.25
    end 0

    What that will do is check every 0.25 seconds that the player is still next to the toilet. If they move away, the sound stops and they have to start again. This would give them an audio 'cue' that tells them they need to stay for the full piss until they get their reward. At least then they will have a choice of whether to leave or stay if they hear a playing approaching.

    You can then use this 'waitcheck' function for any of your healing spots to check that the player is in the right place.

    Just an idea.
    Last edited by 1337Smithy; February 15th, 2020 at 03:45 AM.

  6. #26


    Yep I totally agree about being stuck for no visible or logical reason, it's like having a clip / invisible wall cutting off the road without barbed wire or something visible there. It just doesn't feel right.
    I had thought to close the stall door behind the player when triggered, wait for thread completion then open the door for them.
    Because of the slight differences between these um "stall event" threads I was going to rotate doors open clockwise for one type (i.e #1's) and rotate doors counter clockwise for the other (#2's) but I was at a loss for things like the photocopiers.
    Although I'm not too fussed about keeping the player still for the shorter health pick-ups, just the vending machine and toilets.
    I knew that there was / is a way of detecting if a player was still within the trigger or not, like how you wrote the flag pole script for Amazement and the "isTouching" I've seen in your scripts.

    You've obviously put a lot of thought into these scripts and it shows.
    Your efforts are truly appreciated, mate.
    I think this is exactly what I would like for the map.
    Thank you.

    I'm glad that I stopped by this morning as last night I called the map completed, sent it off to a mate and walked away from the PC.
    I actually watched television for the first time in months, two movies at that. Which I hadn't sat through a movie in bloody years.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts