Aller au contenu

Photo

Which is more efficient and less bug prone: GetFirstPC() or GetOwnedCharacter() ?


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

#26
Lance Botelle

Lance Botelle
  • Members
  • 1 480 messages

M. Rieder wrote...

@Pain,

Is there a place where someone has written down considerations for MP play? I would like my campaigns to be accessible to MP if possible.


Hi Matt,

I gave pointers in my blog ... I will see if I can find the particular links that may give you some pointers.

Here's the main link: http://worldofalthea...ouble-with.html

(*)Less important: http://worldofalthea...-cutscenes.html

(*)Less important: http://worldofalthea...iderations.html

(*) These considerations may only be relevant to my module.

Lance.

Modifié par Lance Botelle, 27 avril 2011 - 04:55 .


#27
painofdungeoneternal

painofdungeoneternal
  • Members
  • 1 799 messages
M Reider just refer to Referencing objects in scripts, if you follow that you should not have any real problems. Nothing in that is specific to MP or SP, each type of script defines functions and object_self as needed.

When there is a clearly defined function to get the activator of an item and getfirstpc is used, you cannot tell me that is correct even if it happens to work. Likewise if you have a spell script, which says OBJECT_SELF is the caster, and the scripter does not know that and uses GetFirstPC(), well that will work of course quite often but it's wrong.

Coding for MP is not what requires more care, the issue is coding properly requires more care, failure to be careful is why things are buggy. This has nothing to do with SP or MP, nor is this very hard, it has to do with people not even trying to figure out the proper functions and latching on to GetFirstPC() because it does not require thinking.

Using the wrong function is almost always a bug which when noticed should be fixed, and the OC scripts are full of bugs which should be fixed.

Note that if you need a test to see IF there is a player on at all, then you are actually able to use GetFirstPC() and seeing if it's valid. Technically you are actually about to do a loop, its just after the first one it's redundant. The issue is when you have a script and you should be using some other function, or OBJECT_SELF, and instead of figuring that out you decide to use GetFirstPC() instead.

If you have to apply a effect to a player, and you were to just do a loop everytime you did GetFirstPC, you'd end up with it working regardless of context, and i think if you did that you'd notice quickly what you are doing does not make sense. So if you gave XP if a certain door is opened, intead of the main PC just getting xp, everyone would get the same XP. Adding a loop like this is actually not very hard to do. However if you use it in a spell script, and spells are castable by NPC's, PC's, DM's, and even cheat cast from locations, how is GetFirstPC() not going to make things wonky all of a sudden.

#28
Kaldor Silverwand

Kaldor Silverwand
  • Members
  • 1 585 messages

Eguintir Eligard wrote...

Using global variables doesn't always work because they are stored independently of saved games.


Since when? I used a handful for islander and the game always worked start to finish (because the globals were stored with the saved game). If they werent the game would have failed to proceed from cut scene #1 on.


There was a fairly recent thread that talked about this. I haven't personally verified it because it wasn't an issue for my campaigns (and if it is it is too late to do anything about it). The statement made was as I recall that global variable values are stored independently of saved games.  So if you set one to value X, save your game as Game 1, then play some more changing it to value Y and save as Game 2, and then load Game 1 the value will be Y, not X. So they are useful as global constants, but not as global variables.

If this is the case then they are not a suitable solution for the problem I am describing. Neither is running an SQL database, which would be overkill for an SP and probably have the same problem.  Maybe campaign variables would work, but if those are also stored in a database independent of the saved game they would have the same problem.

Regards

#29
Shaughn78

Shaughn78
  • Members
  • 637 messages

Kaldor Silverwand wrote...

Eguintir Eligard wrote...





Using global variables doesn't always work because they are stored independently of saved games.


Since when? I used a handful for islander and the game always worked start to finish (because the globals were stored with the saved game). If they werent the game would have failed to proceed from cut scene #1 on.


