blob: a870bd1cfedca00c28619b8b5ed084cd85a1977f [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001// MorgenGrauen MUDlib
2//
3// armour/wear.c -- armour standard object
4//
5// $Id: combat.c 6243 2007-03-15 21:10:21Z Zesstra $
6
7#pragma strict_types
8#pragma save_types
9#pragma no_clone
MG Mud User88f12472016-06-24 23:31:02 +020010#pragma range_check
11
12inherit "/std/clothing/wear";
13
14#define NEED_PROTOTYPES
15
16#include <thing/properties.h>
17#include <living/combat.h>
18#include <living/attributes.h>
19#include <language.h>
20#include <defines.h>
21#include <armour.h>
22
23// Uebernimmt viele wesentliche Eigenschaften aus der Kleidung, daher werden
24// hier auch nur div. Funktionen ueberschrieben, die sich leicht
25// unterschiedlich zur Kleidung verhalten.
26
27// Globale Variablen
28private nosave int logged;
29
30protected void create() {
31 ::create();
32 // P_DAMAGED laesst sich zwar (noch) von aussen setzen, aber bitte nur ueber
33 // die hier definierte Setmethode.
34 // TODO: Direktes Setzen von P_DAMAGED entfernen.
35 Set(P_DAMAGED, PROTECTED, F_MODE_AS);
36}
37
38/* Wenn eine Ruestung vom gleichen Typ im Array ist, gebe diese zurueck. */
39private object TestType(object *armours) {
40 mixed type;
41
42 // Den eigenen Typ feststellen
43 type = QueryProp(P_ARMOUR_TYPE);
44
45 // Zerstoerte Objekte aussortieren
46 armours-=({0});
47
48 foreach(object armour: armours)
49 {
50 if (type==(armour->QueryProp(P_ARMOUR_TYPE)))
51 {
52 // Ruestung vom gleichen Typ gefunden -> zurueckgeben
53 return armour;
54 }
55 }
56 // Keine Ruestung vom gleichen Typ gefunden, also 0 zurueckgeben
57 return 0;
58}
59
60// liefert 1 zurueck, wenn der Spieler die ruestung anziehen darf, 0 sonst.
61protected int _check_wear_restrictions(int silent, int all) {
62 mixed type,res;
63 object *armours;
64
65 type = QueryProp(P_ARMOUR_TYPE);
66
67 // Das DoWear() der Kleidung prueft auf genuegend freie Haende,
68 // prueft aber den Fall nicht ab, ob man hier ein Schild hat, was laut Prop
69 // weniger als eine Hand belegt. Daher hier nachholen und korrigieren. Und
70 // direkt mal loggen, damit das gefixt wird.
71 if ( (type==AT_SHIELD) && QueryProp(P_NR_HANDS)<1 ) {
72 SetProp(P_NR_HANDS,1);
73 log_file("INVALID_SHIELD",
74 sprintf("Fixme: AT_SHIELD item without valid P_NR_HANDS: %O\n",
75 object_name()));
76 }
77
78 armours=(object*)PL->QueryProp(P_ARMOURS) - ({0});
79
80 // Von jedem Ruestungstyp ausser AT_MISC kann man immer nur ein
81 // Teil tragen
82 if ( (type!=AT_MISC) && (res=TestType(armours)) && objectp(res)) {
83 msg(break_string(sprintf(
84 "Du traegst bereits %s als Schutz der Sorte %s.",
85 res->name(WEN,1), type),78,
86 (all?(Name(WER)+": "):0)), all);
87 return(-1);
88 }
89
90 // Ruestungen vom Typ AT_ILLEGAL oder solche mit einem fuer ihren
91 // Ruestungstyp zu hohen Schutzwert koennen nicht angezogen werden
92 if ( (type==AT_ILLEGAL) || (QueryProp(P_AC)>VALID_ARMOUR_CLASS[type])) {
93 write("Ungueltiger Ruestungstyp, bitte Erzmagier verstaendigen.\n");
94 "/p/daemon/ruestungen"->RegisterArmour();
95 return(-2);
96 }
97
98 // Ruestungen, die ein oder mehrere Attribut veraendern und gegen
99 // das gesetzte Limit verstossen, haben keine Wirkung bezueglich der
100 // Attribute. Dies gibt aber nur ne Meldung aus, angezogen werden darf sie
101 // trotzdem.
102 if (mappingp(res=QueryProp(P_M_ATTR_MOD)) && PL->TestLimitViolation(res) ) {
103 write(break_string(sprintf(
104 "Irgendetwas an Deiner Ausruestung verhindert, dass Du Dich mit "
105 "%s so richtig wohl fuehlst.",name(WEM,1)),78,
106 (all?(Name(WER)+": "):0)));
107 }
108
109 // dann mal aus der Kleidung geerbte Pruefungen ausfuehren und Ergebnis
110 // liefern.
111 return ::_check_wear_restrictions(silent,all);
112}
113
114protected void _informwear(int silent, int all) {
115
116 // Ruestungen koennen Resistenzen beeinflussen
117 PL->AddResistanceModifier(QueryProp(P_RESISTANCE_STRENGTHS),
118 QueryProp(P_ARMOUR_TYPE));
119
120 // Ruestungen koennen Attribute aendern/blockieren. Also muessen diese
121 // nach dem Anziehen aktualisiert werden
122 PL->register_modifier(ME);
123 PL->UpdateAttributes();
124
125 // P_TOTAL_AC im Traeger updaten (fuer Query()s)
126 PL->QueryProp(P_TOTAL_AC);
127
128 // Alle Ruestungen werden im awmaster registriert, sobald sie von
129 // einem Spieler gezueckt werden
130 if (!logged && query_once_interactive(PL)) {
131 call_other("/secure/awmaster","RegisterArmour",ME);
132 logged=1;
133 }
134 // noch das aus der Kleidung rufen, damit die Anziehmeldungen auch kommen.
135 // ausserdem laeuft das Anstosses von InformWear() von dort.
136 ::_informwear(silent,all);
137}
138
139
140protected int _check_unwear_restrictions(object worn_by, int silent,
141 int all) {
142 // liefert >=0 zureck, wenn die Kleidung/Ruestung ausgezogen werden kann,
143 // <0 sonst.
144
145 // Schilde belegen (mindestens) eine Hand. Hngl. Wenn man diesen bloeden
146 // Check nicht machen muesste, koennte man sich die ganze Funktion sparen.
147 // Hmpfgrmpfl. Achja, raise_error(), weil das eigentlich ja nicht vorkommen
148 // sollte und gefixt werden soll. Das geht naemlich nur, wenn jemand diese
149 // Prop geaendert, waehrend der Spieler das Schild getragen hatte.
150 if ( (QueryProp(P_ARMOUR_TYPE)==AT_SHIELD) &&
151 QueryProp(P_NR_HANDS)<1 ) {
152 raise_error(sprintf("Fixme: AT_SHIELD beim Ausziehen ohne P_NR_HANDS: %O",
153 object_name()));
154 }
155
156 // Ausziehcheck der Kleidung machen
157 return ::_check_unwear_restrictions(worn_by,silent,all);
158}
159
160protected void _informunwear(object worn_by, int silent, int all) {
161 mixed res;
162 // Gesetzte Resistenzen loeschen
163 worn_by->RemoveResistanceModifier(res=QueryProp(P_ARMOUR_TYPE));
164
165 // Ruestungen koennen Attribute aendern/blockieren. Also muessen diese
166 // nach dem Ausziehen aktualisiert werden
167 worn_by->deregister_modifiers(ME);
168 worn_by->UpdateAttributes();
169
170 // P_TOTAL_AC im Traeger updaten
171 worn_by->QueryProp(P_TOTAL_AC);
172
173 // die geerbte Funktion aus der Kleindung gibt noch meldungen aus und ruft
174 // Informunwear().
175 ::_informunwear(worn_by,silent,all);
176}
177
178// Funktion, die das "trage"/"ziehe * an"-Kommando auswertet
179varargs int do_wear(string str, int silent) {
180 int all;
181
182 // Hat der Spieler "trage alles" eingegeben?
183 all=(str=="alles" || str=="alle ruestungen");
184
185 return(_do_wear(str,silent,all));
186}
187
188// Die Funktion, die das "ziehe * aus"-Kommando auswertet
189varargs int do_unwear(string str, int silent) {
190 int all;
191
192 all=(str=="alles" || str=="alle ruestungen");
193 return(_do_unwear(str,silent,all));
194}
195
196
197// Objekte, die die Beschaedigung einer Ruestung durch direktes Setzen von
198// P_DAMAGED durchfuehren, werden im awmaster geloggt
199static mixed _set_item_damaged(mixed arg) {
200 if (arg && !intp(arg))
201 {
202 return Query(P_DAMAGED, F_VALUE);
203 }
204
205 if (previous_object(1))
206 call_other("/secure/awmaster","RegisterDamager",
207 previous_object(1),QueryProp(P_DAMAGED),arg);
208
209 return Set(P_DAMAGED, arg, F_VALUE);
210}
211
212// Will man eine Ruestung beschaedigen oder reparieren, so macht man das
213// am besten ueber die Funktion Damage(argument). Positive Argumente
214// bedeuten eine Beschaedigung, negative eine Reparatur. Der Rueckgabewert
215// ist die wirklich durchgefuehrte Aenderung des Beschaedigungswertes
216int Damage(int new_dam) {
217 int ac,maximum,old_dam;
218 object w;
219
220 if (!new_dam || !intp(new_dam)) {
221 return 0;
222 }
223
224 if ( (ac=QueryProp(P_AC))<=0 && (new_dam>0) ) {
225 // Sonst wuerde Beschaedigung zur Reparatur fuehren
226 return 0;
227 }
228
229 // Min-AC und MAX_AC beachten
230 if ((ac-new_dam) < MIN_ARMOUR_CLASS) {
231 new_dam = ac-MIN_ARMOUR_CLASS;
232 }
233 else if ((ac-new_dam) >
234 (maximum=VALID_ARMOUR_CLASS[QueryProp(P_ARMOUR_TYPE)])) {
235 new_dam = ac-maximum;
236 }
237
238 // Nie mehr als 100% reparieren
239 if ( ((old_dam=QueryProp(P_DAMAGED))<-new_dam) && (new_dam<0) ) {
240 new_dam=-old_dam;
241 }
242
243 // Aenderungen an der Ruestungsklasse und dem Beschaedigungswert
244 // durchfuehren
245 SetProp(P_AC,(ac-new_dam));
246 // eigene Set-Methode umgehen
247 Set(P_DAMAGED,(old_dam+new_dam),F_VALUE);
248
249 // P_TOTAL_AC im Traeger updaten, wenn vorhanden
250 if (objectp(w=QueryProp(P_WORN)))
251 w->QueryProp(P_TOTAL_AC);
252
253 // Rueckgabewert: Durchgefuehrte Aenderung an P_DAMAGE
254 return new_dam;
255}
256
257public status IsArmour() {return 1;}
258public status IsClothing() {return 0;}
259