Aller au contenu

Photo

Can someone tell me what is wrong with this script?


  • Veuillez vous connecter pour répondre
23 réponses à ce sujet

#1
andysks

andysks
  • Members
  • 1 645 messages

Hi all. After some help I got from Tchos and KevL to complete this script, I now ask all of you :). The script compiles, and seems to be running good. Except the damage section. What it does: Another script spawns a SEF as warning. Then this one, which runs from hb, spawns another SEF like lightning, and if after the warning a member of the party didn't go away, should get some damage. All SEFs and hb running fine, but I don't know why I cannot make the damage to apply. It looks for distance between the OBJECT_SELF, which is the ipoint spawning the lightning SEF and a Faction Member. Or so I think I did...

#include "ginc_effect"

void main()
{
 
	int bAlreadyCast = GetLocalInt(OBJECT_SELF, "CAST");
	if(!bAlreadyCast)
	{
	//Applying SEF and sound.	
	ApplySEFToObject("sp_lightning_hit", OBJECT_SELF,  2.0f);
	PlaySound("sff_electricexp", FALSE);
	
	
	object oPC = GetFirstPC();
        object oFM = GetFirstFactionMember(oPC, FALSE);
    
	//Here we loop through party to see if anyone is near the lightning.
	while (GetIsObjectValid(oFM))
        {
        if (!GetIsOwnedByPlayer(oFM))
        { 
            float fDistance = GetDistanceBetween(OBJECT_SELF, oFM);
			
            if (fDistance <= 3.0f)
            {
             effect eDamage = EffectDamage(12, DAMAGE_TYPE_ELECTRICAL,DAMAGE_POWER_ENERGY, FALSE);
             ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFM);
            }
             
        }
        oFM = GetNextFactionMember(oPC, FALSE);
        }	
	
	SetLocalInt(OBJECT_SELF, "CAST", TRUE);
	DestroyObject(OBJECT_SELF, 4.0f, FALSE);
	}
}


#2
Lance Botelle

Lance Botelle
  • Members
  • 1 480 messages

Hi,

This script self-terminates after 4 seconds regardless of whether a PC is within range to take the damage or not.

Therefore, if this object is spawned and the PCs do not approach it, then the lightning effect will play and the object will destroy itself in four seconds, by which time the PCs may not yet have reached the range when damage is applied.

Without seeing the rest in action, that's all that comes to mind just now.

Just out of interest, won't !GetIsOwnedByPlayer prevent the Main PC from taking damage if the player is playing it?

Cheers,
Lance.



#3
kevL

kevL
  • Members
  • 4 056 messages

Just out of interest, won't !GetIsOwnedByPlayer prevent the Main PC from taking damage if the player is playing it?

!GetIsOwnedByPlayer means not (a) mainPC object. Doesn't matter if player has control, Lance.

you might be thinking of !GetIsPC() - that means not player-controlled object. To prevent a mainPC from taking damage iff it's controlled:

if (!GetIsPC(oTarget)
    || (GetIsPC(oTarget) && !GetIsOwnedByPlayer(oTarget)))
// ... do damage.


For in-game returns - for these and other character functions & variables - see c-info. It's thorough, tested & debugged afaict.

#4
andysks

andysks
  • Members
  • 1 645 messages

I see. Tchos already told me to destroy it later but I guess 4 seconds was not enough. I will test it with more and see how it goes. Thanks.



#5
Lance Botelle

Lance Botelle
  • Members
  • 1 480 messages

!GetIsOwnedByPlayer means not (a) mainPC object. Doesn't matter if player has control, Lance.

you might be thinking of !GetIsPC() - that means not player-controlled object. To prevent a mainPC from taking damage iff it's controlled:









if (!GetIsPC(oTarget)
    || (GetIsPC(oTarget) && !GetIsOwnedByPlayer(oTarget)))
// ... do damage.
For in-game returns - for these and other character functions & variables - see c-info. It's thorough, tested & debugged afaict.

 


Hi KevL,

I find the function description very confusing, for it says ... "Note that if this creature is being controlled by the player, but is not the player's original "owned" character, this will return FALSE." (From below.)

