/* configurable guild room */
/* allows creator to easily add a guild room to use standard skills */
#include <mudlib.h>
inherit ROOM;
#define LEVEL (int)this_player()->query_level()
#define NAME (string)this_player()->query_name()
#define TEXP (int)this_player()->query_total_exp()
#define EXP (int)this_player()->query_exp()
#define GUILD_STR lower_case((string)this_player()->query_guild_string())
#define COST_FOR_JOIN 1000 /* coins to join a new class */
#define CHARISMA (int)this_player()->query_charisma()
#define MASTER_CHA 16
#define QPS (int)this_player()->query_qpoints()
#define DRAINED (int)this_player()->query_level_drained()
#define NO_ADVANCE present("no advance",this_player())
#define PLAY_MONEY (int)this_player()->query_money()
#define G_NAME (string)guild_master->query_name()
mixed *classes; /* class-skill array */
mixed *titles; /* level titles */
mixed *pretitles; /* pretitles for 30+ level */
int *exp; /* exp per level */
int *qp; /* quest points for next level */
int *skill_exp; /* cost for skills */
object guild_master; /* guild master */
string guild_name; /* guild title */
int weapon_rate; /* rate which get weapons proficiencies */
int exp_multiplier;
int skill_exp_multiplier;
object sign;
void set_classes(mixed *arg) { classes = arg; }
void set_titles(mixed *arg) { titles = arg; }
void set_pretitles(mixed *arg) { pretitles = arg; }
void set_exp(int *arg) { exp = arg; }
void set_skill_exp(int *arg) { skill_exp = arg; }
void set_guild_master(object arg) { guild_master = arg; }
void set_guild_name(string arg) { guild_name = arg; }
void set_weapon_rate(int arg) { weapon_rate = arg; }
mixed *query_classes() { return classes; }
mixed *query_titles() { return titles; }
mixed *query_pretitle() { return pretitles; }
int *query_exp() { return exp; }
int *query_skill_exp() { return skill_exp; }
object query_guild_master() { return guild_master; }
string query_guild_name() { return guild_name; }
int query_weapon_rate() { return weapon_rate; }
void init(){
::init();
add_action("train_weapon", "train");
add_action("advance","raise");
add_action("advance","advance");
add_action("cost_for_level","cost");
add_action("join","join");
add_action("leave","leave");
if(!sign) {
sign = clone_object(SIGN);
#ifdef NATIVE_MODE
sign->move(this_object());
#else
move_object(sign, this_object());
#endif /* NATIVE_MODE */
sign->set_message(
" Commands Comments\n"+
" raise, raise <level> ....... Advance level by 1\n"+
" raise <skill> .............. Advances skill by 1\n"+
" cost <level> ............... Exp or coins needed to advance\n"+
" cost <skill> ............... (Not)|Possible to raise skill\n"+
" cost <class> ............... (Not)|Possible to raise skills in class\n"+
" leave <class> .............. Leave a class, set all stats to 0\n"+
" join <class> ............... Join the fighter class only\n"+
" train <weapon> ............. Train in a weapon and become proficient\n"
);
}
}
int get_next_qp(int stat) {
int *qp;
qp = ({
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
12
});
if(stat < 0) return qp[0];
if(stat > 100) return ((stat - 100) *10) + 2; /* worry when close */
return qp[stat];
}
/* exp for next level */
#ifndef AMYLAAR
int get_next_exp(int stat) {
if(!exp) {
exp = ({
0, 1014, 1522, 2283, 3425, 5138,
7707, 11561, 17341, 26012, 39018, 58527,
87791, 131687, 197530, 296296, 444444, 666666,
1000000, 1500000, 2000000, 2500000, 3000000, 3500000,
4000000, 4500000, 5000000, 5500000, 6000000, 6500000,
});
}
if(stat < 0) return exp[0];
if(stat >= sizeof(exp)) {
if(!exp_multiplier) exp_multiplier = 500000;
return exp[sizeof(exp)-1] + (stat-(sizeof(exp)-1))*exp_multiplier;
}
return exp[stat];
}
#else /* amylaar version */
int get_next_exp(int stat) {
int tmp;
if(stat < 1) return 1014;
if(stat < 20)
return 1014 + to_int(1014*exp(stat * log(1.4683496)));
/* ok so it looks silly, but it makes xp for level 20 about 1.5 mill */
else
/*
return to_int(get_next_exp(20) * exp((stat-20) * log(1.17)));
*/
{
tmp = get_next_exp(19) + (500000
* (stat - 19)) + 20000 * (stat - 20) * (stat -19) /2;
if(tmp > 0) return tmp;
else return 500000000000;
}
}
/* The one above is a geometric series. lets try a algebraic one: */
/*
int get_next_exp(int stat) {
return 1014 * (stat + 1) + 10000 * stat * (stat + 1) /2;
}
*/
#endif /* 312MASTER */
/* exp for next stat */
int get_skill_exp(int stat) {
if(stat < 0) return skill_exp[0];
if(stat >= sizeof(skill_exp)) {
if(!skill_exp_multiplier) skill_exp_multiplier = 25000;
return skill_exp[sizeof(skill_exp)-1]
+ (stat-(sizeof(skill_exp)-1))*skill_exp_multiplier;
}
return skill_exp[stat];
}
/* if the player is within 10% of their next level, they advance at a
* cost of 3 times coins of the exp difference. */
int close_enuff(status costing_only){
int required_money, required_exp;
required_exp = get_next_exp(LEVEL);
required_money = (required_exp - EXP) * 3;
if(EXP < required_exp && (required_exp-EXP) < required_exp/10) {
if(PLAY_MONEY > required_money) {
if(!costing_only){
this_player()->add_money(required_money*(-1));
this_player()->set_exp( required_exp);
write(G_NAME +" takes "+ required_money +
" coins from you for extra training.\n");
}
return required_money;
}
}
return 0;
}
/*** exp required ***/
string get_new_title(int next_level){
string *weird_titles;
int gender;
gender = (int)this_player()->query_gender();
while(!sizeof(titles[gender])) gender++;
if(next_level > sizeof((string *)titles[gender]) - 1) {
while(!sizeof((string *)pretitles[gender])) if(++gender > 2) return "";
next_level = (next_level-30)/4;
if(next_level > sizeof((string *)pretitles[gender])) {
next_level = sizeof((string *)pretitles[gender])-1;
}
if(this_player()->query_level() > 29)
this_player() -> set_pretitle((string)pretitles[gender][next_level]);
weird_titles = ({
"the Stranger",
"the Insignificant",
"the Saviour",
"the Blood Stained",
"the Dragon Slayer",
"Orcbane",
"Ironfist",
"the Faithful",
"the Invincible",
"the Meek!!!",
"the Black",
"the White",
"the Incorrigible",
});
return weird_titles[random(sizeof(weird_titles))];
}
while(!sizeof((string *)titles[gender])) if(++gender > 2) return "";
return (string)titles[gender][next_level];
}
/*** advance levels or stats, and costing ***/
status advance(string str, status costing){
int i, j, k;
string stat;
int total, cost, current_stat;
string tmp1;
if(!guild_master) {
write("There is no one here to train you.\n");
return 1;
}
if(this_player()->query_npc()) {
tell_room(this_object(),G_NAME +" laughs heartily!\n");
return 1;
}
if(!this_player()->query_guild_string()) {
this_player()->set_guild_string("no");
}
if(!(lower_case(guild_name) == "no"
&& (GUILD_STR == "banned" || GUILD_STR == "no"))
|| GUILD_STR != lower_case(guild_name)) {
write(G_NAME +" says: Sorry, you can't train here.\n");
return 1;
}
if(DRAINED) {
write(G_NAME +" says: You have been drained by undead,\n"+
" Perhaps you should see a priest before training.\n");
return 1;
}
if(NO_ADVANCE){
write(G_NAME +" says: You are currently under the affect of"+
" magic, I cannot train you\n until it wears off!\n");
return 1;
}
/*** advance a players level ***/
if(!str || str == "level") {
if(costing) {
write("Next Level: "+ get_next_exp(LEVEL) +" experience points ");
if(EXP > get_next_exp(LEVEL)) {
write("(POSSIBLE)\n");
}
else if(close_enuff(1)) {
write("(POSSIBLE: "+ close_enuff(1) +" coins)\n");
}
else {
write("(NOT POSSIBLE)\n");
}
return 1;
}
if(QPS < get_next_qp(LEVEL)) {
notify_fail(G_NAME+" says: You need more quest points to advance\n");
return 0;
}
if(EXP > get_next_exp(LEVEL) || close_enuff(0)) {
this_player()->set_title(get_new_title(LEVEL));
this_player()->set_level(LEVEL + 1);
this_player()->save_character();
say(G_NAME +" trains "+ NAME +" to level "+ LEVEL +".\n");
write(G_NAME +" trains you. You are now level "+ LEVEL +", "+
(string)this_player()->short()+"\n");
return 1;
}
else {
write(G_NAME+" says: You need to train more before advancing.\n");
return 1;
}
return 1;
}
if(costing) { /* recursively cost a class */
if((i = member_array(str,classes)) != -1) {
for(k = 0; k < sizeof(classes[i+1]); k++) {
advance(classes[i+1][k],1);
}
return 1;
}
}
for(i = 1; i < sizeof(classes); i += 2) {
if((j = member_array(str, classes[i])) != -1) {
if(!this_player()->query_class(classes[i-1])
&& classes[i-1] != "general" && classes[i-1] != "primary") {
write(G_NAME +" says: You are not a "+ classes[i-1] +".\n");
}
else {
stat = str;
while(sscanf(stat,"%s %s",stat,tmp1)) stat += "_"+ tmp1;
stat = lower_case(stat);
current_stat = (int)call_other(this_player(),"query_"+stat);
cost = get_skill_exp(current_stat);
if(member_array(stat, ({ "strength", "intelligence", "wisdom",
"dexterity", "constitution", "charisma",
"combat", })) != -1) {
if(current_stat >= (int)call_other(this_player(), "query_max_"+
stat)) {
write(G_NAME+" says: You are more powerful than I am! I can no "+
"longer train you in "+stat+".\n");
return 1;
}
}
if(!(classes[i-1] == "general" || classes[i-1] == "primary")) {
/* Multi-class multiple exp setting cost; was 3/2 */
if(sizeof((string *)this_player()->query_classes()) == 1)
cost *= 1;
else
cost *= (sizeof((string *)this_player()->query_classes())*3)/2;
}
for(k = 0; k < sizeof(classes[i]); k++) {
stat = classes[i][k];
while(sscanf(stat,"%s %s", stat, tmp1)) stat += "_"+ tmp1;
stat = lower_case(stat);
total += (int)call_other(this_player(),"query_"+ stat);
}
if(total > (LEVEL + 1) * sizeof(classes[i])) {
if(costing) {
write("Your level needs to be higher, before you can advance "+
"your "+ str +".\n");
}
else {
write(G_NAME+" says: You need to be of greater Status.\n");
}
return 1;
}
if(EXP<cost) {
if(costing) {
str = extract(str+" ",0,18);
write(capitalize(str) +"Need "+
(cost-EXP) +" extra experience points.\n");
}
else {
write(G_NAME +" says: You need to be more experienced.\n");
}
return 1;
}
if(costing) {
str = extract(str+" ",0,18);
write(capitalize(str) + cost +" experience points.\n");
return 1;
}
stat = str;
while(sscanf(stat,"%s %s",stat,tmp1)) stat += "_"+ tmp1;
call_other(this_player(),"set_"+ lower_case(stat), current_stat+1);
this_player()->set_exp(EXP-cost);
this_player()->save_character();
if(classes[i-1] == "general" || classes[i-1] == "primary") {
write(G_NAME+" helps you to raise your "+ capitalize(str) +".\n");
}
else {
write(G_NAME+" says: I have trained you in the skill of "+
capitalize(str)+"\nused from "+capitalize(classes[i][j])+".\n");
}
say(NAME +" raises "+ this_player()->query_possessive() +" "+
str +".\n");
}
return 1;
}
}
write(G_NAME + " looks at you in a confused manner.\n");
return 1;
}
/*** Cost for raising skill levels ***/
status cost_for_level(string str){
int i;
if(!guild_master) {
write("There is no one here for you to get a costing opinion.\n");
return 1;
}
if(!str) {
write("cost <class|skill|general|primary|level>\n");
return 1;
}
advance(str,1);
return 1;
}
/*** Leave class ***/
status leave(string str) {
if(!guild_master) {
write("There is no one here to remove your class.\n");
return 1;
}
if(!str) {
write(G_NAME +" says: Leave what class?\n");
return 1;
}
if(member_array(str, classes) == -1) {
write(G_NAME +" says: You can't do that here.\n");
return 1;
}
if(this_player() -> query_class(str)) {
write("You are no longer in the class "+str+".\n");
this_player() -> remove_class(str);
call_other(this_player(),"clear_"+ str);
this_player() -> save_character();
}
else
write("You were not in the class "+ str +".\n");
return 1;
}
/*** Join Class ***/
status join(string str) {
int i;
int cost;
string tmp;
status flag;
cost = (int)this_player()->query_level();
cost *= COST_FOR_JOIN;
if(random(CHARISMA) > random(MASTER_CHA))
cost -= random(cost/4);
else
cost += random(cost/3);
if(!guild_master) {
write("There is no one here to join you up.\n");
return 1;
}
if(!str) {
write(G_NAME +" says: What was that? Join what class?\n");
return 1;
write(G_NAME+" says: It will cost you about "+cost+" for new training.\n");
}
if(member_array(str, classes) == -1 || str == "general" || str == "primary"){
write(G_NAME +" says: I can only train you in ");
for(i = 0; i < sizeof(classes); i += 2) {
if(classes[i] == "general" || classes[i] == "primary") continue;
if(flag && i+2 >= sizeof(classes))
write("and ");
else if(flag)
write(", ");
write(classes[i]);
flag = 1;
}
write(".\n");
return 1;
}
if(this_player()->query_class(str)) {
write(G_NAME+" says: You are already in the class "+ str +".\n");
return 1;
}
write(G_NAME+" says: Taking into account your set ways at your level.\n"+
"\t it will be more difficult to start new training.\n");
tmp = (string)call_other("obj/money", "convert", cost);
write(G_NAME+" haggles with you over the cost of new training.\n");
write(G_NAME+" says: "+
"I will have to charge you "+tmp+" for extra tuition.\n");
if((int)this_player()->query_money() < cost) {
write(G_NAME+" says: Without the money, I can't train you in these "+
"new skills.\n");
return 1;
}
write(G_NAME+" takes "+tmp+" for your new training.\n");
this_player()->add_money(-cost);
write("You are now a member of the class "+str+".\n");
this_player()->add_class(str);
this_player() -> save_character();
return 1;
}
status train_weapon(string str) {
string *weap_list;
object obj;
string weapon;
int prof_rate;
if(!guild_master) {
write("There is no one here to train you.\n");
return 1;
}
if(!(lower_case(guild_name) == "no"
&& (GUILD_STR == "banned" || GUILD_STR == "no"))
|| GUILD_STR != lower_case(guild_name)) {
write(G_NAME +" says: Sorry, you can't train here.\n");
return 1;
}
if(!str) {
write(G_NAME +" says: What weapon do you want to train with?\n");
return 1;
}
obj = present(lower_case(str), this_player());
if(!obj) {
write(G_NAME +" says: You dont have that weapon! \n"+
"\t\tHow can I train you in that!!\n");
return 1;
}
weapon = lower_case((string)obj->query_name());
if(this_player()->query_weapon_proficiency(weapon)) {
write(G_NAME +" says: You already know how to use a "+ weapon +"\n");
return 1;
}
if(!obj->query_wielded()) {
write(G_NAME +" says: You must first be able to wield your "+ weapon +
"before I can teach\n\tyou how to use it properly.\n");
return 1;
}
weap_list = (string *)this_player()->query_weapon_prof();
if(!weap_list) { /* there are still some people with it defaulting to 0 */
weap_list = ({});
this_player()->set_weapon_prof(({}));
}
if(weapon_rate)
prof_rate = weapon_rate; /* guild specific weapon rate */
else if(this_player()->query_class("mage"))
prof_rate = 8;
else if(this_player()->query_class("cleric"))
prof_rate = 6;
else if(this_player()->query_class("thief"))
prof_rate = 4;
else /* fighter */
prof_rate = 2;
if(sizeof(weap_list) > ((LEVEL+2)*4)/prof_rate) {
write(G_NAME +" says: One such as you cannot learn so many weapons "+
" at once time\n\tWait a little longer and return later.\n");
return 1;
}
write(G_NAME +" trains you in the use of the "+ weapon +".\n"+
"You feel more proficient in its use.\n");
say(NAME +" trains with "+ G_NAME +" in use of the "+ weapon +".\n");
this_player()->add_weapon_proficiency(weapon);
return 1;
}
int *get_exp_arr() {
int *tmp;
int n;
tmp = ({});
for(n = 0 ; n < 200; n++) tmp += ({ get_next_exp(n) });
return tmp;
}
int query_no_fight() { return 1; }