News:

Be sure to check out the compiled REVIEWS in the Module Review section, where we have added reviews both past and present.

Main Menu

Charm Person

Started by Andy123, September 22, 2023, 10:41:34 PM

Previous topic - Next topic

Andy123

Looks like this spell has a bit of history with giving people grief.

https://forums.goldbox.games/index.php?topic=4034.msg58661#msg58661

I also found this, implemented the suggested changes and the spell worked:
https://github.com/grannypron/uaf_levels/commit/a949d5224412a3ef815917622b22de8eb8036d53

...except it only worked on an old version of the database which had a simpler version of the IsCharmed SA CharDisplayStatus hook:
$SET_HOOK_PARAM( 7,"Charmed ");
$SET_HOOK_PARAM( 6,"");
$RETURN 1;


The lastest version of IsCharmed:
[CharDisplayStatus] = $VAR exp; // time effect expires, gotten from SA that called this one
-exp = $SA_PARAM_GET();
-$IF ($GET_PARTY_TIME() >=# exp)
- {
- $SetFriendly($IndexOf($TargetContext()),$GET_COMBATANT_SA($TargetContext(),"side"));
- $SA_REMOVE();
- $RETURN;
- };
-$SET_HOOK_PARAM( 7,"Charmed "); $SET_HOOK_PARAM( 6,""); $RETURN 1;

...gives these errors:
You cannot view this attachment.

I'm pretty green when it comes to making sense of this stuff, but it looks to me like the latest one is calling on information about when the spell should expire which is not provided. Not sure what the issue with the non-existent actor/no target context is about, or how to fix it.

Assuming we can fix all that, I was hoping there would be a way to have the effects of the spell end after combat.




manikus

The expiration is 'exp' (which is a spell parameter passed to the script).
If you substitute "CharacterContext" for "TargetContext" the messages will go away.

Andy123

Quote from: manikus on September 23, 2023, 07:00:46 PMThe expiration is 'exp' (which is a spell parameter passed to the script).
Does that mean I should find "exp" in the SA which called on IsCharmed (in this case spell_CharmPerson) ?


Quote from: manikus on September 23, 2023, 07:00:46 PMIf you substitute "CharacterContext" for "TargetContext" the messages will go away.
TargetContext appears twice in that script. Should I switch it for CharacterContext in both places or just one of them?

manikus

Quote from: Andy123 on September 23, 2023, 09:11:43 PM
Quote from: manikus on September 23, 2023, 07:00:46 PMThe expiration is 'exp' (which is a spell parameter passed to the script).
Does that mean I should find "exp" in the SA which called on IsCharmed (in this case spell_CharmPerson) ?
No. 'exp' is a variable in this script that stands for " $SA_PARAM_GET()". This is the value assigned to "IsCharmed" when it is created.

Quote from: Andy123 on September 23, 2023, 09:11:43 PM
Quote from: manikus on September 23, 2023, 07:00:46 PMIf you substitute "CharacterContext" for "TargetContext" the messages will go away.
TargetContext appears twice in that script. Should I switch it for CharacterContext in both places or just one of them?
Yes.

Andy123

I think I get it. Variable "exp" is pulled from the line of the script that called the SA. That would be the InvokeSpellOnTarget script of the "spell_CharmPerson" SA, this line in particular:
$SET_CHARACTER_SA($TargetContext(),"IsCharmed",lvl);
...where lvl is a variable consisting of
$GET_CHAR_Lvl(atk,cls);
...where atk is the attacker, and cls is another $SA_PARAM_GET(); this time pulling from the Charm Person spell itself, returning the class of the attacker.

Long story short, "exp" refers to the result of $GET_CHAR_Lvl(attacker, class)

...which I guess would return the level of the casting class of the attacker. So if it's cast by a level 3 magic user, the effects of the spell should go away once party_time is equal to or greater than 3.

Is that 3 rounds? 3 hours? 3 days? Whatever it's supposed to be, the spell appears to have no effect (maybe 3 milliseconds then?). When I delete all the exp stuff, the spell works as intended but is permanent.

manikus

Now we're getting somewhere. ;) It does have a value, its just not the right value.

If you replace the line:
-$SET_CHARACTER_SA($TargetContext(),"IsCharmed",lvl);
with
-$SET_CHARACTER_SA($TargetContext(),"IsCharmed",$GET_PAERTY_TIME() +# lvl);
you will get a much better result.

manikus

You also need to change "spell_CharmPersonOrMammal". I will update the databases with it (and spell_CharmPerson), but for now, I've included it below.

\(BEGIN)
name = spell_CharmPersonOrMammal
[InvokeSpellOnTarget] = $VAR atk; // attacker
-$VAR tgt; // target
-$VAR tNom; // target name
-$VAR cls;
-$VAR int;
-$VAR lvl;
-$VAR exp;
-tgt = $IndexOf($TargetContext());
-atk = $IndexOf($AttackerContext());
-tNom = $GET_CHAR_NAME(tgt);
-$IF ($GET_CHARACTER_SA($TargetContext(),"saved" )) {$RETURN;};
-$IF ($GET_CANBEHELDORCHARMED($TargetContext()) != 1){$RETURN;};
-$IF ($GET_COMBATANT_SA($TargetContext(),"monster_ImmuneCharm") != "-?-?-"){$RETURN;};
-$IF ($GET_MONSTERTYPE_SA(tNom,"monsterLevel") != "-?-?-")
- {  //  MONSTERTYPE_SA checks go here
- $IF ($GET_MONSTERTYPE_SA(tNom,"IsPerson") == "-?-?-" && $GET_ISMAMMAL($TargetContext()) != 1){$RETURN;};
- };
-cls = $SA_PARAM_GET();
-int = $GET_CHAR_LIMITED_INT(tgt);
-lvl = $GET_CHAR_Lvl(atk,cls);
-$IF (int >=# 19) {exp = $GET_PARTY_TIME() +# 14400;};
-$IF (int ==# 18) {exp = $GET_PARTY_TIME() +# (14400 *# 2);};
-$IF (int ==# 17) {exp = $GET_PARTY_TIME() +# (14400 *# 3);};
-$IF (int >=# 15) {exp = $GET_PARTY_TIME() +# (14400 *# 7);};
-$IF (int >=# 13) {exp = $GET_PARTY_TIME() +# (14400 *# 14);};
-$IF (int >=# 10) { exp = $GET_PARTY_TIME() +# (14400 *# 21);};
-$IF (int >=# 7) {exp = $GET_PARTY_TIME() +# (14400 *# 30);};
-$IF (int >=# 4) {exp = $GET_PARTY_TIME() +# (14400 *# 60);};
-$IF (int <=# 3) {exp = $GET_PARTY_TIME() +# (14400 *# 90);};
-$SetFriendly(tgt,$GET_COMBATANT_SA($Myself(),"side"));
-$SET_CHARACTER_SA($TargetContext(),"IsCharmed",exp);
-$SET_CHARACTER_SA($TargetContext(),"DispelLevel",lvl);
\(END)

manikus

You also need to update "spell_CharmPlant" from:
-$SET_CHARACTER_SA($TargetContext(),"IsCharmed",lvl);
with
-$SET_CHARACTER_SA($TargetContext(),"IsCharmed",lvl +# 999999999);

Andy123

#8
Quote from: Andy123 on September 25, 2023, 06:59:59 AMWhen I delete all the exp stuff, the spell works as intended but is permanent.
Prior to you posting your answer above, I tried this in the IsCharmed SA, [CharDisplayStatus] script:
$IF ($GET_PARTY_DAYS() ># 1)
    {
        $SetFriendly($IndexOf($CharacterContext()),$GET_COMBATANT_SA($CharacterContext(),"side"));
        $SA_REMOVE();
        $RETURN;
    };
$SET_HOOK_PARAM( 7,"Charmed "); $SET_HOOK_PARAM( 6,""); $RETURN 1;

...which removes the effect after a day (I have no idea how $Get_Party_Time() is supposed to work, what unit of time it deals with etc).
Doing this, everything pretty much worked as expected.

I then saw your posts and tried making the changes you've suggested. It could just be mad coincidence, but the following happened:
  • When PCs cast Charm Person the spell works, but wears off during combat - much sooner than expected.
  • When monsters use the spellcaster item for Charm Person
    • It has no effect on PCs despite the notification "*PC* is Charmed"
    • Monsters keep casting it at the same PC, even after
      • PC is already (apparently) charmed
      • PC is downed
      • PC is downed with another PC standing on them

...which makes no sense. I appreciate my knowledge of how this all works is sketchy at best, but from what I can tell the change you've suggested should only affect the duration of the spell.

edit: continually casting at downed PCs happens with other spells as well. Seems to be a spellcaster item issue in general and probably deserves its own thread.

manikus

$GET_PARTY_TIME() returns the smallest unit, which is a second.
The Charm Person spell is not meant to last a long time, unlike some of the other charm spells which can last months under the right conditions.

Everything else you just posted needs to be in a mini-mod for hotmustard. Its an engine bug.

Randomdays

#10
Just looking at this now and testing things out.


One thing though if anyone knows, there's a line in the code ;

$IF ($GET_MONSTERTYPE_SA(tNom,"IsPerson") == "-?-?-" && $GET_ISMAMMAL
I though that the "&&" meant "and" and that "||" meant "or"

I'm not sure what the "-?-?-" but I think it deals with the SA's assigned to the creature, but I think "==" means "is" and "!=" means "in not"

So the code above means ( I think) that if the target is a person and(?) is a mammal then continue running the script.


Now with all that, I've been experimenting all day and finally got it work by swapping around some lines in the monster_AbolethEnslave and the IsEnslaved SA's. The target says its enslaved, and it does turn sides and attack your enemy.

Whatever I did, I couldn't get anything else to work. All I have to do is change the text lines from saying "enslaved to " to "Charmed", and I should be good.

Andy, if you're around, can you post your code for the Charm Spell and the IsCharmed SA's? Thanks.

I didn't see this mentioned when I was searching the site, but the problem of the spell saying the target is charmed, whether or not it is, and the rat bit telling me I'm diseased when I'm not, is surprisingly simple.

If you look at the Charm Person or the Charm Person or Mammal spell, there's a line near the bottom that gives you a message when the spell is cast. In this case, "/c charms /t" for c=caster and t=target.

If you changed it to "/c tries to charms /t" it makes more sense. Same with the cause disease spell saying "diseases" instead of "tries to disease"

The Charm Monster Spell actually says "/c casts charm monster" which you go use also I guess, changing monster to person

Now I'm not about how I lost it, but I had the little hearts circling the target when it was charmed, but I lost it. Anyone help me with that?


Nol Drek

#11
Quote from: Randomdays on April 02, 2025, 08:58:47 PMOne thing though if anyone knows, there's a line in the code ;

$IF ($GET_MONSTERTYPE_SA(tNom,"IsPerson") == "-?-?-" && $GET_ISMAMMAL
I thought that the "&&" meant "and" and that "||" meant "or"

I'm not sure what the "-?-?-" but I think it deals with the SA's assigned to the creature, but I think "==" means "is" and "!=" means "is not"

So the code above means ( I think) that if the target is a person and(?) is a mammal then continue running the script.

You are correct that in GPDL (General Purpose Dungeon Language) && means "and", || means "or", == means "is equal to", and != means "is not equal to".

"-?-?-" is the default value of a Special Ability that does not exist.

If the target has a Special Ability, then the value of that Special Ability will be something other than "-?-?-".

If the target does not have the Special Ability, then its value will be "-?-?-".

This website has some useful information: https://www.dianneandpaul.net/UAF/Help/GPDL.html

As does this one: http://manikus.reonis.com/Help/ScriptsInAction-ScriptingForBeginners.html

And finally this one: https://www.dianneandpaul.net/UAF/Help/SASpecialAbilitiesScripts.html

On which you can find a hint which says the following:

$GET_X_SA fetches the parameter value of the special ability. If no such special ability exists then the function returns the value "-?-?-"
My guess is that Paul chose "-?-?-" as the default value because it is very unlikely that one would set something equal to this value on purpose.
"The time has come," the Walrus said, "to talk of many things:
Of shoes — and ships — and sealing-wax — of cabbages — and kings —
And why the sea is boiling hot — and whether pigs have wings."

http://www.noldrek.com

Randomdays

Thanks. I thought I was correct, but at lot of things I'm doing is by guesswork.

Randomdays


So does that mean that for Charm Person OR Mammal should not be

"$IF ($GET_MONSTERTYPE_SA(tNom,"IsPerson") == "-?-?-" && $GET_ISMAMMAL"

But instead

$IF ($GET_MONSTERTYPE_SA(tNom,"IsPerson") == "-?-?-" || $GET_ISMAMMAL

?

Since I finished with all the "Frozen" spells I think, I'm going to start looking at the Charm and Control spells next.