EDIT: OK, I just did a debug test, and I see that no matter who is possessed, the Main PC always returns TRUE and the companions always return FALSE.

EDIT: ... Which means if we use !GetIsOwnedByPlayer, then the loop to do the damage will only affect the companions and NOT the Main PC.

 

I now see that actual possession is not an issue, but the result still means the Main PC will not take damage during this loop. (Is that the desired result?)

 

EDIT: This is why I have NEVER used this function to date! I could never see any reason for it.

Cheers,
Lance.


///////////////////////////////////////////////////////////////////////////////
// GetIsOwnedByPlayer
///////////////////////////////////////////////////////////////////////////////
// Created By: Brock Heinz - OEI
// Created On: 09/19/05
// Description: Checks to see if this creature is owned by a player
// Returns: TRUE if oCreature is owned by a player.
// Note that if this creature is being controlled by the player, but is
// not the player's original "owned" character, this will return
// FALSE. You can check for control with GetIsPC()
///////////////////////////////////////////////////////////////////////////////
int GetIsOwnedByPlayer( object oCreature );



#6
Lance Botelle

Lance Botelle
  • Members
  • 1 480 messages

I see. Tchos already told me to destroy it later but I guess 4 seconds was not enough. I will test it with more and see how it goes. Thanks.


I suppose it depends on how long you want the potential risk to hang around for the PCs. If you want it to hang around until they take damage (i.e. cannot out wait it), then place the destroy function within the distance check as well. ;) If, however, you want to allow the PCs a chance for the lightning to dissipate, then increase your destroy time until the time has passed for it to be safe to pass.

 

EDIT: What Tchos points out below is correct, which means you would have to add a self-checking function within this script that kept firing every second or so to determine of the PCs are within range or not. Then terminate when the time check is over.

Note, from the above discussion between KevL and I, I don't think your player's Main PC will take damage at all. Is this what you wanted?

Cheers,
Lance.



#7
Tchos

Tchos
  • Members
  • 5 042 messages

The damage risk will not increase with a longer delay on the destruction as the script is currently written, because it only checks for PC proximity once (when the lightning SEF and sound effect happen), and then marks itself done.



#8
kevL

kevL
  • Members
  • 4 056 messages

Andy,
based on commments, is this more like what you're after

void main()
{
    SendMessageToPC(GetFirstPC(FALSE), "run Electricity script"); // DEBUG

    if (!GetLocalInt(OBJECT_SELF, "bActive")) // this needs to be set TRUE by the warning ...
    {
        SendMessageToPC(GetFirstPC(FALSE), ". inactive"); // DEBUG
        return;
    }

    SendMessageToPC(GetFirstPC(FALSE), ". ACTIVE"); // DEBUG


    object oPC = GetFirstPC();
    object oFM = GetFirstFactionMember(oPC, FALSE);
    while (GetIsObjectValid(oFM))
    {
        if (!GetIsOwnedByPlayer(oFM))
        {
            float fDistance = GetDistanceBetween(OBJECT_SELF, oFM);
            SendMessageToPC(GetFirstPC(FALSE), GetName(oFM) + ": fDistance = " + FloatToString(fDistance)); // DEBUG

            if (fDistance <= 3.0f)
            {
                SendMessageToPC(GetFirstPC(FALSE), "target found, destroy self"); // DEBUG

                effect eVis = EffectNWN2SpecialEffectFile("sp_lightning_hit");
                ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eVis, OBJECT_SELF, 2.0f);
                PlaySound("sff_electricexp");

                effect eDamage = EffectDamage(12, DAMAGE_TYPE_ELECTRICAL, DAMAGE_POWER_ENERGY);
                ApplyEffectToObject(DURATION_TYPE_INSTANT, eDamage, oFM);

                DestroyObject(OBJECT_SELF, 1.0f);
                break; // one shot
            }
        }

        oFM = GetNextFactionMember(oPC, FALSE);
    }
}