There was a fairly recent thread that talked about this. I haven't personally verified it because it wasn't an issue for my campaigns (and if it is it is too late to do anything about it). The statement made was as I recall that global variable values are stored independently of saved games.  So if you set one to value X, save your game as Game 1, then play some more changing it to value Y and save as Game 2, and then load Game 1 the value will be Y, not X. So they are useful as global constants, but not as global variables.

If this is the case then they are not a suitable solution for the problem I am describing. Neither is running an SQL database, which would be overkill for an SP and probably have the same problem.  Maybe campaign variables would work, but if those are also stored in a database independent of the saved game they would have the same problem.

Regards


To help sow some confusion or maybe resolve it:
I believe that it is campaign variables that are indendent from saved games. \\
This one is just a vague memory, but global variables don't carry over between modules.

Modifié par Shaughn78, 27 avril 2011 - 11:34 .


#30
M. Rieder

M. Rieder
  • Members
  • 2 530 messages
So just to see if I'm on the right track (I'm weeding out the GetFirstPC()) from my scripts.

I want to check if object oPercep is a PC or a companion.

would this work?

if (GetIsOwnedByPlayer(GetFactionLeader(oPercep)))

that should return true for any creature in the PC's party whether a PC or NPC, right?

#31
_Knightmare_

_Knightmare_
  • Members
  • 643 messages

Kaldor Silverwand wrote...

So if you set one to value X, save your game as Game 1, then play some more changing it to value Y and save as Game 2, and then load Game 1 the value will be Y, not X.

This is the workings of campaign variables. It even goes a bit further as well. If you save a game with campaign variable A at value X, then continue to play and change variable A to value Y, EVEN IF YOU DO NOT SAVE THE GAME AGAIN when you reload the saved game, campaign variable A will still be at value Y. So these are totally independant of saves. Once you change a campaign variable it remains changed forever. This is even true if you restart the entire campaign with a brand new PC, the variable will still have the altered value. I found that out that hard way and at one point had to go back and change about 50 scripts.

Shaughn78 wrote...

To help sow some confusion or maybe resolve it:
I believe that it is campaign variables that are indendent from saved games.
This one is just a vague memory, but global variables don't carry over between modules.

This above is accurate.

Modifié par _Knightmare_, 28 avril 2011 - 12:38 .


#32
Shaughn78

Shaughn78
  • Members
  • 637 messages

M. Rieder wrote...

So just to see if I'm on the right track (I'm weeding out the GetFirstPC()) from my scripts.

I want to check if object oPercep is a PC or a companion.

would this work?

if (GetIsOwnedByPlayer(GetFactionLeader(oPercep)))

that should return true for any creature in the PC's party whether a PC or NPC, right?



I pulled this from this code wyrin used with his White Plume Campaign, it covers prety much any player/party member, just replace oPC with whatever you're checking. I have used this a lot with the comunity project currently going on to help ID player created cohorts.

if (GetIsOwnedByPlayer(oPC) || GetIsPC(oPC) || GetIsRosterMember(oPC) || GetIsPlayerCreated(oPC))

#33
Kaldor Silverwand

Kaldor Silverwand
  • Members
  • 1 585 messages
This is the first I have heard that globals do not carry over between modules. I hope that is incorrect. I am going to test that one.

If globals are saved with the game and carry over between modules in a campaign then they are a valid replacement for storing variables on the first PC. I'm not hearing any other alternatives though.
Regards

#34
Kaldor Silverwand

Kaldor Silverwand
  • Members
  • 1 585 messages
I created a simple item that retrieves a global int, displays it, increments it, sets it, retrieves it, and displays it again. I started a game in one module, used the item a couple of times, traveled to an area in another module in the campaign, used the item again and the value was properly carried over. I then saved the game, reloaded it and used the item again and its correct value was displayed.

So the conclusion of this testing is that global variables DO carry over between modules in a campaign and are saved along with saved games. So they seem to be a good way to save persistent variables.

Regards

#35
Shallina

Shallina
  • Members
  • 1 011 messages
GlobalVAR carry over module. And correctly.

CampaignVAR do not behave correctly.

