MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame^] | 1 | // MorgenGrauen MUDlib |
| 2 | // |
| 3 | // gilden_ob.c -- Basisfunktionen einer Gilde |
| 4 | // |
| 5 | // $Id: gilden_ob.c 8433 2013-02-24 13:47:59Z Zesstra $ |
| 6 | #pragma strict_types |
| 7 | #pragma save_types |
| 8 | #pragma no_shadow |
| 9 | #pragma no_clone |
| 10 | #pragma range_check |
| 11 | #pragma pedantic |
| 12 | |
| 13 | inherit "/std/restriction_checker"; |
| 14 | #include <properties.h> |
| 15 | #include <attributes.h> |
| 16 | #include <new_skills.h> |
| 17 | #include <defines.h> |
| 18 | #include <player/fao.h> |
| 19 | #include <wizlevels.h> |
| 20 | |
| 21 | void create() { |
| 22 | // P_GUILD_SKILLS sollte nicht direkt von aussen manipuliert werden... |
| 23 | SetProp(P_GUILD_SKILLS,([])); |
| 24 | Set(P_GUILD_SKILLS,PROTECTED,F_MODE_AS); |
| 25 | } |
| 26 | |
| 27 | mapping _query_guild_skills() { |
| 28 | // eine Kopie zurueckliefern, um versehentliche Aenderungen des |
| 29 | // Originalmappings in der Gilde zu vermeiden. |
| 30 | // Darf nicht ohne weiteres entfernt werden, da es hier im File Code gibt, |
| 31 | // der sich auf die Kopie verlaesst. |
| 32 | return(deep_copy(Query(P_GUILD_SKILLS))); |
| 33 | } |
| 34 | |
| 35 | string GuildName() { |
| 36 | //Gilden muessen Blueprints sein, so. ;-) |
| 37 | return object_name(this_object())[8..]; |
| 38 | } |
| 39 | |
| 40 | varargs int |
| 41 | IsGuildMember(object pl) { |
| 42 | string plg; |
| 43 | |
| 44 | if (!pl && !(pl=this_player())) |
| 45 | return 0; |
| 46 | if (!(plg=(string)pl->QueryProp(P_GUILD))) |
| 47 | return 0; |
| 48 | if (GuildName()!=plg) { |
| 49 | _notify_fail("Du gehoerst dieser Gilde nicht an!\n"); |
| 50 | return 0; |
| 51 | } |
| 52 | return 1; |
| 53 | } |
| 54 | |
| 55 | int check_cond(mixed cond) { |
| 56 | string res; |
| 57 | |
| 58 | if (intp(cond)) { |
| 59 | _notify_fail("Dir fehlt noch die noetige Erfahrung. "+ |
| 60 | "Komm spaeter wieder.\n"); |
| 61 | return (this_player()->QueryProp(P_XP)>=cond); |
| 62 | } |
| 63 | if (mappingp(cond)) { |
| 64 | res=check_restrictions(this_player(),cond); |
| 65 | if (!stringp(res)) return 1; |
| 66 | _notify_fail(res); |
| 67 | return 0; |
| 68 | } |
| 69 | return 1; |
| 70 | } |
| 71 | |
| 72 | int can_advance() { |
| 73 | int lv; |
| 74 | mapping lvs; |
| 75 | |
| 76 | if (!(lv=(int)this_player()->QueryProp(P_GUILD_LEVEL))) return 1; |
| 77 | if (!(lvs=QueryProp(P_GUILD_LEVELS))) return 0; |
| 78 | return check_cond(lvs[lv+1]); // Bedingung fuer naechsten Level testen. |
| 79 | } |
| 80 | |
| 81 | void adjust_title(object pl) { |
| 82 | int lv; |
| 83 | mixed ti; |
| 84 | |
| 85 | |
| 86 | if (!pl || |
| 87 | !(lv=(int)pl->QueryProp(P_GUILD_LEVEL))) |
| 88 | return; |
| 89 | switch((int)pl->QueryProp(P_GENDER)) { |
| 90 | case MALE: |
| 91 | ti=QueryProp(P_GUILD_MALE_TITLES); |
| 92 | break; |
| 93 | case FEMALE: |
| 94 | ti=QueryProp(P_GUILD_FEMALE_TITLES); |
| 95 | break; |
| 96 | default: |
| 97 | return; |
| 98 | } |
| 99 | if (mappingp(ti)) |
| 100 | ti=ti[lv]; |
| 101 | if (stringp(ti)) |
| 102 | pl->SetProp(P_GUILD_TITLE,ti); |
| 103 | |
| 104 | // Spielertitel nullen, damit der Gildentitel angezeigt wird. |
| 105 | if (!IS_SEER(pl) && !FAO_HAS_TITLE_GIFT(pl)) |
| 106 | pl->SetProp(P_TITLE,0); |
| 107 | } |
| 108 | |
| 109 | void do_advance() { |
| 110 | int lv; |
| 111 | |
| 112 | lv=this_player()->QueryProp(P_GUILD_LEVEL)+1; |
| 113 | if (lv<1) lv=1; |
| 114 | this_player()->SetProp(P_GUILD_LEVEL,lv); |
| 115 | adjust_title(this_player()); |
| 116 | } |
| 117 | |
| 118 | int try_advance() { |
| 119 | if (can_advance()) { |
| 120 | if (IsGuildMember(this_player())) |
| 121 | do_advance(); |
| 122 | return 1; |
| 123 | } |
| 124 | return 0; |
| 125 | } |
| 126 | |
| 127 | int beitreten() { |
| 128 | string res; |
| 129 | int erg; |
| 130 | |
| 131 | if (res=check_restrictions(this_player(),QueryProp(P_GUILD_RESTRICTIONS))) { |
| 132 | // Werden die Beitrittsbedingungen erfuellt? |
| 133 | printf("Du kannst dieser Gilde nicht beitreten.\nGrund: %s",res); |
| 134 | return -3; |
| 135 | } |
| 136 | if (erg=(int)GUILDMASTER->beitreten()) { |
| 137 | if (erg<0) |
| 138 | return erg; |
| 139 | if (!(this_player()->QueryProp(P_GUILD_LEVEL))) |
| 140 | try_advance(); // Level 1 wird sofort vergeben |
| 141 | return 1; |
| 142 | } |
| 143 | return 0; |
| 144 | } |
| 145 | |
| 146 | varargs int austreten(int loss) { |
| 147 | return (int)GUILDMASTER->austreten(loss); |
| 148 | } |
| 149 | |
| 150 | int bei_oder_aus_treten(string str) { |
| 151 | if (!str) return 0; |
| 152 | if (sizeof(regexp(({lower_case(str)}), |
| 153 | "\\<aus\\>.*gilde\\>.*\\<aus\\>"))) |
| 154 | return austreten(); |
| 155 | if (sizeof(regexp(({lower_case(str)}), |
| 156 | "(gilde\\>.*\\<bei\\>|\\<in\\>.*gilde\\>.*\\<ein\\>)"))) |
| 157 | return beitreten(); |
| 158 | return 0; |
| 159 | } |
| 160 | |
| 161 | varargs int |
| 162 | AddSkill(string sname, mapping ski) { |
| 163 | mapping skills; |
| 164 | |
| 165 | if (!sname) |
| 166 | return 0; |
| 167 | |
| 168 | // per Query() abfragen, hier ist keine Kopie noetig. |
| 169 | if (!mappingp(skills=Query(P_GUILD_SKILLS))) { |
| 170 | skills=([]); |
| 171 | SetProp(P_GUILD_SKILLS,skills); |
| 172 | } |
| 173 | |
| 174 | if (!mappingp(ski)) |
| 175 | ski=([]); |
| 176 | else |
| 177 | //Zur Sicherheit Kopie erstellen, wer weiss, was der Eintragende noch |
| 178 | //mit seinem Mapping macht... |
| 179 | ski=deep_copy(ski); |
| 180 | |
| 181 | if (!stringp(ski[SI_SKILLFUNC])) |
| 182 | // Wenn keine Funktion angegeben ist, Funktionsname=Skillname |
| 183 | ski[SI_SKILLFUNC]=sname; |
| 184 | |
| 185 | // Gilden-Offsets addieren |
| 186 | ski=AddSkillMappings(QueryProp(P_GLOBAL_SKILLPROPS),ski); |
| 187 | |
| 188 | // Skill setzen. |
| 189 | skills[sname]=ski; |
| 190 | //SetProp() unnoetig, da oben per Query() das Originalmapping erhalten |
| 191 | //wurde. |
| 192 | //SetProp(P_GUILD_SKILLS,skills); |
| 193 | return 1; |
| 194 | } |
| 195 | |
| 196 | |
| 197 | varargs int |
| 198 | AddSpell(string verb, mapping ski) { |
| 199 | mapping skills; |
| 200 | |
| 201 | if (!verb) |
| 202 | return 0; |
| 203 | if (!mappingp(ski)) |
| 204 | ski=([]); |
| 205 | |
| 206 | if (!stringp(ski[SI_SPELLBOOK]) && |
| 207 | !stringp(ski[SI_SPELLBOOK]=QueryProp(P_GUILD_DEFAULT_SPELLBOOK))) |
| 208 | // Wenn kein Spellbook angegeben ist muss ein |
| 209 | // Default-Spellbook angegeben sein, sonst Fehler |
| 210 | return 0; |
| 211 | if (file_size(SPELLBOOK_DIR+ski[SI_SPELLBOOK]+".c")<0) |
| 212 | return 0; // Spellbook sollte auch existieren... |
| 213 | |
| 214 | return AddSkill(lower_case(verb),ski); |
| 215 | } |
| 216 | |
| 217 | mapping QuerySkill(string skill) { |
| 218 | mapping ski; |
| 219 | |
| 220 | // Abfrage per Query(), da vielleicht nur ein Skill gewuenscht |
| 221 | // wird und daher die komplette Kopie des Spellmappings in der Query-Methode |
| 222 | // unnoetig ist. |
| 223 | if (!skill |
| 224 | || !(ski=Query(P_GUILD_SKILLS, F_VALUE)) |
| 225 | || !(ski=ski[skill])) // Gildenspezifische Skilleigenschaften |
| 226 | return 0; |
| 227 | // hier aber dann natuerlich eine Kopie erstellen. ;-) |
| 228 | return(deep_copy(ski)); |
| 229 | } |
| 230 | |
| 231 | mapping QuerySpell(string spell) { |
| 232 | mapping ski,ski2; |
| 233 | string spellbook,sfunc; |
| 234 | |
| 235 | // QuerySkill() hier und QuerySpell() im Spellbook liefern Kopien der |
| 236 | // Skillmappings zurueck, Kopieren hier daher unnoetig. |
| 237 | if (!spell |
| 238 | || !(ski=QuerySkill(spell)) |
| 239 | || !(spellbook=ski[SI_SPELLBOOK])) |
| 240 | return 0; |
| 241 | if (!(sfunc=ski[SI_SKILLFUNC])) |
| 242 | sfunc=spell; |
| 243 | spellbook=SPELLBOOK_DIR+spellbook; |
| 244 | if (!(ski2=(mapping)(spellbook->QuerySpell(sfunc)))) |
| 245 | return 0; |
| 246 | return AddSkillMappings(ski2,ski); // Reihenfolge wichtig! |
| 247 | // Die Gilde kann Spelleigenschaften neu definieren! |
| 248 | } |
| 249 | |
| 250 | varargs int |
| 251 | UseSpell(object caster, string spell, mapping sinfo) { |
| 252 | mapping ski; |
| 253 | string spellbook; |
| 254 | |
| 255 | if (!caster |
| 256 | || !spell |
| 257 | || !(ski=QuerySkill(spell)) // Existiert dieser Spell in dieser Gilde? |
| 258 | || !(spellbook=ski[SI_SPELLBOOK])) // Spellbook muss bekannt sein |
| 259 | return 0; |
| 260 | if (sinfo) |
| 261 | ski+=sinfo; |
| 262 | spellbook=SPELLBOOK_DIR+spellbook; |
| 263 | // printf("%O %O %O %O\n",spellbook,caster,spell,ski); |
| 264 | return (int)spellbook->UseSpell(caster,spell,ski); |
| 265 | } |
| 266 | |
| 267 | static int |
| 268 | InitialSkillAbility(mapping ski, object pl) { |
| 269 | if (!ski || !pl) return 0; |
| 270 | return (300*GetOffset(SI_SKILLLEARN,ski,pl)+ |
| 271 | (200*(int)pl->QueryAttribute(A_INT)* |
| 272 | GetFactor(SI_SKILLLEARN,ski,pl))/100); |
| 273 | } |
| 274 | |
| 275 | int |
| 276 | SkillListe(int what) { |
| 277 | int res; |
| 278 | // Querymethode erstellt Kopie (wichtig!) |
| 279 | mapping allskills=QueryProp(P_GUILD_SKILLS); |
| 280 | string *skills=({}); |
| 281 | string *spells=({}); |
| 282 | |
| 283 | if (!mappingp(allskills) || !sizeof(allskills)) |
| 284 | return 0; |
| 285 | |
| 286 | foreach(string s, mapping sdata: &allskills) { |
| 287 | // Lernlevel ermitteln und speichern. |
| 288 | mapping tmp=QuerySpell(s); |
| 289 | // wenn nix gefunden, dann ist es ein Skill, sonst ein Spell. |
| 290 | if (tmp) { |
| 291 | spells += ({s}); |
| 292 | // das Spellbook hat im Zweifel das SI_SKILLINFO |
| 293 | sdata[SI_SKILLINFO] = tmp[SI_SKILLINFO]; |
| 294 | } |
| 295 | else { |
| 296 | // SI_SKILLINFO steht in diesem Fall schon in sdata... |
| 297 | tmp = QuerySkill(s); |
| 298 | skills += ({s}); |
| 299 | } |
| 300 | // gucken, obs nen Lernlevel gibt und einfach in sdata schreiben |
| 301 | if ( (tmp=tmp[SI_SKILLRESTR_LEARN]) ) |
| 302 | sdata["_restr_level"] = tmp[P_LEVEL]; |
| 303 | } |
| 304 | |
| 305 | // jetzt sortieren. |
| 306 | closure cl = function int (string a, string b) |
| 307 | { return allskills[a]["_restr_level"] > allskills[b]["_restr_level"]; }; |
| 308 | if (what & 0x01) |
| 309 | spells = sort_array(spells, cl); |
| 310 | if (what & 0x02) |
| 311 | skills = sort_array(skills, cl); |
| 312 | |
| 313 | // und ausgeben |
| 314 | cl = function void (string *list) |
| 315 | { |
| 316 | string tmp=""; |
| 317 | int lvl; |
| 318 | foreach(string sp: list) { |
| 319 | lvl = allskills[sp]["_restr_level"]; |
| 320 | if (lvl>0) |
| 321 | tmp += sprintf("%-20s %d\n",sp,lvl); |
| 322 | else |
| 323 | tmp += sprintf("%-20s\n",sp); |
| 324 | if (allskills[sp][SI_SKILLINFO]) |
| 325 | tmp += break_string(allskills[sp][SI_SKILLINFO], 78, |
| 326 | " "); |
| 327 | } |
| 328 | tell_object(PL, tmp); |
| 329 | }; |
| 330 | |
| 331 | if ((what & 0x01) && sizeof(spells)) { |
| 332 | res = 1; |
| 333 | tell_object(PL,sprintf( |
| 334 | "Du kannst versuchen, folgende Zaubersprueche zu lernen:\n" |
| 335 | "%-20s %-3s\n","Zauberspruch","Spielerstufe")); |
| 336 | funcall(cl, spells); |
| 337 | tell_object(PL,break_string( |
| 338 | "Du kannst einen Zauberspruch mit dem Kommando \"lerne\", gefolgt " |
| 339 | "vom Zauberspruchnamen lernen.",78)); |
| 340 | } |
| 341 | if ((what & 0x02) && sizeof(skills)) { |
| 342 | res = 1; |
| 343 | tell_object(PL,sprintf( |
| 344 | "Du kannst versuchen, folgende Faehigkeiten zu erwerben:\n" |
| 345 | "%-20s %-3s\n","Faehigkeit","Spielerstufe")); |
| 346 | funcall(cl, skills); |
| 347 | } |
| 348 | |
| 349 | return res; |
| 350 | } |
| 351 | |
| 352 | varargs int |
| 353 | LearnSpell(string spell,object pl) { |
| 354 | mapping ski,restr; |
| 355 | string res; |
| 356 | mixed learn_initfunc; |
| 357 | int abil,diff; |
| 358 | |
| 359 | // Wenn kein pl gesetzt ist, nehmen wir this_player(), das ist der |
| 360 | // Normalfall. |
| 361 | if (!pl) |
| 362 | pl=this_player(); |
| 363 | if (!IsGuildMember(pl)) { |
| 364 | _notify_fail("Du gehoerst dieser Gilde nicht an!\n"); |
| 365 | return 0; |
| 366 | } |
| 367 | _notify_fail("Was moechtest Du lernen?\n"); |
| 368 | if (!spell) |
| 369 | return SkillListe(0x01); |
| 370 | spell=lower_case(spell); |
| 371 | if (!(ski=QuerySpell(spell))) |
| 372 | return 0; |
| 373 | if (pl->QuerySkill(spell)) { |
| 374 | _notify_fail("Du kannst diesen Spruch doch schon!\n"); |
| 375 | return 0; |
| 376 | } |
| 377 | if ((restr=ski[SI_SKILLRESTR_LEARN]) |
| 378 | && (res=check_restrictions(pl,restr))) { |
| 379 | printf("Du kannst diesen Spruch noch nicht lernen.\nGrund: %s",res); |
| 380 | return 1; |
| 381 | } |
| 382 | abil=InitialSkillAbility(ski,pl); |
| 383 | if (abil<1) abil=1; |
| 384 | if (abil>7500) abil=7500; |
| 385 | write("Du lernst einen neuen Zauberspruch.\n"); |
| 386 | if (!(diff=GetFValueO(SI_DIFFICULTY,ski,pl))) |
| 387 | diff=GetFValueO(SI_SPELLCOST,ski,pl); |
| 388 | pl->ModifySkill(spell,abil,diff); |
| 389 | return 1; |
| 390 | } |
| 391 | |
| 392 | int |
| 393 | LearnSkill(string skill) { |
| 394 | mapping ski,restr; |
| 395 | object pl; |
| 396 | string res; |
| 397 | mixed learn_initfunc; |
| 398 | int abil,diff; |
| 399 | |
| 400 | if (!IsGuildMember(pl=this_player())) { |
| 401 | _notify_fail("Du gehoerst dieser Gilde nicht an!\n"); |
| 402 | return 0; |
| 403 | } |
| 404 | _notify_fail("Was moechtest Du lernen?\n"); |
| 405 | if (!skill) |
| 406 | return SkillListe(0x02); |
| 407 | skill=capitalize(skill); |
| 408 | if (!(ski=QuerySkill(skill))) |
| 409 | return 0; |
| 410 | if (pl->QuerySkill(skill)) { |
| 411 | _notify_fail("Du hast diese Faehigkeit doch schon!\n"); |
| 412 | return 0; |
| 413 | } |
| 414 | if ((restr=ski[SI_SKILLRESTR_LEARN]) |
| 415 | && (res=check_restrictions(pl,restr))) { |
| 416 | printf("Du kannst diese Faehigkeit noch nicht erwerben.\nGrund: %s",res); |
| 417 | return 1; |
| 418 | } |
| 419 | abil=InitialSkillAbility(ski,pl); |
| 420 | if (!abil) abil=1; |
| 421 | if (abil>MAX_ABILITY) abil=MAX_ABILITY; |
| 422 | if (abil<-MAX_ABILITY) abil=-MAX_ABILITY; |
| 423 | write("Du erwirbst eine neue Faehigkeit.\n"); |
| 424 | diff=GetFValueO(SI_DIFFICULTY,ski,pl); |
| 425 | pl->ModifySkill(skill,abil,diff); |
| 426 | return 1; |
| 427 | } |
| 428 | |
| 429 | int GuildRating(object pl) |
| 430 | { |
| 431 | mapping ski; |
| 432 | string *sk; |
| 433 | int i, cnt, sum; |
| 434 | closure qsa; |
| 435 | |
| 436 | if (!IsGuildMember(pl)||!query_once_interactive(pl)) |
| 437 | return 0; |
| 438 | |
| 439 | if (!(ski = QueryProp(P_GUILD_SKILLS)) || |
| 440 | !(qsa = symbol_function("QuerySkillAbility",pl))) |
| 441 | return 0; |
| 442 | |
| 443 | sk = m_indices(ski); |
| 444 | cnt = sizeof(ski); |
| 445 | |
| 446 | for (i=cnt-1, sum=0; i>=0; i--) |
| 447 | sum += funcall(qsa, sk[i]); |
| 448 | |
| 449 | sum = sum/cnt; |
| 450 | if (sum < 0) |
| 451 | sum = 0; |
| 452 | else if (sum > MAX_ABILITY) |
| 453 | sum = MAX_ABILITY; |
| 454 | |
| 455 | return (int)pl->SetProp(P_GUILD_RATING, sum); |
| 456 | } |
| 457 | |
| 458 | // Wird von /std/player/quest.c aufgerufen, wenn Quest geloest. |
| 459 | // (Jedes mal - nicht nur beim ersten mal.) |
| 460 | // Ist zum selbst-ueberschreiben gedacht, sollte aber definiert sein. |
| 461 | void NotifyGiveQuest(object pl, string key){ } |
| 462 | |