MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 1 | // 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 User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 9 | //#pragma range_check |
| 10 | #pragma no_shadow |
| 11 | |
| 12 | inherit "/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*) |
| 25 | protected 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 | |
| 42 | mapping 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 | |
| 55 | string |
| 56 | check_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: |
Bugfix | cffb322 | 2018-12-03 18:01:27 +0100 | [diff] [blame] | 189 | // 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 User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 195 | 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 | |
| 232 | varargs mixed |
| 233 | GetData(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 | |
| 243 | varargs int |
| 244 | GetValue(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 | |
| 255 | varargs int |
| 256 | GetFactor(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 | |
| 268 | varargs int |
| 269 | GetOffset(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 | |
| 281 | varargs int |
| 282 | GetFValue(string vname, mapping map_ldfied, object pl) { |
| 283 | return (GetValue(vname,map_ldfied,pl)*GetFactor(vname,map_ldfied,pl))/100; |
| 284 | } |
| 285 | |
| 286 | varargs int |
| 287 | GetValueO(string vname, mapping map_ldfied, object pl) { |
| 288 | return GetValue(vname,map_ldfied,pl)+GetOffset(vname,map_ldfied,pl); |
| 289 | } |
| 290 | |
| 291 | varargs int |
| 292 | GetFValueO(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 | |
| 297 | varargs int |
| 298 | GetRandFValueO(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 | |
| 303 | mapping 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 | |