Exemple.
campaignVARX is at value Y
Save game1
campaignVARX action1 ---> value X
Load game1
campaignVARX is at value X. Didn't revert to value Y

Modifié par Shallina, 28 avril 2011 - 08:26 .


#36
Lance Botelle

Lance Botelle
  • Members
  • 1 480 messages

Kaldor Silverwand wrote...

I created a simple item that retrieves a global int, displays it, increments it, sets it, retrieves it, and displays it again. I started a game in one module, used the item a couple of times, traveled to an area in another module in the campaign, used the item again and the value was properly carried over. I then saved the game, reloaded it and used the item again and its correct value was displayed.

So the conclusion of this testing is that global variables DO carry over between modules in a campaign and are saved along with saved games. So they seem to be a good way to save persistent variables.

Regards


Hi Kaldor,

That's what I said to you a few pages back. Image IPB

Quote: Unless I am misunderstanding what you ask, or have misunderstood the function, using SetGlobalInt works fine.

Regards,

Lance.

EDIT: As people have said, campaign integers (on the other hand) are designed to stay unchanged between saves, which is a very good thing for people wanting to ensure certain actions cannot be repeated even between saves. I also used campaign integers in quite an unusual way in my NWN1 Soul Shaker module.

Modifié par Lance Botelle, 28 avril 2011 - 11:06 .


#37
Lance Botelle

Lance Botelle
  • Members
  • 1 480 messages

Shallina wrote...

GlobalVAR carry over module. And correctly.

CampaignVAR do not behave correctly.

Exemple.
campaignVARX is at value Y
Save game1
campaignVARX action1 ---> value X
Load game1
campaignVARX is at value X. Didn't revert to value Y


Hi Shallina,

I must correct your statement here, in that Campaign vars DO work exactly as they are supposed to do. They are a database system that can be used to good effect by the very nature that they do not change between saves. As I say above, this is a very good thing. Image IPB After all, what would be the point of having a database system that did not keep the last update on a piece of data regardless of source. It would just be another global int!

Lance,

Modifié par Lance Botelle, 28 avril 2011 - 11:09 .


#38
Shallina

Shallina
  • Members
  • 1 011 messages
EDIT: As people have said, campaign integers (on the other hand) are designed to stay unchanged between saves, which is a very good thing for people wanting to ensure certain actions cannot be repeated even between saves

And that's a very very bad thing, beceause if someone if doing 2 run with 2 differents char at the same time, he'll head into an heavy buggy mess.

Modifié par Shallina, 28 avril 2011 - 11:13 .


#39
Lance Botelle

Lance Botelle
  • Members
  • 1 480 messages

Shaughn78 wrote...

M. Rieder wrote...

So just to see if I'm on the right track (I'm weeding out the GetFirstPC()) from my scripts.

I want to check if object oPercep is a PC or a companion.

would this work?

if (GetIsOwnedByPlayer(GetFactionLeader(oPercep)))

that should return true for any creature in the PC's party whether a PC or NPC, right?



I pulled this from this code wyrin used with his White Plume Campaign, it covers prety much any player/party member, just replace oPC with whatever you're checking. I have used this a lot with the comunity project currently going on to help ID player created cohorts.

if (GetIsOwnedByPlayer(oPC) || GetIsPC(oPC) || GetIsRosterMember(oPC) || GetIsPlayerCreated(oPC))


Hi,

There is also a function in ginc_death, which if included in a script allows this similar function: GetIsPartyMember()

Note: GetIsPlayerCreated in the above check is superfluous to requirement, as GetIsRosterMember will already return the same character as TRUE if they are a party member.

// Determine if oMember is a party member (either a PC, owned by a PC, or a roster member)
int GetIsPartyMember( object oMember=OBJECT_SELF )
{
 return ( GetIsPC( oMember ) || GetIsOwnedByPlayer( oMember ) || GetIsRosterMember( oMember ) );
}


Lance.

Modifié par Lance Botelle, 28 avril 2011 - 11:39 .


#40
Lance Botelle

