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