AddSpell bekommt ein Skillinfomapping
AddSpell bekam bislang in spellarg das Infomapping fuer Defend()
angegeben (Argument spell in Defend).
Intern hat AddSpell dann aber die Daten von sinfo fuer
SpellDefend() in dieses mapping geschrieben (wo sie nicht
hingehoeren) und SpellDefend() konnte so die Daten von
SI_SPELL nicht finden.
Damit die Sprueche von AddSpell() aber von SpellDefend()
im Ziel korrekt verarbeitet werden koennen, muss es ein
sinnvolles Skillinfomapping (sinfo) geben. Ohne Erweiterung
der Semantik von AddSpell, dass das mapping spellarg nun
sinfo ist, koennen Nutzer von AddSpell() aber keine der
SI_* angeben.
Zum Zwecke der Abwaertskompatibilitaet wird das an AddSpell()
uebergebene Mappoing auf die Praesenz von SI_SPELL geprueft.
Ist dieses nicht vorhanden, wird das Mapping als SI_SPELL
interpretiert und in einem neu erzeugten sinfo unter dem
Schluessel SI_SPELL abgelegt.
Als weitere Aenderungen werden die Daten des Spells jetzt
soweit passend unter die geeigneten SI-*-Schluessel
einsortiert und so in P_SPELLS abgelegt.
Change-Id: I10eb464a46b6754640173f7915cea33354c143ed
diff --git a/doc/sphinx/lfun/AddSpell.rst b/doc/sphinx/lfun/AddSpell.rst
index e7eeb42..b16a0e3 100644
--- a/doc/sphinx/lfun/AddSpell.rst
+++ b/doc/sphinx/lfun/AddSpell.rst
@@ -41,7 +41,10 @@
(Optional, bekommt als Argumente object enemy,
int real_damage, string* dam_type)
- spellarg - Spell-Argument fuer Defend(), Default ist "1"
+ sinfo - Skillinfomapping, muss SI_SPELL mit den SP_* fuer
+ den Aufruf von Defend() enthalten
+ Default ist ([SI_SPELL: ([SP_PHYSICAL_ATTACK: 0]),
+ SI_MAGIC_TYPE: ({ MT_ANGRIFF }) ])
BESCHREIBUNG
------------
@@ -87,13 +90,29 @@
muss im selben Objekt definiert sein, sofern der Funktionsname und
keine Closure uebergeben wird.
- Will man einen physischen Angriff ausloesen, MUSS <spellarg> ein Mapping
- mit ([SP_PHYSICAL_ATTACK: 1]) sein. Bei Uebergeben einer 0 oder Weglassen
- des Werts wird an Defend das Default '1' (da es Spells sind) uebergeben.
+ Das Mapping <sinfo> beschreibt den Spell fuer das im Gegner aufgerufene
+ SpellDefend() und Defend(). Es muss ein SI_SPELL fuer das Defend() im
+ Gegner enthalten. Etwaige SI_SKILLDAMAGE, SI_SKILLDAMAGE_TYPE, und
+ SI_CLOSURE werden im Mapping durch die Argumente <damage>, <dam_type> und
+ <func> ueberschrieben.
+ Es wird empfohlen, SI_MAGIC_TYPE zu nutzen, denn dann werden etwaige
+ magische Resistenzen des Ziels beruecksichtigt.
- Wenn damage<=0 oder rate<0 oder keine Meldungen uebergeben werden, wird
- der Spell NICHT eingetragen, sondern die Funktion bricht mit Rueckgabe
- von 0 ab.
+ Frueher war das Argument <sinfo> nur das Mapping, was an Defend() uebergeben
+ wird unter in Skillinfomapping unter dem Key SI_SPELL liegt. Wenn <sinfo>
+ kein SI_SPELL enthaelt, wird aus Gruenden der Kompatibilitaet ein
+ Skillinfomapping konstruiert, welches das hier uebergebene <sinfo> unterhalb
+ des Schluessels SI_SPELL enthaelt: ([ SI_SPELL: sinfo])
+
+ Will man einen physischen Angriff ausloesen, MUSS in sinfo ein Mapping sein
+ und unter SI_SPELL ein Mapping mit dem Key SP_PHYSICAL_ATTACK (Wert != 0)
+ sein.
+ Bei Uebergeben einer 0 oder Weglassen von <sinfo> wird an Defend der Default
+ ([SP_PHYSICAL_ATTACK: 0]) (da es Spells sind) uebergeben.
+
+ Wenn damage < 0 oder rate <= 0, wird der Spell NICHT eingetragen, sondern
+ die Funktion bricht mit Rueckgabe von 0 ab. Ist damage==0, muss eine <func>
+ angegeben werden.
BEISPIELE
---------
@@ -113,7 +132,7 @@
"Der Hexer piekst Dir in die Augen!",
"Der Hexer piekst @WEM in die Augen!", ({DT_PIERCE}),
"augen_stechen");
- AddSpell(2, 5, (string)0, (string)0, (string*)0, "salto_mortalis");
+ AddSpell(2, 5, 0, 0, 0, "salto_mortalis");
(Kleiner Feuerball mit 80% Wahrscheinlichkeit, riesiger mit 10%,
"augen_stechen" mit 8%, "salto_mortalis" mit 2%)
@@ -151,8 +170,8 @@
AddSpell(100, 200+random(200),
"Die kleine Ratte beisst Dich!\n",
"@WER wird von einer kleinen Ratte gebissen!\n",
- ({DT_PIERCE, DT_POISON}), (string)0,
- ([SP_PHYSICAL_ATTACK:1]));
+ ({DT_PIERCE, DT_POISON}), 0,
+ ([ SI_SPELL: ([SP_PHYSICAL_ATTACK:1]) ]) );
// #3 Selektive physische Angriffe (siehe auch man Defend_bsp):
// Will man erreichen, dass einige Ruestungen wirken, andere aber
@@ -167,9 +186,10 @@
AddSpell(20,200+random(200),
"Die kleine Ratte beisst Dir blitzschnell in die Wade!\n",
"@WER wird von einer kleinen Ratte in die Wade gebissen!\n",
- ({DT_PIERCE, DT_POISON}), (string)0,
- ([SP_PHYSICAL_ATTACK:1, SP_NO_ACTIVE_DEFENSE:1,
- SP_REDUCE_ARMOUR: armours]));
+ ({DT_PIERCE, DT_POISON}), 0,
+ ([ SI_SPELL: ([SP_PHYSICAL_ATTACK:1, SP_NO_ACTIVE_DEFENSE:1,
+ SP_REDUCE_ARMOUR: armours])
+ ]) );
// SP_NO_ACTIVE_DEFENSE = 1 schaltet aktive Abwehr (Karate/Klerus) ab
// SP_REDUCE_ARMOUR enthaelt eine Liste von Ruestungstypen mit ihren
diff --git a/std/npc/combat.c b/std/npc/combat.c
index 110d0b0..d4b9448 100644
--- a/std/npc/combat.c
+++ b/std/npc/combat.c
@@ -125,16 +125,13 @@
#define SPELL_TOTALRATE 0
-#define SPELL_DAMAGE 1
+#define SPELL_SINFO 1
#define SPELL_TEXT_FOR_ENEMY 2
#define SPELL_TEXT_FOR_OTHERS 3
-#define SPELL_DAMTYPE 4
-#define SPELL_FUNC 5
-#define SPELL_ARG 6
varargs int AddSpell(int rate, int damage,
string|<int|string>* TextForEnemy, string|<int|string>* TextForOthers,
- string|string* dam_type, string|closure func, int|mapping spellarg)
+ string|string* dam_type, string|closure func, int|mapping sinfo)
{
mixed *spells;
int total_rates;
@@ -146,19 +143,29 @@
// int ist, weil wenn spellarg==0 ist der Default nicht-physischer Angriff
// und bei spellarg!=0 auch. Nur mit einem mapping kann man einen phys.
// Angriff erzeugen.
- if (intp(spellarg))
- spellarg = ([SP_PHYSICAL_ATTACK: 0]);
+ if (intp(sinfo))
+ sinfo = ([ SI_SPELL: ([SP_PHYSICAL_ATTACK: 0]) ]);
+ else
+ {
+ // wenn das sinfo-Mapping nicht den Key SI_SPELL enthaelt, gehen wir davon
+ // aus, dass es ein alter Aufrufer von AddSpell ist, welcher noch davon
+ // ausgeht, dass si_spell an AddSpell() uebergeben werden soll. In diesem
+ // Fall bauen wir ein sinfo und nehmen das uebergebene sinfo als SI_SPELL.
+ if (!member(sinfo,SI_SPELL))
+ sinfo = ([ SI_SPELL: sinfo ]);
+ }
+
+ sinfo[SI_SKILLDAMAGE] = damage;
if(stringp(dam_type))
dam_type=({dam_type});
else if(!pointerp(dam_type))
{
- if(spellarg[SP_PHYSICAL_ATTACK])
+ if(sinfo[SI_SPELL][SP_PHYSICAL_ATTACK])
dam_type=({DT_BLUDGEON});
else
dam_type=({DT_MAGIC});
}
-
foreach(string s : dam_type)
{
if(!VALID_DAMAGE_TYPE(s))
@@ -168,31 +175,31 @@
publish);
}
}
+ sinfo[SI_SKILLDAMAGE_TYPE] = dam_type;
+
+ if(!member(sinfo, SI_MAGIC_TYPE))
+ sinfo[SI_MAGIC_TYPE] = ({ MT_ANGRIFF });
// Falls func ein String ist eine Closure erstellen und diese speichern.
- if(stringp(func) && sizeof(func))
+ if(stringp(func))
{
- cl=symbol_function(func,this_object());
- if(!closurep(cl))
+ if (sizeof(func))
{
- catch(raise_error(
- "AddSpell(): Es konnte keine Closure fuer "+func+" erstellt werden.");
- publish);
+ cl=symbol_function(func,this_object());
+ if(!closurep(cl))
+ {
+ catch(raise_error(
+ "AddSpell(): Es konnte keine Closure fuer "+func+" erstellt werden.");
+ publish);
+ }
}
}
else
{
- // Leerstrings durch 0 ersetzen.
- if(stringp(func))
- {
- cl=0;
- }
- else
- {
- cl=func;
- }
+ cl=func;
}
-
+ sinfo[SI_CLOSURE] = cl;
+
if(damage==0 && !closurep(cl))
{
catch(raise_error(
@@ -216,8 +223,8 @@
raise_error(
"AddSpell(): Falsche Datentypen fuer TextForEnemy");
}
-
- if(!sizeof(TextForOthers) ||
+
+ if(!sizeof(TextForOthers) ||
(pointerp(TextForOthers) && !sizeof(TextForOthers[0])))
{
TextForOthers=0;
@@ -232,7 +239,6 @@
raise_error(
"AddSpell(): Falsche Datentypen fuer TextForOthers");
}
-
// Falls vorhanden, alte Syntax auf die von replace_personal() anpassen,
// die im heart_beat() beim Ausgeben der Meldung verwendet wird.
@@ -247,14 +253,14 @@
TextForOthers[0] = regreplace(TextForOthers[0], "@WEM([^1-9QU])", "@WEM1\\1", 1);
TextForOthers[0] = regreplace(TextForOthers[0], "@WEN([^1-9QU])", "@WEN1\\1", 1);
}
- total_rates=Query("npc:total_rates")+rate;
+
+ total_rates=Query("npc:total_rates", F_VALUE)+rate;
spells=Query(P_SPELLS);
if (!pointerp(spells))
spells=({});
- spells+=({({total_rates, damage, TextForEnemy, TextForOthers,
- dam_type, cl, spellarg})});
+ spells+=({({total_rates, sinfo, TextForEnemy, TextForOthers})});
Set(P_SPELLS,spells);
- Set("npc:total_rates",total_rates);
+ Set("npc:total_rates",total_rates, F_VALUE);
return 1;
}
@@ -359,9 +365,12 @@
|| (QueryProp(P_DISABLE_ATTACK)>0)
|| random(100)>Query(P_SPELLRATE))
return;
- r=random(Query("npc:total_rates"));
- for (i=sizeof(spells)-1;(i>0 && spells[i-1][SPELL_TOTALRATE]>r);i--)
+ // Spell aussuchen, von oben runterlaufen, bis zum ersten Spell, dessen
+ // SPELL_TOTALRATE grosser ist als r.
+ r=random(Query("npc:total_rates", F_VALUE));
+ for (i=sizeof(spells)-1 ; (i>0 && spells[i-1][SPELL_TOTALRATE] > r); i--)
;
+
<int|string>* akt_spell_mess=spells[i][SPELL_TEXT_FOR_ENEMY];
// Nur, wenn ueberhaupt eine Meldung gesetzt wurde, muss diese verarbeitet
// werden.
@@ -383,14 +392,17 @@
({enemy,this_object()}),
this_object());
}
- sinfo = deep_copy(spells[i][SPELL_ARG]);
- if(!mappingp(sinfo))
- sinfo=([ SI_MAGIC_TYPE :({ MT_ANGRIFF }) ]);
- else if(!sinfo[SI_MAGIC_TYPE])
- sinfo[ SI_MAGIC_TYPE]=({ MT_ANGRIFF });
+
+ // Tiefe Kopie, damit wir nach Herzenslust fuer diese Ausfuehrung
+ // manipulieren koennen und alle gerufenen Defend und Ruestung etc. nix
+ // dauerhaft in SI_SPELL kaputt machen koennen.
+ sinfo = deep_copy(spells[i][SPELL_SINFO]);
+ sinfo[SI_ENEMY] = enemy;
+
if(!sinfo[SP_PHYSICAL_ATTACK] &&
(enemy->SpellDefend(this_object(),sinfo) >
- random(MAX_ABILITY+QueryProp(P_LEVEL)*50))){
+ random(MAX_ABILITY+QueryProp(P_LEVEL)*50)))
+ {
enemy->ReceiveMsg(
"Du wehrst den Spruch ab.",
MT_NOTIFICATION,
@@ -403,25 +415,24 @@
({ enemy, this_object()}));
return ;
}
- int damage;
- // Bei 0 sparen wir uns das Defend() und rufen nur die Funktion auf.
- if(spells[i][SPELL_DAMAGE])
+ // Bei 0 sparen wir uns das Defend() und rufen nur weiter unter SI_CLOSURE auf.
+ if(sinfo[SI_SKILLDAMAGE])
{
- damage=random(spells[i][SPELL_DAMAGE])+1;
- enemy->Defend(damage, spells[i][SPELL_DAMTYPE],
- spells[i][SPELL_ARG],
- this_object());
+ sinfo[SI_SKILLDAMAGE] = random(sinfo[SI_SKILLDAMAGE]) + 1;
+ enemy->Defend(sinfo[SI_SKILLDAMAGE], sinfo[SI_SKILLDAMAGE_TYPE],
+ sinfo[SI_SPELL], this_object());
}
// Falls der Gegner (oder wir) im Defend stirbt, hier abbrechen
- if ( !objectp(ME) || !objectp(enemy)
+ if ( !objectp(ME) || !objectp(enemy)
|| enemy->QueryProp(P_GHOST) ) return;
-
- closure cl = spells[i][SPELL_FUNC];
+
+ closure cl = sinfo[SI_CLOSURE];
if (cl)
{
if (closurep(cl))
- catch(funcall(cl, enemy, damage, spells[i][SPELL_DAMTYPE]);publish);
+ catch(funcall(cl, enemy, sinfo[SI_SKILLDAMAGE],
+ sinfo[SI_SKILLDAMAGE_TYPE]);publish);
else
raise_error(sprintf("P_SPELL defekt: SPELL_FUNC in Spell %i ist keine "
"Closure.\n", i));