blob: 4130585781d3738694e704a14458d367984311c5 [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{
495 if ( !stringp(str) ||
496 (query_verb()[0..3]=="zieh" && sscanf(str,"%s hervor",str)!=1) )
497 {
498 return 0;
499 }
500
501 if (!id(str))
502 {
503 _notify_fail("Du hast sowas nicht.\n");
504 return 0;
505 }
506
507 return DoWield(silent);
508}
509
510// Die Funktion, die das "wegstecken"-Kommando auswertet
511int unwield(string str)
512{ int parry;
513 string dummy;
514
515 // Erstmal die Eingabe auswerten. Ist dies wirklich ein Kommando
516 // zum Wegstecken?
517 if ( !stringp(str) || (sscanf(str,"%s weg", dummy)!=1 &&
518 sscanf(str,"%s ein", dummy)!=1 &&
519 sscanf(str,"%s zurueck", dummy)!=1 ) )
520 {
521 return 0;
522 }
523
524 str = dummy;
525 parry=QueryProp(P_PARRY);
526
527 // Ist wirklich diese Waffe gemeint?
528 if ( !stringp(str) || !id(str) ||
bugfixaf2be4f2020-03-22 19:13:07 +0100529 ((parry<PARRY_ONLY)&&(({object})PL->QueryProp(P_WEAPON)!=ME)) ||
530 ((parry>PARRY_NOT)&&(({object})PL->QueryProp(P_PARRY_WEAPON)!=ME)) )
MG Mud User88f12472016-06-24 23:31:02 +0200531 {
532 return 0;
533 }
534
535 // Man kann nur Waffen wegstecken, die man auch bei sich hat
536 if (environment() != PL)
537 {
538 _notify_fail("Diese Waffe gehoert Dir nicht!\n");
539 return 0;
540 }
541
542 // Und natuerlich geht das auch nur, wenn die Waffe gezueckt ist.
543 if (!QueryProp(P_WIELDED))
544 {
545 _notify_fail("Diese Waffe hast Du gar nicht gezueckt ...\n");
546 return 0;
547 }
548
549 return DoUnwield();
550}
551
552// Die Funktion, die den Schaden berechnet, den die Waffe verursacht
553int QueryDamage(object enemy)
554{ int dam;
555 mixed hit_func;
556 object wielder;
557
558 // Nur gezueckte Waffen machen Schaden
559 if (!objectp(wielder=QueryProp(P_WIELDED)))
560 return 0;
561
562 // Den Basis-Schaden berechnen. Die Staerke des Benutzers wird
563 // hier beruecksichtigt.
bugfixaf2be4f2020-03-22 19:13:07 +0100564 dam = (2*QueryProp(P_WC)+10*(({int})wielder->QueryAttribute(A_STR)))/3;
MG Mud User88f12472016-06-24 23:31:02 +0200565
566 // Wie gut man getroffen hat, wird ueber ein random() simuliert
567 dam = random(1+dam);
568
569 // Ist eine HitFunc gesetzt, dann wird diese ausgewertet. Der
570 // Rueckgabe-Wert wird zum Schaden addiert
571 if (!hit_cl || !get_type_info(hit_cl,2))
572 {
573 if (objectp(hit_func=QueryProp(P_HIT_FUNC)))
574 {
575 hit_cl=symbol_function("HitFunc",hit_func);
576 }
577 }
578 if (hit_cl && get_type_info(hit_cl,2))
579 {
580 dam += funcall(hit_cl,enemy);
581 }
582
583 // Zeitpunkt der letzten Benutzung ausgeben
584 SetProp(P_LAST_USE,time());
585
586 // Berechneten Schaden zurueckgeben
587 return dam;
588}
589
590// Die Funktion, die bei Parierwaffen den Schutzwert berechnet.
591int QueryDefend(string* dam_type, mixed spell, object enemy)
592{ int prot;
593 mixed def_func;
594 object pl;
595
596 prot = 0;
597
598 // Ruestungen schuetzen nur gegen physikalischen Schaden
599 if (!spell || (mappingp(spell) && spell[SP_PHYSICAL_ATTACK]))
600 {
601 if (sizeof(filter(dam_type,PHYSICAL_DAMAGE_TYPES)))
602 {
603 prot = random(1+QueryProp(P_AC));
604 }
605 }
606
607 // Ist eine DefendFunc gesetzt, wird diese ausgewertet
608 if (!defend_cl || !get_type_info(defend_cl,2))
609 {
610 if (objectp(def_func=QueryProp(P_DEFEND_FUNC)))
611 {
612 defend_cl=symbol_function("DefendFunc",def_func);
613 }
614 }
615 //Bei Netztoten keine (zurueckschlagende) DefendFunc
616 if (defend_cl && get_type_info(defend_cl,2) &&
617 objectp(pl=QueryProp(P_WIELDED)) && (!query_once_interactive(pl) ||
618 interactive(pl)) )
619 {
620 // Der Rueckgabewert der DefendFunc wird zum Schutz addiert
621 prot += funcall(defend_cl, dam_type, spell, enemy);
622 }
623
624 // Zeitpunkt der letzten Benutzung ausgeben
625 SetProp(P_LAST_USE,time());
626
627 // Berechneten Schutz zurueckgeben
628 return prot;
629}
630
631// Die Anzahl der von einer Waffe benoetigten Haende darf natuerlich nicht
632// kleiner als 1 sein.
633int _set_nr_hands(int arg)
634{
635 if (!intp(arg) || (arg<1) )
636 return Query(P_NR_HANDS, F_VALUE);
637 return Set(P_NR_HANDS, arg, F_VALUE);
638}
639
640// Der Schadenstyp einer Waffe darf zwar als string angegeben werden, wird
641// intern aber immer als array gespeichert
642mixed _set_dam_type(mixed arg)
643{
644 if (pointerp(arg))
645 {
646 return Set(P_DAM_TYPE, arg, F_VALUE);
647 }
648 else if (stringp(arg))
649 {
650 return Set(P_DAM_TYPE, ({ arg }), F_VALUE);
651 }
652 return Query(P_DAM_TYPE, F_VALUE);
653}
654
655// Objekte, die die Beschaedigung einer Waffe durch direktes Setzen von
656// P_DAMAGED durchfuehren, werden im awmaster geloggt
657mixed _set_item_damaged(mixed arg)
658{
659 if (arg && !intp(arg))
660 {
661 return Query(P_DAMAGED, F_VALUE);
662 }
663
664 if (previous_object(1))
665 call_other("/secure/awmaster","RegisterDamager",
666 previous_object(1),QueryProp(P_DAMAGED),arg);
667
668 return Set(P_DAMAGED,arg,F_VALUE);
669}
670
671// Wird etwas an P_HIT_FUNC geaendert, muss die zugehoerige closure
672// erstmal geloescht werden.
673mixed _set_hit_func(mixed arg)
674{
675 hit_cl=0;
676 return Set(P_HIT_FUNC, arg, F_VALUE);
677}
678
679// Wird etwas an P_DEFEND_FUNC geaendert, muss die zugehoerige closure
680// erstmal geloescht werden.
681mixed _set_defend_func(mixed arg)
682{
683 defend_cl=0;
684 return Set(P_DEFEND_FUNC, arg, F_VALUE);
685}
686
687// Die maximale Waffenklasse einer Waffe berechnet sich natuerlich aus
688// der aktuellen Waffenklasse und der Beschaedigung. Eine Ausnahme bilden
689// hier Waffen, deren effektive Waffenklasse groesser ist als diese Summe
690int _query_max_wc()
691{ int a,b;
692
693 a=QueryProp(P_WC)+QueryProp(P_DAMAGED);
694 b=QueryProp(P_EFFECTIVE_WC);
695 if (b>a)
696 return b;
697 return a;
698}
699
700// Will man eine Waffe beschaedigen oder reparieren, so macht man das
701// am besten ueber die Funktion Damage(argument). Positive Argumente
702// bedeuten eine Beschaedigung, negative eine Reparatur. Der Rueckgabewert
703// ist die wirklich durchgefuehrte Aenderung des Beschaedigungswertes
704int Damage(int new_dam)
705{ int wc,old_dam;
706 object w;
707
708 // Uebergebenes Argument pruefen
709 if (!new_dam || !intp(new_dam))
710 {
711 return 0;
712 }
713
714 // Bei Waffen, die nicht ausschliesslich zur Parade eingesetzt werden,
715 // geht die Beschaedigung auf die Kampfkraft, sprich: P_WC
716 if (QueryProp(P_PARRY)<PARRY_ONLY)
717 {
718 if ((wc=QueryProp(P_WC))<=MIN_WEAPON_CLASS && new_dam>0)
719 {
720 // Sonst wuerde Beschaedigung zur Reparatur fuehren
721 return 0;
722 }
723
724 // Min-WC und Max-WC beachten
725 if ((wc-new_dam) < MIN_WEAPON_CLASS)
726 {
727 new_dam = wc-MIN_WEAPON_CLASS;
728 }
729 else if ((wc-new_dam) > MAX_WEAPON_CLASS)
730 {
731 new_dam = wc-MAX_WEAPON_CLASS;
732 }
733
734 // Nie mehr als 100% reparieren
735 if (((old_dam=QueryProp(P_DAMAGED))<-new_dam) && new_dam<0)
736 {
737 new_dam=-old_dam;
738 }
739
740 // Aenderungen an der Waffenklasse und der dem Beschaedigungswert
741 // durchfuehren
742 SetProp(P_WC,(wc-new_dam));
743 // Ausnahmeweise Set, um die loggende Setmethode zu umgehen.
744 // TODO: SetProp, sobald direktes Beschaedigen raus ist.
745 Set(P_DAMAGED, old_dam+new_dam, F_VALUE);
746
747 // P_TOTAL_WC im Traeger updaten, so vorhanden
748 if (objectp(w=QueryProp(P_WIELDED)))
bugfixaf2be4f2020-03-22 19:13:07 +0100749 ({int})w->QueryProp(P_TOTAL_WC);
MG Mud User88f12472016-06-24 23:31:02 +0200750
751 // Rueckgabewert: Durchgefuehrte Aenderung an P_DAMAGE
752 return new_dam;
753 }
754
755 // Bei reinen Parierwaffen geht die Beschaedigung auf die
756 // Schutzwirkung, sprich: P_AC
757
758 if ((wc=QueryProp(P_AC))<=0 && new_dam>0)
759 {
760 // Sonst wuerde Beschaedigung zur Reparatur fuehren
761 return 0;
762 }
763
764 // Min-AC=0 und Max-AC beachten
765 if ((wc-new_dam) < MIN_PARRY_CLASS)
766 {
767 new_dam = wc-MIN_PARRY_CLASS;
768 }
769 else if ((wc-new_dam) > MAX_PARRY_CLASS)
770 {
771 new_dam = wc-MAX_PARRY_CLASS;
772 }
773
774 // Nie mehr als 100% reparieren
775 if (((old_dam=QueryProp(P_DAMAGED))<-new_dam) && new_dam<0)
776 {
777 new_dam=-old_dam;
778 }
779
780 // Aenderungen an der Ruestungsklasse und dem Beschaedigungswert
781 // durchfuehren
782 SetProp(P_AC,wc-new_dam);
783 // Ausnahmeweise Set, um die loggende Setmethode zu umgehen.
784 // TODO: SetProp, sobald direktes Beschaedigen raus ist.
785 Set(P_DAMAGED,old_dam+new_dam, F_VALUE);
786
787 // P_TOTAL_AC im Traeger updaten, so vorhanden
788 if (objectp(w=QueryProp(P_WIELDED)))
bugfixaf2be4f2020-03-22 19:13:07 +0100789 ({int})w->QueryProp(P_TOTAL_AC);
MG Mud User88f12472016-06-24 23:31:02 +0200790
791 // Rueckgabewert: Durchgefuehrte Aenderung an P_DAMAGE
792 return new_dam;
793}
794
795// Wird die Waffe einer Belastung ausgesetzt (z.B. wenn man damit
796// zuschlaegt), dann wird TakeFlaw() aufgerufen.
797varargs void TakeFlaw(object enemy)
798{ int c;
799
800 // Flaw-Wert erhoehen
801 flaw++;
802
803 // Ist der Waffe eine Qualitaet gesetzt worden, so kann es zu einer
804 // allmaehlichen Beschaedigung der Waffe kommen
805 if ((c=QueryProp(P_QUALITY)) && !(flaw%c))
806 Damage(1);
807
808 // Zeitpunkt des ersten Aufrufes festhalten
809 if (!ftime)
810 ftime=time();
811}
812
813// Die Flaw-Daten koennen natuerlich auch abgerufen werden
814mixed *QueryFlaw()
815{
816 return({flaw,ftime,dtime(ftime)});
817}
818