MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame^] | 1 | // 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; |
| 30 | private nosave int logged; |
| 31 | private nosave closure defend_cl, hit_cl; |
| 32 | |
| 33 | void 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. |
| 65 | public 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 | */ |
| 74 | void 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 | */ |
| 143 | void 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 |
| 206 | protected void InformWield(object pl, int silent) |
| 207 | { |
| 208 | return; |
| 209 | } |
| 210 | |
| 211 | // Diese Funktion wird aufgerufen, wenn die Waffe wirklich weggesteckt |
| 212 | // wird |
| 213 | protected void InformUnwield(object pl, int silent) |
| 214 | { |
| 215 | return; |
| 216 | } |
| 217 | |
| 218 | |
| 219 | // wield_me soll knallen. |
| 220 | varargs 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. |
| 227 | varargs 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. |
| 401 | varargs 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 |
| 494 | varargs 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 |
| 512 | int 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 |
| 554 | int 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. |
| 592 | int 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. |
| 634 | int _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 |
| 643 | mixed _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 |
| 658 | mixed _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. |
| 674 | mixed _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. |
| 682 | mixed _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 |
| 691 | int _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 |
| 705 | int 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. |
| 798 | varargs 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 |
| 815 | mixed *QueryFlaw() |
| 816 | { |
| 817 | return({flaw,ftime,dtime(ftime)}); |
| 818 | } |
| 819 | |