ps. tested. That worked (from a stock cabinet's heartbeat), I took out the 'ginc_effect' dependency, and use "bActive" local TRUE before it will trigger

#9
kevL

kevL
  • Members
  • 4 056 messages

ps. i bet that PlaySound() isn't doing squat there and should be taken out. Usually a sound ninja is needed to get sound to play from any object without an action queue, like a cabinet or iPoint ... anything other than a character or perhaps an explicit sound-object. The sound I heard is likely coming from the .SEF



#10
Lance Botelle

Lance Botelle
  • Members
  • 1 480 messages

Hi KevL,
 
Yes, "sounds" can be a pain ... I now have a failsafe system that creates a temporary placeable object at the PC location to play the sound and then destroy itself. Works like a charm!
 
And sorry to stress this point, BUT ... won't the if statement if (!GetIsOwnedByPlayer(oFM)) mean that the Main PC won't suffer any damage? This may be the desired effect wanted .... but, I wanted to make sure I had understood this function as you understood it.

I think you need:- if(!GetIsOwnedByPlayer(oFM) || GetIsPC(oFM)) to ensure everybody in the party (including the Main PC) is damaged.
 
EDIT: I even made myself a GetMainPC(); function to:
 
( A ) Have a function to get the Main "owned" PC, and ....
( B ) Use the same to determine if the tested creature was a member of the party by NOT excluding the MainPC in such loops. (!= OBJECT_INVALID) *
 
* Using said function on an "owned" PC would return itself and NOT OBJECT_INVALID.
 
EDIT 2: The other function, GetOwnedCharacter, is a somewhat more complicated function, which can be used to retrieve the Main PC, which indirectly does tell us if the oFM making the check is a party member or not by not returning an OBJECT_INVALID. However, its use in a loop is not so straight forward, especially if you want to include other members in a party that the official functions do not include.
 
 
Cheers,
Lance.
 
A SIMPLE TEST:-
 
Create a switch, which when used causes damage/feedback to everybody in a party using a loop. Here is the equivalent to the code used above but without the "!":-
 

	object oPlayer = GetLastUsedBy(); 
object oFM = GetFirstFactionMember(oPlayer, FALSE);
		
		while(oFM != OBJECT_INVALID)
		{
			if(GetIsOwnedByPlayer(oFM))
			{
				SendMessageToPC(oPlayer, ">>> " + GetName(oFM) + " IS OWNED BY PLAYER");			
			}
			
			else {SendMessageToPC(oPlayer, ">>> " + GetName(oFM) + " IS NOT OWNED BY PLAYER");}
		
			oFM = GetNextFactionMember(oPlayer, FALSE);
		}

This will always return the Main "original" PC no matter who the player posses. Reversing the logic using the "!" will just mean all party members EXCEPT the Main PC will be returned.



#11
andysks

andysks
  • Members
  • 1 645 messages

I am not sure I am following the factions here, but I need to say for Lance's favor to avoid confusion that the PC should as well take damage in my situation. I didn't have time to test the script KevL posted, but I would think that he tested it without companions(?), so maybe the main PC does indeed takes damage :). I will test now with companions and see what's going on.



#12
andysks

andysks
  • Members
  • 1 645 messages

K I've seen a lot of things, I might write a book about :D. What can cause a script to fire on an area, even if it's not attached anywhere? This is taking me to other places. I will post both scripts now and see maybe what's going on with more clarity and help.

 

This script's job is to spawn the warning and the ipoint which will cause pain and effect. This is created in the beginning of the combat and destroyed at the end.

(Problems with it after the script).

#include "x0_i0_position"
#include "ginc_effect"

void main()
{
	
    object oPC    = GetFirstPC();
    object oArea  = GetArea(oPC);
    object oCenter= GetObjectByTag("area_center_ip");
    location lLoc = GetRandomLocation(oArea, OBJECT_INVALID, 0.0f);
    

    ApplySEFToLocation("ror_pc_guardian_glow1", lLoc, 3.0);
    CreateObject(OBJECT_TYPE_PLACEABLE, "plc_roe_ip_bpcapt", lLoc, 0, "");

}

So I get into the game, on a newly created testing area and I see the effects spawning even without activating them with a lever.

 

