blob: d266acc20cdb8d01b845d8add4060123190b3806 [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001// MorgenGrauen MUDlib
2//
3// weapon/combat.c -- combat part of the weapon standard object
4//
5// $Id: combat.c 9425 2016-01-02 18:19:40Z Zesstra $
6
7#include <sys_debug.h>
8
9#pragma strict_types
10#pragma save_types
11#pragma no_clone
MG Mud User88f12472016-06-24 23:31:02 +020012#pragma range_check
13
14#define NEED_PROTOTYPES
15
16#include <thing/properties.h>
17#include <thing/commands.h>
18#include <thing/description.h>
19#include <properties.h>
20#include <language.h>
21#include <combat.h>
22#include <attributes.h>
23#include <defines.h>
24#include <moving.h>
25#include <new_skills.h>
26
27// Globale Variablen
28 int ftime, flaw;
29private nosave int logged;
30private nosave closure defend_cl, hit_cl;
31
32void create()
33{
34 // Variablen initialisieren
35 logged=ftime=flaw=0;
36 defend_cl=0;
37 hit_cl=0;
38
39 // Einige Grundwerte setzen
40 SetProp(P_WEAPON_TYPE, WT_CLUB);
41 SetProp(P_DAM_TYPE, ({DT_BLUDGEON}));
42 SetProp(P_NR_HANDS, 2);
43 SetProp(P_PARRY,PARRY_NOT);
44 SetProp(P_AC,0);
45 Set(P_RESTRICTIONS,([]),F_VALUE);
46 Set(P_LAST_USE,time(),F_VALUE);
47
48 // Einige Properties sollten nicht von aussen gesetzt werden koennen
49 Set(P_PARRY, PROTECTED, F_MODE_AS);
50 Set(P_WIELDED, PROTECTED, F_MODE_AS);
51 Set(P_LAST_USE,PROTECTED, F_MODE_AS);
52
53 // Diese kann von aussen gesetzt werden (noch), aber bitte nur ueber die
54 // hier definierte Setmethode.
55 Set(P_DAMAGED, PROTECTED, F_MODE_AS);
56
57 // Eine Waffe benoetigt Kommandos, mit denen man sie zuecken
58 // und wegstecken kann
59 AddCmd( ({"zueck","zuecke","zieh","ziehe"}), "wield" );
60 AddCmd( ({"steck","stecke"}), "unwield" );
61}
62
63// aktuelles Lebewesen, was diese Waffe zur Zeit gezueckt hat.
64public object QueryUser()
65{
66 return QueryProp(P_WIELDED);
67}
68
69/*
70 * Ausgabe einer Meldung beim Zuecken geht nur an Spieler, nicht an NPC.
71 * Die Umgebung bekommt natuerlich immer eine Meldung.
72 */
73void doWieldMessage()
74{
75 string *str, s1;
76
77 if(QueryProp(P_WIELD_MSG)) // Ist eine WieldMsg gesetzt?
78 {
79 if(closurep(QueryProp(P_WIELD_MSG))) // Sogar als eigene Fkt.?
80 {
81 str = funcall(QueryProp(P_WIELD_MSG),this_player());
82
83 if(interactive(this_player()))
84 {
bugfixaf2be4f2020-03-22 19:13:07 +010085 ({int})this_player()->ReceiveMsg(str[0],
MG Mud User88f12472016-06-24 23:31:02 +020086 MT_NOTIFICATION|MSG_BS_LEAVE_LFS, MA_WIELD, 0,
87 this_player());
88 }
89
90 if ( objectp(environment()) && objectp(environment(environment())) )
91 send_room(environment(environment()),
92 str[1],
93 MT_LOOK|MSG_BS_LEAVE_LFS,
94 MA_WIELD, 0, ({this_player()}), environment());
95 return;
96 }
97 else if(interactive(this_player()))
98 {
99 s1 = replace_personal(sprintf(QueryProp(P_WIELD_MSG)[0],"@WEN2"),
100 ({this_player(),this_object()}), 1);
101
bugfixaf2be4f2020-03-22 19:13:07 +0100102 ({int})this_player()->ReceiveMsg(s1,
MG Mud User88f12472016-06-24 23:31:02 +0200103 MT_NOTIFICATION|MSG_BS_LEAVE_LFS, MA_WIELD, 0,
104 this_player());
105 }
106
107 // Abwaertskompatibel: Das erste %s wird zu WEN1, das zweite zu WEN2
108 s1 = replace_personal(sprintf(QueryProp(P_WIELD_MSG)[1],"@WEN1","@WEN2"),
109 ({this_player(), this_object()}), 1);
110
111 if ( objectp(environment()) && objectp(environment(environment())) )
112 send_room(environment(environment()),
113 s1,
114 MT_LOOK|MSG_BS_LEAVE_LFS,
115 MA_WIELD, 0, ({this_player()}), environment());
116 return;
117 }
118 /*
119 * Keine WieldMsg gesetzt, Ausgabe der Default-Meldungen.
120 */
121 else if(interactive(this_player()))
122 {
bugfixaf2be4f2020-03-22 19:13:07 +0100123 ({int})this_player()->ReceiveMsg(
MG Mud User88f12472016-06-24 23:31:02 +0200124 "Du zueckst "+name(WEN,1)+".",
125 MT_NOTIFICATION, MA_WIELD, 0, this_player());
126 }
127
128 //s.o. ersetzt durch tell_room()
129 //say(break_string(this_player()->Name(WER)+" zueckt "
130 // +name(WEN,0)+".",78),({ this_player() }));
131 if ( objectp(environment()) && objectp(environment(environment())) )
132 send_room(environment(environment()),
bugfixaf2be4f2020-03-22 19:13:07 +0100133 ({string})this_player()->Name(WER)+" zueckt "+name(WEN,0)+".",
MG Mud User88f12472016-06-24 23:31:02 +0200134 MT_LOOK,
135 MA_WIELD, 0, ({this_player()}), environment());
136}
137
138/*
139 * Ausgabe einer Meldung beim Wegstecken geht nur an Spieler, nicht an NPC.
140 * Die Umgebung bekommt immer eine Meldung.
141 */
142void doUnwieldMessage(object wielded_by)
143{
144 string *str,s1;
145
146 if(!objectp(wielded_by)) // Hoops! Gar nicht gezueckt? Abbruch!
147 {
148 return;
149 }
150
151 if(QueryProp(P_UNWIELD_MSG)) // Hier gibt es eine UnwieldMsg.
152 {
153 if(closurep(QueryProp(P_UNWIELD_MSG))) // Sogar als Closure, wow :-)
154 {
155 str = funcall(QueryProp(P_UNWIELD_MSG),wielded_by);
156
157 if(interactive(wielded_by))
158 {
bugfixaf2be4f2020-03-22 19:13:07 +0100159 ({int})wielded_by->ReceiveMsg(str[0],
MG Mud User88f12472016-06-24 23:31:02 +0200160 MT_NOTIFICATION|MSG_BS_LEAVE_LFS, MA_UNWIELD, 0, wielded_by);
161 }
162 if ( objectp(environment()) && objectp(environment(environment())) )
163 send_room(environment(environment()),
164 str[1],
165 MT_LOOK|MSG_BS_LEAVE_LFS,
166 MA_UNWIELD, 0, ({wielded_by}), environment());
167 return;
168 }
169
170 else if(interactive(wielded_by))
171 {
172 s1 = replace_personal(sprintf(QueryProp(P_UNWIELD_MSG)[0],"@WEN2"),
173 ({this_player(),this_object()}), 1);
bugfixaf2be4f2020-03-22 19:13:07 +0100174 ({int})wielded_by->ReceiveMsg(s1,
MG Mud User88f12472016-06-24 23:31:02 +0200175 MT_NOTIFICATION|MSG_BS_LEAVE_LFS, MA_UNWIELD, 0, wielded_by);
176 }
177
178 s1 = replace_personal(sprintf(QueryProp(P_UNWIELD_MSG)[1],"@WEN1","@WEN2"),
179 ({wielded_by, this_object()}), 1);
180
181 if ( objectp(environment()) && objectp(environment(environment())) )
182 send_room(environment(environment()),
183 s1,
184 MT_LOOK|MSG_BS_LEAVE_LFS,
185 MA_UNWIELD, 0, ({wielded_by}), environment());
186 return;
187 }
188 /*
189 * Keine UnwieldMsg, also Default-Meldungen ausgeben.
190 */
191 else if(interactive(wielded_by))
192 {
bugfixaf2be4f2020-03-22 19:13:07 +0100193 ({int})wielded_by->ReceiveMsg(
MG Mud User88f12472016-06-24 23:31:02 +0200194 "Du steckst "+name(WEN,1)+" zurueck.",
195 MT_NOTIFICATION, MA_UNWIELD, 0, wielded_by);
196 }
197 if ( objectp(environment()) && objectp(environment(environment())) )
198 send_room(environment(environment()),
bugfixaf2be4f2020-03-22 19:13:07 +0100199 ({string})wielded_by->Name(WER) +" steckt "+name(WEN,0)+" zurueck.",
MG Mud User88f12472016-06-24 23:31:02 +0200200 MT_LOOK,
201 MA_UNWIELD, 0, ({wielded_by}), environment());
202}
203
204// Diese Funktion wird aufgerufen, wenn die Waffe wirklich gezueckt wird
205protected void InformWield(object pl, int silent)
206{
207 return;
208}
209
210// Diese Funktion wird aufgerufen, wenn die Waffe wirklich weggesteckt
211// wird
212protected void InformUnwield(object pl, int silent)
213{
214 return;
215}
216
217
218// wield_me soll knallen.
219varargs int wield_me(int silent)
220{
221 raise_error("wield_me() ist veraltet. Bitte nutze DoWield()\n");
222 return 1;
223}
224
225// Die Funktion, die das eigentliche Zuecken durchfuehrt.
226varargs int DoWield(int silent)
227{ int dex, parry;
228 closure cl;
229 mixed res;
230
231 // Man kann nur Waffen zuecken, die man auch im Inventory hat.
232 if (environment()!=PL)
233 {
234 _notify_fail( break_string(
235 "Du musst "+name(WEN,1)+" schon erst nehmen!",78) );
236 return 0;
237 }
238
239 // Eine gezueckte Waffe kann man natuerlich nicht nochmal zuecken
240 if (QueryProp(P_WIELDED))
241 {
242 notify_fail("Das hast Du schon gemacht!\n");
243 return 0;
244 }
245
246 // Waffen, die ein oder mehrere Attribut veraendern und gegen
247 // das gesetzte Limit verstossen, haben keine Wirkung bezueglich der
248 // Attribute.
bugfixaf2be4f2020-03-22 19:13:07 +0100249 if ( mappingp(res=QueryProp(P_M_ATTR_MOD)) && ({int})PL->TestLimitViolation(res) )
MG Mud User88f12472016-06-24 23:31:02 +0200250 {
251 write(break_string(
252 "Irgendetwas an Deiner Ausruestung verhindert, dass Du Dich mit "+
253 name(WEM,1)+" so richtig wohl fuehlst.",78));
254 }
255
256 // Ueber P_RESTRICTIONS kann man einige Restriktionen definieren, ohne
257 // gleich auf eine WieldFunc zurueckgreifen zu muessen.
258 // Die Auswertung erfolgt ueber den RestrictionChecker
259 if ( (res=QueryProp(P_RESTRICTIONS)) && mappingp(res) &&
bugfixaf2be4f2020-03-22 19:13:07 +0100260 (res=call_other("/std/restriction_checker","check_restrictions",
MG Mud User88f12472016-06-24 23:31:02 +0200261 PL,res)) && stringp(res) )
262 {
263 notify_fail(res);
264 return 0;
265 }
266
bugfixaf2be4f2020-03-22 19:13:07 +0100267 parry=QueryProp(P_PARRY);
268 dex=({int})PL->QueryAttribute(A_DEX);
MG Mud User88f12472016-06-24 23:31:02 +0200269
270 // Testen, ob der Spieler die noetige Geschicklichkeit besitzt, um
271 // mit dieser (Parier)Waffe umgehen zu koennen
272 if ( ((parry<PARRY_ONLY) && ((dex+8)*10)<QueryProp(P_WC)) ||
273 ((parry>PARRY_NOT) && ((dex+5)*2 )<QueryProp(P_AC)) )
274 {
275 notify_fail(
276 "Du bist nicht geschickt genug, um mit dieser Waffe umzugehen.\n");
277 return 0;
278 }
279
280 // Eine Gezueckte Waffe muss natuerlich erst mal weggesteckt werden.
bugfixaf2be4f2020-03-22 19:13:07 +0100281 if ( (parry<PARRY_ONLY) && objectp(res=({object})PL->QueryProp(P_WEAPON)) )
MG Mud User88f12472016-06-24 23:31:02 +0200282 {
bugfixaf2be4f2020-03-22 19:13:07 +0100283 if ( (({int})res->DoUnwield(silent)) && !(({object})PL->QueryProp(P_WEAPON)) )
MG Mud User88f12472016-06-24 23:31:02 +0200284 {
285 // Wenn die alte Waffe weggesteckt werden konnte, nochmal
286 // versuchen zu zuecken
287 return DoWield(silent);
288 }
289 else
290 {
291 // Sonst Meldung ausgeben
292 notify_fail("Das geht nicht, solange Du noch eine andere "+
293 "Waffe gezueckt hast.\n");
294 return 0;
295 }
296 }
297 // Das gleiche gilt natuerlich fuer Parierwaffen
bugfixaf2be4f2020-03-22 19:13:07 +0100298 if ( (parry>PARRY_NOT) && objectp(res=({object})PL->QueryProp(P_PARRY_WEAPON)) )
MG Mud User88f12472016-06-24 23:31:02 +0200299 {
bugfixaf2be4f2020-03-22 19:13:07 +0100300 if ( (({int})res->DoUnwield(silent)) && !(({object})PL->QueryProp(P_PARRY_WEAPON)) )
MG Mud User88f12472016-06-24 23:31:02 +0200301 {
302 // Wenn die alte Parierwaffe weggesteckt werden konnte, nochmal
303 // versuchen zu zuecken
304 return DoWield(silent);
305 }
306 else
307 {
308 // Sonst Meldung ausgeben
309 notify_fail("Das geht nicht, solange Du noch eine andere "+
heull00125706652018-02-05 15:07:50 +0100310 "Parierwaffe gezueckt hast.\n");
MG Mud User88f12472016-06-24 23:31:02 +0200311 return 0;
312 }
313 }
314
315 // Ist eine WieldFunc gesetzt, wird diese aufgerufen.
316 if (objectp(res=QueryProp(P_WIELD_FUNC))
bugfixaf2be4f2020-03-22 19:13:07 +0100317 && !(({int})res->WieldFunc(ME,silent,environment())))
MG Mud User88f12472016-06-24 23:31:02 +0200318 {
319 // Eine Meldung sollte schon von der WieldFunc ausgegeben werden.
320 return 1;
321 }
322
323 // Die zulaessigen Hoechstwerte duerfen natuerlich nicht
324 // ueberschritten werden.
325 if ( (parry<PARRY_ONLY) && (QueryProp(P_WC)>MAX_WEAPON_CLASS) )
326 {
327 notify_fail(
328 "Ungueltige Waffenklasse, bitte Erzmagier verstaendigen.\n");
329 return 0;
330 }
331 if ( (parry>PARRY_NOT) && (QueryProp(P_AC)>MAX_PARRY_CLASS) )
332 {
333 notify_fail(
334 "Ungueltige Parierklasse, bitte Erzmagier verstaendigen.\n");
335 return 0;
336 }
337
338 // Testen, ob der Zuecker genug Haende frei hat.
bugfixaf2be4f2020-03-22 19:13:07 +0100339 if (!(({int})PL->UseHands(ME,QueryProp(P_NR_HANDS))))
MG Mud User88f12472016-06-24 23:31:02 +0200340 {
341 notify_fail("Du hast keine Hand mehr frei.\n");
342 return 0;
343 }
344
345 // Ok, jetzt ist alles klar, die (Parier)Waffe wird gezueckt
346 SetProp(P_WIELDED, PL);
347 SetProp(P_EQUIP_TIME,time());
348
349 cl=symbol_function("SetProp",PL);
350
351 if (parry<PARRY_ONLY)
352 {
353 // Dieses Objekt als Waffe setzen
354 funcall(cl,P_WEAPON, ME );
355 }
356 if (parry>PARRY_NOT)
357 {
358 // Dieses Objekt als Parierwaffe setzen
359 funcall(cl,P_PARRY_WEAPON, ME );
360 }
361
362 // Waffen koennen Attribute aendern/blockieren. Also muessen diese
363 // nach dem Zuecken aktualisiert werden
bugfixaf2be4f2020-03-22 19:13:07 +0100364 ({void})PL->register_modifier(ME);
365 ({void})PL->UpdateAttributes();
MG Mud User88f12472016-06-24 23:31:02 +0200366
367 // P_TOTAL_AC/P_TOTAL_WC im Spieler aktualisieren. Da dort Attribute
368 // eingehen, kann das erst hier gemacht werden.
369 if (parry<PARRY_ONLY)
370 {
bugfixaf2be4f2020-03-22 19:13:07 +0100371 ({int})PL->QueryProp(P_TOTAL_WC);
MG Mud User88f12472016-06-24 23:31:02 +0200372 }
373 if (parry>PARRY_NOT)
374 {
bugfixaf2be4f2020-03-22 19:13:07 +0100375 ({int})PL->QueryProp(P_TOTAL_AC);
MG Mud User88f12472016-06-24 23:31:02 +0200376 }
377
378 // Zueck-Meldung ausgeben, wenn das silent-Flag nicht gesetzt ist
379 if (!silent)
380 {
381 doWieldMessage();
382 }
383
384 // Alle Waffen werden im awmaster registriert, sobald sie von einem
385 // Spieler gezueckt werden
386 if (!logged && query_once_interactive(PL))
387 {
388 call_other("/secure/awmaster","RegisterWeapon",ME);
389 logged=1;
390 }
391
392 // Inform-Funktion aufrufen
393 InformWield(PL,silent);
394
395 // Fertig mit dem Zuecken
396 return 1;
397}
398
399// Die Funktion, die das eigentliche Wegstecken durchfuehrt.
400varargs int DoUnwield(int silent)
401{ closure cl;
402 int parry;
403 mixed res;
404 object wielded_by;
405
406 // Waffen, die nicht gezueckt sind, kann man natuerlich nicht
407 // wegstecken
408 if (!objectp(wielded_by=QueryProp(P_WIELDED)))
409 {
410 return 0;
411 }
412
413 // Ist eine UnwieldFunc gesetzt, wird diese aufgerufen
414 if ( objectp(res=QueryProp(P_UNWIELD_FUNC)) &&
bugfixaf2be4f2020-03-22 19:13:07 +0100415 !(({int})res->UnwieldFunc(ME,silent,wielded_by)) )
MG Mud User88f12472016-06-24 23:31:02 +0200416 {
417 // Eine Meldung muss die UnwieldFunc schon selbst ausgeben.
418 return 1;
419 }
420
421 // Eine verfluchte Waffe kann man natuerlich nicht wegstecken - aber
422 // auch da gibts Ausnahmefaelle, wie z.B. den Tod eines Spielers
423 if ((res=QueryProp(P_CURSED)) && !(silent&M_NOCHECK))
424 {
425 if (stringp(res))
426 {
427 // Stand in P_CURSED ein String? Dann diesen ausgeben
428 tell_object(wielded_by,
429 (res[<1]=='\n' ? res : break_string(res,78)));
430 }
431 else
432 {
433 // Sonst eine Standard-Meldung ausgeben
434 tell_object(wielded_by, break_string(
435 "Du kannst "+name(WEN)+" nicht wegstecken.",78));
436 }
437 return 1;
438 }
439
440 // Ok, jetzt ist alles klar, die (Parier)Waffe wird weggesteckt
441 parry=QueryProp(P_PARRY);
442 cl=symbol_function("SetProp",wielded_by);
443
444 if (parry<PARRY_ONLY)
445 {
446 // Eintrag als Waffe im Spieler loeschen
447 funcall(cl,P_WEAPON, 0);
448 }
449 if (parry>PARRY_NOT)
450 {
451 // Eintrag als Parierwaffe im Spieler loeschen
452 funcall(cl,P_PARRY_WEAPON, 0);
453 }
454
455 // Im Spieler die Zeit setzen, zu der er zuletzt eine Waffe weggesteckt
456 // hat.
457 funcall(cl,P_UNWIELD_TIME,time());
458
459 // Meldung ausgeben, wenn silent-Flag nicht gesetzt ist
460 if (!silent)
461 {
462 doUnwieldMessage(wielded_by);
463 }
464
465 // Die Haende, die bisher von der Waffe benutzt wurden, freigeben
bugfixaf2be4f2020-03-22 19:13:07 +0100466 ({int})wielded_by->FreeHands(ME);
MG Mud User88f12472016-06-24 23:31:02 +0200467 SetProp(P_WIELDED, 0);
468
469 // Waffen koennen Attribute aendern/blockieren. Also muessen diese
470 // nach dem Wegstecken aktualisiert werden
bugfixaf2be4f2020-03-22 19:13:07 +0100471 ({void})wielded_by->deregister_modifier(ME);
472 ({void})wielded_by->UpdateAttributes();
MG Mud User88f12472016-06-24 23:31:02 +0200473
474 // P_TOTAL_AC/P_TOTAL_WC im Spieler aktualisieren. Da dort Attribute
475 // eingehen, kann das erst hier gemacht werden.
476 if (parry<PARRY_ONLY)
477 {
bugfixaf2be4f2020-03-22 19:13:07 +0100478 ({int})wielded_by->QueryProp(P_TOTAL_WC);
MG Mud User88f12472016-06-24 23:31:02 +0200479 }
480 if (parry>PARRY_NOT)
481 {
bugfixaf2be4f2020-03-22 19:13:07 +0100482 ({int})wielded_by->QueryProp(P_TOTAL_AC);
MG Mud User88f12472016-06-24 23:31:02 +0200483 }
484
485 // Inform-Funktion aufrufen
486 InformUnwield(wielded_by, silent);
487
488 // Fertig mit dem Wegstecken
489 return 1;
490}
491
492// Die Funktion, die das "zuecken"-Kommando auswertet
493varargs int wield(string str, int silent)
494{
Arathorn7166e0e2020-04-11 12:35:25 +0200495 if ( QueryProp(P_INVIS) )
496 return 0;
497
MG Mud User88f12472016-06-24 23:31:02 +0200498 if ( !stringp(str) ||
499 (query_verb()[0..3]=="zieh" && sscanf(str,"%s hervor",str)!=1) )
500 {
501 return 0;
502 }
503
504 if (!id(str))
505 {
506 _notify_fail("Du hast sowas nicht.\n");
507 return 0;
508 }
509
510 return DoWield(silent);
511}
512
513// Die Funktion, die das "wegstecken"-Kommando auswertet
514int unwield(string str)
Arathorn7166e0e2020-04-11 12:35:25 +0200515{
516 if ( QueryProp(P_INVIS) )
517 return 0;
518
519 int parry;
MG Mud User88f12472016-06-24 23:31:02 +0200520 string dummy;
521
522 // Erstmal die Eingabe auswerten. Ist dies wirklich ein Kommando
523 // zum Wegstecken?
524 if ( !stringp(str) || (sscanf(str,"%s weg", dummy)!=1 &&
525 sscanf(str,"%s ein", dummy)!=1 &&
526 sscanf(str,"%s zurueck", dummy)!=1 ) )
527 {
528 return 0;
529 }
530
531 str = dummy;
532 parry=QueryProp(P_PARRY);
533
534 // Ist wirklich diese Waffe gemeint?
535 if ( !stringp(str) || !id(str) ||
bugfixaf2be4f2020-03-22 19:13:07 +0100536 ((parry<PARRY_ONLY)&&(({object})PL->QueryProp(P_WEAPON)!=ME)) ||
537 ((parry>PARRY_NOT)&&(({object})PL->QueryProp(P_PARRY_WEAPON)!=ME)) )
MG Mud User88f12472016-06-24 23:31:02 +0200538 {
539 return 0;
540 }
541
542 // Man kann nur Waffen wegstecken, die man auch bei sich hat
543 if (environment() != PL)
544 {
545 _notify_fail("Diese Waffe gehoert Dir nicht!\n");
546 return 0;
547 }
548
549 // Und natuerlich geht das auch nur, wenn die Waffe gezueckt ist.
550 if (!QueryProp(P_WIELDED))
551 {
552 _notify_fail("Diese Waffe hast Du gar nicht gezueckt ...\n");
553 return 0;
554 }
555
556 return DoUnwield();
557}
558
559// Die Funktion, die den Schaden berechnet, den die Waffe verursacht
560int QueryDamage(object enemy)
561{ int dam;
562 mixed hit_func;
563 object wielder;
564
565 // Nur gezueckte Waffen machen Schaden
566 if (!objectp(wielder=QueryProp(P_WIELDED)))
567 return 0;
568
569 // Den Basis-Schaden berechnen. Die Staerke des Benutzers wird
570 // hier beruecksichtigt.
bugfixaf2be4f2020-03-22 19:13:07 +0100571 dam = (2*QueryProp(P_WC)+10*(({int})wielder->QueryAttribute(A_STR)))/3;
MG Mud User88f12472016-06-24 23:31:02 +0200572
573 // Wie gut man getroffen hat, wird ueber ein random() simuliert
574 dam = random(1+dam);
575
576 // Ist eine HitFunc gesetzt, dann wird diese ausgewertet. Der
577 // Rueckgabe-Wert wird zum Schaden addiert
578 if (!hit_cl || !get_type_info(hit_cl,2))
579 {
580 if (objectp(hit_func=QueryProp(P_HIT_FUNC)))
581 {
582 hit_cl=symbol_function("HitFunc",hit_func);
583 }
584 }
585 if (hit_cl && get_type_info(hit_cl,2))
586 {
587 dam += funcall(hit_cl,enemy);
588 }
589
590 // Zeitpunkt der letzten Benutzung ausgeben
591 SetProp(P_LAST_USE,time());
592
593 // Berechneten Schaden zurueckgeben
594 return dam;
595}
596
597// Die Funktion, die bei Parierwaffen den Schutzwert berechnet.
598int QueryDefend(string* dam_type, mixed spell, object enemy)
599{ int prot;
600 mixed def_func;
601 object pl;
602
603 prot = 0;
604
605 // Ruestungen schuetzen nur gegen physikalischen Schaden
606 if (!spell || (mappingp(spell) && spell[SP_PHYSICAL_ATTACK]))
607 {
608 if (sizeof(filter(dam_type,PHYSICAL_DAMAGE_TYPES)))
609 {
610 prot = random(1+QueryProp(P_AC));
611 }
612 }
613
614 // Ist eine DefendFunc gesetzt, wird diese ausgewertet
615 if (!defend_cl || !get_type_info(defend_cl,2))
616 {
617 if (objectp(def_func=QueryProp(P_DEFEND_FUNC)))
618 {
619 defend_cl=symbol_function("DefendFunc",def_func);
620 }
621 }
622 //Bei Netztoten keine (zurueckschlagende) DefendFunc
623 if (defend_cl && get_type_info(defend_cl,2) &&
624 objectp(pl=QueryProp(P_WIELDED)) && (!query_once_interactive(pl) ||
625 interactive(pl)) )
626 {
627 // Der Rueckgabewert der DefendFunc wird zum Schutz addiert
628 prot += funcall(defend_cl, dam_type, spell, enemy);
629 }
630
631 // Zeitpunkt der letzten Benutzung ausgeben
632 SetProp(P_LAST_USE,time());
633
634 // Berechneten Schutz zurueckgeben
635 return prot;
636}
637
638// Die Anzahl der von einer Waffe benoetigten Haende darf natuerlich nicht
639// kleiner als 1 sein.
640int _set_nr_hands(int arg)
641{
642 if (!intp(arg) || (arg<1) )
643 return Query(P_NR_HANDS, F_VALUE);
644 return Set(P_NR_HANDS, arg, F_VALUE);
645}
646
647// Der Schadenstyp einer Waffe darf zwar als string angegeben werden, wird
648// intern aber immer als array gespeichert
649mixed _set_dam_type(mixed arg)
650{
651 if (pointerp(arg))
652 {
653 return Set(P_DAM_TYPE, arg, F_VALUE);
654 }
655 else if (stringp(arg))
656 {
657 return Set(P_DAM_TYPE, ({ arg }), F_VALUE);
658 }
659 return Query(P_DAM_TYPE, F_VALUE);
660}
661
662// Objekte, die die Beschaedigung einer Waffe durch direktes Setzen von
663// P_DAMAGED durchfuehren, werden im awmaster geloggt
664mixed _set_item_damaged(mixed arg)
665{
666 if (arg && !intp(arg))
667 {
668 return Query(P_DAMAGED, F_VALUE);
669 }
670
671 if (previous_object(1))
672 call_other("/secure/awmaster","RegisterDamager",
673 previous_object(1),QueryProp(P_DAMAGED),arg);
674
675 return Set(P_DAMAGED,arg,F_VALUE);
676}
677
678// Wird etwas an P_HIT_FUNC geaendert, muss die zugehoerige closure
679// erstmal geloescht werden.
680mixed _set_hit_func(mixed arg)
681{
682 hit_cl=0;
683 return Set(P_HIT_FUNC, arg, F_VALUE);
684}
685
686// Wird etwas an P_DEFEND_FUNC geaendert, muss die zugehoerige closure
687// erstmal geloescht werden.
688mixed _set_defend_func(mixed arg)
689{
690 defend_cl=0;
691 return Set(P_DEFEND_FUNC, arg, F_VALUE);
692}
693
694// Die maximale Waffenklasse einer Waffe berechnet sich natuerlich aus
695// der aktuellen Waffenklasse und der Beschaedigung. Eine Ausnahme bilden
696// hier Waffen, deren effektive Waffenklasse groesser ist als diese Summe
697int _query_max_wc()
698{ int a,b;
699
700 a=QueryProp(P_WC)+QueryProp(P_DAMAGED);
701 b=QueryProp(P_EFFECTIVE_WC);
702 if (b>a)
703 return b;
704 return a;
705}
706
707// Will man eine Waffe beschaedigen oder reparieren, so macht man das
708// am besten ueber die Funktion Damage(argument). Positive Argumente
709// bedeuten eine Beschaedigung, negative eine Reparatur. Der Rueckgabewert
710// ist die wirklich durchgefuehrte Aenderung des Beschaedigungswertes
711int Damage(int new_dam)
712{ int wc,old_dam;
713 object w;
714
715 // Uebergebenes Argument pruefen
716 if (!new_dam || !intp(new_dam))
717 {
718 return 0;
719 }
720
721 // Bei Waffen, die nicht ausschliesslich zur Parade eingesetzt werden,
722 // geht die Beschaedigung auf die Kampfkraft, sprich: P_WC
723 if (QueryProp(P_PARRY)<PARRY_ONLY)
724 {
725 if ((wc=QueryProp(P_WC))<=MIN_WEAPON_CLASS && new_dam>0)
726 {
727 // Sonst wuerde Beschaedigung zur Reparatur fuehren
728 return 0;
729 }
730
731 // Min-WC und Max-WC beachten
732 if ((wc-new_dam) < MIN_WEAPON_CLASS)
733 {
734 new_dam = wc-MIN_WEAPON_CLASS;
735 }
736 else if ((wc-new_dam) > MAX_WEAPON_CLASS)
737 {
738 new_dam = wc-MAX_WEAPON_CLASS;
739 }
740
741 // Nie mehr als 100% reparieren
742 if (((old_dam=QueryProp(P_DAMAGED))<-new_dam) && new_dam<0)
743 {
744 new_dam=-old_dam;
745 }
746
747 // Aenderungen an der Waffenklasse und der dem Beschaedigungswert
748 // durchfuehren
749 SetProp(P_WC,(wc-new_dam));
750 // Ausnahmeweise Set, um die loggende Setmethode zu umgehen.
751 // TODO: SetProp, sobald direktes Beschaedigen raus ist.
752 Set(P_DAMAGED, old_dam+new_dam, F_VALUE);
753
754 // P_TOTAL_WC im Traeger updaten, so vorhanden
755 if (objectp(w=QueryProp(P_WIELDED)))
bugfixaf2be4f2020-03-22 19:13:07 +0100756 ({int})w->QueryProp(P_TOTAL_WC);
MG Mud User88f12472016-06-24 23:31:02 +0200757
758 // Rueckgabewert: Durchgefuehrte Aenderung an P_DAMAGE
759 return new_dam;
760 }
761
762 // Bei reinen Parierwaffen geht die Beschaedigung auf die
763 // Schutzwirkung, sprich: P_AC
764
765 if ((wc=QueryProp(P_AC))<=0 && new_dam>0)
766 {
767 // Sonst wuerde Beschaedigung zur Reparatur fuehren
768 return 0;
769 }
770
771 // Min-AC=0 und Max-AC beachten
772 if ((wc-new_dam) < MIN_PARRY_CLASS)
773 {
774 new_dam = wc-MIN_PARRY_CLASS;
775 }
776 else if ((wc-new_dam) > MAX_PARRY_CLASS)
777 {
778 new_dam = wc-MAX_PARRY_CLASS;
779 }
780
781 // Nie mehr als 100% reparieren
782 if (((old_dam=QueryProp(P_DAMAGED))<-new_dam) && new_dam<0)
783 {
784 new_dam=-old_dam;
785 }
786
787 // Aenderungen an der Ruestungsklasse und dem Beschaedigungswert
788 // durchfuehren
789 SetProp(P_AC,wc-new_dam);
790 // Ausnahmeweise Set, um die loggende Setmethode zu umgehen.
791 // TODO: SetProp, sobald direktes Beschaedigen raus ist.
792 Set(P_DAMAGED,old_dam+new_dam, F_VALUE);
793
794 // P_TOTAL_AC im Traeger updaten, so vorhanden
795 if (objectp(w=QueryProp(P_WIELDED)))
bugfixaf2be4f2020-03-22 19:13:07 +0100796 ({int})w->QueryProp(P_TOTAL_AC);
MG Mud User88f12472016-06-24 23:31:02 +0200797
798 // Rueckgabewert: Durchgefuehrte Aenderung an P_DAMAGE
799 return new_dam;
800}
801
802// Wird die Waffe einer Belastung ausgesetzt (z.B. wenn man damit
803// zuschlaegt), dann wird TakeFlaw() aufgerufen.
804varargs void TakeFlaw(object enemy)
805{ int c;
806
807 // Flaw-Wert erhoehen
808 flaw++;
809
810 // Ist der Waffe eine Qualitaet gesetzt worden, so kann es zu einer
811 // allmaehlichen Beschaedigung der Waffe kommen
812 if ((c=QueryProp(P_QUALITY)) && !(flaw%c))
813 Damage(1);
814
815 // Zeitpunkt des ersten Aufrufes festhalten
816 if (!ftime)
817 ftime=time();
818}
819
820// Die Flaw-Daten koennen natuerlich auch abgerufen werden
821mixed *QueryFlaw()
822{
823 return({flaw,ftime,dtime(ftime)});
824}
825