blob: 1c6802130ae626bd6e7b263ab4e4dad16718d2b9 [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
Zesstra9033eee2021-05-06 19:57:20 +020058 // Um Rundungsverluste zu reduzieren, wird P_AC anfangs mit 10000
59 // skaliert. Beim runterskalieren wird aufgerundet (Addition von
60 // 5000 vor Division).
61 int pac = QueryProp(P_AC) * 10000;
MG Mud User88f12472016-06-24 23:31:02 +020062 if (pac > 0)
Zesstra9033eee2021-05-06 19:57:20 +020063 prot = ((pac/4 + random(pac*3/4 + 1) + 5000)/10000) || 1;
MG Mud User88f12472016-06-24 23:31:02 +020064 object stat = find_object("/d/erzmagier/zesstra/pacstat");
65 if (stat)
bugfixd94d0932020-04-08 11:27:13 +020066 ({string})stat->acstat(QueryProp(P_ARMOUR_TYPE),prot,
MG Mud User88f12472016-06-24 23:31:02 +020067 random(pac)+1);
68
69 // ruestungschutz an defendfunc weitermelden
70 if (mappingp(spell) &&
71 mappingp(einfo=spell[EINFO_DEFEND])) {
72 // Schutz d. akt. Ruestung vermerken.
73 einfo[DEFEND_CUR_ARMOUR_PROT]=prot;
74 // daten der Ruestung vermerken.
75 if (mappingp(einfo[DEFEND_ARMOURS])) {
76 einfo[DEFEND_ARMOURS][ME,DEF_ARMOUR_PROT]=prot;
77 }
78 } // ende vom if (mapping(spell) ...)
79 } // ende vom if (phys Schaden)
80
81 } // ende vom else (wenn kein AT_MISC)
82
83 // Ist eine DefendFunc gesetzt, wird diese ausgewertet
84 if (closurep(defend_cl)) {
85 if (!objectp(get_type_info(defend_cl,2))) {
86 // Closure gesetzt, aber nicht gueltig, schauen, ob wir sie neu
87 // erstellen koennen.
88 if (objectp(def_func=QueryProp(P_DEFEND_FUNC))) {
89 defend_cl=symbol_function("DefendFunc",def_func);
90 }
91 // sonst loeschen, um spaeter diesen Zweig ganz zu sparen.
92 else defend_cl=0;
93 }
94 // BTW: Es ist ok, wenn defend_cl jetzt 0 ist, dann liefert funcall()
95 // auch 0.
96 // Bei Netztoten keine (zurueckschlagende) DefendFunc
97 if (objectp(pl=QueryProp(P_WORN)) && (!query_once_interactive(pl) ||
98 interactive(pl)) ) {
99 // Der Rueckgabewert der DefendFunc wird zum Schutz addiert
100 prot += funcall(defend_cl, dam_type, spell, enemy);
101 // leider kann die DefendFunc jetzt auch noch das Objekt zerstoert
102 // haben...
103 if (!objectp(this_object()))
104 return prot;
105 }
106 }
107
108 // Zeitpunkt der letzten Benutzung ausgeben
109 SetProp(P_LAST_USE,time());
110
111 // Berechneten Schutz zurueckgeben
112 return prot;
113}
114
115// Es duerfen nur "legale" Ruestungstypen gesetzt werden, ansonsten
116// wird AT_ILLEGAL gesetzt.
117static mixed _set_armour_type(mixed type ) {
bugfixd94d0932020-04-08 11:27:13 +0200118 if (!({int})COMBAT_MASTER->valid_armour_type(type))
MG Mud User88f12472016-06-24 23:31:02 +0200119 {
120 Set(P_ARMOUR_TYPE, (type=AT_ILLEGAL), F_VALUE);
121 }
122 else
123 {
124 Set(P_ARMOUR_TYPE, type);
125 }
126 AddId(type);
127
128 resistance_strengths=([]);
129 return type;
130}
131
132
133// Wird etwas an P_DEFEND_FUNC geaendert, muss die zugehoerige closure
134// neu erstellt werden.
135static object _set_defend_func(object arg) {
136 if (objectp(arg) &&
137 closurep(defend_cl=symbol_function("DefendFunc",arg))) {
138 return Set(P_DEFEND_FUNC, arg, F_VALUE);
139 }
140 defend_cl=0;
141 return(Set(P_DEFEND_FUNC, 0, F_VALUE));
142}
143
144// Auch Ruestungen koennen einen Schadenstyp haben. Dieser kann als string
145// oder array angegeben werden, wird aber intern auf jeden Fall als
146// array gespeichert.
147static mixed _set_dam_type(mixed arg) {
148 if (pointerp(arg))
149 {
150 return Set(P_DAM_TYPE, arg, F_VALUE);
151 }
152 else if (stringp(arg))
153 {
154 return Set(P_DAM_TYPE, ({ arg }), F_VALUE);
155 }
156 return Query(P_DAM_TYPE, F_VALUE);
157}
158
159// Ruestungen koennen Resistenzen setzen. Diese werden jedoch nicht wie
160// "normale" Resistenzen gesetzt, sondern als Prozentwerte der fuer diesen
161// Typ maximal zulaesigen Resistenz. Die Aenderung der Resistenzen darf
162// nur durch die Ruestung selbst erfolgen.
163// Beispiel: ([DT_FIRE: 100, DT_WATER: -150])
164// max. Feuerresistenz, 1.5fache Anfaelligkeit
165static mixed _set_resistance_strengths(mixed resmap) {
166 float max_res;
167 object worn_by;
168
169 // Es duerfen nur mappings angegeben werden
170 if (!mappingp(resmap))
171 {
172 return -1;
173 }
174
175 // die Maxwerte muessen jeweils durch -100 geteilt sein, da hinterher
176 // mit der Prozentzahl multipliziert wird und die angabe der Vorzeichen
177 // hier umgekehrt wie bei den "normalen" Resistenzen ist. Der
178 // Maximalwert ist vom Ruestungstyp abhaengig.
179 switch (QueryProp(P_ARMOUR_TYPE))
180 {
181 case AT_CLOAK :
182 case AT_RING :
183 case AT_AMULET : max_res=-0.0010;
184 break;
185 case AT_SHIELD :
186 case AT_ARMOUR : max_res=-0.0015;
187 break;
188 default : max_res=-0.0005;
189 }
190
191 // Resistenz-Mapping aktualisieren
192 resistance_strengths=([]);
193 foreach(string damtype, int res: resmap)
194 {
195 if (!intp(res)) res=to_int(res);
196 // Mehr als 100 Prozent ist nicht erlaubt
197 if (res>100)
198 {
199 res=100;
200 }
201 else if (res<0)
202 {
203 res=(res/4)*5;
204 // Man kann auch nicht beliebig negativ werden
205 if (res<-1000)
206 {
207 res=-1000;
208 }
209 }
210 // Der Resistenzwert berechnet sich aus dem Produkt des
211 // Maximalwertes und der Prozentzahl
212 resistance_strengths[damtype]=res*max_res;
213 }
214
215 // Werden die Resistenzen bei einer getragenen Ruestung geaendert,
216 // muss der Traeger davon natuerlich beeinflusst werden.
217 if (objectp(worn_by=QueryProp(P_WORN)))
218 {
bugfixd94d0932020-04-08 11:27:13 +0200219 ({int})worn_by->AddResistanceModifier(resistance_strengths,
MG Mud User88f12472016-06-24 23:31:02 +0200220 QueryProp(P_ARMOUR_TYPE));
221 }
222 return resistance_strengths;
223}
224
225// Bei einem QueryProp(P_RESISTANCE_STRENGTHS) soll das aktuelle
226// Resistenzen-Mapping zurueckgegeben werden
227static mapping _query_resistance_strengths() {
228 return (resistance_strengths||([]));
229}
230