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 |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 12 | #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; |
| 29 | private nosave int logged; |
| 30 | private nosave closure defend_cl, hit_cl; |
| 31 | |
| 32 | void 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. |
| 64 | public 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 | */ |
| 73 | void 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 | { |
bugfix | af2be4f | 2020-03-22 19:13:07 +0100 | [diff] [blame] | 85 | ({int})this_player()->ReceiveMsg(str[0], |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 86 | 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 | |
bugfix | af2be4f | 2020-03-22 19:13:07 +0100 | [diff] [blame] | 102 | ({int})this_player()->ReceiveMsg(s1, |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 103 | 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 | { |
bugfix | af2be4f | 2020-03-22 19:13:07 +0100 | [diff] [blame] | 123 | ({int})this_player()->ReceiveMsg( |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 124 | "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()), |
bugfix | af2be4f | 2020-03-22 19:13:07 +0100 | [diff] [blame] | 133 | ({string})this_player()->Name(WER)+" zueckt "+name(WEN,0)+".", |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 134 | 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 | */ |
| 142 | void 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 | { |
bugfix | af2be4f | 2020-03-22 19:13:07 +0100 | [diff] [blame] | 159 | ({int})wielded_by->ReceiveMsg(str[0], |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 160 | 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); |
bugfix | af2be4f | 2020-03-22 19:13:07 +0100 | [diff] [blame] | 174 | ({int})wielded_by->ReceiveMsg(s1, |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 175 | 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 | { |
bugfix | af2be4f | 2020-03-22 19:13:07 +0100 | [diff] [blame] | 193 | ({int})wielded_by->ReceiveMsg( |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 194 | "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()), |
bugfix | af2be4f | 2020-03-22 19:13:07 +0100 | [diff] [blame] | 199 | ({string})wielded_by->Name(WER) +" steckt "+name(WEN,0)+" zurueck.", |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 200 | MT_LOOK, |
| 201 | MA_UNWIELD, 0, ({wielded_by}), environment()); |
| 202 | } |
| 203 | |
| 204 | // Diese Funktion wird aufgerufen, wenn die Waffe wirklich gezueckt wird |
| 205 | protected void InformWield(object pl, int silent) |
| 206 | { |
| 207 | return; |
| 208 | } |
| 209 | |
| 210 | // Diese Funktion wird aufgerufen, wenn die Waffe wirklich weggesteckt |
| 211 | // wird |
| 212 | protected void InformUnwield(object pl, int silent) |
| 213 | { |
| 214 | return; |
| 215 | } |
| 216 | |
| 217 | |
| 218 | // wield_me soll knallen. |
| 219 | varargs 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. |
| 226 | varargs 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. |
bugfix | af2be4f | 2020-03-22 19:13:07 +0100 | [diff] [blame] | 249 | if ( mappingp(res=QueryProp(P_M_ATTR_MOD)) && ({int})PL->TestLimitViolation(res) ) |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 250 | { |
| 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) && |
bugfix | af2be4f | 2020-03-22 19:13:07 +0100 | [diff] [blame] | 260 | (res=call_other("/std/restriction_checker","check_restrictions", |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 261 | PL,res)) && stringp(res) ) |
| 262 | { |
| 263 | notify_fail(res); |
| 264 | return 0; |
| 265 | } |
| 266 | |
bugfix | af2be4f | 2020-03-22 19:13:07 +0100 | [diff] [blame] | 267 | parry=QueryProp(P_PARRY); |
| 268 | dex=({int})PL->QueryAttribute(A_DEX); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 269 | |
| 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. |
bugfix | af2be4f | 2020-03-22 19:13:07 +0100 | [diff] [blame] | 281 | if ( (parry<PARRY_ONLY) && objectp(res=({object})PL->QueryProp(P_WEAPON)) ) |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 282 | { |
bugfix | af2be4f | 2020-03-22 19:13:07 +0100 | [diff] [blame] | 283 | if ( (({int})res->DoUnwield(silent)) && !(({object})PL->QueryProp(P_WEAPON)) ) |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 284 | { |
| 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 |
bugfix | af2be4f | 2020-03-22 19:13:07 +0100 | [diff] [blame] | 298 | if ( (parry>PARRY_NOT) && objectp(res=({object})PL->QueryProp(P_PARRY_WEAPON)) ) |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 299 | { |
bugfix | af2be4f | 2020-03-22 19:13:07 +0100 | [diff] [blame] | 300 | if ( (({int})res->DoUnwield(silent)) && !(({object})PL->QueryProp(P_PARRY_WEAPON)) ) |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 301 | { |
| 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 "+ |
heull001 | 2570665 | 2018-02-05 15:07:50 +0100 | [diff] [blame] | 310 | "Parierwaffe gezueckt hast.\n"); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 311 | return 0; |
| 312 | } |
| 313 | } |
| 314 | |
| 315 | // Ist eine WieldFunc gesetzt, wird diese aufgerufen. |
| 316 | if (objectp(res=QueryProp(P_WIELD_FUNC)) |
bugfix | af2be4f | 2020-03-22 19:13:07 +0100 | [diff] [blame] | 317 | && !(({int})res->WieldFunc(ME,silent,environment()))) |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 318 | { |
| 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. |
bugfix | af2be4f | 2020-03-22 19:13:07 +0100 | [diff] [blame] | 339 | if (!(({int})PL->UseHands(ME,QueryProp(P_NR_HANDS)))) |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 340 | { |
| 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 |
bugfix | af2be4f | 2020-03-22 19:13:07 +0100 | [diff] [blame] | 364 | ({void})PL->register_modifier(ME); |
| 365 | ({void})PL->UpdateAttributes(); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 366 | |
| 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 | { |
bugfix | af2be4f | 2020-03-22 19:13:07 +0100 | [diff] [blame] | 371 | ({int})PL->QueryProp(P_TOTAL_WC); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 372 | } |
| 373 | if (parry>PARRY_NOT) |
| 374 | { |
bugfix | af2be4f | 2020-03-22 19:13:07 +0100 | [diff] [blame] | 375 | ({int})PL->QueryProp(P_TOTAL_AC); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 376 | } |
| 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. |
| 400 | varargs 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)) && |
bugfix | af2be4f | 2020-03-22 19:13:07 +0100 | [diff] [blame] | 415 | !(({int})res->UnwieldFunc(ME,silent,wielded_by)) ) |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 416 | { |
| 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 |
bugfix | af2be4f | 2020-03-22 19:13:07 +0100 | [diff] [blame] | 466 | ({int})wielded_by->FreeHands(ME); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 467 | SetProp(P_WIELDED, 0); |
| 468 | |
| 469 | // Waffen koennen Attribute aendern/blockieren. Also muessen diese |
| 470 | // nach dem Wegstecken aktualisiert werden |
bugfix | af2be4f | 2020-03-22 19:13:07 +0100 | [diff] [blame] | 471 | ({void})wielded_by->deregister_modifier(ME); |
| 472 | ({void})wielded_by->UpdateAttributes(); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 473 | |
| 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 | { |
bugfix | af2be4f | 2020-03-22 19:13:07 +0100 | [diff] [blame] | 478 | ({int})wielded_by->QueryProp(P_TOTAL_WC); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 479 | } |
| 480 | if (parry>PARRY_NOT) |
| 481 | { |
bugfix | af2be4f | 2020-03-22 19:13:07 +0100 | [diff] [blame] | 482 | ({int})wielded_by->QueryProp(P_TOTAL_AC); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 483 | } |
| 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 |
| 493 | varargs int wield(string str, int silent) |
| 494 | { |
Arathorn | 7166e0e | 2020-04-11 12:35:25 +0200 | [diff] [blame] | 495 | if ( QueryProp(P_INVIS) ) |
| 496 | return 0; |
| 497 | |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 498 | if ( !stringp(str) || |
| 499 | (query_verb()[0..3]=="zieh" && sscanf(str,"%s hervor",str)!=1) ) |
| 500 | { |
| 501 | return 0; |
| 502 | } |
| 503 | |
| 504 | if (!id(str)) |
| 505 | { |
| 506 | _notify_fail("Du hast sowas nicht.\n"); |
| 507 | return 0; |
| 508 | } |
| 509 | |
| 510 | return DoWield(silent); |
| 511 | } |
| 512 | |
| 513 | // Die Funktion, die das "wegstecken"-Kommando auswertet |
| 514 | int unwield(string str) |
Arathorn | 7166e0e | 2020-04-11 12:35:25 +0200 | [diff] [blame] | 515 | { |
| 516 | if ( QueryProp(P_INVIS) ) |
| 517 | return 0; |
| 518 | |
| 519 | int parry; |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 520 | string dummy; |
| 521 | |
| 522 | // Erstmal die Eingabe auswerten. Ist dies wirklich ein Kommando |
| 523 | // zum Wegstecken? |
| 524 | if ( !stringp(str) || (sscanf(str,"%s weg", dummy)!=1 && |
| 525 | sscanf(str,"%s ein", dummy)!=1 && |
| 526 | sscanf(str,"%s zurueck", dummy)!=1 ) ) |
| 527 | { |
| 528 | return 0; |
| 529 | } |
| 530 | |
| 531 | str = dummy; |
| 532 | parry=QueryProp(P_PARRY); |
| 533 | |
| 534 | // Ist wirklich diese Waffe gemeint? |
| 535 | if ( !stringp(str) || !id(str) || |
bugfix | af2be4f | 2020-03-22 19:13:07 +0100 | [diff] [blame] | 536 | ((parry<PARRY_ONLY)&&(({object})PL->QueryProp(P_WEAPON)!=ME)) || |
| 537 | ((parry>PARRY_NOT)&&(({object})PL->QueryProp(P_PARRY_WEAPON)!=ME)) ) |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 538 | { |
| 539 | return 0; |
| 540 | } |
| 541 | |
| 542 | // Man kann nur Waffen wegstecken, die man auch bei sich hat |
| 543 | if (environment() != PL) |
| 544 | { |
| 545 | _notify_fail("Diese Waffe gehoert Dir nicht!\n"); |
| 546 | return 0; |
| 547 | } |
| 548 | |
| 549 | // Und natuerlich geht das auch nur, wenn die Waffe gezueckt ist. |
| 550 | if (!QueryProp(P_WIELDED)) |
| 551 | { |
| 552 | _notify_fail("Diese Waffe hast Du gar nicht gezueckt ...\n"); |
| 553 | return 0; |
| 554 | } |
| 555 | |
| 556 | return DoUnwield(); |
| 557 | } |
| 558 | |
| 559 | // Die Funktion, die den Schaden berechnet, den die Waffe verursacht |
| 560 | int QueryDamage(object enemy) |
| 561 | { int dam; |
| 562 | mixed hit_func; |
| 563 | object wielder; |
| 564 | |
| 565 | // Nur gezueckte Waffen machen Schaden |
| 566 | if (!objectp(wielder=QueryProp(P_WIELDED))) |
| 567 | return 0; |
| 568 | |
| 569 | // Den Basis-Schaden berechnen. Die Staerke des Benutzers wird |
| 570 | // hier beruecksichtigt. |
bugfix | af2be4f | 2020-03-22 19:13:07 +0100 | [diff] [blame] | 571 | dam = (2*QueryProp(P_WC)+10*(({int})wielder->QueryAttribute(A_STR)))/3; |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 572 | |
| 573 | // Wie gut man getroffen hat, wird ueber ein random() simuliert |
| 574 | dam = random(1+dam); |
| 575 | |
| 576 | // Ist eine HitFunc gesetzt, dann wird diese ausgewertet. Der |
| 577 | // Rueckgabe-Wert wird zum Schaden addiert |
| 578 | if (!hit_cl || !get_type_info(hit_cl,2)) |
| 579 | { |
| 580 | if (objectp(hit_func=QueryProp(P_HIT_FUNC))) |
| 581 | { |
| 582 | hit_cl=symbol_function("HitFunc",hit_func); |
| 583 | } |
| 584 | } |
| 585 | if (hit_cl && get_type_info(hit_cl,2)) |
| 586 | { |
| 587 | dam += funcall(hit_cl,enemy); |
| 588 | } |
| 589 | |
| 590 | // Zeitpunkt der letzten Benutzung ausgeben |
| 591 | SetProp(P_LAST_USE,time()); |
| 592 | |
| 593 | // Berechneten Schaden zurueckgeben |
| 594 | return dam; |
| 595 | } |
| 596 | |
| 597 | // Die Funktion, die bei Parierwaffen den Schutzwert berechnet. |
| 598 | int QueryDefend(string* dam_type, mixed spell, object enemy) |
| 599 | { int prot; |
| 600 | mixed def_func; |
| 601 | object pl; |
| 602 | |
| 603 | prot = 0; |
| 604 | |
| 605 | // Ruestungen schuetzen nur gegen physikalischen Schaden |
| 606 | if (!spell || (mappingp(spell) && spell[SP_PHYSICAL_ATTACK])) |
| 607 | { |
| 608 | if (sizeof(filter(dam_type,PHYSICAL_DAMAGE_TYPES))) |
| 609 | { |
| 610 | prot = random(1+QueryProp(P_AC)); |
| 611 | } |
| 612 | } |
| 613 | |
| 614 | // Ist eine DefendFunc gesetzt, wird diese ausgewertet |
| 615 | if (!defend_cl || !get_type_info(defend_cl,2)) |
| 616 | { |
| 617 | if (objectp(def_func=QueryProp(P_DEFEND_FUNC))) |
| 618 | { |
| 619 | defend_cl=symbol_function("DefendFunc",def_func); |
| 620 | } |
| 621 | } |
| 622 | //Bei Netztoten keine (zurueckschlagende) DefendFunc |
| 623 | if (defend_cl && get_type_info(defend_cl,2) && |
| 624 | objectp(pl=QueryProp(P_WIELDED)) && (!query_once_interactive(pl) || |
| 625 | interactive(pl)) ) |
| 626 | { |
| 627 | // Der Rueckgabewert der DefendFunc wird zum Schutz addiert |
| 628 | prot += funcall(defend_cl, dam_type, spell, enemy); |
| 629 | } |
| 630 | |
| 631 | // Zeitpunkt der letzten Benutzung ausgeben |
| 632 | SetProp(P_LAST_USE,time()); |
| 633 | |
| 634 | // Berechneten Schutz zurueckgeben |
| 635 | return prot; |
| 636 | } |
| 637 | |
| 638 | // Die Anzahl der von einer Waffe benoetigten Haende darf natuerlich nicht |
| 639 | // kleiner als 1 sein. |
| 640 | int _set_nr_hands(int arg) |
| 641 | { |
| 642 | if (!intp(arg) || (arg<1) ) |
| 643 | return Query(P_NR_HANDS, F_VALUE); |
| 644 | return Set(P_NR_HANDS, arg, F_VALUE); |
| 645 | } |
| 646 | |
| 647 | // Der Schadenstyp einer Waffe darf zwar als string angegeben werden, wird |
| 648 | // intern aber immer als array gespeichert |
| 649 | mixed _set_dam_type(mixed arg) |
| 650 | { |
| 651 | if (pointerp(arg)) |
| 652 | { |
| 653 | return Set(P_DAM_TYPE, arg, F_VALUE); |
| 654 | } |
| 655 | else if (stringp(arg)) |
| 656 | { |
| 657 | return Set(P_DAM_TYPE, ({ arg }), F_VALUE); |
| 658 | } |
| 659 | return Query(P_DAM_TYPE, F_VALUE); |
| 660 | } |
| 661 | |
| 662 | // Objekte, die die Beschaedigung einer Waffe durch direktes Setzen von |
| 663 | // P_DAMAGED durchfuehren, werden im awmaster geloggt |
| 664 | mixed _set_item_damaged(mixed arg) |
| 665 | { |
| 666 | if (arg && !intp(arg)) |
| 667 | { |
| 668 | return Query(P_DAMAGED, F_VALUE); |
| 669 | } |
| 670 | |
| 671 | if (previous_object(1)) |
| 672 | call_other("/secure/awmaster","RegisterDamager", |
| 673 | previous_object(1),QueryProp(P_DAMAGED),arg); |
| 674 | |
| 675 | return Set(P_DAMAGED,arg,F_VALUE); |
| 676 | } |
| 677 | |
| 678 | // Wird etwas an P_HIT_FUNC geaendert, muss die zugehoerige closure |
| 679 | // erstmal geloescht werden. |
| 680 | mixed _set_hit_func(mixed arg) |
| 681 | { |
| 682 | hit_cl=0; |
| 683 | return Set(P_HIT_FUNC, arg, F_VALUE); |
| 684 | } |
| 685 | |
| 686 | // Wird etwas an P_DEFEND_FUNC geaendert, muss die zugehoerige closure |
| 687 | // erstmal geloescht werden. |
| 688 | mixed _set_defend_func(mixed arg) |
| 689 | { |
| 690 | defend_cl=0; |
| 691 | return Set(P_DEFEND_FUNC, arg, F_VALUE); |
| 692 | } |
| 693 | |
| 694 | // Die maximale Waffenklasse einer Waffe berechnet sich natuerlich aus |
| 695 | // der aktuellen Waffenklasse und der Beschaedigung. Eine Ausnahme bilden |
| 696 | // hier Waffen, deren effektive Waffenklasse groesser ist als diese Summe |
| 697 | int _query_max_wc() |
| 698 | { int a,b; |
| 699 | |
| 700 | a=QueryProp(P_WC)+QueryProp(P_DAMAGED); |
| 701 | b=QueryProp(P_EFFECTIVE_WC); |
| 702 | if (b>a) |
| 703 | return b; |
| 704 | return a; |
| 705 | } |
| 706 | |
| 707 | // Will man eine Waffe beschaedigen oder reparieren, so macht man das |
| 708 | // am besten ueber die Funktion Damage(argument). Positive Argumente |
| 709 | // bedeuten eine Beschaedigung, negative eine Reparatur. Der Rueckgabewert |
| 710 | // ist die wirklich durchgefuehrte Aenderung des Beschaedigungswertes |
| 711 | int Damage(int new_dam) |
| 712 | { int wc,old_dam; |
| 713 | object w; |
| 714 | |
| 715 | // Uebergebenes Argument pruefen |
| 716 | if (!new_dam || !intp(new_dam)) |
| 717 | { |
| 718 | return 0; |
| 719 | } |
| 720 | |
| 721 | // Bei Waffen, die nicht ausschliesslich zur Parade eingesetzt werden, |
| 722 | // geht die Beschaedigung auf die Kampfkraft, sprich: P_WC |
| 723 | if (QueryProp(P_PARRY)<PARRY_ONLY) |
| 724 | { |
| 725 | if ((wc=QueryProp(P_WC))<=MIN_WEAPON_CLASS && new_dam>0) |
| 726 | { |
| 727 | // Sonst wuerde Beschaedigung zur Reparatur fuehren |
| 728 | return 0; |
| 729 | } |
| 730 | |
| 731 | // Min-WC und Max-WC beachten |
| 732 | if ((wc-new_dam) < MIN_WEAPON_CLASS) |
| 733 | { |
| 734 | new_dam = wc-MIN_WEAPON_CLASS; |
| 735 | } |
| 736 | else if ((wc-new_dam) > MAX_WEAPON_CLASS) |
| 737 | { |
| 738 | new_dam = wc-MAX_WEAPON_CLASS; |
| 739 | } |
| 740 | |
| 741 | // Nie mehr als 100% reparieren |
| 742 | if (((old_dam=QueryProp(P_DAMAGED))<-new_dam) && new_dam<0) |
| 743 | { |
| 744 | new_dam=-old_dam; |
| 745 | } |
| 746 | |
| 747 | // Aenderungen an der Waffenklasse und der dem Beschaedigungswert |
| 748 | // durchfuehren |
| 749 | SetProp(P_WC,(wc-new_dam)); |
| 750 | // Ausnahmeweise Set, um die loggende Setmethode zu umgehen. |
| 751 | // TODO: SetProp, sobald direktes Beschaedigen raus ist. |
| 752 | Set(P_DAMAGED, old_dam+new_dam, F_VALUE); |
| 753 | |
| 754 | // P_TOTAL_WC im Traeger updaten, so vorhanden |
| 755 | if (objectp(w=QueryProp(P_WIELDED))) |
bugfix | af2be4f | 2020-03-22 19:13:07 +0100 | [diff] [blame] | 756 | ({int})w->QueryProp(P_TOTAL_WC); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 757 | |
| 758 | // Rueckgabewert: Durchgefuehrte Aenderung an P_DAMAGE |
| 759 | return new_dam; |
| 760 | } |
| 761 | |
| 762 | // Bei reinen Parierwaffen geht die Beschaedigung auf die |
| 763 | // Schutzwirkung, sprich: P_AC |
| 764 | |
| 765 | if ((wc=QueryProp(P_AC))<=0 && new_dam>0) |
| 766 | { |
| 767 | // Sonst wuerde Beschaedigung zur Reparatur fuehren |
| 768 | return 0; |
| 769 | } |
| 770 | |
| 771 | // Min-AC=0 und Max-AC beachten |
| 772 | if ((wc-new_dam) < MIN_PARRY_CLASS) |
| 773 | { |
| 774 | new_dam = wc-MIN_PARRY_CLASS; |
| 775 | } |
| 776 | else if ((wc-new_dam) > MAX_PARRY_CLASS) |
| 777 | { |
| 778 | new_dam = wc-MAX_PARRY_CLASS; |
| 779 | } |
| 780 | |
| 781 | // Nie mehr als 100% reparieren |
| 782 | if (((old_dam=QueryProp(P_DAMAGED))<-new_dam) && new_dam<0) |
| 783 | { |
| 784 | new_dam=-old_dam; |
| 785 | } |
| 786 | |
| 787 | // Aenderungen an der Ruestungsklasse und dem Beschaedigungswert |
| 788 | // durchfuehren |
| 789 | SetProp(P_AC,wc-new_dam); |
| 790 | // Ausnahmeweise Set, um die loggende Setmethode zu umgehen. |
| 791 | // TODO: SetProp, sobald direktes Beschaedigen raus ist. |
| 792 | Set(P_DAMAGED,old_dam+new_dam, F_VALUE); |
| 793 | |
| 794 | // P_TOTAL_AC im Traeger updaten, so vorhanden |
| 795 | if (objectp(w=QueryProp(P_WIELDED))) |
bugfix | af2be4f | 2020-03-22 19:13:07 +0100 | [diff] [blame] | 796 | ({int})w->QueryProp(P_TOTAL_AC); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 797 | |
| 798 | // Rueckgabewert: Durchgefuehrte Aenderung an P_DAMAGE |
| 799 | return new_dam; |
| 800 | } |
| 801 | |
| 802 | // Wird die Waffe einer Belastung ausgesetzt (z.B. wenn man damit |
| 803 | // zuschlaegt), dann wird TakeFlaw() aufgerufen. |
| 804 | varargs void TakeFlaw(object enemy) |
| 805 | { int c; |
| 806 | |
| 807 | // Flaw-Wert erhoehen |
| 808 | flaw++; |
| 809 | |
| 810 | // Ist der Waffe eine Qualitaet gesetzt worden, so kann es zu einer |
| 811 | // allmaehlichen Beschaedigung der Waffe kommen |
| 812 | if ((c=QueryProp(P_QUALITY)) && !(flaw%c)) |
| 813 | Damage(1); |
| 814 | |
| 815 | // Zeitpunkt des ersten Aufrufes festhalten |
| 816 | if (!ftime) |
| 817 | ftime=time(); |
| 818 | } |
| 819 | |
| 820 | // Die Flaw-Daten koennen natuerlich auch abgerufen werden |
| 821 | mixed *QueryFlaw() |
| 822 | { |
| 823 | return({flaw,ftime,dtime(ftime)}); |
| 824 | } |
| 825 | |