The next one, KevL's, is the script running from the ipoint which is created by the previous one's heartbeat. Its job is to create another effect and damage. Then mark as done and destroy itself. I won't post it since it's KevL's from above at the moment. So, KevL noted that the "bActive" should get set by the warning. That is, the script above. And then the script causing damage, set it back to FALSE? Or will that be taken cared of by the Destruction of the second ipoint, so no need to set it back and up again on every heartbeat?

 

The two together, seem to have consistency problems. I have no clue why. In the beginning I wanted to have the regulator be responsible only for spawning the second ipoint. And every effect and damage to happen from there. However I couldn't figure out how to create a warning, wait, and then the rest. If this is going way over my league I will drop it and go for something easier for this boss fight.



#13
Lance Botelle

Lance Botelle
  • Members
  • 1 480 messages

Hi andysks,
 
OK, maybe I should try approaching a solution from afresh ... bearing in mind what you already know ... and what I think you want.
 
With that in mind, why not approach this using one simple placeable object and its heartbeat script?
 
E.g. (Using pseudocode explanation/theory)
 
Heartbeat on placeable checks every six seconds ....
 
1) If the player is Not in the area, simply return and wait another heartbeat.
2) If the player is in the area but still way out of the placeable for the effect, then simply return and wait another heatbeat.
3) If the player is within x distance of placeable on its heartbeat, then fire a SEF via placeable as a warning.
4) If the player is within y (closer than x) distance of placeable on its heartbeat, then do the damage to the PCs within range.
5) Choose to destroy (or deactivate) placeable object as you see fit ... i.e. You can simply switch its state on or off with a variable.

 

You can make this fairly simple by not messing with heartbeat rates (i.e. keep to six seconds) or increase if the PCs get closer (using SetCustomHeartbeat *) for more accuracy. Or, if the PCs have to destroy the placeable, then every six seconds having damage should be more than enough, especially if it takes more than a couple of rounds to destroy it subject to its hit points.

 

And as long as you don't have a ton of placeables with heartbeat scripts, then this won't be a resource issue. I have quite a few running, and I still don't notice any issues ... and I mean quite a few.

 

The point is, you don't have to destroy this placeable until you want it destroyed ... if at all. It can remain as a deadly device with every beat of its heart. ;)

 

Cheers,

Lance.
 

* If you use this function, be sure to lower the rate again if the PCs back away from the placeable object. This could if left unchecked potentially affect resources if used in many places.



#14
andysks

andysks
  • Members
  • 1 645 messages

Lance thanks for the reply. This is a boss fight, something like the boss' special power. So to answer the numbered points:

 

1: I can create the placeable when the fight starts. So it doesn't need to return if we are not there.

2: Same goes here.

3: The SEFs will fire anyway. No matter where we stand. Only if in bad luck we stand where the warning SEF spawns, then we need to care and move. So I don't think a check on the distance is needed for the warning SEF to fire.

4: Here is needed however, yes.

5; And this yes, in the end of the battle.

 

I think I got people confused, because I didn't want to spoil too much. But what the hell, here is the sequence of what I wanted exactly.

 

1: Fight starts with a trash talk, where in the end I create an ipoint with a heartbeat. Let's call this ipoint1

2: This heartbeat checks conditions and creates other ipoints. Let's call this ipoint2

3: The ipoint1 creates a warning effect on a random location, and on the same location an ipoint2. Regardless of distance, where PCs stand etc. Plain random.

4: PC sees the warning, or not, and has to go away because of (5).

5: ipoint2 creates a lightning effect and causes damage to any party member, including the main PC if they didn't go away enough.

6: ipoint2 destroys itself, but first marking the process as done.

7: ipoint1 continues creating ipoint2s, so that we may have 2-3 at the same time but that's OK.

8: Battle ends and ipoint1 destroys itself so that we stop the whole thing.

 

I did this with a spell and it worked to be honest, but the call lightning had too big of a radius to be used so I chose an effect that will be small and just on the warning's spot.

 

The first script I posted, worked fine except the damage. I guessed it's the loop but then things got more complicated. And the other thing I mentioned, what can cause such a thing? An area with nothing on it but the ipoint1 script firing? Is it getting the location lLoc = GetRandomLocation(oArea, OBJECT_INVALID, 0.0f);