Lance Botelle
  • Members
  • 1 480 messages

Shallina wrote...


EDIT: As people have said, campaign integers (on the other hand) are designed to stay unchanged between saves, which is a very good thing for people wanting to ensure certain actions cannot be repeated even between saves

And that's a very very bad thing, beceause if someone if doing 2 run with 2 differents char at the same time, he'll head into an heavy buggy mess.



Hi Shallina,

Not if the mod is scripted correctly to account for this kind of thing. Note, also, that campaign ints would not be used to check the sort of thing that would cause major problems with gameplay. For instance, I use campaign ints to check for exploits in play, but not for anything else. It would still be possible for a player to play with two PCs and avoid this exploit, as I take that into account when coding. However, if someone is going to the trouble of playing my module with two PCs at the same time (intercahnging the PC between plays), then I guess they deserve  a little extra. ;)

Bottom line, these are still a very good thing if used correctly. The problem is, not many people take enough care when using them.

Lance.

EDIT: Here is my own warning to players that may be trying to restart a game with the same PC. Note: A player simply reloading does not get this warning, but they will have been warned that reloading a game does not allow them to gain any benefits over puzzles or answers to problems in the game manual. NB: The "harming" refers to puzzle exploit checks being reset, so the player is gaining an unfair advantage by continuing the game with the same PC ... OK, so you now you know how to cheat in my module. Just don't tell anybody. Image IPB

Image IPB

Modifié par Lance Botelle, 28 avril 2011 - 01:26 .


#41
Lance Botelle

Lance Botelle
  • Members
  • 1 480 messages

_Knightmare_ wrote...

Shaughn78 wrote...

To help sow some confusion or maybe resolve it:
I believe that it is campaign variables that are indendent from saved games.
This one is just a vague memory, but global variables don't carry over between modules.

This above is accurate.


Hi _Knightmare,

This is NOTaccurate, as Global variables DO carry over between modules.

Lance.

Modifié par Lance Botelle, 28 avril 2011 - 11:38 .


#42
Shaughn78

Shaughn78
  • Members
  • 637 messages

Lance Botelle wrote...

_Knightmare_ wrote...

Shaughn78 wrote...

To help sow some confusion or maybe resolve it:
I believe that it is campaign variables that are indendent from saved games.
This one is just a vague memory, but global variables don't carry over between modules.

This above is accurate.


Hi _Knightmare,

This is NOTaccurate, as Global variables DO carry over between modules.

Lance.


OK, so I did mangage to sow some confusion, but it looks like it is now sorted out.

#43
Lance Botelle

Lance Botelle
  • Members
  • 1 480 messages

Shaughn78 wrote...
OK, so I did mangage to sow some confusion, but it looks like it is now sorted out.


Hi Shaughn,

It can be very confusing. Image IPB

That's why I have tried to emphasise these points, just to help people get on the right track. Image IPB

Lance.

#44
The Fred

The Fred
  • Members
  • 2 516 messages
With regards to campaign variables, it's perhaps not fair to say they don't act "properly", it's just that they don't act how you might expect or want them to. This can make them very dangerous and very messy. Unless you have some anti-exploit-type use for them, they're probably not worth the trouble (though I think I used them in NWN1 to pass info from one module to the next).

#45
Lance Botelle

Lance Botelle
  • Members
  • 1 480 messages

The Fred wrote...

With regards to campaign variables, it's perhaps not fair to say they don't act "properly", it's just that they don't act how you might expect or want them to. This can make them very dangerous and very messy. Unless you have some anti-exploit-type use for them, they're probably not worth the trouble (though I think I used them in NWN1 to pass info from one module to the next).



Hi The Fred,

Agreed. Image IPB

Lance.

#46
M. Rieder

M. Rieder
  • Members
  • 2 530 messages
I have exclusively used local variables mainly because I do not completely understand global variables and have a vague recollection of reading somewhere that for some reason, they were not preferable to local variables.

Could someone please discuss when a global variable may be better than local and what (if any) dangers there are with using global variables.

