| // MorgenGrauen MUDlib |
| // |
| // weapon/combat.c -- combat part of the weapon standard object |
| // |
| // $Id: combat.c 9425 2016-01-02 18:19:40Z Zesstra $ |
| |
| #include <sys_debug.h> |
| |
| #pragma strict_types |
| #pragma save_types |
| #pragma no_clone |
| #pragma pedantic |
| #pragma range_check |
| |
| #define NEED_PROTOTYPES |
| |
| #include <thing/properties.h> |
| #include <thing/commands.h> |
| #include <thing/description.h> |
| #include <properties.h> |
| #include <language.h> |
| #include <combat.h> |
| #include <attributes.h> |
| #include <defines.h> |
| #include <moving.h> |
| #include <new_skills.h> |
| |
| // Globale Variablen |
| int ftime, flaw; |
| private nosave int logged; |
| private nosave closure defend_cl, hit_cl; |
| |
| void create() |
| { |
| // Variablen initialisieren |
| logged=ftime=flaw=0; |
| defend_cl=0; |
| hit_cl=0; |
| |
| // Einige Grundwerte setzen |
| SetProp(P_WEAPON_TYPE, WT_CLUB); |
| SetProp(P_DAM_TYPE, ({DT_BLUDGEON})); |
| SetProp(P_NR_HANDS, 2); |
| SetProp(P_PARRY,PARRY_NOT); |
| SetProp(P_AC,0); |
| Set(P_RESTRICTIONS,([]),F_VALUE); |
| Set(P_LAST_USE,time(),F_VALUE); |
| |
| // Einige Properties sollten nicht von aussen gesetzt werden koennen |
| Set(P_PARRY, PROTECTED, F_MODE_AS); |
| Set(P_WIELDED, PROTECTED, F_MODE_AS); |
| Set(P_LAST_USE,PROTECTED, F_MODE_AS); |
| |
| // Diese kann von aussen gesetzt werden (noch), aber bitte nur ueber die |
| // hier definierte Setmethode. |
| Set(P_DAMAGED, PROTECTED, F_MODE_AS); |
| |
| // Eine Waffe benoetigt Kommandos, mit denen man sie zuecken |
| // und wegstecken kann |
| AddCmd( ({"zueck","zuecke","zieh","ziehe"}), "wield" ); |
| AddCmd( ({"steck","stecke"}), "unwield" ); |
| } |
| |
| // aktuelles Lebewesen, was diese Waffe zur Zeit gezueckt hat. |
| public object QueryUser() |
| { |
| return QueryProp(P_WIELDED); |
| } |
| |
| /* |
| * Ausgabe einer Meldung beim Zuecken geht nur an Spieler, nicht an NPC. |
| * Die Umgebung bekommt natuerlich immer eine Meldung. |
| */ |
| void doWieldMessage() |
| { |
| string *str, s1; |
| |
| if(QueryProp(P_WIELD_MSG)) // Ist eine WieldMsg gesetzt? |
| { |
| if(closurep(QueryProp(P_WIELD_MSG))) // Sogar als eigene Fkt.? |
| { |
| str = funcall(QueryProp(P_WIELD_MSG),this_player()); |
| |
| if(interactive(this_player())) |
| { |
| this_player()->ReceiveMsg(str[0], |
| MT_NOTIFICATION|MSG_BS_LEAVE_LFS, MA_WIELD, 0, |
| this_player()); |
| } |
| |
| if ( objectp(environment()) && objectp(environment(environment())) ) |
| send_room(environment(environment()), |
| str[1], |
| MT_LOOK|MSG_BS_LEAVE_LFS, |
| MA_WIELD, 0, ({this_player()}), environment()); |
| return; |
| } |
| else if(interactive(this_player())) |
| { |
| s1 = replace_personal(sprintf(QueryProp(P_WIELD_MSG)[0],"@WEN2"), |
| ({this_player(),this_object()}), 1); |
| |
| this_player()->ReceiveMsg(s1, |
| MT_NOTIFICATION|MSG_BS_LEAVE_LFS, MA_WIELD, 0, |
| this_player()); |
| } |
| |
| // Abwaertskompatibel: Das erste %s wird zu WEN1, das zweite zu WEN2 |
| s1 = replace_personal(sprintf(QueryProp(P_WIELD_MSG)[1],"@WEN1","@WEN2"), |
| ({this_player(), this_object()}), 1); |
| |
| if ( objectp(environment()) && objectp(environment(environment())) ) |
| send_room(environment(environment()), |
| s1, |
| MT_LOOK|MSG_BS_LEAVE_LFS, |
| MA_WIELD, 0, ({this_player()}), environment()); |
| return; |
| } |
| /* |
| * Keine WieldMsg gesetzt, Ausgabe der Default-Meldungen. |
| */ |
| else if(interactive(this_player())) |
| { |
| this_player()->ReceiveMsg( |
| "Du zueckst "+name(WEN,1)+".", |
| MT_NOTIFICATION, MA_WIELD, 0, this_player()); |
| } |
| |
| //s.o. ersetzt durch tell_room() |
| //say(break_string(this_player()->Name(WER)+" zueckt " |
| // +name(WEN,0)+".",78),({ this_player() })); |
| if ( objectp(environment()) && objectp(environment(environment())) ) |
| send_room(environment(environment()), |
| this_player()->Name(WER)+" zueckt "+name(WEN,0)+".", |
| MT_LOOK, |
| MA_WIELD, 0, ({this_player()}), environment()); |
| } |
| |
| /* |
| * Ausgabe einer Meldung beim Wegstecken geht nur an Spieler, nicht an NPC. |
| * Die Umgebung bekommt immer eine Meldung. |
| */ |
| void doUnwieldMessage(object wielded_by) |
| { |
| string *str,s1; |
| |
| if(!objectp(wielded_by)) // Hoops! Gar nicht gezueckt? Abbruch! |
| { |
| return; |
| } |
| |
| if(QueryProp(P_UNWIELD_MSG)) // Hier gibt es eine UnwieldMsg. |
| { |
| if(closurep(QueryProp(P_UNWIELD_MSG))) // Sogar als Closure, wow :-) |
| { |
| str = funcall(QueryProp(P_UNWIELD_MSG),wielded_by); |
| |
| if(interactive(wielded_by)) |
| { |
| wielded_by->ReceiveMsg(str[0], |
| MT_NOTIFICATION|MSG_BS_LEAVE_LFS, MA_UNWIELD, 0, wielded_by); |
| } |
| if ( objectp(environment()) && objectp(environment(environment())) ) |
| send_room(environment(environment()), |
| str[1], |
| MT_LOOK|MSG_BS_LEAVE_LFS, |
| MA_UNWIELD, 0, ({wielded_by}), environment()); |
| return; |
| } |
| |
| else if(interactive(wielded_by)) |
| { |
| s1 = replace_personal(sprintf(QueryProp(P_UNWIELD_MSG)[0],"@WEN2"), |
| ({this_player(),this_object()}), 1); |
| wielded_by->ReceiveMsg(s1, |
| MT_NOTIFICATION|MSG_BS_LEAVE_LFS, MA_UNWIELD, 0, wielded_by); |
| } |
| |
| s1 = replace_personal(sprintf(QueryProp(P_UNWIELD_MSG)[1],"@WEN1","@WEN2"), |
| ({wielded_by, this_object()}), 1); |
| |
| if ( objectp(environment()) && objectp(environment(environment())) ) |
| send_room(environment(environment()), |
| s1, |
| MT_LOOK|MSG_BS_LEAVE_LFS, |
| MA_UNWIELD, 0, ({wielded_by}), environment()); |
| return; |
| } |
| /* |
| * Keine UnwieldMsg, also Default-Meldungen ausgeben. |
| */ |
| else if(interactive(wielded_by)) |
| { |
| wielded_by->ReceiveMsg( |
| "Du steckst "+name(WEN,1)+" zurueck.", |
| MT_NOTIFICATION, MA_UNWIELD, 0, wielded_by); |
| } |
| if ( objectp(environment()) && objectp(environment(environment())) ) |
| send_room(environment(environment()), |
| wielded_by->Name(WER) +" steckt "+name(WEN,0)+" zurueck.", |
| MT_LOOK, |
| MA_UNWIELD, 0, ({wielded_by}), environment()); |
| } |
| |
| // Diese Funktion wird aufgerufen, wenn die Waffe wirklich gezueckt wird |
| protected void InformWield(object pl, int silent) |
| { |
| return; |
| } |
| |
| // Diese Funktion wird aufgerufen, wenn die Waffe wirklich weggesteckt |
| // wird |
| protected void InformUnwield(object pl, int silent) |
| { |
| return; |
| } |
| |
| |
| // wield_me soll knallen. |
| varargs int wield_me(int silent) |
| { |
| raise_error("wield_me() ist veraltet. Bitte nutze DoWield()\n"); |
| return 1; |
| } |
| |
| // Die Funktion, die das eigentliche Zuecken durchfuehrt. |
| varargs int DoWield(int silent) |
| { int dex, parry; |
| closure cl; |
| mixed res; |
| |
| // Man kann nur Waffen zuecken, die man auch im Inventory hat. |
| if (environment()!=PL) |
| { |
| _notify_fail( break_string( |
| "Du musst "+name(WEN,1)+" schon erst nehmen!",78) ); |
| return 0; |
| } |
| |
| // Eine gezueckte Waffe kann man natuerlich nicht nochmal zuecken |
| if (QueryProp(P_WIELDED)) |
| { |
| notify_fail("Das hast Du schon gemacht!\n"); |
| return 0; |
| } |
| |
| // Waffen, die ein oder mehrere Attribut veraendern und gegen |
| // das gesetzte Limit verstossen, haben keine Wirkung bezueglich der |
| // Attribute. |
| if ( mappingp(res=QueryProp(P_M_ATTR_MOD)) && PL->TestLimitViolation(res) ) |
| { |
| write(break_string( |
| "Irgendetwas an Deiner Ausruestung verhindert, dass Du Dich mit "+ |
| name(WEM,1)+" so richtig wohl fuehlst.",78)); |
| } |
| |
| // Ueber P_RESTRICTIONS kann man einige Restriktionen definieren, ohne |
| // gleich auf eine WieldFunc zurueckgreifen zu muessen. |
| // Die Auswertung erfolgt ueber den RestrictionChecker |
| if ( (res=QueryProp(P_RESTRICTIONS)) && mappingp(res) && |
| (res=(string)call_other("/std/restriction_checker","check_restrictions", |
| PL,res)) && stringp(res) ) |
| { |
| notify_fail(res); |
| return 0; |
| } |
| |
| parry=(int)QueryProp(P_PARRY); |
| dex=(int)PL->QueryAttribute(A_DEX); |
| |
| // Testen, ob der Spieler die noetige Geschicklichkeit besitzt, um |
| // mit dieser (Parier)Waffe umgehen zu koennen |
| if ( ((parry<PARRY_ONLY) && ((dex+8)*10)<QueryProp(P_WC)) || |
| ((parry>PARRY_NOT) && ((dex+5)*2 )<QueryProp(P_AC)) ) |
| { |
| notify_fail( |
| "Du bist nicht geschickt genug, um mit dieser Waffe umzugehen.\n"); |
| return 0; |
| } |
| |
| // Eine Gezueckte Waffe muss natuerlich erst mal weggesteckt werden. |
| if ( (parry<PARRY_ONLY) && objectp(res=(object)PL->QueryProp(P_WEAPON)) ) |
| { |
| if ( (res->DoUnwield(silent)) && !((object)PL->QueryProp(P_WEAPON)) ) |
| { |
| // Wenn die alte Waffe weggesteckt werden konnte, nochmal |
| // versuchen zu zuecken |
| return DoWield(silent); |
| } |
| else |
| { |
| // Sonst Meldung ausgeben |
| notify_fail("Das geht nicht, solange Du noch eine andere "+ |
| "Waffe gezueckt hast.\n"); |
| return 0; |
| } |
| } |
| // Das gleiche gilt natuerlich fuer Parierwaffen |
| if ( (parry>PARRY_NOT) && objectp(res=(object)PL->QueryProp(P_PARRY_WEAPON)) ) |
| { |
| if ( (res->DoUnwield(silent)) && !(PL->QueryProp(P_PARRY_WEAPON)) ) |
| { |
| // Wenn die alte Parierwaffe weggesteckt werden konnte, nochmal |
| // versuchen zu zuecken |
| return DoWield(silent); |
| } |
| else |
| { |
| // Sonst Meldung ausgeben |
| notify_fail("Das geht nicht, solange Du noch eine andere "+ |
| "Paierwaffe gezueckt hast.\n"); |
| return 0; |
| } |
| } |
| |
| // Ist eine WieldFunc gesetzt, wird diese aufgerufen. |
| if (objectp(res=QueryProp(P_WIELD_FUNC)) |
| && !(res->WieldFunc(ME,silent,environment()))) |
| { |
| // Eine Meldung sollte schon von der WieldFunc ausgegeben werden. |
| return 1; |
| } |
| |
| // Die zulaessigen Hoechstwerte duerfen natuerlich nicht |
| // ueberschritten werden. |
| if ( (parry<PARRY_ONLY) && (QueryProp(P_WC)>MAX_WEAPON_CLASS) ) |
| { |
| notify_fail( |
| "Ungueltige Waffenklasse, bitte Erzmagier verstaendigen.\n"); |
| return 0; |
| } |
| if ( (parry>PARRY_NOT) && (QueryProp(P_AC)>MAX_PARRY_CLASS) ) |
| { |
| notify_fail( |
| "Ungueltige Parierklasse, bitte Erzmagier verstaendigen.\n"); |
| return 0; |
| } |
| |
| // Testen, ob der Zuecker genug Haende frei hat. |
| if (!(PL->UseHands(ME,QueryProp(P_NR_HANDS)))) |
| { |
| notify_fail("Du hast keine Hand mehr frei.\n"); |
| return 0; |
| } |
| |
| // Ok, jetzt ist alles klar, die (Parier)Waffe wird gezueckt |
| SetProp(P_WIELDED, PL); |
| SetProp(P_EQUIP_TIME,time()); |
| |
| cl=symbol_function("SetProp",PL); |
| |
| if (parry<PARRY_ONLY) |
| { |
| // Dieses Objekt als Waffe setzen |
| funcall(cl,P_WEAPON, ME ); |
| } |
| if (parry>PARRY_NOT) |
| { |
| // Dieses Objekt als Parierwaffe setzen |
| funcall(cl,P_PARRY_WEAPON, ME ); |
| } |
| |
| // Waffen koennen Attribute aendern/blockieren. Also muessen diese |
| // nach dem Zuecken aktualisiert werden |
| PL->register_modifier(ME); |
| PL->UpdateAttributes(); |
| |
| // P_TOTAL_AC/P_TOTAL_WC im Spieler aktualisieren. Da dort Attribute |
| // eingehen, kann das erst hier gemacht werden. |
| if (parry<PARRY_ONLY) |
| { |
| PL->QueryProp(P_TOTAL_WC); |
| } |
| if (parry>PARRY_NOT) |
| { |
| PL->QueryProp(P_TOTAL_AC); |
| } |
| |
| // Zueck-Meldung ausgeben, wenn das silent-Flag nicht gesetzt ist |
| if (!silent) |
| { |
| doWieldMessage(); |
| } |
| |
| // Alle Waffen werden im awmaster registriert, sobald sie von einem |
| // Spieler gezueckt werden |
| if (!logged && query_once_interactive(PL)) |
| { |
| call_other("/secure/awmaster","RegisterWeapon",ME); |
| logged=1; |
| } |
| |
| // Inform-Funktion aufrufen |
| InformWield(PL,silent); |
| |
| // Fertig mit dem Zuecken |
| return 1; |
| } |
| |
| // Die Funktion, die das eigentliche Wegstecken durchfuehrt. |
| varargs int DoUnwield(int silent) |
| { closure cl; |
| int parry; |
| mixed res; |
| object wielded_by; |
| |
| // Waffen, die nicht gezueckt sind, kann man natuerlich nicht |
| // wegstecken |
| if (!objectp(wielded_by=QueryProp(P_WIELDED))) |
| { |
| return 0; |
| } |
| |
| // Ist eine UnwieldFunc gesetzt, wird diese aufgerufen |
| if ( objectp(res=QueryProp(P_UNWIELD_FUNC)) && |
| !(res->UnwieldFunc(ME,silent,wielded_by)) ) |
| { |
| // Eine Meldung muss die UnwieldFunc schon selbst ausgeben. |
| return 1; |
| } |
| |
| // Eine verfluchte Waffe kann man natuerlich nicht wegstecken - aber |
| // auch da gibts Ausnahmefaelle, wie z.B. den Tod eines Spielers |
| if ((res=QueryProp(P_CURSED)) && !(silent&M_NOCHECK)) |
| { |
| if (stringp(res)) |
| { |
| // Stand in P_CURSED ein String? Dann diesen ausgeben |
| tell_object(wielded_by, |
| (res[<1]=='\n' ? res : break_string(res,78))); |
| } |
| else |
| { |
| // Sonst eine Standard-Meldung ausgeben |
| tell_object(wielded_by, break_string( |
| "Du kannst "+name(WEN)+" nicht wegstecken.",78)); |
| } |
| return 1; |
| } |
| |
| // Ok, jetzt ist alles klar, die (Parier)Waffe wird weggesteckt |
| parry=QueryProp(P_PARRY); |
| cl=symbol_function("SetProp",wielded_by); |
| |
| if (parry<PARRY_ONLY) |
| { |
| // Eintrag als Waffe im Spieler loeschen |
| funcall(cl,P_WEAPON, 0); |
| } |
| if (parry>PARRY_NOT) |
| { |
| // Eintrag als Parierwaffe im Spieler loeschen |
| funcall(cl,P_PARRY_WEAPON, 0); |
| } |
| |
| // Im Spieler die Zeit setzen, zu der er zuletzt eine Waffe weggesteckt |
| // hat. |
| funcall(cl,P_UNWIELD_TIME,time()); |
| |
| // Meldung ausgeben, wenn silent-Flag nicht gesetzt ist |
| if (!silent) |
| { |
| doUnwieldMessage(wielded_by); |
| } |
| |
| // Die Haende, die bisher von der Waffe benutzt wurden, freigeben |
| wielded_by->FreeHands(ME); |
| SetProp(P_WIELDED, 0); |
| |
| // Waffen koennen Attribute aendern/blockieren. Also muessen diese |
| // nach dem Wegstecken aktualisiert werden |
| wielded_by->deregister_modifier(ME); |
| wielded_by->UpdateAttributes(); |
| |
| // P_TOTAL_AC/P_TOTAL_WC im Spieler aktualisieren. Da dort Attribute |
| // eingehen, kann das erst hier gemacht werden. |
| if (parry<PARRY_ONLY) |
| { |
| wielded_by->QueryProp(P_TOTAL_WC); |
| } |
| if (parry>PARRY_NOT) |
| { |
| wielded_by->QueryProp(P_TOTAL_AC); |
| } |
| |
| // Inform-Funktion aufrufen |
| InformUnwield(wielded_by, silent); |
| |
| // Fertig mit dem Wegstecken |
| return 1; |
| } |
| |
| // Die Funktion, die das "zuecken"-Kommando auswertet |
| varargs int wield(string str, int silent) |
| { |
| if ( !stringp(str) || |
| (query_verb()[0..3]=="zieh" && sscanf(str,"%s hervor",str)!=1) ) |
| { |
| return 0; |
| } |
| |
| if (!id(str)) |
| { |
| _notify_fail("Du hast sowas nicht.\n"); |
| return 0; |
| } |
| |
| return DoWield(silent); |
| } |
| |
| // Die Funktion, die das "wegstecken"-Kommando auswertet |
| int unwield(string str) |
| { int parry; |
| string dummy; |
| |
| // Erstmal die Eingabe auswerten. Ist dies wirklich ein Kommando |
| // zum Wegstecken? |
| if ( !stringp(str) || (sscanf(str,"%s weg", dummy)!=1 && |
| sscanf(str,"%s ein", dummy)!=1 && |
| sscanf(str,"%s zurueck", dummy)!=1 ) ) |
| { |
| return 0; |
| } |
| |
| str = dummy; |
| parry=QueryProp(P_PARRY); |
| |
| // Ist wirklich diese Waffe gemeint? |
| if ( !stringp(str) || !id(str) || |
| ((parry<PARRY_ONLY)&&((object)PL->QueryProp(P_WEAPON)!=ME)) || |
| ((parry>PARRY_NOT)&&((object)PL->QueryProp(P_PARRY_WEAPON)!=ME)) ) |
| { |
| return 0; |
| } |
| |
| // Man kann nur Waffen wegstecken, die man auch bei sich hat |
| if (environment() != PL) |
| { |
| _notify_fail("Diese Waffe gehoert Dir nicht!\n"); |
| return 0; |
| } |
| |
| // Und natuerlich geht das auch nur, wenn die Waffe gezueckt ist. |
| if (!QueryProp(P_WIELDED)) |
| { |
| _notify_fail("Diese Waffe hast Du gar nicht gezueckt ...\n"); |
| return 0; |
| } |
| |
| return DoUnwield(); |
| } |
| |
| // Die Funktion, die den Schaden berechnet, den die Waffe verursacht |
| int QueryDamage(object enemy) |
| { int dam; |
| mixed hit_func; |
| object wielder; |
| |
| // Nur gezueckte Waffen machen Schaden |
| if (!objectp(wielder=QueryProp(P_WIELDED))) |
| return 0; |
| |
| // Den Basis-Schaden berechnen. Die Staerke des Benutzers wird |
| // hier beruecksichtigt. |
| dam = (2*QueryProp(P_WC)+10*((int)wielder->QueryAttribute(A_STR)))/3; |
| |
| // Wie gut man getroffen hat, wird ueber ein random() simuliert |
| dam = random(1+dam); |
| |
| // Ist eine HitFunc gesetzt, dann wird diese ausgewertet. Der |
| // Rueckgabe-Wert wird zum Schaden addiert |
| if (!hit_cl || !get_type_info(hit_cl,2)) |
| { |
| if (objectp(hit_func=QueryProp(P_HIT_FUNC))) |
| { |
| hit_cl=symbol_function("HitFunc",hit_func); |
| } |
| } |
| if (hit_cl && get_type_info(hit_cl,2)) |
| { |
| dam += funcall(hit_cl,enemy); |
| } |
| |
| // Zeitpunkt der letzten Benutzung ausgeben |
| SetProp(P_LAST_USE,time()); |
| |
| // Berechneten Schaden zurueckgeben |
| return dam; |
| } |
| |
| // Die Funktion, die bei Parierwaffen den Schutzwert berechnet. |
| int QueryDefend(string* dam_type, mixed spell, object enemy) |
| { int prot; |
| mixed def_func; |
| object pl; |
| |
| prot = 0; |
| |
| // Ruestungen schuetzen nur gegen physikalischen Schaden |
| if (!spell || (mappingp(spell) && spell[SP_PHYSICAL_ATTACK])) |
| { |
| if (sizeof(filter(dam_type,PHYSICAL_DAMAGE_TYPES))) |
| { |
| prot = random(1+QueryProp(P_AC)); |
| } |
| } |
| |
| // Ist eine DefendFunc gesetzt, wird diese ausgewertet |
| if (!defend_cl || !get_type_info(defend_cl,2)) |
| { |
| if (objectp(def_func=QueryProp(P_DEFEND_FUNC))) |
| { |
| defend_cl=symbol_function("DefendFunc",def_func); |
| } |
| } |
| //Bei Netztoten keine (zurueckschlagende) DefendFunc |
| if (defend_cl && get_type_info(defend_cl,2) && |
| objectp(pl=QueryProp(P_WIELDED)) && (!query_once_interactive(pl) || |
| interactive(pl)) ) |
| { |
| // Der Rueckgabewert der DefendFunc wird zum Schutz addiert |
| prot += funcall(defend_cl, dam_type, spell, enemy); |
| } |
| |
| // Zeitpunkt der letzten Benutzung ausgeben |
| SetProp(P_LAST_USE,time()); |
| |
| // Berechneten Schutz zurueckgeben |
| return prot; |
| } |
| |
| // Die Anzahl der von einer Waffe benoetigten Haende darf natuerlich nicht |
| // kleiner als 1 sein. |
| int _set_nr_hands(int arg) |
| { |
| if (!intp(arg) || (arg<1) ) |
| return Query(P_NR_HANDS, F_VALUE); |
| return Set(P_NR_HANDS, arg, F_VALUE); |
| } |
| |
| // Der Schadenstyp einer Waffe darf zwar als string angegeben werden, wird |
| // intern aber immer als array gespeichert |
| mixed _set_dam_type(mixed arg) |
| { |
| if (pointerp(arg)) |
| { |
| return Set(P_DAM_TYPE, arg, F_VALUE); |
| } |
| else if (stringp(arg)) |
| { |
| return Set(P_DAM_TYPE, ({ arg }), F_VALUE); |
| } |
| return Query(P_DAM_TYPE, F_VALUE); |
| } |
| |
| // Objekte, die die Beschaedigung einer Waffe durch direktes Setzen von |
| // P_DAMAGED durchfuehren, werden im awmaster geloggt |
| mixed _set_item_damaged(mixed arg) |
| { |
| if (arg && !intp(arg)) |
| { |
| return Query(P_DAMAGED, F_VALUE); |
| } |
| |
| if (previous_object(1)) |
| call_other("/secure/awmaster","RegisterDamager", |
| previous_object(1),QueryProp(P_DAMAGED),arg); |
| |
| return Set(P_DAMAGED,arg,F_VALUE); |
| } |
| |
| // Wird etwas an P_HIT_FUNC geaendert, muss die zugehoerige closure |
| // erstmal geloescht werden. |
| mixed _set_hit_func(mixed arg) |
| { |
| hit_cl=0; |
| return Set(P_HIT_FUNC, arg, F_VALUE); |
| } |
| |
| // Wird etwas an P_DEFEND_FUNC geaendert, muss die zugehoerige closure |
| // erstmal geloescht werden. |
| mixed _set_defend_func(mixed arg) |
| { |
| defend_cl=0; |
| return Set(P_DEFEND_FUNC, arg, F_VALUE); |
| } |
| |
| // Die maximale Waffenklasse einer Waffe berechnet sich natuerlich aus |
| // der aktuellen Waffenklasse und der Beschaedigung. Eine Ausnahme bilden |
| // hier Waffen, deren effektive Waffenklasse groesser ist als diese Summe |
| int _query_max_wc() |
| { int a,b; |
| |
| a=QueryProp(P_WC)+QueryProp(P_DAMAGED); |
| b=QueryProp(P_EFFECTIVE_WC); |
| if (b>a) |
| return b; |
| return a; |
| } |
| |
| // Will man eine Waffe beschaedigen oder reparieren, so macht man das |
| // am besten ueber die Funktion Damage(argument). Positive Argumente |
| // bedeuten eine Beschaedigung, negative eine Reparatur. Der Rueckgabewert |
| // ist die wirklich durchgefuehrte Aenderung des Beschaedigungswertes |
| int Damage(int new_dam) |
| { int wc,old_dam; |
| object w; |
| |
| // Uebergebenes Argument pruefen |
| if (!new_dam || !intp(new_dam)) |
| { |
| return 0; |
| } |
| |
| // Bei Waffen, die nicht ausschliesslich zur Parade eingesetzt werden, |
| // geht die Beschaedigung auf die Kampfkraft, sprich: P_WC |
| if (QueryProp(P_PARRY)<PARRY_ONLY) |
| { |
| if ((wc=QueryProp(P_WC))<=MIN_WEAPON_CLASS && new_dam>0) |
| { |
| // Sonst wuerde Beschaedigung zur Reparatur fuehren |
| return 0; |
| } |
| |
| // Min-WC und Max-WC beachten |
| if ((wc-new_dam) < MIN_WEAPON_CLASS) |
| { |
| new_dam = wc-MIN_WEAPON_CLASS; |
| } |
| else if ((wc-new_dam) > MAX_WEAPON_CLASS) |
| { |
| new_dam = wc-MAX_WEAPON_CLASS; |
| } |
| |
| // Nie mehr als 100% reparieren |
| if (((old_dam=QueryProp(P_DAMAGED))<-new_dam) && new_dam<0) |
| { |
| new_dam=-old_dam; |
| } |
| |
| // Aenderungen an der Waffenklasse und der dem Beschaedigungswert |
| // durchfuehren |
| SetProp(P_WC,(wc-new_dam)); |
| // Ausnahmeweise Set, um die loggende Setmethode zu umgehen. |
| // TODO: SetProp, sobald direktes Beschaedigen raus ist. |
| Set(P_DAMAGED, old_dam+new_dam, F_VALUE); |
| |
| // P_TOTAL_WC im Traeger updaten, so vorhanden |
| if (objectp(w=QueryProp(P_WIELDED))) |
| w->QueryProp(P_TOTAL_WC); |
| |
| // Rueckgabewert: Durchgefuehrte Aenderung an P_DAMAGE |
| return new_dam; |
| } |
| |
| // Bei reinen Parierwaffen geht die Beschaedigung auf die |
| // Schutzwirkung, sprich: P_AC |
| |
| if ((wc=QueryProp(P_AC))<=0 && new_dam>0) |
| { |
| // Sonst wuerde Beschaedigung zur Reparatur fuehren |
| return 0; |
| } |
| |
| // Min-AC=0 und Max-AC beachten |
| if ((wc-new_dam) < MIN_PARRY_CLASS) |
| { |
| new_dam = wc-MIN_PARRY_CLASS; |
| } |
| else if ((wc-new_dam) > MAX_PARRY_CLASS) |
| { |
| new_dam = wc-MAX_PARRY_CLASS; |
| } |
| |
| // Nie mehr als 100% reparieren |
| if (((old_dam=QueryProp(P_DAMAGED))<-new_dam) && new_dam<0) |
| { |
| new_dam=-old_dam; |
| } |
| |
| // Aenderungen an der Ruestungsklasse und dem Beschaedigungswert |
| // durchfuehren |
| SetProp(P_AC,wc-new_dam); |
| // Ausnahmeweise Set, um die loggende Setmethode zu umgehen. |
| // TODO: SetProp, sobald direktes Beschaedigen raus ist. |
| Set(P_DAMAGED,old_dam+new_dam, F_VALUE); |
| |
| // P_TOTAL_AC im Traeger updaten, so vorhanden |
| if (objectp(w=QueryProp(P_WIELDED))) |
| w->QueryProp(P_TOTAL_AC); |
| |
| // Rueckgabewert: Durchgefuehrte Aenderung an P_DAMAGE |
| return new_dam; |
| } |
| |
| // Wird die Waffe einer Belastung ausgesetzt (z.B. wenn man damit |
| // zuschlaegt), dann wird TakeFlaw() aufgerufen. |
| varargs void TakeFlaw(object enemy) |
| { int c; |
| |
| // Flaw-Wert erhoehen |
| flaw++; |
| |
| // Ist der Waffe eine Qualitaet gesetzt worden, so kann es zu einer |
| // allmaehlichen Beschaedigung der Waffe kommen |
| if ((c=QueryProp(P_QUALITY)) && !(flaw%c)) |
| Damage(1); |
| |
| // Zeitpunkt des ersten Aufrufes festhalten |
| if (!ftime) |
| ftime=time(); |
| } |
| |
| // Die Flaw-Daten koennen natuerlich auch abgerufen werden |
| mixed *QueryFlaw() |
| { |
| return({flaw,ftime,dtime(ftime)}); |
| } |
| |