on... a module scale? Even if it's placed on a small area? Because, numbered again:

 

Area 1: Has all scripts running and I see warnings and stuff.

Area 2: Is a completely empty area, from scripts and placeables but I still see the stuff, lol.



#15
Lance Botelle

Lance Botelle
  • Members
  • 1 480 messages

Lance thanks for the reply. This is a boss fight, something like the boss' special power. So to answer the numbered points:
 
1: I can create the placeable when the fight starts. So it doesn't need to return if we are not there.
2: Same goes here.
3: The SEFs will fire anyway. No matter where we stand. Only if in bad luck we stand where the warning SEF spawns, then we need to care and move. So I don't think a check on the distance is needed for the warning SEF to fire.
4: Here is needed however, yes.
5; And this yes, in the end of the battle.


To do point 4 and 5, just add them as "if" statements to the script you already have then, checking the new distance to the PCs.
 

I think I got people confused, because I didn't want to spoil too much. But what the hell, here is the sequence of what I wanted exactly.


Yes, I can understand that. :)

1: Fight starts with a trash talk, where in the end I create an ipoint with a heartbeat. Let's call this ipoint1
2: This heartbeat checks conditions and creates other ipoints. Let's call this ipoint2
3: The ipoint1 creates a warning effect on a random location, and on the same location an ipoint2. Regardless of distance, where PCs stand etc. Plain random.
4: PC sees the warning, or not, and has to go away because of (5).
5: ipoint2 creates a lightning effect and causes damage to any party member, including the main PC if they didn't go away enough.
6: ipoint2 destroys itself, but first marking the process as done.
7: ipoint1 continues creating ipoint2s, so that we may have 2-3 at the same time but that's OK.
8: Battle ends and ipoint1 destroys itself so that we stop the whole thing.


I'm still trying to picture this, but assuming I understand ...

Why not avoid creating an ipoint1 and just jump straight to creating all the ipoint2s you will need that react/activate according to their own HB scripts? (After all, the area where they are to be created can't be that big surely?) Note also, that if an ipoint is destroyed, there is no need to mark it as done, because it no longer exists anyway ... unless you want to prevent it from activating again prior to the next HB. In other words, make ipoint2s autonomous and not rely on ipoint1 if possible.
 

I did this with a spell and it worked to be honest, but the call lightning had too big of a radius to be used so I chose an effect that will be small and just on the warning's spot.


Makes sense.
 

The first script I posted, worked fine except the damage. I guessed it's the loop but then things got more complicated. And the other thing I mentioned, what can cause such a thing? An area with nothing on it but the ipoint1 script firing? Is it getting the location lLoc = GetRandomLocation(oArea, OBJECT_INVALID, 0.0f);
on... a module scale? Even if it's placed on a small area? Because, numbered again:
 
Area 1: Has all scripts running and I see warnings and stuff.
Area 2: Is a completely empty area, from scripts and placeables but I still see the stuff, lol.


I'm not sure I understand this part. However, scripts can fire in an area you don't occupy (unless you code otherwise) and you may be getting feedback from that ... i.e. Feedback can come from any area. But, as I say, I'm not sure I understand what you are trying to say here.

Come back to me with more if you want.

Cheers,
Lance.

#16
Tchos

Tchos
  • Members
  • 5 042 messages

I was the one who suggested ipoint 1 to him, because I like to work with "master control" regulators for events such as boss fights, where they run the show for the duration of the event, controlling as many separate elements as necessary.  The secondary ipoints are ones that I designated as "fire and forget" spell ipoints originally (when he mentioned the ipoint was casting Call Lightning before), which would have a single job -- cast Call Lightning, then destroy itself.  The script has changed since then, so this method may not make as much sense.  The marking as done is indeed a safety net to prevent it from casting the spell again before it destroys itself.



#17
Lance Botelle

Lance Botelle
  • Members
  • 1 480 messages

I was the one who suggested ipoint 1 to him, because I like to work with "master control" regulators for events such as boss fights, where they run the show for the duration of the event, controlling as many separate elements as necessary.  The secondary ipoints are ones that I designated as "fire and forget" spell ipoints originally (when he mentioned the ipoint was casting Call Lightning before), which would have a single job -- cast Call Lightning, then destroy itself.  The script has changed since then, so this method may not make as much sense.  The marking as done is indeed a safety net to prevent it from casting the spell again before it destroys itself.


Hi Tchos,

No problem. :) It's just one of those things that is bound to happen when scripters get their hands on something ... There can be as many versions as there are scripters.

