blob: e6881318a968d463718a7e0634ea900e9bb50a1d [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001// MorgenGrauen MUDlib
2//
3// armour/combat.c -- armour standard object
4//
5// $Id: combat.c 9092 2015-01-19 23:57:50Z Zesstra $
6
7#pragma strict_types
8#pragma save_types
9#pragma no_clone
10#pragma pedantic
11#pragma range_check
12
13#define NEED_PROTOTYPES
14
15#include <thing/properties.h>
16#include <thing/commands.h>
17#include <thing/description.h>
18#include <config.h>
19#include <combat.h>
20#include <language.h>
21#include <defines.h>
22#include <new_skills.h>
23
24
25// Globale Variablen
26private nosave closure defend_cl;
27private nosave mapping resistance_strengths=([]);
28
29void create() {
30 // Einige Grundwerte setzen
31 Set(P_ARMOUR_TYPE, AT_ILLEGAL, F_VALUE);
32 Set(P_LAST_USE,time(),F_VALUE);
33}
34
35// Die Funktion, die den Schutzwert berechnet, den die Ruestung bietet
36int QueryDefend(string|string* dam_type, int|mapping spell, object enemy)
37{
38 int prot;
39 mixed def_func;
40 object pl;
41 // Zum Cachen von spell[EINFO_DEFEND], haeufiges Lookup aus dem Mapping
42 // koennte unnoetig Zeit kosten.
43 mapping einfo;
44
45 // AT_MISC-Ruetungen schuetzen normalerweise gar nicht...
46 if (QueryProp(P_ARMOUR_TYPE)==AT_MISC) {
47 // es sei denn, sie haben eine spezielle DefendFunc
48 if (!closurep(defend_cl)) return(0);
49 }
50 else {
51 // ansonsten Ruestungsschutz ermitteln und in EINFO_DEFEND vermerken.
52 // (Beides fuer AT_MISC in jedem Fall unnoetig)
53
54 // Ruestungen schuetzen nur gegen physikalischen Schaden
55 if ((!spell || (mappingp(spell) && spell[SP_PHYSICAL_ATTACK]))
56 && sizeof(filter(dam_type,PHYSICAL_DAMAGE_TYPES)))
57 {
58 // Schutz bestimmen, Minimum 1, aber nur wenn P_AC > 0
59 int pac = QueryProp(P_AC);
60 if (pac > 0)
61 prot = (pac/4 + random(pac*3/4 + 1)) || 1 ;
62 object stat = find_object("/d/erzmagier/zesstra/pacstat");
63 if (stat)
64 stat->acstat(QueryProp(P_ARMOUR_TYPE),prot,
65 random(pac)+1);
66
67 // ruestungschutz an defendfunc weitermelden
68 if (mappingp(spell) &&
69 mappingp(einfo=spell[EINFO_DEFEND])) {
70 // Schutz d. akt. Ruestung vermerken.
71 einfo[DEFEND_CUR_ARMOUR_PROT]=prot;
72 // daten der Ruestung vermerken.
73 if (mappingp(einfo[DEFEND_ARMOURS])) {
74 einfo[DEFEND_ARMOURS][ME,DEF_ARMOUR_PROT]=prot;
75 }
76 } // ende vom if (mapping(spell) ...)
77 } // ende vom if (phys Schaden)
78
79 } // ende vom else (wenn kein AT_MISC)
80
81 // Ist eine DefendFunc gesetzt, wird diese ausgewertet
82 if (closurep(defend_cl)) {
83 if (!objectp(get_type_info(defend_cl,2))) {
84 // Closure gesetzt, aber nicht gueltig, schauen, ob wir sie neu
85 // erstellen koennen.
86 if (objectp(def_func=QueryProp(P_DEFEND_FUNC))) {
87 defend_cl=symbol_function("DefendFunc",def_func);
88 }
89 // sonst loeschen, um spaeter diesen Zweig ganz zu sparen.
90 else defend_cl=0;
91 }
92 // BTW: Es ist ok, wenn defend_cl jetzt 0 ist, dann liefert funcall()
93 // auch 0.
94 // Bei Netztoten keine (zurueckschlagende) DefendFunc
95 if (objectp(pl=QueryProp(P_WORN)) && (!query_once_interactive(pl) ||
96 interactive(pl)) ) {
97 // Der Rueckgabewert der DefendFunc wird zum Schutz addiert
98 prot += funcall(defend_cl, dam_type, spell, enemy);
99 // leider kann die DefendFunc jetzt auch noch das Objekt zerstoert
100 // haben...
101 if (!objectp(this_object()))
102 return prot;
103 }
104 }
105
106 // Zeitpunkt der letzten Benutzung ausgeben
107 SetProp(P_LAST_USE,time());
108
109 // Berechneten Schutz zurueckgeben
110 return prot;
111}
112
113// Es duerfen nur "legale" Ruestungstypen gesetzt werden, ansonsten
114// wird AT_ILLEGAL gesetzt.
115static mixed _set_armour_type(mixed type ) {
116 if (!COMBAT_MASTER->valid_armour_type(type))
117 {
118 Set(P_ARMOUR_TYPE, (type=AT_ILLEGAL), F_VALUE);
119 }
120 else
121 {
122 Set(P_ARMOUR_TYPE, type);
123 }
124 AddId(type);
125
126 resistance_strengths=([]);
127 return type;
128}
129
130
131// Wird etwas an P_DEFEND_FUNC geaendert, muss die zugehoerige closure
132// neu erstellt werden.
133static object _set_defend_func(object arg) {
134 if (objectp(arg) &&
135 closurep(defend_cl=symbol_function("DefendFunc",arg))) {
136 return Set(P_DEFEND_FUNC, arg, F_VALUE);
137 }
138 defend_cl=0;
139 return(Set(P_DEFEND_FUNC, 0, F_VALUE));
140}
141
142// Auch Ruestungen koennen einen Schadenstyp haben. Dieser kann als string
143// oder array angegeben werden, wird aber intern auf jeden Fall als
144// array gespeichert.
145static mixed _set_dam_type(mixed arg) {
146 if (pointerp(arg))
147 {
148 return Set(P_DAM_TYPE, arg, F_VALUE);
149 }
150 else if (stringp(arg))
151 {
152 return Set(P_DAM_TYPE, ({ arg }), F_VALUE);
153 }
154 return Query(P_DAM_TYPE, F_VALUE);
155}
156
157// Ruestungen koennen Resistenzen setzen. Diese werden jedoch nicht wie
158// "normale" Resistenzen gesetzt, sondern als Prozentwerte der fuer diesen
159// Typ maximal zulaesigen Resistenz. Die Aenderung der Resistenzen darf
160// nur durch die Ruestung selbst erfolgen.
161// Beispiel: ([DT_FIRE: 100, DT_WATER: -150])
162// max. Feuerresistenz, 1.5fache Anfaelligkeit
163static mixed _set_resistance_strengths(mixed resmap) {
164 float max_res;
165 object worn_by;
166
167 // Es duerfen nur mappings angegeben werden
168 if (!mappingp(resmap))
169 {
170 return -1;
171 }
172
173 // die Maxwerte muessen jeweils durch -100 geteilt sein, da hinterher
174 // mit der Prozentzahl multipliziert wird und die angabe der Vorzeichen
175 // hier umgekehrt wie bei den "normalen" Resistenzen ist. Der
176 // Maximalwert ist vom Ruestungstyp abhaengig.
177 switch (QueryProp(P_ARMOUR_TYPE))
178 {
179 case AT_CLOAK :
180 case AT_RING :
181 case AT_AMULET : max_res=-0.0010;
182 break;
183 case AT_SHIELD :
184 case AT_ARMOUR : max_res=-0.0015;
185 break;
186 default : max_res=-0.0005;
187 }
188
189 // Resistenz-Mapping aktualisieren
190 resistance_strengths=([]);
191 foreach(string damtype, int res: resmap)
192 {
193 if (!intp(res)) res=to_int(res);
194 // Mehr als 100 Prozent ist nicht erlaubt
195 if (res>100)
196 {
197 res=100;
198 }
199 else if (res<0)
200 {
201 res=(res/4)*5;
202 // Man kann auch nicht beliebig negativ werden
203 if (res<-1000)
204 {
205 res=-1000;
206 }
207 }
208 // Der Resistenzwert berechnet sich aus dem Produkt des
209 // Maximalwertes und der Prozentzahl
210 resistance_strengths[damtype]=res*max_res;
211 }
212
213 // Werden die Resistenzen bei einer getragenen Ruestung geaendert,
214 // muss der Traeger davon natuerlich beeinflusst werden.
215 if (objectp(worn_by=QueryProp(P_WORN)))
216 {
217 worn_by->AddResistanceModifier(resistance_strengths,
218 QueryProp(P_ARMOUR_TYPE));
219 }
220 return resistance_strengths;
221}
222
223// Bei einem QueryProp(P_RESISTANCE_STRENGTHS) soll das aktuelle
224// Resistenzen-Mapping zurueckgegeben werden
225static mapping _query_resistance_strengths() {
226 return (resistance_strengths||([]));
227}
228