Jump to content

Creating a campfire with a healing area effect


gigantibyte

Recommended Posts

If this has already been created, let me know. Actually, any mod item with a semi-persistent proximity effect on actor values would be useful to learn from. Is there anything that works like radiation in reverse?

 

I've updated my mod to make gathering scrap wood a thing. With 5 scraps of wood the player can build a campfire. (Well, at this point, it's just a copy of the campfire activator model, bound to a static object.) Adding activate options, such access to recipe menu won't be a problem, but I rather not have the campfire act as a quick healing station. Instead, the campfire when lit will emit a healing field that the player must be inside to gradually benefit from. If I can get this working, it should be like the Radiation Limb Regeneration perk from FO3.

 

I think I may be able to accomplish the regeneration aspect through use of the GetFirstRef / GetNextRef / GetRefs functions. I've just never used them, so I'm unsure of the parameters I need to confine the search for actor references in a world space. I don't want the campfire to heal everyone in the Mojave! The healing field should be restricted to actors within a few arm lengths of the campfire.

 

The campfire will have flame visuals and eventually burn out of course, and I hope to add other features such as using action points to heal faster, and an added danger of attracting hostiles. For now though, I certainly would be grateful if anyone could help with the script needed to get the actor references that meet the campfire's proximity condition.

Edited by gigantibyte
Link to comment
Share on other sites

Do you want this healing effect to work for all actors or only for the player?

 

If it's only the player, you just need a script attached to the campfire form to check the players distance and apply healing by casting a spell or by modifying the actor value directly.

 

If it's for all actors, then you need to do the same thing, but you need to get the references of all nearby actors before you can do something with them. That's where GetFirstRef/GetNextRef comes in.

Link to comment
Share on other sites

If it's for all actors, then you need to do the same thing, but you need to get the references of all nearby actors before you can do something with them. That's where GetFirstRef/GetNextRef comes in.

 

All actors. The aim is for the healing effect to work on companions too. It should work on enemies as well, so that the player must be careful where they build it.

 

For GetFirstRef/GetNextRef, I think I have a handle on the example script given in the wiki. I just need a proper distance number to the actor from the campfire and include

if ActorRef.GetDistance <= ValidDistance

in the loop to validate the actors. But what do I set GetNextRef's cell depth parameter to? And what's the scale with GetDistance?

Link to comment
Share on other sites

I think a cell depth of 1 should be fine, that will get you all the actors in the player's current cell as well as the 8 surrounding cells.

 

If I remember correctly, an NPC has a default height of about 128 units, so you can use that to work out how large the distance should be.

Link to comment
Share on other sites

Thanks! A related question if you know. To create a campfire players need to drop some scrap wood and activate it. In case the player just leaves the scrap wood on the ground, I'd like it to be eventually deleted. According to the page for MarkForDelete "With items that can be dropped from inventory but work on their own, every drop and every pickup is a disable." Does this mean I don't need to include Disable in the scrap wood's object script? My intention is do a MarkForDelete on the scrap wood as soon as it is dropped, but obviously it can't be disabled right away. It would just be a fail safe, because under normal use the scrapwood will be disabled upon building a campfire, and the campfire will be diabled once it burns out.

 

Edit: Nevermind. I setup the object script to disable/markfordelete in the Onload block, after it has loaded at least once normally.

 

So mostly everything is working as envisioned. Drop some wood, then activate it to assemble the wood into a campfire form. Click on the assembled wood again to light the fire. Once the fire is lit, the GetFirstRef/GetNextRef loop runs, and it does indeed find actors. (I scripted a popup to appear each time one was found.) It just doesn't seem to be finding the player, and there isn't any distance condition yet. I set the loop to award a cap to each actor found, but my wallet never grew. Not sure what's up...

 

Maybe the player is not supposed to be found?

Edited by gigantibyte
Link to comment
Share on other sites

Wait, I'm confused. You drop the wood from your inventory and then you activate it to build the campfire, right? But if you run disable/markfordelete in the OnLoad block of the wood, doesn't it disappear immediately?

 

As for the rest, yes, the player is a special condition, since he isn't returned by those functions. I completely forgot about that. This is, of course, trivial to set up, just do things as you would normally if it was to only work for the player, as I described in the first post.

Edited by Ladez
Link to comment
Share on other sites

Wait, I'm confused. You drop the wood from your inventory and then you activate it to build the campfire, right? But if you run disable/markfordelete in the OnLoad block of the wood, doesn't it disappear immediately?

 

It doesn't hopefully through the use of a control variable, but maybe my script is configured incorrectly and the scrap wood will never disappear. Could you review the following?

scn UltmScrapWoodScript

ref User
int awaitingInput
int MenuChoice
int DoOnce

Begin onActivate

    let UltmSMainQuest.ScrapWoodCount := GetRefCount
     Set User to GetActionRef
     If GetActionRef != Player
          User.Activate
     Elseif GetActionRef == Player
        let awaitingInput := 1
        messageboxEX "What would you like to do?|Assemble wood for campfire|Take|Cancel"
    endif

end