#47
Kaldor Silverwand

Kaldor Silverwand
  • Members
  • 1 585 messages

Lance Botelle wrote...

Kaldor Silverwand wrote...
So the conclusion of this testing is that global variables DO carry over between modules in a campaign and are saved along with saved games. So they seem to be a good way to save persistent variables.


Hi Kaldor,

That's what I said to you a few pages back. Image IPB

Quote: Unless I am misunderstanding what you ask, or have misunderstood the function, using SetGlobalInt works fine.

Lance


Yep. You and Eguintar both. This also matched my long standing belief about the characteristics of global variables, but I had never confirmed my belief explicitly and there was some confusion so an explicit test seemed a worthwhile thing to do.

#48
Shallina

Shallina
  • Members
  • 1 011 messages
Global VAR can be accessed everywhere anytime. You use a testYES var for a quest, and use the same name for an other quest 6 month later, if they are global var it will actually be the same VAR.

Basically you introduced a bug where 2 independant quest becomme linked. By using local VAr you attach the VAR to a known object specific to your module (unless you store it in the GetFirstPC() or in a campaign OBJECT), and even if you use the same name, since you are storing them in different object, you won't screw up.
It can also becomme very good for generic script that can performe multiple independant task with same variable name, but have no bug beceause those VAR are stored in different object.

And the screen of Lance show clearly the danger of campaign VAR, you can't have mutiple run of the same mod on the same machine at the same time.

Basically 2 brothers that play their solo run at different hours on the same computer would be screwed.

Modifié par Shallina, 28 avril 2011 - 02:53 .


#49
The Fred

The Fred
  • Members
  • 2 516 messages
Personally I use locals pretty much exclusively, too. I just haven't had call to use anything else (yet).

Shallina wrote...
You use a testYES var for a quest, and use the same name for an other quest 6 month later, if they are global var it will actually be the same VAR.

If you are storing local variables on, say, the PC or the module, you will have exactly the same issue. This has nothing to do with campaign/global/local variables, it has to do with variable naming, which can always cause problems if you screw it up.

IIRC, you can specify a player to whom the campaign variable applies (at least, you could with NWN1 database variables), so unless someone did a second run with the same char or loaded up from a saved game, you wouldn't have issues from havign two runs on the same PC. Of course, given the save-independant behaviour of these variables, I can't see many instances where I would want to use them, but if you did have one, there's nothing wrong with doing so... so long as you know what you're getting into.

#50
Kaldor Silverwand

Kaldor Silverwand
  • Members
  • 1 585 messages

M. Rieder wrote...

I have exclusively used local variables mainly because I do not completely understand global variables and have a vague recollection of reading somewhere that for some reason, they were not preferable to local variables.

Could someone please discuss when a global variable may be better than local and what (if any) dangers there are with using global variables.


It seems that global variables are associated with the game and are therefore always accessible, whereas local variables are associated with specific objects in a game and therefore are only accessible if that object exists and is accessible.

So an example use might be that I have an NPC and I want to know later in the game if the party has met the NPC before.
- I could use a local variable stored on the NPC to indicate that the NPC has been met but that will only allow making the determination while in the module the NPC object is in and only as long as the NPC exists.
- I could use a local variable stored on the party member who conversed with the NPC. That might be a good solution for multi-player if meeting the NPC isn't that important to the plot. But for plot points you may want to treat the party collectively so if one party member speaks to the NPC it is as if they all did. That is a problem if you store a local variable on a party member that may later drop out of the game.
- I could use a local variable stored on the module but that would only be accessible while the party is in that module and maybe for the plot it would be important to know in areas in another module.
- I could use a global variable and then the fact can be tested anyplace and anytime later in the game regardless of what happens to the NPC object and changes in the party membership.

I think the only thing to be careful of with globals is that you use some kind of naming standard to avoid conflicts.

edit: Basically the same as what Shallina said above more succinctly while I was typing this out.

Regards

Modifié par Kaldor Silverwand, 28 avril 2011 - 03:06 .