blob: 390ad7722a395eef923d6cc5a982c11879abfbee [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001// MorgenGrauen MUDlib
2//
3// player/skills.c -- Spielerskills
4//
5// $Id: skills.c 8809 2014-05-08 19:52:48Z Zesstra $
6
7//
8// 2003-01-20: Nun Zooks Baustelle
9//
Vanion50652322020-03-10 21:13:25 +010010#pragma strict_types
MG Mud User88f12472016-06-24 23:31:02 +020011#pragma save_types
12#pragma range_check
13#pragma no_clone
MG Mud User88f12472016-06-24 23:31:02 +020014
15inherit "/std/living/skills";
16
17#include <combat.h>
18#include <new_skills.h>
19#include <properties.h>
20#include <break_string.h>
21#include <wizlevels.h>
22
23#define NEED_PROTOTYPES
24#include <player/base.h>
25#include <player/gmcp.h>
26#undef NEED_PROTOTYPES
27
28// Dieses Mapping speichert die deaktivierten Skills der einzelnen Gilden
29// Diese werden in den Gilden ueber P_GUILD_DEACTIVATED_SKILL gesetzt.
30nosave mapping deactivated_skills = ([]);
31
32// Flag fuer den Kompatibilitaetsmodus des Kampfs (Emulation von
33// 2s-Alarmzeit). Wenn != 0 speichert das Flag gleichzeitig die Zeit des
34// letzten Heartbeats. Auf diese Zeit wird der Startpunkt eines Spellfatigues
35// ggf. zurueckdatiert. (max. eine Sekunde)
36int spell_fatigue_compat_mode;
37
38// Ein create() fuer das Mapping
39
40protected void create()
41{
42 mapping act;
43
44 ::create();
45
46 // Wir holen die Gilden aus dem Gildenmaster
47 foreach(string guild:
Vanion50652322020-03-10 21:13:25 +010048 ({string *})call_other(GUILDMASTER,"QueryProp",P_VALID_GUILDS))
MG Mud User88f12472016-06-24 23:31:02 +020049 {
bugfixd94d0932020-04-08 11:27:13 +020050 if(catch(act=({mapping})call_other("/gilden/"+guild,"QueryProp",
MG Mud User88f12472016-06-24 23:31:02 +020051 P_GUILD_DEACTIVATE_SKILLS); publish ))
52 log_file("WEAPON_SKILLS", sprintf ("%s: Gilde nicht ladbar: "
53 +"TP: %O, TI: %O, PO: %O, Gilde: %s\n", dtime(time()),
54 this_player(), this_interactive(), previous_object(), guild));
55 else if (act) // wenn act, ins Mapping aufnehmen.
56 deactivated_skills+=([guild:act]);
57 }
58 // keine echte Prop mehr, Save-Modus unnoetig.
59 Set(P_NEXT_SPELL_TIME,SAVE,F_MODE_AD);
60
61 Set(P_SKILLSVERSION, SAVE|SECURED, F_MODE_AS);
62}
63
64// Das Mapping kann man auch abfragen
65
66public mapping GetDeactivatedSkills()
67{
68 return copy(deactivated_skills);
69}
70
71// Funktion, die sagt ob ein ANY-Skill deaktiviert ist.
72public int is_deactivated_skill(string sname,string guild)
73{
74 if (deactivated_skills[guild])
75 return deactivated_skills[guild][sname];
76 return 0;
77}
78
79
80// Funktion fuer die Waffenskills
81// traegt die allg. Waffenskills ein. Wird ggf. von FixSkills() gerufen.
82// (Das Eintragen bedeutet nicht, dass die aktiv sind! Aber bei Gildenwechsel
83// werden sie nicht eingetragen).
84private void set_weapon_skills() {
85
86 if (QuerySkillAbility(FIGHT(WT_SWORD))<=0)
87 ModifySkill(FIGHT(WT_SWORD),([SI_SKILLABILITY:0]),150,"ANY");
88 if (QuerySkillAbility(FIGHT(WT_AXE))<=0)
89 ModifySkill(FIGHT(WT_AXE),([SI_SKILLABILITY:0]),150,"ANY");
90 if (QuerySkillAbility(FIGHT(WT_SPEAR))<=0)
91 ModifySkill(FIGHT(WT_SPEAR),([SI_SKILLABILITY:0]),150,"ANY");
92 if (QuerySkillAbility(FIGHT(WT_WHIP))<=0)
93 ModifySkill(FIGHT(WT_WHIP),([SI_SKILLABILITY:0]),150,"ANY");
94 if (QuerySkillAbility(FIGHT(WT_KNIFE))<=0)
95 ModifySkill(FIGHT(WT_KNIFE),([SI_SKILLABILITY:0]),150,"ANY");
96 if (QuerySkillAbility(FIGHT(WT_CLUB))<=0)
97 ModifySkill(FIGHT(WT_CLUB),([SI_SKILLABILITY:0]),150,"ANY");
98 if (QuerySkillAbility(FIGHT(WT_STAFF))<=0)
99 ModifySkill(FIGHT(WT_STAFF),([SI_SKILLABILITY:0]),150,"ANY");
100}
101
102// initialisiert die Skills fuer Spieler (momentan: allg. Waffenskills setzen
103// und P_SKILLS_VERSION)
104protected void InitSkills() {
105 mapping ski;
106 // schonmal initialisiert?
107 if (mappingp(ski=Query(P_NEWSKILLS, F_VALUE)) && sizeof(ski))
108 return;
109
110 // allg. Waffenskills aktivieren
111 set_weapon_skills();
112
113 // Version setzen
114 SetProp(P_SKILLSVERSION, CURRENT_SKILL_VERSION);
115 Set(P_SKILLSVERSION, SAVE|SECURED, F_MODE_AS);
116}
117
118// Updated Skills aus Version 0 und 1 heraus.
119private void FixSkillV1(string skillname, mixed sinfo) {
120 // alte Skills auf mappings normieren
121 if (intp(sinfo)) {
122 sinfo = ([SI_SKILLABILITY: sinfo ]);
123 }
124 // Eine Reihe von Daten werden geloescht, da die Daten aus der
125 // Gilde/Spellbook frisch kommen sollten und sie nicht spieler-individuell
126 // sind: SI_CLOSURE (wird onthefly korrekt neu erzeugt), SI_SKILLARG,
127 // SI_NUMBER_ENEMIES, SI_NUMBER_FRIENDS, SI_DISTANCE, SI_WIDTH, SI_DEPTH,
128 // SI_TESTFLAG, SI_ENEMY, SI_FRIEND.
129 // Ausserdem sind alle SP_* im toplevel falsch, die muessen a) in SI_SPELL
130 // und sollten b) nicht im Spieler gespeichert werden, sondern von
131 // Gilden/Spellbook jeweils frisch kommen.
132 // all dieses Zeug landete in alten Spielern im Savefile.
133 if (mappingp(sinfo))
134 sinfo -= ([SI_CLOSURE, SI_SKILLARG, SI_NUMBER_ENEMIES, SI_NUMBER_FRIENDS,
135 SI_DISTANCE, SI_WIDTH, SI_DEPTH, SI_TESTFLAG, SI_ENEMY,
136 SI_FRIEND, SP_NAME, SP_SHOW_DAMAGE, SP_REDUCE_ARMOUR,
137 SP_PHYSICAL_ATTACK, SP_RECURSIVE, SP_NO_ENEMY,
138 SP_NO_ACTIVE_DEFENSE, SP_GLOBAL_ATTACK ]);
139 else
140 {
141 tell_object(this_object(),sprintf(
142 "\n**** ACHTUNG - FEHLER ***\n"
143 "Deine Skills enthalten einen defekten Skill %O:\n"
144 "Bitte lass dies von einem Erzmagier ueberpruefen.\n",
145 skillname));
146 }
147}
148
149// Updatet und repariert ggf. Skillmappings in Spielern
150protected void FixSkills() {
151
152 // nur bei genug rechenzeit loslegen
153 if (get_eval_cost() < 750000) {
154 call_out(#'FixSkills, 1);
155 return;
156 }
157 // wenn gar keine Skills da (?): InitSkills() rufen.
158 mapping allskills = Query(P_NEWSKILLS, F_VALUE);
159 if (!mappingp(allskills) || !sizeof(allskills)) {
160 InitSkills();
161 return;
162 }
163
164 // Die Fallthroughs in diesem switch sind voll Absicht!
165 switch(QueryProp(P_SKILLSVERSION)) {
166 // bei Version 0 und 1 das gleiche tun
167 case 0: // von 0 auf 1
168 case 1: // von 1 auf 2
169 foreach(string gilde, mapping skills: allskills) {
170 if (!stringp(gilde)) {
171 // sollte nicht vorkommen - tat aber... *seufz*
172 m_delete(skills, gilde);
173 continue;
174 }
175 walk_mapping(skills, #'FixSkillV1);
176 }
177 // allg. Waffenskills aktivieren, einige alte Spieler haben die noch
178 // nicht.
179 set_weapon_skills();
180 // Speicherflag fuer die Versionsprop muss noch gesetzt werden.
181 Set(P_SKILLSVERSION, SAVE|SECURED, F_MODE_AS);
182 // Version ist jetzt 2.
183 SetProp(P_SKILLSVERSION, 2);
184 // Fall-through
185 case 2:
186 // gibt es noch nicht, nichts machen.
187 //SetProp(P_SKILLSVERSION, 3);
188 // Fall-through, ausser es sind zuwenig Ticks da!
189 if (get_eval_cost() < 750000)
190 break;
191 }
192 // Falls noch nicht auf der aktuellen Version angekommen, neuer callout
193 if (QueryProp(P_SKILLSVERSION) < CURRENT_SKILL_VERSION)
194 call_out(#'FixSkills, 2);
195}
196
197protected void updates_after_restore(int newflag) {
198 //Allgemeine Waffenskills aktivieren, wenn noetig
199 // Wird nun von InitSkills bzw. FixSkills uebernommen, falls noetig.
200 if (newflag) {
201 InitSkills();
202 }
203 else if (QueryProp(P_SKILLSVERSION) < CURRENT_SKILL_VERSION) {
204 // Falls noetig, Skills fixen/updaten. *grummel*
205 FixSkills();
206 }
207 // Prop gibt es nicht mehr. SAVE-Status loeschen.
208 Set(P_GUILD_PREVENTS_RACESKILL,SAVE,F_MODE_AD);
209}
210
211// Standardisierte Nahkampf-Funktion fuer alle Nahkampf-Waffenarten
212protected mapping ShortRangeSkill(object me, string sname, mapping sinfo)
213{
214 int val, w;
215 object enemy;
216
217 if (!mappingp(sinfo) || !objectp(sinfo[P_WEAPON]))
218 return 0;
219
220 w = ([WT_KNIFE : 8,
221 WT_SWORD : 5,
222 WT_AXE : 4,
223 WT_SPEAR : 6,
224 WT_CLUB : 1,
225 WT_WHIP : 9,
bugfixd94d0932020-04-08 11:27:13 +0200226 WT_STAFF : 7])[({string})sinfo[P_WEAPON]->QueryProp(P_WEAPON_TYPE)];
MG Mud User88f12472016-06-24 23:31:02 +0200227
228
bugfixd94d0932020-04-08 11:27:13 +0200229 val = sinfo[SI_SKILLABILITY]*(({int})sinfo[P_WEAPON]->QueryProp(P_WC)*
MG Mud User88f12472016-06-24 23:31:02 +0200230 (w*QueryAttribute(A_DEX)+
231 (10-w)*QueryAttribute(A_STR))/700)
232 /MAX_ABILITY;
233
234 if (val > 85) {
235 log_file("WEAPON_SKILLS", sprintf("%s: Zu hoher Schaden von: "
236 +"TO: %O, TI: %O, PO: %O, val: %d, A_DEX: %d, A_STR: %d, "
237 +"P_WEAPON: %O, P_WC: %d\n", dtime(time()),
Zesstra9ad254c2019-09-27 00:30:41 +0200238 this_object(), this_interactive(),
239 previous_object(), val,
MG Mud User88f12472016-06-24 23:31:02 +0200240 QueryAttribute(A_DEX),
241 QueryAttribute(A_STR), sinfo[P_WEAPON],
bugfixd94d0932020-04-08 11:27:13 +0200242 ({int})sinfo[P_WEAPON]->QueryProp(P_WC)));
MG Mud User88f12472016-06-24 23:31:02 +0200243 val = 85;
244 }
245
246 /*
Zesstra9ad254c2019-09-27 00:30:41 +0200247 Der zusaetzliche Schaden der allgemeinen Waffenskills berechnet
MG Mud User88f12472016-06-24 23:31:02 +0200248 sich wie folgt:
249
250 sinfo[SI_SKILLABILITY)* (P_WC * ( X ) / 800) / MAX_ABILITY
251
252 Dabei beruecksichtigt X je nach Waffentyp in unterschiedlicher
253 Gewichtung die Werte fuer Geschicklichkeit und Staerke.
254
255 X ==
256
257 Messer : 8*A_DEX + 2*A_STR
258 Schwert : 5*A_DEX + 5*A_STR
259 Axt : 4*A_DEX + 6*A_STR
260 Speer : 6*A_DEX + 4*A_STR
261 Keule : 1*A_DEX + 9*A_STR
262 Peitsche : 9*A_DEX + 1*A_STR
263 */
264
265 sinfo[SI_SKILLDAMAGE]+=val;
266
267
268 /* Lernen: Wird immer schwieriger, nur bei jedem 20. Schlag im Schnitt,
Drache Humnidb9f15f2018-03-15 22:00:18 +0100269 * und nur dann, wenn der Gegner auch XP gibt.
270 * EM-Beschluss: Lernen wird leichter (jeder 5. Schlag, skillabhaengig)
271 * und bei jedem 300. Schlag lernt man auch so. Ferner wird noch
272 * ueberprueft, ob der Skill schon maximal ist, wenn man sonst in
273 * jedem Falle lernen wurde.
274 */
275 if ((random(MAX_ABILITY+1)>sinfo[SI_SKILLABILITY] && !random(5))
276 || (!random(300) && sinfo[SI_SKILLABILITY]<MAX_ABILITY))
MG Mud User88f12472016-06-24 23:31:02 +0200277 {
278 enemy=sinfo[SI_ENEMY];
bugfixd94d0932020-04-08 11:27:13 +0200279 if (objectp(enemy) && (({int})enemy->QueryProp(P_XP)>0))
MG Mud User88f12472016-06-24 23:31:02 +0200280 {
281 object ausbilder;
282 // log_file("humni/log_wurm","Haut: %s und zwar %s, mit xp %d\n",geteuid(this_object()),to_string(enemy),enemy->QueryProp(P_XP));
283 LearnSkill(sname, random(5), 150);
284 // Gibt es einen Ausbilder?
285 if (QueryProp(P_WEAPON_TEACHER) &&
286 ausbilder=find_player(QueryProp(P_WEAPON_TEACHER)))
287 {
288 // Ist der Ausbilder anwesend?
289 if (present(ausbilder,environment()))
290 {
291 // Ausbilder und Azubi muessen dieselbe Waffe haben.
292 //string wt_aus,wt_azu;
293 object waf_aus,waf_azu;
294
295 waf_azu=QueryProp(P_WEAPON);
bugfixd94d0932020-04-08 11:27:13 +0200296 waf_aus=({object})call_other(ausbilder,"QueryProp",P_WEAPON);
MG Mud User88f12472016-06-24 23:31:02 +0200297
298 //wt_azu=call_other(waf_azu,"QueryProp",P_WEAPON_TYPE);
299 //wt_aus=call_other(waf_aus,"QueryProp",P_WEAPON_TYPE);
300 //if (wt_azu==wt_aus)
301 if (objectp(waf_aus) && objectp(waf_azu) &&
Vanion50652322020-03-10 21:13:25 +0100302 ({string})waf_aus->QueryProp(P_WEAPON_TYPE)
303 == ({string})waf_azu->QueryProp(P_WEAPON_TYPE))
MG Mud User88f12472016-06-24 23:31:02 +0200304 {
305 // Bonus von bis zu 5 Punkten
306 //log_file("humni/log_azubi",
307 // sprintf("Azubi %O und Ausbilder %O : Waffentypen %s und %s, gelernt\n",this_object(),
308 // ausbilder, wt_azu, wt_aus));
309 LearnSkill(sname,random(6),150);
310 }
311 }
312 }
313 }
314 }
315
316 /*
317 Die Schwierigkeit liegt bei 150, so dass
318 ein Lvl. 1 Spieler maximal 15% Skill
319 usw...
320 lernen kann. (Genaue Tabelle in /std/living/skills bei LimitAbility)
321 */
322
323 return sinfo;
324}
325
326
327// Standardisierte Fernkampf-Funktion fuer alle Fernkampf-Waffenarten
328
329// *** noch deaktiviert ***
330
331protected mapping LongRangeSkill(object me, string sname, mapping sinfo, int dam)
332{ int abil,val;
333
334 if (!mappingp(sinfo) || !dam || !objectp(sinfo[P_WEAPON]) ||
bugfixd94d0932020-04-08 11:27:13 +0200335 (({int})sinfo[P_WEAPON]->QueryProp(P_SHOOTING_WC))<5)
MG Mud User88f12472016-06-24 23:31:02 +0200336 return 0;
337
338 abil=sinfo[SI_SKILLABILITY]+sinfo[OFFSET(SI_SKILLABILITY)];
339 val=dam*abil/MAX_ABILITY;
340 val=val/2+random(val/2+1);
341 val=(val*QuerySkillAttribute(SA_DAMAGE))/100;
342 sinfo[SI_SKILLDAMAGE]+=val;
343
344 if (random(MAX_ABILITY+1)>sinfo[SI_SKILLABILITY] && random(50)==42)
345 LearnSkill(sname, 1, 150);
346
347 return sinfo;
348}
349
350
351
352// Die einzelnen Waffenskills rufen dann nur die Standard-Funktion auf.
353
354protected mapping StdSkill_Fight_axe(object me, string sname, mapping sinfo)
355{
356 return ShortRangeSkill(me, sname, sinfo);
357}
358
359protected mapping StdSkill_Fight_club(object me, string sname, mapping sinfo)
360{
361 return ShortRangeSkill(me, sname, sinfo);
362}
363
364protected mapping StdSkill_Fight_knife(object me, string sname, mapping sinfo)
365{
366 return ShortRangeSkill(me, sname, sinfo);
367}
368
369protected mapping StdSkill_Fight_spear(object me, string sname, mapping sinfo)
370{
371 return ShortRangeSkill(me, sname, sinfo);
372}
373
374protected mapping StdSkill_Fight_sword(object me, string sname, mapping sinfo)
375{
376 return ShortRangeSkill(me, sname, sinfo);
377}
378
379protected mapping StdSkill_Fight_whip(object me, string sname, mapping sinfo)
380{
381 return ShortRangeSkill(me, sname, sinfo);
382}
383
384protected mapping StdSkill_Fight_staff(object me, string sname, mapping sinfo)
385{
386 return ShortRangeSkill(me, sname, sinfo);
387}
388
389
390
391
392// Die Fernwaffenskills sind Munitionsabhaengig
393
394// *** noch deaktiviert ***
395
396protected mapping StdSkill_Shoot_arrow(object me, string sname, mapping sinfo)
397{
398 return LongRangeSkill(me, sname, sinfo, 40);
399}
400
401protected mapping StdSkill_Shoot_bolt(object me, string sname, mapping sinfo)
402{
403 return LongRangeSkill(me, sname, sinfo, 40);
404}
405
406protected mapping StdSkill_Shoot_dart(object me, string sname, mapping sinfo)
407{
408 return LongRangeSkill(me, sname, sinfo, 20);
409}
410
411protected mapping StdSkill_Shoot_stone(object me, string sname, mapping sinfo)
412{
413 return LongRangeSkill(me, sname, sinfo, 40);
414}
415
416protected mixed _query_localcmds() {
417 return ({ ({"spruchermuedung","enable_spell_fatigue_compat",0,0}) });
418}
419
420
421
422// *** Kompatibilitaetsmodus fuer Spellfatigues (Emulation 2s-Alarmzeit) ***
423
424/** Speichert eine Spellfatigue von <duration> Sekunden fuer <key>.
425 * Ist hier nur fuer den Spellfatigue-Compat-mode.
426 * <key> darf 0 sein und bezeichnet das globale Spellfatigue.
427 * Rueckgabewert: Ablaufzeit der gesetzten Sperre
428 -1, wenn noch eine nicht-abgelaufene Sperre auf dem <key> lag.
429 0, wenn duration 0 ist.
430 */
431public varargs int SetSpellFatigue(int duration, string key) {
432
433 // 0 sollte nie eine Sperre bewirken, auch nicht im compat mode.
434 if (!duration) return 0;
435
436 if (spell_fatigue_compat_mode) {
437 // Spell-Fatigues auf HBs synchronisieren (2s-Alarmzeit-Emulation).
438 // Aufrunden auf ganzzahlige Vielfache von __HEART_BEAT_INTERVAL__
439 if (duration % __HEART_BEAT_INTERVAL__)
440 ++duration;
441
442 // Startpunkt des Delay soll Beginn der aktuellen Kampfrunde (HB-Zyklus)
443 // sein, ggf. um max. eine Sekunde zurueckdatieren.
444 // (spell_fatigue_compat_mode hat die Zeit des letzten HB-Aufrufs)
445 // Falls durch irgendein Problem (z.B. sehr hohe Last), der letzte HB
446 // laenger als 1s zurueckliegt, funktioniert das natuerlich nicht, aber
447 // bei fatigue+=spell_fatigue_compat_mode kann der Spieler zuviel Zeit
448 // einsparen.
449 if (time() > spell_fatigue_compat_mode)
450 --duration; //1s zurueckdatieren
451 }
452
453 return ::SetSpellFatigue(duration, key);
454}
455
456/** Befehlsfunktion fuer Spieler um den Spellfatigue-Kompatibilitaetsmodus
457 * umzuschalten.
458 */
459public int enable_spell_fatigue_compat(string cmd) {
460 if (QueryProp(P_LAST_COMBAT_TIME) + 600 > time()) {
461 write(break_string(
462 "Im Kampf oder kurz nach einem Kampf kannst Du nicht zwischen "
463 "alter und neuer Spruchermuedung umschalten.\n"
464 "Momentan benutzt Du die "
465 + (spell_fatigue_compat_mode ? "alte (ungenauere)" : "neue (normale)")
466 + " Spruchermuedung.",78,0,BS_LEAVE_MY_LFS));
467 return 1;
468 }
469
470 if (cmd=="alt") {
471 spell_fatigue_compat_mode=time();
472 write(break_string(
473 "Alte Spruchermuedung wurde eingeschaltet. Alle Ermuedungspausen "
474 "zwischen Spruechen werden auf Vielfache von 2s aufgerundet und "
475 "beginnen in der Regel am Anfang Deiner Kampfrunde."));
476 return 1;
477 }
478 else if (cmd=="neu" || cmd=="normal") {
479 spell_fatigue_compat_mode=0;
480 write(break_string(
481 "Normale Spruchermuedung wurde eingeschaltet. Alle Ermuedungspausen "
482 "zwischen Spruechen werden sekundengenau berechnet."));
483 return 1;
484 }
485
486 notify_fail(break_string(
487 "Moechtest Du die alte oder die neue Spruchermuedung?\n"
488 "Momentan benutzt Du die "
489 + (spell_fatigue_compat_mode ? "alte (ungenauere)" : "neue (normale)")
490 + " Spruchermuedung.",78,0,BS_LEAVE_MY_LFS));
491 return 0;
492}
493
494/** Speichert die Zeit des letztes Heartbeats.
495 */
496protected void heart_beat() {
497 if (spell_fatigue_compat_mode)
498 spell_fatigue_compat_mode = time();
499}
500
501static int _set_guild_level(int num)
502{ string gilde;
503 mapping levels;
504
505 if ( !(gilde=QueryProp(P_GUILD)) )
506 return 0;
507
508 if ( !mappingp(levels=Query(P_GUILD_LEVEL)) )
509 levels=([]);
510
511 levels[gilde]=num;
512 Set(P_GUILD_LEVEL,levels);
513 GMCP_Char( ([P_GUILD_LEVEL: num]) );
514
515 return num;
516}
517
518static int _query_guild_level()
519{ string gilde;
520 mapping levels;
521
522 if ( !(gilde=QueryProp(P_GUILD)) )
523 return 0;
524
525 if ( !mappingp(levels=Query(P_GUILD_LEVEL)) )
526 return 0;
527
528 return levels[gilde];
529}
530
531static string _set_guild_title(string t)
532{ string gilde;
533 mapping titles;
534
535 if ( !(gilde=QueryProp(P_GUILD)) )
536 return 0;
537
538 if ( !mappingp(titles=Query(P_GUILD_TITLE)) )
539 titles=([]);
540
541 titles[gilde]=t;
542 Set(P_GUILD_TITLE,titles);
543 GMCP_Char( ([P_GUILD_TITLE: t]) );
544 return t;
545}
546
547static string _query_guild_title()
548{ string gilde,t;
549 object g;
550 mapping titles;
551
552 if ( !(gilde=QueryProp(P_GUILD)) )
553 return 0;
554
555 if ( !mappingp(titles=Query(P_GUILD_TITLE)) )
556 titles=([]);
557
558 t=titles[gilde];
559 if ( !t && query_once_interactive(this_object())
560 && objectp(g=find_object("/gilden/"+gilde)) )
561 {
bugfixd94d0932020-04-08 11:27:13 +0200562 ({void})g->adjust_title(this_object());
MG Mud User88f12472016-06-24 23:31:02 +0200563 SetProp(P_TITLE,0);
564
565 if ( !mappingp(titles=Query(P_GUILD_TITLE)) )
566 return 0;
567
568 t=titles[gilde];
569 }
570
571 return t;
572}
573
574
575static string _set_guild(string gildenname)
576{ object pre;
577
578 if (!objectp(pre=previous_object()))
579 return 0;
580
581 if ( pre!=this_object() // Das Lebewesen selber darf die Gilde setzen,
582 && object_name(pre)!=GUILDMASTER // der Gildenmaster auch
583 && (!this_player()
584 || this_player() != this_interactive()
585 || !IS_ARCH(this_player())
586 )
587 )
588 return 0;
589
590 Set(P_GUILD,gildenname);
591 GMCP_Char( ([P_GUILD: gildenname]) );
592 return gildenname;
593}
594
595static string _query_guild()
596{ string res;
597
598 if ( !(res=Query(P_GUILD)) && query_once_interactive(this_object()) )
599 {
600 // Spieler, die keiner Gilde angehoeren, gehoeren zur Abenteurergilde
601 if ( !(res=QueryProp(P_DEFAULT_GUILD)) )
602 return DEFAULT_GUILD;
603 else
604 Set(P_GUILD,res);
605 return res;
606 }
607
608 return res;
609}
610
611static string _query_title()
612{ string ti;
613
614 if ( stringp(ti=Query(P_TITLE)) )
615 return ti;
616
617 return QueryProp(P_GUILD_TITLE);
618}
619
620static string _set_title(string t)
621{
622 Set(P_TITLE, t, F_VALUE);
623 GMCP_Char( ([P_TITLE: t]) );
624 return t;
625}
626