blob: 3435ba4ae7790d5e113da34b4aaa911aaaee48fc [file] [log] [blame]
// MorgenGrauen MUDlib
//
// gilden_ob.c -- Basisfunktionen einer Gilde
//
// $Id: gilden_ob.c 8433 2013-02-24 13:47:59Z Zesstra $
#pragma strict_types
#pragma save_types
#pragma no_shadow
#pragma no_clone
#pragma range_check
inherit "/std/restriction_checker";
#include <properties.h>
#include <attributes.h>
#include <new_skills.h>
#include <defines.h>
#include <player/fao.h>
#include <wizlevels.h>
void create() {
// P_GUILD_SKILLS sollte nicht direkt von aussen manipuliert werden...
SetProp(P_GUILD_SKILLS,([]));
Set(P_GUILD_SKILLS,PROTECTED,F_MODE_AS);
}
mapping _query_guild_skills() {
// eine Kopie zurueckliefern, um versehentliche Aenderungen des
// Originalmappings in der Gilde zu vermeiden.
// Darf nicht ohne weiteres entfernt werden, da es hier im File Code gibt,
// der sich auf die Kopie verlaesst.
return(deep_copy(Query(P_GUILD_SKILLS)));
}
string GuildName() {
//Gilden muessen Blueprints sein, so. ;-)
return object_name(this_object())[8..];
}
varargs int
IsGuildMember(object pl) {
string plg;
if (!pl && !(pl=this_player()))
return 0;
if (!(plg=({string})pl->QueryProp(P_GUILD)))
return 0;
if (GuildName()!=plg) {
_notify_fail("Du gehoerst dieser Gilde nicht an!\n");
return 0;
}
return 1;
}
int check_cond(mixed cond) {
string res;
if (intp(cond)) {
_notify_fail("Dir fehlt noch die noetige Erfahrung. "+
"Komm spaeter wieder.\n");
return (({int})this_player()->QueryProp(P_XP)>=cond);
}
if (mappingp(cond)) {
res=check_restrictions(this_player(),cond);
if (!stringp(res)) return 1;
_notify_fail(res);
return 0;
}
return 1;
}
int can_advance() {
int lv;
mapping lvs;
if (!(lv=({int})this_player()->QueryProp(P_GUILD_LEVEL))) return 1;
if (!(lvs=QueryProp(P_GUILD_LEVELS))) return 0;
return check_cond(lvs[lv+1]); // Bedingung fuer naechsten Level testen.
}
void adjust_title(object pl) {
int lv;
mixed ti;
if (!pl ||
!(lv=({int})pl->QueryProp(P_GUILD_LEVEL)))
return;
switch(({int})pl->QueryProp(P_GENDER)) {
case MALE:
ti=QueryProp(P_GUILD_MALE_TITLES);
break;
case FEMALE:
ti=QueryProp(P_GUILD_FEMALE_TITLES);
break;
default:
return;
}
if (mappingp(ti))
ti=ti[lv];
if (stringp(ti))
({string})pl->SetProp(P_GUILD_TITLE,ti);
// Spielertitel nullen, damit der Gildentitel angezeigt wird.
if (!IS_SEER(pl) && !FAO_HAS_TITLE_GIFT(pl))
({string})pl->SetProp(P_TITLE,0);
}
void do_advance() {
int lv;
lv=({int})this_player()->QueryProp(P_GUILD_LEVEL)+1;
if (lv<1) lv=1;
({int})this_player()->SetProp(P_GUILD_LEVEL,lv);
adjust_title(this_player());
}
int try_advance() {
if (can_advance()) {
if (IsGuildMember(this_player()))
do_advance();
return 1;
}
return 0;
}
int beitreten() {
string res;
int erg;
if (res=check_restrictions(this_player(),QueryProp(P_GUILD_RESTRICTIONS))) {
// Werden die Beitrittsbedingungen erfuellt?
printf("Du kannst dieser Gilde nicht beitreten.\nGrund: %s",res);
return -3;
}
if (erg=({int})GUILDMASTER->beitreten()) {
if (erg<0)
return erg;
if (!(({int})this_player()->QueryProp(P_GUILD_LEVEL)))
try_advance(); // Level 1 wird sofort vergeben
return 1;
}
return 0;
}
varargs int austreten(int loss) {
return ({int})GUILDMASTER->austreten(loss);
}
int bei_oder_aus_treten(string str) {
if (!str) return 0;
if (sizeof(regexp(({lower_case(str)}),
"\\<aus\\>.*gilde\\>.*\\<aus\\>")))
return austreten();
if (sizeof(regexp(({lower_case(str)}),
"(gilde\\>.*\\<bei\\>|\\<in\\>.*gilde\\>.*\\<ein\\>)")))
return beitreten();
return 0;
}
varargs int
AddSkill(string sname, mapping ski) {
mapping skills;
if (!sname)
return 0;
// per Query() abfragen, hier ist keine Kopie noetig.
if (!mappingp(skills=Query(P_GUILD_SKILLS))) {
skills=([]);
SetProp(P_GUILD_SKILLS,skills);
}
if (!mappingp(ski))
ski=([]);
else
//Zur Sicherheit Kopie erstellen, wer weiss, was der Eintragende noch
//mit seinem Mapping macht...
ski=deep_copy(ski);
if (!stringp(ski[SI_SKILLFUNC]))
// Wenn keine Funktion angegeben ist, Funktionsname=Skillname
ski[SI_SKILLFUNC]=sname;
// Gilden-Offsets addieren
ski=AddSkillMappings(QueryProp(P_GLOBAL_SKILLPROPS),ski);
// Skill setzen.
skills[sname]=ski;
//SetProp() unnoetig, da oben per Query() das Originalmapping erhalten
//wurde.
//SetProp(P_GUILD_SKILLS,skills);
return 1;
}
varargs int
AddSpell(string verb, mapping ski) {
mapping skills;
if (!verb)
return 0;
if (!mappingp(ski))
ski=([]);
if (!stringp(ski[SI_SPELLBOOK]) &&
!stringp(ski[SI_SPELLBOOK]=QueryProp(P_GUILD_DEFAULT_SPELLBOOK)))
// Wenn kein Spellbook angegeben ist muss ein
// Default-Spellbook angegeben sein, sonst Fehler
return 0;
if (file_size(SPELLBOOK_DIR+ski[SI_SPELLBOOK]+".c")<0)
return 0; // Spellbook sollte auch existieren...
return AddSkill(lower_case(verb),ski);
}
mapping QuerySkill(string skill) {
mapping ski;
// Abfrage per Query(), da vielleicht nur ein Skill gewuenscht
// wird und daher die komplette Kopie des Spellmappings in der Query-Methode
// unnoetig ist.
if (!skill
|| !(ski=Query(P_GUILD_SKILLS, F_VALUE))
|| !(ski=ski[skill])) // Gildenspezifische Skilleigenschaften
return 0;
// hier aber dann natuerlich eine Kopie erstellen. ;-)
return(deep_copy(ski));
}
mapping QuerySpell(string spell) {
mapping ski,ski2;
string spellbook,sfunc;
// QuerySkill() hier und QuerySpell() im Spellbook liefern Kopien der
// Skillmappings zurueck, Kopieren hier daher unnoetig.
if (!spell
|| !(ski=QuerySkill(spell))
|| !(spellbook=ski[SI_SPELLBOOK]))
return 0;
if (!(sfunc=ski[SI_SKILLFUNC]))
sfunc=spell;
spellbook=SPELLBOOK_DIR+spellbook;
if (!(ski2=({mapping})(spellbook->QuerySpell(sfunc))))
return 0;
return AddSkillMappings(ski2,ski); // Reihenfolge wichtig!
// Die Gilde kann Spelleigenschaften neu definieren!
}
varargs int
UseSpell(object caster, string spell, mapping sinfo) {
mapping ski;
string spellbook;
if (!caster
|| !spell
|| !(ski=QuerySkill(spell)) // Existiert dieser Spell in dieser Gilde?
|| !(spellbook=ski[SI_SPELLBOOK])) // Spellbook muss bekannt sein
return 0;
if (sinfo)
ski+=sinfo;
spellbook=SPELLBOOK_DIR+spellbook;
// printf("%O %O %O %O\n",spellbook,caster,spell,ski);
return ({int})spellbook->UseSpell(caster,spell,ski);
}
static int
InitialSkillAbility(mapping ski, object pl) {
if (!ski || !pl) return 0;
return (300*GetOffset(SI_SKILLLEARN,ski,pl)+
(200*({int})pl->QueryAttribute(A_INT)*
GetFactor(SI_SKILLLEARN,ski,pl))/100);
}
int
SkillListe(int what) {
int res;
// Querymethode erstellt Kopie (wichtig!)
mapping allskills=QueryProp(P_GUILD_SKILLS);
string *skills=({});
string *spells=({});
if (!mappingp(allskills) || !sizeof(allskills))
return 0;
foreach(string s, mapping sdata: &allskills) {
// Lernlevel ermitteln und speichern.
mapping tmp=QuerySpell(s);
// wenn nix gefunden, dann ist es ein Skill, sonst ein Spell.
if (tmp) {
spells += ({s});
// das Spellbook hat im Zweifel das SI_SKILLINFO
sdata[SI_SKILLINFO] = tmp[SI_SKILLINFO];
}
else {
// SI_SKILLINFO steht in diesem Fall schon in sdata...
tmp = QuerySkill(s);
skills += ({s});
}
// gucken, obs nen Lernlevel gibt und einfach in sdata schreiben
if ( (tmp=tmp[SI_SKILLRESTR_LEARN]) )
sdata["_restr_level"] = tmp[P_LEVEL];
}
// jetzt sortieren.
closure cl = function int (string a, string b)
{ return allskills[a]["_restr_level"] > allskills[b]["_restr_level"]; };
if (what & 0x01)
spells = sort_array(spells, cl);
if (what & 0x02)
skills = sort_array(skills, cl);
// und ausgeben
cl = function void (string *list)
{
string tmp="";
int lvl;
foreach(string sp: list) {
lvl = allskills[sp]["_restr_level"];
if (lvl>0)
tmp += sprintf("%-20s %d\n",sp,lvl);
else
tmp += sprintf("%-20s\n",sp);
if (allskills[sp][SI_SKILLINFO])
tmp += break_string(allskills[sp][SI_SKILLINFO], 78,
" ");
}
tell_object(PL, tmp);
};
if ((what & 0x01) && sizeof(spells)) {
res = 1;
tell_object(PL,sprintf(
"Du kannst versuchen, folgende Zaubersprueche zu lernen:\n"
"%-20s %-3s\n","Zauberspruch","Spielerstufe"));
funcall(cl, spells);
tell_object(PL,break_string(
"Du kannst einen Zauberspruch mit dem Kommando \"lerne\", gefolgt "
"vom Zauberspruchnamen lernen.",78));
}
if ((what & 0x02) && sizeof(skills)) {
res = 1;
tell_object(PL,sprintf(
"Du kannst versuchen, folgende Faehigkeiten zu erwerben:\n"
"%-20s %-3s\n","Faehigkeit","Spielerstufe"));
funcall(cl, skills);
}
return res;
}
varargs int
LearnSpell(string spell,object pl) {
mapping ski,restr;
string res;
mixed learn_initfunc;
int abil,diff;
// Wenn kein pl gesetzt ist, nehmen wir this_player(), das ist der
// Normalfall.
if (!pl)
pl=this_player();
if (!IsGuildMember(pl)) {
_notify_fail("Du gehoerst dieser Gilde nicht an!\n");
return 0;
}
_notify_fail("Was moechtest Du lernen?\n");
if (!spell)
return SkillListe(0x01);
spell=lower_case(spell);
if (!(ski=QuerySpell(spell)))
return 0;
if (({mapping})pl->QuerySkill(spell)) {
_notify_fail("Du kannst diesen Spruch doch schon!\n");
return 0;
}
if ((restr=ski[SI_SKILLRESTR_LEARN])
&& (res=check_restrictions(pl,restr))) {
printf("Du kannst diesen Spruch noch nicht lernen.\nGrund: %s",res);
return 1;
}
abil=InitialSkillAbility(ski,pl);
if (abil<1) abil=1;
if (abil>7500) abil=7500;
write("Du lernst einen neuen Zauberspruch.\n");
if (!(diff=GetFValueO(SI_DIFFICULTY,ski,pl)))
diff=GetFValueO(SI_SPELLCOST,ski,pl);
({void})pl->ModifySkill(spell,abil,diff);
return 1;
}
int
LearnSkill(string skill) {
mapping ski,restr;
object pl;
string res;
mixed learn_initfunc;
int abil,diff;
if (!IsGuildMember(pl=this_player())) {
_notify_fail("Du gehoerst dieser Gilde nicht an!\n");
return 0;
}
_notify_fail("Was moechtest Du lernen?\n");
if (!skill)
return SkillListe(0x02);
skill=capitalize(skill);
if (!(ski=QuerySkill(skill)))
return 0;
if (({mapping})pl->QuerySkill(skill)) {
_notify_fail("Du hast diese Faehigkeit doch schon!\n");
return 0;
}
if ((restr=ski[SI_SKILLRESTR_LEARN])
&& (res=check_restrictions(pl,restr))) {
printf("Du kannst diese Faehigkeit noch nicht erwerben.\nGrund: %s",res);
return 1;
}
abil=InitialSkillAbility(ski,pl);
if (!abil) abil=1;
if (abil>MAX_ABILITY) abil=MAX_ABILITY;
if (abil<-MAX_ABILITY) abil=-MAX_ABILITY;
write("Du erwirbst eine neue Faehigkeit.\n");
diff=GetFValueO(SI_DIFFICULTY,ski,pl);
({void})pl->ModifySkill(skill,abil,diff);
return 1;
}
int GuildRating(object pl)
{
mapping ski;
string *sk;
int i, cnt, sum;
closure qsa;
if (!IsGuildMember(pl)||!query_once_interactive(pl))
return 0;
if (!(ski = QueryProp(P_GUILD_SKILLS)) ||
!(qsa = symbol_function("QuerySkillAbility",pl)))
return 0;
sk = m_indices(ski);
cnt = sizeof(ski);
for (i=cnt-1, sum=0; i>=0; i--)
sum += funcall(qsa, sk[i]);
sum = sum/cnt;
if (sum < 0)
sum = 0;
else if (sum > MAX_ABILITY)
sum = MAX_ABILITY;
return ({int})pl->SetProp(P_GUILD_RATING, sum);
}
// Wird von /std/player/quest.c aufgerufen, wenn Quest geloest.
// (Jedes mal - nicht nur beim ersten mal.)
// Ist zum selbst-ueberschreiben gedacht, sollte aber definiert sein.
void NotifyGiveQuest(object pl, string key){ }