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