I just find it easier to keep objects independent from one another so that they are autonomous. That way, if one falls over, the others should (hopefully) remain OK. My brain can cope better with that as well. ;)

Cheers,
Lance.

#18
kevL

kevL
  • Members
  • 4 056 messages

i'm sitting on what i think is a pretty nifty method:

1. put script in Area hb slot
2. put tag of Boss creature in script & recompile
3. that's it.

Guardians start spawning once a local_int is set on the Area (from dialog, trigger, whatever). They stop spawning and the rest are destroyed once the Boss is killed. They can be stopped temporarily by setting a different local_int on the Area.

They spawn at random walkable points within a specified distance from the Boss. No warning is given and none seems needed, because their heartbeats don't fire for 6 seconds. The evil red ball that appears around PC's head should be a clue ...

Here's the nifty part: they randomly disappear and respawn. They also disappear and respawn when triggered by a close PC-faction.


I made things like maxDistance/minDistance and visFx .Sef ( and Boss Tag ) and damage-delivered and zone-radius easily alterable,
it uses the stock iPoint (alterable to any placeable) and assigns it a heartbeat script automatically (also alterable). I might throw it up to the Vault after it gestates a bit. Also put in a ReflexAdjusted saving throw before damage.

Pastebin:
dangerzone_are_hb
dangerzone_plc_hb

There's too much going on there for me to test before the end of the month, so ... RFC.


ps, yeah i took out the !PC thing ... I just thought you, andy, had something special going there, like "only truePC can approach this safely" ( /shucks )



#19
Lance Botelle

Lance Botelle
  • Members
  • 1 480 messages

Hi KevL,

Been busy I see. ;)

Those scripts are certainly worth a look. Interesting to see how the "initialization" script is bigger than the "damaging" one.

 

Good to see you came to the same conclusion about the !PC thing ... Can't have the Main PC get it all their own way. ;)

Cheers,
Lance.



#20
kevL

kevL
  • Members
  • 4 056 messages

Been busy I see. ;)

my head's been stuck in stuff like this for the past year

so, an afternoon in NwScript is ... nice.  :|_~


Those scripts are certainly worth a look. Interesting to see how the "initialization" script is bigger than the "damaging" one.

The area_hb script is longer because it's the regulator, checking how many minions there are, where it's safe to place another one, etc. I guess it could be moved to an iPoint so it doesn't create hassles with other area_hb scripts,

#21
Lance Botelle

Lance Botelle
  • Members
  • 1 480 messages

my head's been stuck in stuff like this for the past year

so, an afternoon in NwScript is ... nice.  :|_~


Hi KevL,

I have no idea what that is! .... :D Looks far too complicated. ;)

Some sort of C&C strategy like thing?

Cheers,
Lance.

#22
kevL

kevL
  • Members
  • 4 056 messages

heh, yeah it is sorta like C&C !

google images

except, as well as being an overall strategy game, it balances against micromanaging tactical combat (2 games in one that mesh seamlessly -- what happens in one part significantly impacts what happens in the other part)


and gotta dig the groovy 320x200x8bbp graphics



#23
Tchos

Tchos
  • Members
  • 5 042 messages

One of those games I mentioned in another thread as turning 20 years old this year.  :)  (Assuming UFO: Enemy Unknown is the same thing as the original X-com.)



#24
kevL

kevL
  • Members
  • 4 056 messages

UFO: Enemy Unknown - european title
X-COM: UFO Defense - north american title

when i played the game in the 90's i didn't think anything of the flavor text, which half the time is just wrong IG. But after the millenia when I realized it's all based on real-world UFO lore i laughed hard  :)


Elerium-115