Begin MenuMode
    if awaitingInput == 1
        Let MenuChoice := GetButtonPressed
        if MenuChoice == -1
            return
        endif
        let awaitingInput := -0
        if MenuChoice == 0
            if GetRefCount >= 5
                let UltmSMainQuest.CamfireRef := placeatme UltmSCampfire 1
                let UltmSMainQuest.ScrapWoodCount := GetRefCount
                disable
                markfordelete
            else
                messageboxEX "Not enough wood"
            endif
        elseif MenuChoice == 1
            player.additem UltmScrapWood UltmSMainQuest.ScrapWoodCount
            disable
            markfordelete
        endif
    endif
end

Begin Onload
    if DoOnce
        disable
        markfordelete
    else
        let DoOnce := 1
    endif
end

Right now though, I'm having fun trying modify health and body parts gradually. Using a Setav can make a body part health go over the base of 100, and since Setav affects base, I can't use it on Health. RestoreAV on the other hand seems to restore up to the value given, so I can't do a RestoreAV Heath 1 every second to restore 1 unit of health. Maybe something like this:

if (rActor.GetBaseAV Health) > (rActor.GetAV Health)
     let NewHealth := (rActor.GetAV Health) + 1
     rActor.RestoreAV Heath NewHealth
endif

then repeat for each body part, like PerceptionCondition, but with 100 instead of GetBaseAV.

 

Edit: "let UltmSMainQuest.CamfireRef := placeatme UltmSCampfire 1" above is actually useless. It turns out I didn't need to pass the reference anywhere.

Edited by gigantibyte
Link to comment
Share on other sites

It doesn't hopefully through the use of a control variable, but maybe my script is configured incorrectly and the scrap wood will never disappear. Could you review the following?

 

Ah, that makes sense. The wood will disappear the second time the 3d art is loaded, since by that time the variable is set.

 

Right now though, I'm having fun trying modify health and body parts gradually. Using a Setav can make a body part health go over the base of 100, and since Setav affects base, I can't use it on Health. RestoreAV on the other hand seems to restore up to the value given, so I can't do a RestoreAV Heath 1 every second to restore 1 unit of health. Maybe something like this:

 

Maybe using an actor effect will simplify things a bit. That way you don't have to do all these calculations in order to heal over time. Just apply it on actors that are within range and remove it when they leave.

Link to comment
Share on other sites

Woohoo! I finally got the effect functioning as desired.

 


Maybe using an actor effect will simplify things a bit. That way you don't have to do all these calculations in order to heal over time. Just apply it on actors that are within range and remove it when they leave.

 

^ This is indeed the best solution. Modifying the health values in a controlled fashion through script alone is tricky. So I created a new "spell" that used several effects. There is an inherent effect called 'Restore Health Stimpak' effect, which modifies both health and conditions, but the magnitude value works on different scales for health and limbs. A magnitude of 1 for instance restores 1 unit of health, but only 0.1 units of limb condition. Here's what the "spell" looks like:

 

http://i.imgur.com/7UrXjbU.jpg

 

 

There's also a separate restore effect for all limbs, but without checks to prevent condition values over 100. I had to add that condition myself for each limb like this:

 

http://i.imgur.com/KGl2IEu.jpg

 

 

Finally, although 'Restore Health' didn't allow the player's health to go over the maximum, it did set the companion's health over the limit. Since each companion would have a different maximum health value, I had to add a check for this in my script, and "damage" the health back down to normal. Here's the script section for regeneration:

    if Burning == 1
        if timer < BurnTime
            let timer += GetSecondsPassed
            if count <= timer
                let count += 1 ; make sure a full second passes, not a fraction
                if GetDistance player <= 150
                            player.CastImmediateOnSelf UltmSCampFireSpell
                endif    
                set rActor to GetFirstRef 200 1 ; * 200 == actors
                while rActor != 0
                    if rActor.GetDead || rActor.GetDisabled || rActor.GetIsCreature
                         ; skip
                       else
                          if GetDistance rActor <= 150
                            rActor.CastImmediateOnSelf UltmSCampFireSpell
                            if rActor.GetBaseActorValue Health < rActor.GetAV Health
                                rActor.DamageAV Health 1
                            endif
                        endif
                    endif
                      set rActor to GetNextRef ; * make sure this is within the loop or CTD
                loop
            endif
        else

Restoration is slow, but a distance of 150 seems reasonable in-game. Move too far away, and the regeneration stops. As for the speed, I think I'll leave it the way it is, and wait for comments. At present it takes 100 seconds to fully restore a limb from a condition of 0, give-or-take a few decimal points. Also, my companion ended up with a Health value of 1 over the base. An acceptable result I think. No limbs went over 100 which is great.

Edited by gigantibyte
Link to comment
Share on other sites

I now tend to avoid to put a scanner and x nested conditions inside the same frame, especially when it uses a function like getdistance, I would suggest to stage it.

 

anyway, when I've seen this amazing campfire idea, I thought to a solution I personally never tried but I've read people were using it in the past... a fake explosion. no sound or graphic, only its radius and eventually some spell casted on those affected by this fake explosion

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...