#include <iostream> #include <ctime> #include <fstream> #include <vector> #include <cstdlib> using namespace std; #include "merc.h" #include "skill.h" #include "skill_code.h" //lookup table, etc #include "skill_c.include" vector<Skill> SkillTable; //Skill SkillTable[MAX_SKILL]; /*fixme: Program received signal SIGSEGV, Segmentation fault. 0x00000003 in ?? () (gdb) bt #0 0x00000003 in ?? () #1 0x080b51a1 in event_update() () at stl_vector.h:501 #2 0x080b6e80 in update_handler() () at update.c:1144 #3 0x0806f4d6 in game_loop_unix(int) (control=6) at comm.c:860 #4 0x0806f023 in main (argc=2, argv=0xbffff754) at comm.c:464 */ /*****************************************************************************/ /**********************************Class Methods******************************/ /*****************************************************************************/ Skill::Skill(void) { cast_code = pulse_code = upkeep_code = expire_code = NULL; magic_type = magic_level = target = skill_flags = lag = hours = upkeep = gsn = 0; valid = false; for (int i = 0; i < MAX_MAGIC_TYPE; i++) { base_cost[i] = 0; upkeep_cost[i] = 0; } } Skill::Skill(const Skill &SkFoo) { name = SkFoo.name; pulse_self = SkFoo.pulse_self; off_self = SkFoo.off_self; off_room = SkFoo.off_room; upkeep_self = SkFoo.upkeep_self; magic_type = SkFoo.magic_type; magic_level = SkFoo.magic_level; target = SkFoo.target; skill_flags = SkFoo.skill_flags; for (int i = 0; i < MAX_MAGIC_TYPE; i++) { base_cost[i] = SkFoo.base_cost[i]; upkeep_cost[i] = SkFoo.upkeep_cost[i]; } lag = SkFoo.lag; hours = SkFoo.hours; upkeep = SkFoo.upkeep; gsn = SkFoo.gsn; assign_code(gsn); valid = SkFoo.valid; } Skill &Skill::operator= (const Skill &SkFoo) { name = SkFoo.name; pulse_self = SkFoo.pulse_self; off_self = SkFoo.off_self; off_room = SkFoo.off_room; upkeep_self = SkFoo.upkeep_self; magic_type = SkFoo.magic_type; magic_level = SkFoo.magic_level; target = SkFoo.target; skill_flags = SkFoo.skill_flags; for (int i = 0; i < MAX_MAGIC_TYPE; i++) { base_cost[i] = SkFoo.base_cost[i]; upkeep_cost[i] = SkFoo.upkeep_cost[i]; } lag = SkFoo.lag; hours = SkFoo.hours; upkeep = SkFoo.upkeep; gsn = SkFoo.gsn; assign_code(gsn); valid = SkFoo.valid; return *this; } //for STL sort of vector //Less-than method //input: The RHS Skill //output: nothing //returns: True if LHS skill is valid and RHS is not //false cases: V V, V I, I I //only true case: I V (switch) //fixme: newly validated skills are being put infront of already valid skills //fixme fixme fixme fixme 6/26/2004 5:41AM bool Skill::operator< (const Skill &rhsSkill) const { /* if (!valid && rhsSkill.valid) return false; else return true; */ if (valid && !rhsSkill.valid) return true; else return false; } bool Skill::assign_code(const int foo) { bool ret_val = false; //if foo >= COMPILED_MAX_SKILL then it is a new skill that //does not have any functions yet compiled into the game. //You must recompile for newly-added skills to be linked //to their functions. if (foo >= 0 && foo < COMPILED_MAX_SKILL) { //gsn = skill_code_table[foo].gsn; //*gsn = foo; cast_code = skill_code_table[foo].cast_code; pulse_code = skill_code_table[foo].pulse_code; upkeep_code = skill_code_table[foo].upkeep_code; expire_code = skill_code_table[foo].expire_code; ret_val = true; } return ret_val; } bool Skill::validate(void) { ofstream fout_h, fout_c; //have to have this instead of returning just member 'valid' because //after the resort *this skill's gsn changes. bool Validated = false; fout_h.open(SKILLCODE_H_FILE, ofstream::out | ofstream::app); fout_c.open(SKILLCODE_C_FILE, ofstream::out | ofstream::app); if (!valid && fout_h && fout_c) { if (cast_code) { fout_h << "DECLARE_SKILL_FUN( " << name << "_cast_code );" << endl; fout_c << "SKILL_RET " << name << "_cast_code (CHAR_DATA *ch, const char *argument)" << endl << "{" << endl << " return DEFAULT_RETURN;" << endl << "}" << endl << endl; } if (pulse_code) { fout_h << "DECLARE_SKILL_FUN( " << name << "_pulse_code );" << endl; fout_c << "SKILL_RET " << name << "_pulse_code (CHAR_DATA *ch, const char *argument)" << endl << "{" << endl << " return DEFAULT_RETURN;" << endl << "}" << endl << endl; } if (upkeep_code) { fout_h << "DECLARE_SKILL_FUN( " << name << "_upkeep_code );" << endl; fout_c << "SKILL_RET " << name << "_upkeep_code (CHAR_DATA *ch, const char *argument)" << endl << "{" << endl << " return DEFAULT_RETURN;" << endl << "}" << endl << endl; } if (expire_code) { fout_h << "DECLARE_SKILL_FUN( " << name << "_expire_code );" << endl; fout_c << "SKILL_RET " << name << "_expire_code (CHAR_DATA *ch, const char *argument)" << endl << "{" << endl << " return DEFAULT_RETURN;" << endl << "}" << endl << endl; } valid = true; Validated = true; } fout_h << endl; fout_h.close(); fout_c.close(); //required! Pushes newly-validated skill to the top. //if we don't so this, the function lookup table save will fuck up. (sucks!) // //if you wanted to fix this, self, you could use std::map, key = skill's name, //value = functions. fixme! (or 4 maps, one for each func) sort(SkillTable.begin(), SkillTable.end()); //have to re-assign GSNs, sadly. This won't affect previous skills, //just shakes up the invalid skills and newly-validated skill a bit. for (unsigned int indx = 0; indx < SkillTable.size(); indx++) { SkillTable[indx].gsn = indx; } return Validated; } //Ofstream insertion operator //input: Ofstream reference, Skill to insert into the stream //output: Skill to insert into stream //returns: reference to the stream (for chaining: fout << skill << endl) ofstream &operator<<( ofstream &ofs, const Skill &skillin ) { //jh new ofs << "***BEGIN SKILL***" << endl; ofs << "Skill " << skillin.gsn << endl; ofs << skillin.name << endl; ofs << skillin.pulse_self << endl; ofs << skillin.off_self << endl; ofs << skillin.off_room << endl; ofs << skillin.upkeep_self << endl; ofs << skillin.magic_type << endl; ofs << skillin.magic_level << endl; ofs << skillin.target << endl; ofs << skillin.skill_flags << endl; for (int i = 0; i < MAX_MAGIC_TYPE; i++) { ofs << skillin.base_cost[i] << " "; } ofs << endl; for (int i = 0; i < MAX_MAGIC_TYPE; i++) { ofs << skillin.upkeep_cost[i] << " "; } ofs << endl; ofs << skillin.lag << endl; ofs << skillin.hours << endl; ofs << skillin.upkeep << endl; return ofs; } //Ifstream extraction operator //input: Ifstream reference, Skill to extract out of the stream //output: nothing //returns: reference to the stream (for chaining: fin >> skill >> whatever) ifstream &operator>>( ifstream &ifs, Skill &skillin ) { string parse = ""; //cleanup (JH new 6/26/2004 8:25PM) while (parse != "***BEGIN SKILL***") getline(ifs, parse); //"Skill 6" <-- 6 = gsn getline(ifs, parse); parse.erase(0, 6); skillin.gsn = atoi (parse.c_str()); getline(ifs, skillin.name); //hack getline(ifs, skillin.pulse_self); if (skillin.pulse_self.length() < 3) skillin.pulse_self = ""; //hack getline(ifs, skillin.off_self); if (skillin.off_self.length() < 3) skillin.off_self = ""; //hack getline(ifs, skillin.off_room); if (skillin.off_room.length() < 3) skillin.off_room = ""; //hack getline(ifs, skillin.upkeep_self); if (skillin.upkeep_self.length() < 3) skillin.upkeep_self = ""; ifs >> skillin.magic_type; ifs >> skillin.magic_level; ifs >> skillin.target; ifs >> skillin.skill_flags; for (int i = 0; i < MAX_MAGIC_TYPE; i++) { ifs >> skillin.base_cost[i]; } for (int i = 0; i < MAX_MAGIC_TYPE; i++) { ifs >> skillin.upkeep_cost[i]; } ifs >> skillin.lag; ifs >> skillin.hours; ifs >> skillin.upkeep; //assign gsn and other misc. skillin.assign_code(skillin.gsn); skillin.valid = true; return ifs; } /*****************************************************************************/ /**********************************Utility functions**************************/ /*****************************************************************************/ int save_skills (void) { ofstream fout(SKILL_FILE); //how many skills will we end up having? We don't save invalid skills. int skill_count = 0; unsigned int indx; if (!fout) { bugf("Cannot open %s to write skills.", SKILL_FILE); return 1; } fout << "SkullMUD Skills Data V1.0" << endl; fout << "*************************" << endl; for (indx = 0; indx < SkillTable.size(); indx++) { if (SkillTable[indx].valid) { fout << SkillTable[indx]; skill_count++; } } fout.close(); save_include_files(skill_count); return 0; } int load_skills (void) { char buf[MSL]; Skill SkillLoad; ifstream fin(SKILL_FILE); if (!fin) { bugf("Cannot open %s to load skills.", SKILL_FILE); return 0; } //snatch first couple of lines. fin.getline(buf, MSL); fin.getline(buf, MSL); //Now let the skill's methods do the rest. for (int sk_ref = 0; sk_ref < MAX_SKILL; sk_ref++) { writelogf("Loading skill %d...", sk_ref); fin >> SkillLoad; if (!fin.good()) { bugf("ERROR: %s is corrupt.", SKILL_FILE); bugf("Skill %d will be discarded.", sk_ref); break; } SkillTable.push_back(SkillLoad); writelogf("[test] SkillTable[%d].name = %s", sk_ref, SkillTable[sk_ref].name.c_str()); } fin.close(); return SkillTable.size(); }; //Save include files int save_include_files(const int skill_count) { //Save skill.c include first. /**********************************************************************/ ofstream fout(SKILLINCLUDE_C_FILE); if (!fout) { bugf("Cannot open %s to write skills", SKILLINCLUDE_C_FILE); return 1; } fout << endl; //write table fout << "const struct skill_code_type skill_code_table[] = " << endl << "{" << endl; for (unsigned int i = 0; i < SkillTable.size(); i++) { if (!SkillTable[i].valid) continue; fout << " {\"" << SkillTable[i].name << "\", "; //validity check: new code and some other skills won't actually //have all 4 functions. I check for that here. if (SkillTable[i].cast_code) fout << SkillTable[i].name << "_cast_code, "; else fout << "NULL, "; if (SkillTable[i].pulse_code) fout << SkillTable[i].name << "_pulse_code, "; else fout << "NULL, "; if (SkillTable[i].upkeep_code) fout << SkillTable[i].name << "_upkeep_code, "; else fout << "NULL, "; if (SkillTable[i].expire_code) fout << SkillTable[i].name << "_expire_code"; else fout << "NULL"; /* if (i == SkillTable.size() - 1) fout << "}" << endl; else fout << "}," << endl; */ //JH rewrote above if (i == SkillTable.size() - 1 || !SkillTable[i + 1].valid) fout << "}" << endl; else fout << "}," << endl; } fout << "};" << endl << endl; //write MAX_SKILL //MAX_SKILL is allowed to be actively changed in-game. fout << "int MAX_SKILL = " << skill_count << ";" << endl << endl; //Write compiled, this is used to ensure the copy constructor doesn't //call assign_code for a non-existent entry in the function table. //Doing so would result in a seg fault. //Sadly, you must recompile to add in said functions. fout << "const int COMPILED_MAX_SKILL = " << skill_count << ";" << endl << endl; fout.close(); //hack: had to do this because, well, fuck. system( "touch ../src/skill*" ); return 0; } int find_skill(const char *argument) { int ret_skill = -1; unsigned int indx; for (indx = 0; indx < SkillTable.size(); indx++) { if (SkillTable[indx].name == argument) ret_skill = SkillTable[indx].gsn; } return ret_skill; } /*****************************************************************************/ /****************************Skill-related functions**************************/ /*****************************************************************************/ bool fail_upkeep_cost(CHAR_DATA *caster, int iskill) { bool bFail = false; for (int i = 0; i < MAX_MAGIC_TYPE; i++) { //if not enough mana, the affect/spell will fail if ((caster->magic_points[i] - SkillTable[iskill].upkeep_cost[i]) < 0) bFail = true; caster->magic_points[i] = UMAX(0, (caster->magic_points[i] - SkillTable[iskill].upkeep_cost[i])); } return bFail; } void do_cast (CHAR_DATA *ch, char *argument) { char arg_spell[MIL], arg_targ[MIL]; argument = one_argument( argument, arg_spell); argument = one_argument( argument, arg_targ ); //lookup spell by name, get its || start here 6/14/2004 11:50PM }