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