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