blob: 333ea3c9f01427c8fe61584472b15e5d6cfd063e [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");
MG Mud User88f12472016-06-24 23:31:02 +0200222}
223
224// Die Funktion, die das eigentliche Zuecken durchfuehrt.
225varargs int DoWield(int silent)
226{ int dex, parry;
227 closure cl;
228 mixed res;
229
230 // Man kann nur Waffen zuecken, die man auch im Inventory hat.
231 if (environment()!=PL)
232 {
233 _notify_fail( break_string(
234 "Du musst "+name(WEN,1)+" schon erst nehmen!",78) );
235 return 0;
236 }
237
238 // Eine gezueckte Waffe kann man natuerlich nicht nochmal zuecken
239 if (QueryProp(P_WIELDED))
240 {
241 notify_fail("Das hast Du schon gemacht!\n");
242 return 0;
243 }
244
245 // Waffen, die ein oder mehrere Attribut veraendern und gegen
246 // das gesetzte Limit verstossen, haben keine Wirkung bezueglich der
247 // Attribute.
bugfixaf2be4f2020-03-22 19:13:07 +0100248 if ( mappingp(res=QueryProp(P_M_ATTR_MOD)) && ({int})PL->TestLimitViolation(res) )
MG Mud User88f12472016-06-24 23:31:02 +0200249 {
250 write(break_string(
251 "Irgendetwas an Deiner Ausruestung verhindert, dass Du Dich mit "+
252 name(WEM,1)+" so richtig wohl fuehlst.",78));
253 }
254
255 // Ueber P_RESTRICTIONS kann man einige Restriktionen definieren, ohne
256 // gleich auf eine WieldFunc zurueckgreifen zu muessen.
257 // Die Auswertung erfolgt ueber den RestrictionChecker
258 if ( (res=QueryProp(P_RESTRICTIONS)) && mappingp(res) &&
bugfixd94d0932020-04-08 11:27:13 +0200259 (res=({string})call_other("/std/restriction_checker","check_restrictions",
MG Mud User88f12472016-06-24 23:31:02 +0200260 PL,res)) && stringp(res) )
261 {
262 notify_fail(res);
263 return 0;
264 }
265
bugfixaf2be4f2020-03-22 19:13:07 +0100266 parry=QueryProp(P_PARRY);
267 dex=({int})PL->QueryAttribute(A_DEX);
MG Mud User88f12472016-06-24 23:31:02 +0200268
269 // Testen, ob der Spieler die noetige Geschicklichkeit besitzt, um
270 // mit dieser (Parier)Waffe umgehen zu koennen
271 if ( ((parry<PARRY_ONLY) && ((dex+8)*10)<QueryProp(P_WC)) ||
272 ((parry>PARRY_NOT) && ((dex+5)*2 )<QueryProp(P_AC)) )
273 {
274 notify_fail(
275 "Du bist nicht geschickt genug, um mit dieser Waffe umzugehen.\n");
276 return 0;
277 }
278
279 // Eine Gezueckte Waffe muss natuerlich erst mal weggesteckt werden.
bugfixaf2be4f2020-03-22 19:13:07 +0100280 if ( (parry<PARRY_ONLY) && objectp(res=({object})PL->QueryProp(P_WEAPON)) )
MG Mud User88f12472016-06-24 23:31:02 +0200281 {
bugfixaf2be4f2020-03-22 19:13:07 +0100282 if ( (({int})res->DoUnwield(silent)) && !(({object})PL->QueryProp(P_WEAPON)) )
MG Mud User88f12472016-06-24 23:31:02 +0200283 {
284 // Wenn die alte Waffe weggesteckt werden konnte, nochmal
285 // versuchen zu zuecken
286 return DoWield(silent);
287 }
288 else
289 {
290 // Sonst Meldung ausgeben
291 notify_fail("Das geht nicht, solange Du noch eine andere "+
292 "Waffe gezueckt hast.\n");
293 return 0;
294 }
295 }
296 // Das gleiche gilt natuerlich fuer Parierwaffen
bugfixaf2be4f2020-03-22 19:13:07 +0100297 if ( (parry>PARRY_NOT) && objectp(res=({object})PL->QueryProp(P_PARRY_WEAPON)) )
MG Mud User88f12472016-06-24 23:31:02 +0200298 {
bugfixaf2be4f2020-03-22 19:13:07 +0100299 if ( (({int})res->DoUnwield(silent)) && !(({object})PL->QueryProp(P_PARRY_WEAPON)) )
MG Mud User88f12472016-06-24 23:31:02 +0200300 {
301 // Wenn die alte Parierwaffe weggesteckt werden konnte, nochmal
302 // versuchen zu zuecken
303 return DoWield(silent);
304 }
305 else
306 {
307 // Sonst Meldung ausgeben
308 notify_fail("Das geht nicht, solange Du noch eine andere "+
heull00125706652018-02-05 15:07:50 +0100309 "Parierwaffe gezueckt hast.\n");
MG Mud User88f12472016-06-24 23:31:02 +0200310 return 0;
311 }
312 }
313
314 // Ist eine WieldFunc gesetzt, wird diese aufgerufen.
315 if (objectp(res=QueryProp(P_WIELD_FUNC))
bugfixaf2be4f2020-03-22 19:13:07 +0100316 && !(({int})res->WieldFunc(ME,silent,environment())))
MG Mud User88f12472016-06-24 23:31:02 +0200317 {
318 // Eine Meldung sollte schon von der WieldFunc ausgegeben werden.
319 return 1;
320 }
321
322 // Die zulaessigen Hoechstwerte duerfen natuerlich nicht
323 // ueberschritten werden.
324 if ( (parry<PARRY_ONLY) && (QueryProp(P_WC)>MAX_WEAPON_CLASS) )
325 {
326 notify_fail(
327 "Ungueltige Waffenklasse, bitte Erzmagier verstaendigen.\n");
328 return 0;
329 }
330 if ( (parry>PARRY_NOT) && (QueryProp(P_AC)>MAX_PARRY_CLASS) )
331 {
332 notify_fail(
333 "Ungueltige Parierklasse, bitte Erzmagier verstaendigen.\n");
334 return 0;
335 }
336
337 // Testen, ob der Zuecker genug Haende frei hat.
bugfixaf2be4f2020-03-22 19:13:07 +0100338 if (!(({int})PL->UseHands(ME,QueryProp(P_NR_HANDS))))
MG Mud User88f12472016-06-24 23:31:02 +0200339 {
340 notify_fail("Du hast keine Hand mehr frei.\n");
341 return 0;
342 }
343
344 // Ok, jetzt ist alles klar, die (Parier)Waffe wird gezueckt
345 SetProp(P_WIELDED, PL);
346 SetProp(P_EQUIP_TIME,time());
347
348 cl=symbol_function("SetProp",PL);
349
350 if (parry<PARRY_ONLY)
351 {
352 // Dieses Objekt als Waffe setzen
353 funcall(cl,P_WEAPON, ME );
354 }
355 if (parry>PARRY_NOT)
356 {
357 // Dieses Objekt als Parierwaffe setzen
358 funcall(cl,P_PARRY_WEAPON, ME );
359 }
360
361 // Waffen koennen Attribute aendern/blockieren. Also muessen diese
362 // nach dem Zuecken aktualisiert werden
bugfixaf2be4f2020-03-22 19:13:07 +0100363 ({void})PL->register_modifier(ME);
364 ({void})PL->UpdateAttributes();
MG Mud User88f12472016-06-24 23:31:02 +0200365
366 // P_TOTAL_AC/P_TOTAL_WC im Spieler aktualisieren. Da dort Attribute
367 // eingehen, kann das erst hier gemacht werden.
368 if (parry<PARRY_ONLY)
369 {
bugfixaf2be4f2020-03-22 19:13:07 +0100370 ({int})PL->QueryProp(P_TOTAL_WC);
MG Mud User88f12472016-06-24 23:31:02 +0200371 }
372 if (parry>PARRY_NOT)
373 {
bugfixaf2be4f2020-03-22 19:13:07 +0100374 ({int})PL->QueryProp(P_TOTAL_AC);
MG Mud User88f12472016-06-24 23:31:02 +0200375 }
376
377 // Zueck-Meldung ausgeben, wenn das silent-Flag nicht gesetzt ist
378 if (!silent)
379 {
380 doWieldMessage();
381 }
382
383 // Alle Waffen werden im awmaster registriert, sobald sie von einem
384 // Spieler gezueckt werden
385 if (!logged && query_once_interactive(PL))
386 {
387 call_other("/secure/awmaster","RegisterWeapon",ME);
388 logged=1;
389 }
390
391 // Inform-Funktion aufrufen
392 InformWield(PL,silent);
393
394 // Fertig mit dem Zuecken
395 return 1;
396}
397
398// Die Funktion, die das eigentliche Wegstecken durchfuehrt.
399varargs int DoUnwield(int silent)
400{ closure cl;
401 int parry;
402 mixed res;
403 object wielded_by;
404
405 // Waffen, die nicht gezueckt sind, kann man natuerlich nicht
406 // wegstecken
407 if (!objectp(wielded_by=QueryProp(P_WIELDED)))
408 {
409 return 0;
410 }
411
412 // Ist eine UnwieldFunc gesetzt, wird diese aufgerufen
413 if ( objectp(res=QueryProp(P_UNWIELD_FUNC)) &&
bugfixaf2be4f2020-03-22 19:13:07 +0100414 !(({int})res->UnwieldFunc(ME,silent,wielded_by)) )
MG Mud User88f12472016-06-24 23:31:02 +0200415 {
416 // Eine Meldung muss die UnwieldFunc schon selbst ausgeben.
417 return 1;
418 }
419
420 // Eine verfluchte Waffe kann man natuerlich nicht wegstecken - aber
421 // auch da gibts Ausnahmefaelle, wie z.B. den Tod eines Spielers
422 if ((res=QueryProp(P_CURSED)) && !(silent&M_NOCHECK))
423 {
424 if (stringp(res))
425 {
426 // Stand in P_CURSED ein String? Dann diesen ausgeben
427 tell_object(wielded_by,
428 (res[<1]=='\n' ? res : break_string(res,78)));
429 }
430 else
431 {
432 // Sonst eine Standard-Meldung ausgeben
433 tell_object(wielded_by, break_string(
434 "Du kannst "+name(WEN)+" nicht wegstecken.",78));
435 }
436 return 1;
437 }
438
439 // Ok, jetzt ist alles klar, die (Parier)Waffe wird weggesteckt
440 parry=QueryProp(P_PARRY);
441 cl=symbol_function("SetProp",wielded_by);
442
443 if (parry<PARRY_ONLY)
444 {
445 // Eintrag als Waffe im Spieler loeschen
446 funcall(cl,P_WEAPON, 0);
447 }
448 if (parry>PARRY_NOT)
449 {
450 // Eintrag als Parierwaffe im Spieler loeschen
451 funcall(cl,P_PARRY_WEAPON, 0);
452 }
453
454 // Im Spieler die Zeit setzen, zu der er zuletzt eine Waffe weggesteckt
455 // hat.
456 funcall(cl,P_UNWIELD_TIME,time());
457
458 // Meldung ausgeben, wenn silent-Flag nicht gesetzt ist
459 if (!silent)
460 {
461 doUnwieldMessage(wielded_by);
462 }
463
464 // Die Haende, die bisher von der Waffe benutzt wurden, freigeben
bugfixaf2be4f2020-03-22 19:13:07 +0100465 ({int})wielded_by->FreeHands(ME);
MG Mud User88f12472016-06-24 23:31:02 +0200466 SetProp(P_WIELDED, 0);
467
468 // Waffen koennen Attribute aendern/blockieren. Also muessen diese
469 // nach dem Wegstecken aktualisiert werden
bugfixaf2be4f2020-03-22 19:13:07 +0100470 ({void})wielded_by->deregister_modifier(ME);
471 ({void})wielded_by->UpdateAttributes();
MG Mud User88f12472016-06-24 23:31:02 +0200472
473 // P_TOTAL_AC/P_TOTAL_WC im Spieler aktualisieren. Da dort Attribute
474 // eingehen, kann das erst hier gemacht werden.
475 if (parry<PARRY_ONLY)
476 {
bugfixaf2be4f2020-03-22 19:13:07 +0100477 ({int})wielded_by->QueryProp(P_TOTAL_WC);
MG Mud User88f12472016-06-24 23:31:02 +0200478 }
479 if (parry>PARRY_NOT)
480 {
bugfixaf2be4f2020-03-22 19:13:07 +0100481 ({int})wielded_by->QueryProp(P_TOTAL_AC);
MG Mud User88f12472016-06-24 23:31:02 +0200482 }
483
484 // Inform-Funktion aufrufen
485 InformUnwield(wielded_by, silent);
486
487 // Fertig mit dem Wegstecken
488 return 1;
489}
490
491// Die Funktion, die das "zuecken"-Kommando auswertet
492varargs int wield(string str, int silent)
493{
Arathorn7166e0e2020-04-11 12:35:25 +0200494 if ( QueryProp(P_INVIS) )
495 return 0;
496
MG Mud User88f12472016-06-24 23:31:02 +0200497 if ( !stringp(str) ||
498 (query_verb()[0..3]=="zieh" && sscanf(str,"%s hervor",str)!=1) )
499 {
500 return 0;
501 }
502
503 if (!id(str))
504 {
505 _notify_fail("Du hast sowas nicht.\n");
506 return 0;
507 }
508
509 return DoWield(silent);
510}
511
512// Die Funktion, die das "wegstecken"-Kommando auswertet
513int unwield(string str)
Arathorn7166e0e2020-04-11 12:35:25 +0200514{
515 if ( QueryProp(P_INVIS) )
516 return 0;
517
518 int parry;
MG Mud User88f12472016-06-24 23:31:02 +0200519 string dummy;
520
521 // Erstmal die Eingabe auswerten. Ist dies wirklich ein Kommando
522 // zum Wegstecken?
523 if ( !stringp(str) || (sscanf(str,"%s weg", dummy)!=1 &&
524 sscanf(str,"%s ein", dummy)!=1 &&
525 sscanf(str,"%s zurueck", dummy)!=1 ) )
526 {
527 return 0;
528 }
529
530 str = dummy;
531 parry=QueryProp(P_PARRY);
532
533 // Ist wirklich diese Waffe gemeint?
534 if ( !stringp(str) || !id(str) ||
bugfixaf2be4f2020-03-22 19:13:07 +0100535 ((parry<PARRY_ONLY)&&(({object})PL->QueryProp(P_WEAPON)!=ME)) ||
536 ((parry>PARRY_NOT)&&(({object})PL->QueryProp(P_PARRY_WEAPON)!=ME)) )
MG Mud User88f12472016-06-24 23:31:02 +0200537 {
538 return 0;
539 }
540
541 // Man kann nur Waffen wegstecken, die man auch bei sich hat
542 if (environment() != PL)
543 {
544 _notify_fail("Diese Waffe gehoert Dir nicht!\n");
545 return 0;
546 }
547
548 // Und natuerlich geht das auch nur, wenn die Waffe gezueckt ist.
549 if (!QueryProp(P_WIELDED))
550 {
551 _notify_fail("Diese Waffe hast Du gar nicht gezueckt ...\n");
552 return 0;
553 }
554
555 return DoUnwield();
556}
557
558// Die Funktion, die den Schaden berechnet, den die Waffe verursacht
559int QueryDamage(object enemy)
560{ int dam;
561 mixed hit_func;
562 object wielder;
563
564 // Nur gezueckte Waffen machen Schaden
565 if (!objectp(wielder=QueryProp(P_WIELDED)))
566 return 0;
567
568 // Den Basis-Schaden berechnen. Die Staerke des Benutzers wird
569 // hier beruecksichtigt.
bugfixaf2be4f2020-03-22 19:13:07 +0100570 dam = (2*QueryProp(P_WC)+10*(({int})wielder->QueryAttribute(A_STR)))/3;
MG Mud User88f12472016-06-24 23:31:02 +0200571
572 // Wie gut man getroffen hat, wird ueber ein random() simuliert
573 dam = random(1+dam);
574
575 // Ist eine HitFunc gesetzt, dann wird diese ausgewertet. Der
576 // Rueckgabe-Wert wird zum Schaden addiert
577 if (!hit_cl || !get_type_info(hit_cl,2))
578 {
579 if (objectp(hit_func=QueryProp(P_HIT_FUNC)))
580 {
581 hit_cl=symbol_function("HitFunc",hit_func);
582 }
583 }
584 if (hit_cl && get_type_info(hit_cl,2))
585 {
586 dam += funcall(hit_cl,enemy);
587 }
588
589 // Zeitpunkt der letzten Benutzung ausgeben
590 SetProp(P_LAST_USE,time());
591
592 // Berechneten Schaden zurueckgeben
593 return dam;
594}
595
596// Die Funktion, die bei Parierwaffen den Schutzwert berechnet.
597int QueryDefend(string* dam_type, mixed spell, object enemy)
598{ int prot;
599 mixed def_func;
600 object pl;
601
602 prot = 0;
603
604 // Ruestungen schuetzen nur gegen physikalischen Schaden
605 if (!spell || (mappingp(spell) && spell[SP_PHYSICAL_ATTACK]))
606 {
607 if (sizeof(filter(dam_type,PHYSICAL_DAMAGE_TYPES)))
608 {
609 prot = random(1+QueryProp(P_AC));
610 }
611 }
612
613 // Ist eine DefendFunc gesetzt, wird diese ausgewertet
614 if (!defend_cl || !get_type_info(defend_cl,2))
615 {
616 if (objectp(def_func=QueryProp(P_DEFEND_FUNC)))
617 {
618 defend_cl=symbol_function("DefendFunc",def_func);
619 }
620 }
621 //Bei Netztoten keine (zurueckschlagende) DefendFunc
622 if (defend_cl && get_type_info(defend_cl,2) &&
623 objectp(pl=QueryProp(P_WIELDED)) && (!query_once_interactive(pl) ||
624 interactive(pl)) )
625 {
626 // Der Rueckgabewert der DefendFunc wird zum Schutz addiert
627 prot += funcall(defend_cl, dam_type, spell, enemy);
628 }
629
630 // Zeitpunkt der letzten Benutzung ausgeben
631 SetProp(P_LAST_USE,time());
632
633 // Berechneten Schutz zurueckgeben
634 return prot;
635}
636
637// Die Anzahl der von einer Waffe benoetigten Haende darf natuerlich nicht
638// kleiner als 1 sein.
639int _set_nr_hands(int arg)
640{
641 if (!intp(arg) || (arg<1) )
642 return Query(P_NR_HANDS, F_VALUE);
643 return Set(P_NR_HANDS, arg, F_VALUE);
644}
645
646// Der Schadenstyp einer Waffe darf zwar als string angegeben werden, wird
647// intern aber immer als array gespeichert
648mixed _set_dam_type(mixed arg)
649{
650 if (pointerp(arg))
651 {
652 return Set(P_DAM_TYPE, arg, F_VALUE);
653 }
654 else if (stringp(arg))
655 {
656 return Set(P_DAM_TYPE, ({ arg }), F_VALUE);
657 }
658 return Query(P_DAM_TYPE, F_VALUE);
659}
660
661// Objekte, die die Beschaedigung einer Waffe durch direktes Setzen von
662// P_DAMAGED durchfuehren, werden im awmaster geloggt
663mixed _set_item_damaged(mixed arg)
664{
665 if (arg && !intp(arg))
666 {
667 return Query(P_DAMAGED, F_VALUE);
668 }
669
670 if (previous_object(1))
671 call_other("/secure/awmaster","RegisterDamager",
672 previous_object(1),QueryProp(P_DAMAGED),arg);
673
674 return Set(P_DAMAGED,arg,F_VALUE);
675}
676
677// Wird etwas an P_HIT_FUNC geaendert, muss die zugehoerige closure
678// erstmal geloescht werden.
679mixed _set_hit_func(mixed arg)
680{
681 hit_cl=0;
682 return Set(P_HIT_FUNC, arg, F_VALUE);
683}
684
685// Wird etwas an P_DEFEND_FUNC geaendert, muss die zugehoerige closure
686// erstmal geloescht werden.
687mixed _set_defend_func(mixed arg)
688{
689 defend_cl=0;
690 return Set(P_DEFEND_FUNC, arg, F_VALUE);
691}
692
693// Die maximale Waffenklasse einer Waffe berechnet sich natuerlich aus
694// der aktuellen Waffenklasse und der Beschaedigung. Eine Ausnahme bilden
695// hier Waffen, deren effektive Waffenklasse groesser ist als diese Summe
696int _query_max_wc()
697{ int a,b;
698
699 a=QueryProp(P_WC)+QueryProp(P_DAMAGED);
700 b=QueryProp(P_EFFECTIVE_WC);
701 if (b>a)
702 return b;
703 return a;
704}
705
706// Will man eine Waffe beschaedigen oder reparieren, so macht man das
707// am besten ueber die Funktion Damage(argument). Positive Argumente
708// bedeuten eine Beschaedigung, negative eine Reparatur. Der Rueckgabewert
709// ist die wirklich durchgefuehrte Aenderung des Beschaedigungswertes
710int Damage(int new_dam)
711{ int wc,old_dam;
712 object w;
713
714 // Uebergebenes Argument pruefen
715 if (!new_dam || !intp(new_dam))
716 {
717 return 0;
718 }
719
720 // Bei Waffen, die nicht ausschliesslich zur Parade eingesetzt werden,
721 // geht die Beschaedigung auf die Kampfkraft, sprich: P_WC
722 if (QueryProp(P_PARRY)<PARRY_ONLY)
723 {
724 if ((wc=QueryProp(P_WC))<=MIN_WEAPON_CLASS && new_dam>0)
725 {
726 // Sonst wuerde Beschaedigung zur Reparatur fuehren
727 return 0;
728 }
729
730 // Min-WC und Max-WC beachten
731 if ((wc-new_dam) < MIN_WEAPON_CLASS)
732 {
733 new_dam = wc-MIN_WEAPON_CLASS;
734 }
735 else if ((wc-new_dam) > MAX_WEAPON_CLASS)
736 {
737 new_dam = wc-MAX_WEAPON_CLASS;
738 }
739
740 // Nie mehr als 100% reparieren
741 if (((old_dam=QueryProp(P_DAMAGED))<-new_dam) && new_dam<0)
742 {
743 new_dam=-old_dam;
744 }
745
746 // Aenderungen an der Waffenklasse und der dem Beschaedigungswert
747 // durchfuehren
748 SetProp(P_WC,(wc-new_dam));
749 // Ausnahmeweise Set, um die loggende Setmethode zu umgehen.
750 // TODO: SetProp, sobald direktes Beschaedigen raus ist.
751 Set(P_DAMAGED, old_dam+new_dam, F_VALUE);
752
753 // P_TOTAL_WC im Traeger updaten, so vorhanden
754 if (objectp(w=QueryProp(P_WIELDED)))
bugfixaf2be4f2020-03-22 19:13:07 +0100755 ({int})w->QueryProp(P_TOTAL_WC);
MG Mud User88f12472016-06-24 23:31:02 +0200756
757 // Rueckgabewert: Durchgefuehrte Aenderung an P_DAMAGE
758 return new_dam;
759 }
760
761 // Bei reinen Parierwaffen geht die Beschaedigung auf die
762 // Schutzwirkung, sprich: P_AC
763
764 if ((wc=QueryProp(P_AC))<=0 && new_dam>0)
765 {
766 // Sonst wuerde Beschaedigung zur Reparatur fuehren
767 return 0;
768 }
769
770 // Min-AC=0 und Max-AC beachten
771 if ((wc-new_dam) < MIN_PARRY_CLASS)
772 {
773 new_dam = wc-MIN_PARRY_CLASS;
774 }
775 else if ((wc-new_dam) > MAX_PARRY_CLASS)
776 {
777 new_dam = wc-MAX_PARRY_CLASS;
778 }
779
780 // Nie mehr als 100% reparieren
781 if (((old_dam=QueryProp(P_DAMAGED))<-new_dam) && new_dam<0)
782 {
783 new_dam=-old_dam;
784 }
785
786 // Aenderungen an der Ruestungsklasse und dem Beschaedigungswert
787 // durchfuehren
788 SetProp(P_AC,wc-new_dam);
789 // Ausnahmeweise Set, um die loggende Setmethode zu umgehen.
790 // TODO: SetProp, sobald direktes Beschaedigen raus ist.
791 Set(P_DAMAGED,old_dam+new_dam, F_VALUE);
792
793 // P_TOTAL_AC im Traeger updaten, so vorhanden
794 if (objectp(w=QueryProp(P_WIELDED)))
bugfixaf2be4f2020-03-22 19:13:07 +0100795 ({int})w->QueryProp(P_TOTAL_AC);
MG Mud User88f12472016-06-24 23:31:02 +0200796
797 // Rueckgabewert: Durchgefuehrte Aenderung an P_DAMAGE
798 return new_dam;
799}
800
801// Wird die Waffe einer Belastung ausgesetzt (z.B. wenn man damit
802// zuschlaegt), dann wird TakeFlaw() aufgerufen.
803varargs void TakeFlaw(object enemy)
804{ int c;
805
806 // Flaw-Wert erhoehen
807 flaw++;
808
809 // Ist der Waffe eine Qualitaet gesetzt worden, so kann es zu einer
810 // allmaehlichen Beschaedigung der Waffe kommen
811 if ((c=QueryProp(P_QUALITY)) && !(flaw%c))
812 Damage(1);
813
814 // Zeitpunkt des ersten Aufrufes festhalten
815 if (!ftime)
816 ftime=time();
817}
818
819// Die Flaw-Daten koennen natuerlich auch abgerufen werden
820mixed *QueryFlaw()
821{
822 return({flaw,ftime,dtime(ftime)});
823}
824