blob: a88f63063635a1db5d69e989d02b78fb7d83f638 [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001// MorgenGrauen MUDlib
2//
3// restriction_checker.c -- Beschraenkungen in Gilden, Spells und Skills
4//
5// $Id: restriction_checker.c 8754 2014-04-26 13:12:58Z Zesstra $
6#pragma strong_types
7#pragma save_types
8#pragma no_clone
9#pragma pedantic
10//#pragma range_check
11#pragma no_shadow
12
13inherit "/std/util/executer";
14
15#define NEED_PROTOTYPES
16#include <thing/properties.h>
17#include <properties.h>
18#include <new_skills.h>
19#include <wizlevels.h>
20#include <questmaster.h>
21
22#define DEBUG(x) if (find_player("zesstra")) tell_object(find_player("zesstra"),x)
23
24// erweitert um das <pl> argument und die extra-Argument, die bereits in <fun>
25// angegeben wurden. (*grummel*)
26protected mixed execute_anything(mixed fun, object pl, varargs mixed args)
27{
28 //DEBUG(sprintf("ex_any(): Fun: %O, Ob: %O, args: %O\n",fun,pl,args));
29 // wenn in fun schon extraargumente stehen, dann pl einfuegen und args
30 // dranhaengen.
31 if (pointerp(fun) && sizeof(fun) > 2)
32 {
33 // args kann ({}) sein, wenn keine Extraargumente uebergeben wurden, macht
34 // aber nix.
35 args = ({pl}) + fun[2..] + args;
36 fun = fun[0..1];
37 return ::execute_anything(fun, args...);
38 }
39 // s.o.
40 return ::execute_anything(fun, pl, args...);
41}
42
43mapping race_modifier(object pl, mapping map_ldfied) {
44 mapping rmap,help;
45
46 if (mappingp(map_ldfied) && member(map_ldfied,SM_RACE) && objectp(pl) &&
47 mappingp(rmap=map_ldfied[SM_RACE]))
48// if (mappingp(help=rmap[pl->_query_real_race()]))
49 if (mappingp(help=rmap[pl->QueryProp(P_REAL_RACE)]))
50 return map_ldfied+help;
51 else if(member(rmap,"*") && mappingp(help=rmap["*"]))
52 return map_ldfied+help;
53 return map_ldfied;
54}
55
56string
57check_restrictions(object pl, mapping restr) {
58 /* Folgende Einschraenkungen koennen geprueft werden:
59 * - Mindestwerte bei allen Attributen und Properties Level, QP, XP
60 * - bestimmte Rassen koennen ausgeschlossen werden bzw. erlaubt werden
61 * (SR_EXCLUDE_RACE ist ein Array von ausgeschlossenen Rassen,
62 * SR_INCLUDE_RACE eines mit eingeschlossenen)
63 * - SR_RACE kann ein Mapping sein, dass Rassen ein eigenes
64 * Restriction-mapping zuordnet. "*" steht fuer alle anderen Rassen.
65 */
66 closure cl,cl2;
67 string race, guild;
68
69 if (!mappingp(restr) || !sizeof(restr)) return 0; // Keine Einschraenkungen
70 if (!objectp(pl)) return "";
71 if (pl->QueryDisguise())
72 return "Zieh erst mal den Tarnhelm aus.\n";
73
74 restr=race_modifier(&pl,&restr);
75
76 cl=symbol_function("QueryProp",pl);
77 cl2=symbol_function("QueryAttribute",pl);
78
79 foreach(string to_check, mixed condition: restr)
80 {
81 switch(to_check)
82 {
83 case P_LEVEL:
84 if (funcall(cl,P_LEVEL) < condition)
85 return "Deine Stufe reicht dafuer nicht aus.\n";
86 break;
87 case P_GUILD_LEVEL:
88 if (funcall(cl,P_GUILD_LEVEL) < condition)
89 return "Deine Gildenstufe reicht dafuer nicht aus.\n";
90 break;
91 case SR_SEER: // das macht nun wahrlich nur bei interactives sinn!!!
92 if (condition && query_once_interactive(pl) && !IS_SEER(pl))
93 return "Du musst dazu erst Seher werden.\n";
94 break;
95 case P_XP:
96 if (funcall(cl,P_XP) < condition)
97 return "Du hast nicht genuegend Erfahrung dafuer.\n";
98 break;
99 case P_QP:
100 if (funcall(cl,P_QP) < condition)
101 return "Du hast nicht genuegend Aufgaben geloest.\n";
102 break;
103 case P_ALCOHOL:
104 if (funcall(cl,P_ALCOHOL) >= condition)
105 return "Du bist zu besoffen.\n";
106 break;
107 case P_DRINK:
108 if (funcall(cl,P_DRINK) >= condition)
109 return "Du hast zuviel getrunken.\n";
110 break;
111 case P_FOOD:
112 if (funcall(cl,P_FOOD) >= condition)
113 return "Du hast zuviel gegessen.\n";
114 break;
115 case P_DEAF:
116 if (funcall(cl,P_DEAF))
117 return "Du kannst nichts hoeren.\n";
118 break;
119 case P_BLIND:
120 if (funcall(cl,P_BLIND))
121 return "Du kannst nichts sehen.\n";
122 break;
123 case P_FROG:
124 if (funcall(cl,P_FROG))
125 return "Als Frosch kannst Du das leider nicht.\n";
126 break;
127 case A_INT:
128 if (funcall(cl2,A_INT) < condition)
129 return "Deine Intelligenz reicht dafuer nicht aus.\n";
130 break;
131 case A_DEX:
132 if (funcall(cl2,A_DEX) < condition)
133 return "Deine Geschicklichkeit reicht dafuer nicht aus.\n";
134 break;
135 case A_CON:
136 if (funcall(cl2,A_CON) < condition)
137 return "Deine Ausdauer reicht dafuer nicht aus.\n";
138 break;
139 case A_STR:
140 if (funcall(cl2,A_STR) < condition)
141 return "Deine Staerke reicht dafuer nicht aus.\n";
142 break;
143 case SR_BAD:
144 if (funcall(cl,P_ALIGN) < condition)
145 return "Du bist zu boese.\n";
146 break;
147 case SR_GOOD:
148 if (funcall(cl,P_ALIGN) > condition)
149 return "Du bist nicht boese genug.\n";
150 break;
151 case SR_MIN_SIZE:
152 if (funcall(cl,P_SIZE) < condition)
153 return "Du bist dafuer zu klein.\n";
154 break;
155 case SR_MAX_SIZE:
156 if (funcall(cl,P_SIZE) > condition)
157 return "Du bist dafuer zu gross.\n";
158 break;
159 case SR_FREE_HANDS:
160 if (condition > (funcall(cl,P_MAX_HANDS)-funcall(cl,P_USED_HANDS)))
161 return "Du hast nicht genug freie Haende dafuer.\n";
162 break;
163 case SR_EXCLUDE_RACE:
164 if (IS_LEARNER(pl))
165 race=funcall(cl,P_RACE);
166 else
167 race=funcall(cl,P_REAL_RACE); //race=pl->_query_real_race();
168 if ( pointerp(condition) && member(condition,race)>=0 )
169 return ("Als "+race+" kannst Du das nicht.\n");
170 break;
171 case SR_INCLUDE_RACE:
172 if (IS_LEARNER(pl))
173 race=funcall(cl,P_RACE);
174 else
175 race=funcall(cl,P_REAL_RACE); //race=pl->_query_real_race();
176 if (pointerp(condition) && member(condition,race)<0)
177 return ("Als "+race+" kannst Du das nicht.\n");
178 break;
179 case SR_EXCLUDE_GUILD:
180 guild=funcall(cl,P_GUILD);
181 if (pointerp(condition) && member(condition,guild)>=0)
182 return ("Mit Deiner Gildenzugehoerigkeit kannst Du das nicht.\n");
183 break;
184 case SR_INCLUDE_GUILD:
185 guild=funcall(cl,P_GUILD);
186 if (pointerp(condition) && member(condition,guild)<0)
187 return ("Mit Deiner Gildenzugehoerigkeit kannst Du das nicht.\n");
188 break;
189 case SR_FUN:
Bugfixcffb3222018-12-03 18:01:27 +0100190 // In aller Regel sollte die Funktion dann nicht in diesem Objekt
191 // gerufen werden, sondern in dem, was uns ruft.
192 if(stringp(condition) && extern_call())
193 {
194 condition=({previous_object(),condition});
195 }
MG Mud User88f12472016-06-24 23:31:02 +0200196 string res=execute_anything(condition, pl);
197 if (stringp(res))
198 return res;
199 break;
200 case SR_PROP:
201 foreach ( string propname, mixed value, string msg: condition ) {
202 if ( funcall(cl, propname) != value )
203 return ( stringp(msg) && sizeof(msg) ? msg :
204 "Koennte es sein, dass Du vergessen hast, etwas zu "
205 "erledigen?\n");
206 }
207 break;
208 case SR_QUEST:
209 if (pointerp(condition))
210 {
211 // geloeste Quests aus der Liste der Bedingungen entfernen
212 condition -= filter(condition, "QueryQuest", pl);
213 if ( sizeof(condition) )
214 return ("Du musst zuerst das Abenteuer '"+condition[0]+
215 "' loesen.\n");
216 }
217 break;
218 case SR_MINIQUEST:
219 if (pointerp(condition))
220 {
221 closure unsolved_MQs = function int (mixed mq_num)
222 { return !(QM)->HasMiniQuest(pl, mq_num); };
223 if ( sizeof(filter(condition, unsolved_MQs)) )
224 return "Du hast eine benoetigte Miniquest noch nicht geloest.\n";
225 // Der Name der MQ wird absichtlich nicht explizit ausgegeben.
226 }
227 break;
228 } // switch
229 } // foreach
230 return 0;
231}
232
233varargs mixed
234GetData(string dname, mapping map_ldfied, object pl) {
235 mixed dat,res;
236
237 if (!dname || !mappingp(map_ldfied)) return 0;
238 if (closurep(dat=map_ldfied[dname]) && (res=funcall(dat,pl,map_ldfied)))
239 return res;
240 return dat;
241
242}
243
244varargs int
245GetValue(string vname, mapping map_ldfied, object pl) {
246 mixed dat,res;
247
248 // printf("GetValue(%O): %O\n",vname,map_ldfied);
249 if (!vname || !map_ldfied) return 0;
250 if ((dat=map_ldfied[vname]) && (res=execute_anything(dat,pl,map_ldfied)))
251 return res;
252 // printf("Value: %O\n",dat);
253 return intp(dat) ? dat : 0;
254}
255
256varargs int
257GetFactor(string fname, mapping map_ldfied, object pl) {
258 mixed res;
259
260 // printf("GetFactor(%O):\n",fname);
261 if (!fname || !(res=GetValue(FACTOR(fname),map_ldfied,pl)))
262 return 100;
263 if (res<10) res=10;
264 else if (res>1000) res=1000;
265 // printf("Factor: %O\n",res);
266 return res;
267}
268
269varargs int
270GetOffset(string oname, mapping map_ldfied, object pl) {
271 mixed res;
272
273 // printf("GetOffset(%O):\n",oname);
274 if (!oname || !(res=GetValue(OFFSET(oname),map_ldfied,pl)))
275 return 0;
276 if (res<-10000) res=-10000;
277 else if (res>10000) res=10000;
278 // printf("Offset: %O\n",res);
279 return res;
280}
281
282varargs int
283GetFValue(string vname, mapping map_ldfied, object pl) {
284 return (GetValue(vname,map_ldfied,pl)*GetFactor(vname,map_ldfied,pl))/100;
285}
286
287varargs int
288GetValueO(string vname, mapping map_ldfied, object pl) {
289 return GetValue(vname,map_ldfied,pl)+GetOffset(vname,map_ldfied,pl);
290}
291
292varargs int
293GetFValueO(string vname, mapping map_ldfied, object pl) {
294 return ((GetValue(vname,map_ldfied,pl)*GetFactor(vname,map_ldfied,pl))/100
295 + GetOffset(vname,map_ldfied,pl));
296}
297
298varargs int
299GetRandFValueO(string vname, mapping map_ldfied, object pl) {
300 return (random(GetValue(vname,map_ldfied,pl)*GetFactor(vname,map_ldfied,pl))/100
301 + GetOffset(vname,map_ldfied,pl));
302}
303
304mapping AddSkillMappings(mapping oldmap, mapping newmap) {
305 mapping res,t1,t2;
306 mixed *inx,ind;
307 int i;
308
309 if (!mappingp(oldmap)) return newmap;
310 if (!mappingp(newmap)) return oldmap;
311 inx=({SI_SKILLRESTR_LEARN,SI_SKILLRESTR_USE,SM_RACE});
312 res=oldmap+newmap;
313 for (i=sizeof(inx);i--;) {
314 ind=inx[i];
315 t1=oldmap[ind];
316 t2=newmap[ind];
317 if (t1) {
318 if (t2)
319 res[ind]=t1+t2;
320 else
321 res[ind]=t1;
322 } else {
323 if (t2)
324 res[ind]=t2;
325 }
326 }
327 return res;
328}
329