// file: newdb.cpp // author: Andrew Hynek // contents: implementation of the index classes #include <unistd.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <time.h> #include "structs.h" #include "newdb.h" #include "db.h" #include "comm.h" // for shutdown() #include "file.h" #include "utils.h" #include "memory.h" #include "handler.h" #include "vtable.h" #include "constants.h" #include "interpreter.h" // for alias extern void kill_ems(char *); static const char *const INDEX_FILENAME = "etc/pfiles/index"; extern char *cleanup(char *dest, const char *src); // ____________________________________________________________________________ // // global variables // ____________________________________________________________________________ PCIndex playerDB; // ____________________________________________________________________________ // // PCIndex -- the PC database class: implementation // ____________________________________________________________________________ int entry_compare(const void *one, const void *two) { PCIndex::entry *ptr1 = (PCIndex::entry *)one; PCIndex::entry *ptr2 = (PCIndex::entry *)two; if (ptr1->id < ptr2->id) return -1; else if (ptr1->id > ptr2->id) return 1; return 0; } static void init_char(struct char_data * ch) { int i; /* create a player_special structure */ if (ch->player_specials == NULL) { ch->player_specials = new player_special_data; } ch->player_specials->saved.freeze_level = 0; ch->player_specials->saved.invis_level = 0; ch->player_specials->saved.incog_level = 0; ch->player_specials->saved.wimp_level = 0; ch->player_specials->saved.bad_pws = 0; set_title(ch, NULL); GET_LOADROOM(ch) = NOWHERE; GET_WAS_IN(ch) = NOWHERE; ch->player.time.birth = time(0); ch->player.time.played = 0; ch->player.time.logon = time(0); ch->player.time.lastdisc = time(0); ch->player.weight = (int)gen_size(GET_RACE(ch), 0, 3, GET_SEX(ch)); ch->player.height = (int)gen_size(GET_RACE(ch), 1, 3, GET_SEX(ch)); ch->points.max_mental = 1000; ch->points.max_physical = 1000; ch->points.mental = GET_MAX_MENTAL(ch); ch->points.physical = GET_MAX_PHYSICAL(ch); GET_BALLISTIC(ch) = GET_TOTALBAL(ch) = GET_IMPACT(ch) = GET_TOTALIMP(ch) = 0; ch->points.sustained[0] = 0; ch->points.sustained[1] = 0; ch->points.grade = 0; if (access_level(ch, LVL_VICEPRES)) { GET_COND(ch, FULL) = -1; GET_COND(ch, THIRST) = -1; GET_COND(ch, DRUNK) = -1; } else { GET_COND(ch,FULL) = 24; GET_COND(ch, THIRST) = 24; GET_COND(ch, DRUNK) = 0; } if (!access_level(ch, LVL_VICEPRES)) for (i = 1; i <= MAX_SKILLS; i++) { SET_SKILL(ch, i, 0) } else for (i = 1; i <= MAX_SKILLS; i++) { SET_SKILL(ch, i, 100); } ch->char_specials.saved.affected_by.Clear(); } static void init_char_strings(char_data *ch) { if (ch->player.physical_text.keywords) delete [] ch->player.physical_text.keywords; size_t len = strlen(GET_CHAR_NAME(ch)) + 1; // + strlen(race) + 2; ch->player.physical_text.keywords = new char[len]; strcpy(ch->player.physical_text.keywords, GET_CHAR_NAME(ch)); *(ch->player.physical_text.keywords) = LOWER(*ch->player.physical_text.keywords); if (ch->player.physical_text.name) delete [] ch->player.physical_text.name; if (ch->player.physical_text.room_desc) delete [] ch->player.physical_text.room_desc; if (ch->player.background) delete [] ch->player.background; if (ch->player.physical_text.look_desc) delete [] ch->player.physical_text.look_desc; { char temp[256]; sprintf(temp, "A %s %s", genders[(int)GET_SEX(ch)], pc_race_types[(int)GET_RACE(ch)]); ch->player.physical_text.name = str_dup(temp); sprintf(temp, "A %s %s voice.", genders[(int)GET_SEX(ch)], pc_race_types[(int)GET_RACE(ch)]); ch->player.physical_text.room_desc = str_dup(temp); ch->player.physical_text.look_desc = str_dup("A fairly nondescript thing.\n"); ch->player.background = str_dup("A boring character.\n"); } set_title(ch, "^y(Newbie)^n"); set_pretitle(ch, NULL); set_whotitle(ch, " New "); switch(GET_RACE(ch)) { case RACE_HUMAN: set_whotitle(ch, "Human"); break; case RACE_DWARF: set_whotitle(ch, "Dwarf"); break; case RACE_ELF: set_whotitle(ch, "Elf"); break; case RACE_ORK: set_whotitle(ch, "Ork"); break; case RACE_TROLL: set_whotitle(ch, "Troll"); break; case RACE_CYCLOPS: set_whotitle(ch, "Cyclops"); break; case RACE_KOBOROKURU: set_whotitle(ch, "Koborokuru"); break; case RACE_FOMORI: set_whotitle(ch, "Fomori"); break; case RACE_MENEHUNE: set_whotitle(ch, "Menehune"); break; case RACE_HOBGOBLIN: set_whotitle(ch, "Hobgoblin"); break; case RACE_GIANT: set_whotitle(ch, "Giant"); break; case RACE_GNOME: set_whotitle(ch, "Gnome"); break; case RACE_ONI: set_whotitle(ch, "Oni"); break; case RACE_WAKYAMBI: set_whotitle(ch, "Wakyambi"); break; case RACE_OGRE: set_whotitle(ch, "Ogre"); break; case RACE_MINOTAUR: set_whotitle(ch, " Minotaur"); break; case RACE_SATYR: set_whotitle(ch, "Satyr"); break; case RACE_NIGHTONE: set_whotitle(ch, "Night-One"); break; case RACE_DRYAD: set_whotitle(ch, "Dryad"); break; case RACE_DRAGON: set_whotitle(ch, "Dragon"); break; default: mudlog("No race found at set_whotitle in class.cc", NULL, LOG_SYSLOG, TRUE); set_whotitle(ch, "CHKLG"); /* Will set incase the players */ } /* race is undeterminable */ GET_PROMPT(ch) = str_dup("< @pP @mM > "); ch->player.matrixprompt = str_dup("< @pP @mM > "); } /* Some initializations for characters, including initial skills */ void do_start(struct char_data * ch) { void advance_level(struct char_data * ch); GET_LEVEL(ch) = 1; GET_KARMA(ch) = 0; GET_REP(ch) = 0; GET_NOT(ch) = 0; GET_TKE(ch) = 0; ch->points.max_physical = 1000; ch->points.max_mental = 1000; ch->char_specials.saved.left_handed = (!number(0, 9) ? 1 : 0); GET_WIELDED(ch, 0) = 0; GET_WIELDED(ch, 1) = 0; advance_level(ch); GET_PHYSICAL(ch) = GET_MAX_PHYSICAL(ch); GET_MENTAL(ch) = GET_MAX_MENTAL(ch); GET_COND(ch, THIRST) = 24; GET_COND(ch, FULL) = 24; GET_COND(ch, DRUNK) = 0; GET_LOADROOM(ch) = 8039; PLR_FLAGS(ch).SetBit(PLR_NEWBIE); PRF_FLAGS(ch).SetBits(PRF_AUTOEXIT, PRF_LONGEXITS, ENDBIT); PLR_FLAGS(ch).SetBit(PLR_AUTH); ch->player.time.played = 0; ch->player.time.logon = time(0); ch->player.time.lastdisc = time(0); } /* Gain maximum in various points */ void advance_level(struct char_data * ch) { int i; if (IS_SENATOR(ch)) { for (i = 0; i < 3; i++) GET_COND(ch, i) = (char) -1; GET_KARMA(ch) = 0; GET_REP(ch) = 0; GET_TKE(ch) = 0; GET_NOT(ch) = 0; if (PRF_FLAGGED(ch, PRF_PKER)) PRF_FLAGS(ch).RemoveBit(PRF_PKER); PRF_FLAGS(ch).SetBits(PRF_HOLYLIGHT, PRF_ROOMFLAGS, PRF_NOHASSLE, ENDBIT); } playerDB.SaveChar(ch); playerDB.Update(ch); sprintf(buf, "%s advanced to %s.", GET_CHAR_NAME(ch), status_ratings[(int)GET_LEVEL(ch)]); mudlog(buf, ch, LOG_MISCLOG, TRUE); } static bool load_char(const char *name, char_data *ch, bool logon) { File fl; int i; char filename[MAX_STRING_LENGTH]; char buf[MAX_STRING_LENGTH], bits[MAX_STRING_LENGTH]; for (i = 0;(*(bits + i) = LOWER(*(name + i))); i++) ; sprintf(filename, "%s%s%c%s%s%s", PLR_PREFIX, SLASH, *bits, SLASH, bits, PLR_SUFFIX); fl.Open(filename, "r"); if (!fl.IsOpen()) { sprintf(buf, "SYSERR: Couldn't open player file %s", filename); mudlog(buf, NULL, LOG_SYSLOG, TRUE); return false; } VTable data; data.Parse(&fl); fl.Close(); /* character initializations */ /* initializations necessary to keep some things straight */ init_char(ch); for(i = 1; i <= MAX_SKILLS; i++) GET_SKILL(ch, i) = 0; ch->char_specials.carry_weight = 0; ch->char_specials.carry_items = 0; GET_BALLISTIC(ch) = GET_TOTALBAL(ch) = GET_IMPACT(ch) = GET_TOTALIMP(ch) = 0; ch->points.init_dice = 0; ch->points.init_roll = 0; ch->points.sustained[1] = 0; ch->points.sustained[0] = 0; GET_LAST_TELL(ch) = NOBODY; if (!data.GetString("Character", NULL)) { sprintf(buf, "Error: no character name in %s", filename); mudlog(buf, NULL, LOG_SYSLOG, true); return false; } else if (!data.GetString("Password", NULL)) { sprintf(buf, "Error: no password in %s", filename); mudlog(buf, NULL, LOG_SYSLOG, true); return false; } ch->player.char_name = str_dup(data.GetString("Character", NULL)); memset(GET_PASSWD(ch), 0, MAX_PWD_LENGTH); strncpy(GET_PASSWD(ch), data.GetString("Password", NULL), MAX_PWD_LENGTH); GET_RACE(ch) = data.LookupInt("Race", pc_race_types, RACE_HUMAN); GET_SEX(ch) = data.LookupInt("Gender", genders, SEX_NEUTRAL); GET_LEVEL(ch) = data.LookupInt("Rank", status_ratings, 0); AFF_FLAGS(ch).FromString(data.GetString("AffFlags", "0")); PLR_FLAGS(ch).FromString(data.GetString("PlrFlags", "0")); PRF_FLAGS(ch).FromString(data.GetString("PrfFlags", "0")); { // player text text_data *text_tab[3] = { &ch->player.physical_text, &ch->player.astral_text, &ch->player.matrix_text }; const char *section_tab[3] = { "PHYSICAL TEXT", "ASTRAL TEXT", "MATRIX TEXT" }; for (int i = 0; i < 3; i++) { if (data.DoesSectionExist(section_tab[i])) { text_data *ptr = text_tab[i]; char field[128], defawlt[128]; sprintf(field, "%s/Keywords", section_tab[i]); ptr->keywords = str_dup(data.GetString(field, GET_CHAR_NAME(ch))); sprintf(field, "%s/Name", section_tab[i]); ptr->name = str_dup(data.GetString(field, GET_CHAR_NAME(ch))); sprintf(defawlt, "An internal error occurred, but %s is here.\n", GET_CHAR_NAME(ch)); sprintf(field, "%s/RoomDesc", section_tab[i]); ptr->room_desc = str_dup(data.GetString(field, defawlt)); sprintf(field, "%s/LookDesc", section_tab[i]); ptr->look_desc = str_dup(data.GetString(field, defawlt)); } } } { // miscellaneous text POOFIN(ch) = str_dup(data.GetString("MISC TEXT/PoofIn", NULL)); POOFOUT(ch) = str_dup(data.GetString("MISC TEXT/PoofOut", NULL)); GET_TITLE(ch) = str_dup(data.GetString("MISC TEXT/Title", NULL)); GET_PRETITLE(ch) = str_dup(data.GetString("MISC TEXT/Pretitle", NULL)); GET_WHOTITLE(ch) = str_dup(data.GetString("MISC TEXT/Whotitle", NULL)); ch->player.prompt = str_dup(data.GetString("MISC TEXT/Prompt", NULL)); ch->player.matrixprompt = str_dup(data.GetString("MISC TEXT/MatrixPrompt", NULL)); ch->player.host = str_dup(data.GetString("MISC TEXT/Host", NULL)); ch->player.background = str_dup(data.GetString("MISC TEXT/Background", "A boring character.\n")); } { // attributes GET_REAL_BOD(ch) = data.GetInt("ATTRIBUTES/Bod", 1); GET_REAL_QUI(ch) = data.GetInt("ATTRIBUTES/Qui", 1); GET_REAL_STR(ch) = data.GetInt("ATTRIBUTES/Str", 1); GET_REAL_CHA(ch) = data.GetInt("ATTRIBUTES/Cha", 1); GET_REAL_INT(ch) = data.GetInt("ATTRIBUTES/Int", 1); GET_REAL_WIL(ch) = data.GetInt("ATTRIBUTES/Wil", 1); ch->real_abils.mag = data.GetInt("ATTRIBUTES/Mag", 0); GET_PP(ch) = data.GetInt("ATTRIBUTES/PowerPoints", ch->real_abils.mag); ch->real_abils.ess = data.GetInt("ATTRIBUTES/EssenceTotal", 600); ch->real_abils.esshole = data.GetInt("ATTRIBUTES/EssenceHole", 0); ch->real_abils.bod_index = data.GetInt("ATTRIBUTES/BiowarIndex", 0); ch->real_abils.highestindex = data.GetInt("ATTRIBUTES/HighestIndex", 0); GET_REAL_REA(ch) = (GET_REAL_QUI(ch) + GET_REAL_INT(ch)) / 2; } { ch->real_abils.defense_pool = data.GetInt("POOLS/Dodge", 0); ch->real_abils.body_pool = data.GetInt("POOLS/Body", 0); ch->real_abils.hacking_pool_max = data.GetInt("POOLS/MaxHacking", 0); ch->real_abils.casting_pool = data.GetInt("POOLS/Casting", 0); ch->real_abils.drain_pool = data.GetInt("POOLS/Drain", 0); ch->real_abils.spell_defense_pool = data.GetInt("POOLS/SpellDefense", 0); ch->real_abils.reflection_pool = data.GetInt("POOLS/Reflecting", 0); } ch->aff_abils = ch->real_abils; { // points GET_HEIGHT(ch) = data.GetInt("POINTS/Height", 150); GET_WEIGHT(ch) = data.GetInt("POINTS/Weight", 70); GET_TRADITION(ch) = data.GetInt("POINTS/Tradition", TRAD_MUNDANE); GET_ASPECT(ch) = data.GetInt("POINTS/Aspect", ASPECT_FULL); GET_TOTEM(ch) = data.GetInt("POINTS/Totem", TOTEM_UNDEFINED); GET_TOTEMSPIRIT(ch) = data.GetInt("POINTS/TotemSpirit", 0); GET_NUYEN(ch) = data.GetInt("POINTS/Cash", 0); GET_BANK(ch) = data.GetInt("POINTS/Bank", 0); GET_KARMA(ch) = data.GetInt("POINTS/Karma", 0); GET_REP(ch) = data.GetInt("POINTS/Rep", 0); GET_TKE(ch) = data.GetInt("POINTS/TKE", 0); GET_NOT(ch) = data.GetInt("Points/Notoriety", 0); GET_SIG(ch) = data.GetInt("POINTS/Sig", 0); GET_GRADE(ch) = data.GetInt("POINTS/UsedGrade", 0); ch->points.extrapp = data.GetInt("POINTS/ExtraPower", 0); GET_PHYSICAL(ch) = data.GetInt("POINTS/Physical", 1000); GET_PHYSICAL_LOSS(ch) = data.GetInt("POINTS/PhysicalLoss", 0); GET_MENTAL(ch) = data.GetInt("POINTS/Mental", 1000); GET_MENTAL_LOSS(ch) = data.GetInt("POINTS/MentalLoss", 0); GET_PERM_BOD_LOSS(ch) = data.GetInt("POINTS/PermBodLoss", 0); GET_CENTERINGSKILL(ch) = data.GetInt("POINTS/Centering", 0); if (PLR_FLAGGED(ch, PLR_AUTH)) { GET_ATT_POINTS(ch) = data.GetInt("POINTS/AttPoints", 0); GET_SKILL_POINTS(ch) = data.GetInt("POINTS/SkillPoints", 0); GET_FORCE_POINTS(ch) = data.GetInt("POINTS/ForcePoints", 0); GET_RESTRING_POINTS(ch) = data.GetInt("POINTS/RestringPoints", 0); } ch->player_specials->saved.zonenum = data.GetInt("POINTS/ZoneNumber", 0); ch->player_specials->saved.wimp_level = data.GetInt("POINTS/WimpLevel", 0); ch->player_specials->saved.freeze_level = data.GetInt("POINTS/FreezeLevel", 0); ch->player_specials->saved.invis_level = data.GetInt("POINTS/InvisLevel", 0); ch->player_specials->saved.incog_level = data.GetInt("POINTS/IncogLevel", 0); ch->player_specials->saved.bad_pws = data.GetInt("POINTS/BadPWs", 0); ch->player_specials->saved.load_room = data.GetLong("POINTS/LoadRoom", NOWHERE); ch->player_specials->saved.last_in = data.GetLong("POINTS/LastRoom", NOWHERE); GET_LASTROOM(ch) = data.GetLong("POINTS/Home", NOWHERE); ch->char_specials.saved.left_handed = data.GetInt("POINTS/LeftHanded", 0); ch->char_specials.arrive = str_dup(data.GetString("POINTS/ArriveText", NULL)); ch->char_specials.leave = str_dup(data.GetString("POINTS/LeaveText", NULL)); GET_LANGUAGE(ch) = data.GetInt("POINTS/CurLang", SKILL_ENGLISH); GET_MASKING(ch) = data.GetInt("POINTS/Masking", 0); if (GET_LANGUAGE(ch) == 0) { GET_SKILL(ch, SKILL_ENGLISH) = 10; GET_LANGUAGE(ch) = SKILL_ENGLISH; } if (GET_LANGUAGE(ch) < SKILL_ENGLISH) GET_LANGUAGE(ch) = SKILL_ENGLISH; ch->player.time.lastdisc = data.GetLong("POINTS/LastD", time(NULL)); ch->player.time.logon = data.GetLong("POINTS/Last", time(NULL)); ch->player.time.birth = data.GetLong("POINTS/Born", time(NULL)); ch->player.time.played = data.GetInt("POINTS/Played", 0); } { // conditions GET_COND(ch, FULL) = data.GetInt("CONDITIONS/Hunger", 0); GET_COND(ch, THIRST) = data.GetInt("CONDITIONS/Thirst", 0); GET_COND(ch, DRUNK) = data.GetInt("CONDITIONS/Drunk", 0); } if (GET_LEVEL(ch) == LVL_MORTAL) { // Drugs GET_DRUG_STAGE(ch) = data.GetInt("DRUGS/Stage", 0); GET_DRUG_DURATION(ch) = data.GetInt("DRUGS/Duration", 0); GET_DRUG_AFFECT(ch) = data.GetInt("DRUGS/Affect", 0); GET_DRUG_DOSE(ch) = data.GetInt("DRUGS/Dose", 0); for (int i = 0; i < NUM_DRUGS - 1;) { const char *sect_name = data.GetIndexSection("DRUGS", i); sprintf(buf, "%s/Addict", sect_name); GET_DRUG_ADDICT(ch, ++i) = data.GetInt(buf, 0); sprintf(buf, "%s/Doses", sect_name); GET_DRUG_DOSES(ch, i) = data.GetInt(buf, 0); sprintf(buf, "%s/Edge", sect_name); GET_DRUG_EDGE(ch, i) = data.GetInt(buf, 0); sprintf(buf, "%s/LastFix", sect_name); GET_DRUG_LASTFIX(ch, i) = data.GetInt(buf, 0); sprintf(buf, "%s/Addtime", sect_name); GET_DRUG_ADDTIME(ch, i) = data.GetInt(buf, 0); sprintf(buf, "%s/Tolerant", sect_name); GET_DRUG_TOLERANT(ch, i) = data.GetInt(buf, 0); sprintf(buf, "%s/LastWith", sect_name); GET_DRUG_LASTWITH(ch, i) = data.GetInt(buf, 0); } } { // skills const int num_skills = data.NumFields("SKILLS"); for (int j = 0; j < num_skills; j++) { const char *skill_name = data.GetIndexField("SKILLS", j); int idx; for (idx = 0; idx <= MAX_SKILLS; idx++) if (!str_cmp(skills[idx].name, skill_name)) break; if (idx > 0 && idx <= MAX_SKILLS) GET_SKILL(ch, idx) = data.GetIndexInt("SKILLS", j, 0); } } { const int num_skills = data.NumFields("POWERS"); for (int j = 0; j < num_skills; j++) { const char *skill_name = data.GetIndexField("POWERS", j); int idx; for (idx = 1; idx <= ADEPT_NUMPOWER; idx++) if (!str_cmp(adept_powers[idx], skill_name)) break; GET_POWER_TOTAL(ch, idx) = data.GetIndexInt("POWERS", j, 0); } } { const int num_skills = data.NumFields("METAMAGIC"); for (int j = 0; j < num_skills; j++) { const char *skill_name = data.GetIndexField("METAMAGIC", j); int idx; for (idx = 0; idx <= META_MAX; idx++) if (!str_cmp(metamagic[idx], skill_name)) break; GET_METAMAGIC(ch, idx) = data.GetIndexInt("METAMAGIC", j, 0); } } { // spells const int num_spells = data.NumSubsections("SPELL"); for (int j = 0; j < num_spells; j++) { const char *sect_name = data.GetIndexSection("SPELL", j); char field[128]; spell_data *spell = new spell_data; sprintf(field, "%s/Name", sect_name); spell->name = str_dup(data.GetString(field, "An unnamed spell")); sprintf(field, "%s/Type", sect_name); spell->type = data.GetInt(field, 0); sprintf(field, "%s/SubType", sect_name); spell->subtype = data.GetInt(field, 0); sprintf(field, "%s/Force", sect_name); spell->force = data.GetInt(field, 1); spell->next = ch->spells; ch->spells = spell; } } { const int num_spirits = data.NumSubsections("SPIRITS"); struct spirit_data *last = NULL; for (int j = 0; j < num_spirits; j++) { const char *sect_name = data.GetIndexSection("SPIRITS", j); char field[128]; spirit_data *spirit = new spirit_data; sprintf(field, "%s/Type", sect_name); spirit->type = data.GetInt(field, 0); sprintf(field, "%s/Services", sect_name); spirit->services = data.GetInt(field, 0); sprintf(field, "%s/Idnum", sect_name); spirit->id = data.GetInt(field, 0); sprintf(field, "%s/Force", sect_name); spirit->force = data.GetInt(field, 0); if (last) last->next = spirit; else GET_SPIRIT(ch) = spirit; GET_NUM_SPIRITS(ch)++; last = spirit; } } STOP_WORKING(ch); AFF_FLAGS(ch).RemoveBits(AFF_MANNING, AFF_RIG, AFF_PILOT, AFF_BANISH, AFF_FEAR, AFF_STABILIZE, AFF_SPELLINVIS, AFF_SPELLIMPINVIS, AFF_DETOX, AFF_RESISTPAIN, AFF_TRACKING, AFF_TRACKED, ENDBIT); PLR_FLAGS(ch).RemoveBits(PLR_REMOTE, PLR_SWITCHED, PLR_MATRIX, PLR_PROJECT, PLR_EDITING, PLR_WRITING, PLR_PERCEIVE, PLR_VISA, ENDBIT); { // aliases const int num_aliaii = data.NumFields("ALIASES"); for (int j = 0; j < num_aliaii; j++) { alias *a = new alias; a->command = str_dup(data.GetIndexField("ALIASES", j)); a->replacement = str_dup(data.GetIndexString("ALIASES", j, NULL)); if (strchr(a->replacement, ALIAS_SEP_CHAR) || strchr(a->replacement, ALIAS_VAR_CHAR)) a->type = ALIAS_COMPLEX; else a->type = ALIAS_SIMPLE; a->next = GET_ALIASES(ch); GET_ALIASES(ch) = a; } } { const int num_mem = data.NumFields("MEMORY"); for (int j = 0; j < num_mem; j++) { remem *a = new remem; a->mem = str_dup(data.GetIndexField("MEMORY", j)); a->idnum = atol(data.GetIndexString("MEMORY", j, NULL)); a->next = GET_MEMORY(ch); GET_MEMORY(ch) = a; } } { char field[128]; for (int j = 0; j <= QUEST_TIMER - 1; j++) { sprintf(field, "QUESTS/Quest %d", j); GET_LQUEST(ch, j) = data.GetInt(field, 0); } } { struct obj_data *obj = NULL, *last_obj = NULL; struct phone_data *k; long vnum; int inside = 0, last_in = 0; int num_objs = data.NumSubsections("WORN"); for (int i = 0; i < num_objs; i++) { const char *sect_name = data.GetIndexSection("WORN", i); sprintf(buf, "%s/Vnum", sect_name); vnum = data.GetLong(buf, 0); if (vnum > 0 && (obj = read_object(vnum, VIRTUAL))) { sprintf(buf, "%s/Name", sect_name); obj->restring = str_dup(data.GetString(buf, NULL)); sprintf(buf, "%s/Photo", sect_name); obj->photo = str_dup(data.GetString(buf, NULL)); for (int x = 0; x < 10; x++) { sprintf(buf, "%s/Value %d", sect_name, x); GET_OBJ_VAL(obj, x) = data.GetInt(buf, GET_OBJ_VAL(obj, x)); } if (GET_OBJ_TYPE(obj) == ITEM_PHONE && GET_OBJ_VAL(obj, 2) && !logon) { sprintf(buf, "%04d%04d", GET_OBJ_VAL(obj, 0), GET_OBJ_VAL(obj, 1)); k = new phone_data; k->number = atoi(buf); k->phone = obj; k->rtg = GET_OBJ_VAL(obj, 8); if (phone_list) k->next = phone_list; phone_list = k; } else if (GET_OBJ_TYPE(obj) == ITEM_PHONE && GET_OBJ_VAL(obj, 2)) GET_OBJ_VAL(obj, 9) = 1; if (GET_OBJ_TYPE(obj) == ITEM_FOCUS && GET_OBJ_VAL(obj, 0) == FOCI_SUSTAINED) GET_OBJ_VAL(obj, 4) = 0; if (GET_OBJ_TYPE(obj) == ITEM_FOCUS && GET_OBJ_VAL(obj, 4)) GET_FOCI(ch)++; sprintf(buf, "%s/Condition", sect_name); GET_OBJ_CONDITION(obj) = data.GetInt(buf, GET_OBJ_CONDITION(obj)); sprintf(buf, "%s/Cost", sect_name); GET_OBJ_COST(obj) = data.GetInt(buf, 1); sprintf(buf, "%s/Timer", sect_name); GET_OBJ_TIMER(obj) = data.GetInt(buf, 0); sprintf(buf, "%s/Attempt", sect_name); GET_OBJ_ATTEMPT(obj) = data.GetInt(buf, 0); // sprintf(buf, "%s/ExtraFlags", sect_name); // GET_OBJ_EXTRA(obj).FromString(data.GetString(buf, "0")); sprintf(buf, "%s/Inside", sect_name); inside = data.GetInt(buf, 0); if (inside > 0) { if (inside == last_in) last_obj = last_obj->in_obj; else if (inside < last_in) while (inside <= last_in) { last_obj = last_obj->in_obj; last_in--; } if (last_obj) obj_to_obj(obj, last_obj); } else { sprintf(buf, "%s/Worn", sect_name); equip_char(ch, obj, data.GetInt(buf, 0)); } last_in = inside; last_obj = obj; } } } { struct obj_data *last_obj = NULL, *obj; struct phone_data *k; int vnum = 0; int inside = 0, last_in = 0; int num_objs = data.NumSubsections("INV"); for (int j = 0; j < num_objs; j++) { const char *sect_name = data.GetIndexSection("INV", j); sprintf(buf, "%s/Vnum", sect_name); vnum = data.GetLong(buf, 0); if (vnum > 0 && (obj = read_object(vnum, VIRTUAL))) { sprintf(buf, "%s/Name", sect_name); obj->restring = str_dup(data.GetString(buf, NULL)); sprintf(buf, "%s/Photo", sect_name); obj->photo = str_dup(data.GetString(buf, NULL)); for (int x = 0; x < 10; x++) { sprintf(buf, "%s/Value %d", sect_name, x); GET_OBJ_VAL(obj, x) = data.GetInt(buf, GET_OBJ_VAL(obj, x)); } if (GET_OBJ_TYPE(obj) == ITEM_PHONE && GET_OBJ_VAL(obj, 2) && !logon) { sprintf(buf, "%04d%04d", GET_OBJ_VAL(obj, 0), GET_OBJ_VAL(obj, 1)); k = new phone_data; k->number = atoi(buf); k->phone = obj; k->rtg = GET_OBJ_VAL(obj, 8); if (phone_list) k->next = phone_list; phone_list = k; } else if (GET_OBJ_TYPE(obj) == ITEM_PHONE && GET_OBJ_VAL(obj, 2)) GET_OBJ_VAL(obj, 9) = 1; if (GET_OBJ_TYPE(obj) == ITEM_FOCUS && GET_OBJ_VAL(obj, 0) == FOCI_SUSTAINED) GET_OBJ_VAL(obj, 4) = 0; if (GET_OBJ_TYPE(obj) == ITEM_FOCUS && GET_OBJ_VAL(obj, 4)) GET_FOCI(ch)++; sprintf(buf, "%s/Condition", sect_name); GET_OBJ_CONDITION(obj) = data.GetInt(buf, GET_OBJ_CONDITION(obj)); sprintf(buf, "%s/Cost", sect_name); GET_OBJ_COST(obj) = data.GetInt(buf, 1); sprintf(buf, "%s/Timer", sect_name); GET_OBJ_TIMER(obj) = data.GetInt(buf, 0); sprintf(buf, "%s/Attempt", sect_name); GET_OBJ_ATTEMPT(obj) = data.GetInt(buf, 0); // sprintf(buf, "%s/ExtraFlags", sect_name); // GET_OBJ_EXTRA(obj).FromString(data.GetString(buf, "0")); sprintf(buf, "%s/Inside", sect_name); inside = data.GetInt(buf, 0); if (inside > 0) { if (inside == last_in) last_obj = last_obj->in_obj; else if (inside < last_in) while (inside <= last_in) { last_obj = last_obj->in_obj; last_in--; } if (last_obj) obj_to_obj(obj, last_obj); } else obj_to_char(obj, ch); last_in = inside; last_obj = obj; } } } { struct obj_data *obj, *last_obj; struct phone_data *k; int vnum = 0, last_in = 0, inside = 0; int num_objs = data.NumSubsections("CYBERWAR"); for (int j = 0; j < num_objs; j++) { const char *sect_name = data.GetIndexSection("CYBERWAR", j); sprintf(buf, "%s/Vnum", sect_name); vnum = data.GetLong(buf, 0); if (vnum > 0 && (obj = read_object(vnum, VIRTUAL))) { sprintf(buf, "%s/Name", sect_name); obj->restring = str_dup(data.GetString(buf, NULL)); sprintf(buf, "%s/Photo", sect_name); obj->photo = str_dup(data.GetString(buf, NULL)); for (int x = 0; x < 10; x++) { sprintf(buf, "%s/Value %d", sect_name, x); GET_OBJ_VAL(obj, x) = data.GetInt(buf, GET_OBJ_VAL(obj, x)); } if (GET_OBJ_VAL(obj, 0) == CYB_PHONE && GET_OBJ_VAL(obj, 7) && !logon) { sprintf(buf, "%04d%04d", GET_OBJ_VAL(obj, 3), GET_OBJ_VAL(obj, 6)); k = new phone_data; k->number = atoi(buf); k->phone = obj; k->rtg = GET_OBJ_VAL(obj, 8); if (phone_list) k->next = phone_list; phone_list = k; } else if (GET_OBJ_VAL(obj, 2) == 4 && GET_OBJ_VAL(obj, 7)) GET_OBJ_VAL(obj, 9) = 1; sprintf(buf, "%s/Cost", sect_name); GET_OBJ_COST(obj) = data.GetInt(buf, 1); sprintf(buf, "%s/Level", sect_name); inside = data.GetInt(buf, 0); if (inside > 0) { if (inside == last_in) last_obj = last_obj->in_obj; else if (inside < last_in) while (inside <= last_in) { last_obj = last_obj->in_obj; last_in--; } if (last_obj) obj_to_obj(obj, last_obj); } else obj_to_cyberware(obj, ch); last_in = inside; last_obj = obj; } } } { struct obj_data *obj; int vnum = 0; int num_objs = data.NumSubsections("BIOWAR"); for (int j = 0; j < num_objs; j++) { const char *sect_name = data.GetIndexSection("BIOWAR", j); sprintf(buf, "%s/Vnum", sect_name); vnum = data.GetLong(buf, 0); if (vnum > 0 && (obj = read_object(vnum, VIRTUAL))) { for (int x = 0; x < 10; x++) { sprintf(buf, "%s/Value %d", sect_name, x); GET_OBJ_VAL(obj, x) = data.GetInt(buf, GET_OBJ_VAL(obj, x)); } sprintf(buf, "%s/Cost", sect_name); GET_OBJ_COST(obj) = data.GetInt(buf, 1); obj_to_bioware(obj, ch); } } } for (struct obj_data *jack = ch->cyberware; jack; jack = jack->next_content) if (GET_OBJ_VAL(jack, 0) == CYB_CHIPJACK) { int max = 0; for (struct obj_data *wire = ch->cyberware; wire; wire = wire->next_content) if (GET_OBJ_VAL(wire, 0) == CYB_SKILLWIRE) max = GET_OBJ_VAL(wire, 1); for (struct obj_data *chip = jack->contains; chip; chip = chip->next_content) ch->char_specials.saved.skills[GET_OBJ_VAL(chip, 0)][1] = skills[GET_OBJ_VAL(chip, 0)].type ? GET_OBJ_VAL(chip, 1) : MIN(max, GET_OBJ_VAL(chip, 1)); break; } else if (GET_OBJ_VAL(jack, 0) == CYB_MEMORY) { int max = 0; for (struct obj_data *wire = ch->cyberware; wire; wire = wire->next_content) if (GET_OBJ_VAL(wire, 0) == CYB_SKILLWIRE) max = GET_OBJ_VAL(wire, 1); for (struct obj_data *chip = jack->contains; chip; chip = chip->next_content) ch->char_specials.saved.skills[GET_OBJ_VAL(chip, 0)][1] = skills[GET_OBJ_VAL(chip, 0)].type ? GET_OBJ_VAL(chip, 1) : MIN(max, GET_OBJ_VAL(chip, 1)); break; } affect_total(ch); if ((((long) (time(0) - ch->player.time.lastdisc)) >= SECS_PER_REAL_HOUR)) { GET_PHYSICAL(ch) = GET_MAX_PHYSICAL(ch); GET_MENTAL(ch) = GET_MAX_MENTAL(ch); if (AFF_FLAGS(ch).IsSet(AFF_HEALED)) AFF_FLAGS(ch).SetBit(AFF_HEALED); } if ( !IS_SENATOR(ch) ) PRF_FLAGS(ch).RemoveBit(PRF_ROLLS); if (((long) (time(0) - ch->player.time.lastdisc) >= SECS_PER_REAL_HOUR * 2) || (GET_LAST_IN(ch) > 599 && GET_LAST_IN(ch) < 700)) { GET_LAST_IN(ch) = GET_LOADROOM(ch); GET_PHYSICAL(ch) = GET_MAX_PHYSICAL(ch); GET_MENTAL(ch) = GET_MAX_MENTAL(ch); } if (!logon) ch->player.time.logon = time(0); // initialization for imms if(IS_SENATOR(ch)) { GET_COND(ch, FULL) = -1; GET_COND(ch, THIRST) = -1; GET_COND(ch, DRUNK) = -1; } switch (GET_RACE(ch)) { case RACE_HUMAN: case RACE_OGRE: NATURAL_VISION(ch) = NORMAL; break; case RACE_DWARF: case RACE_GNOME: case RACE_MENEHUNE: case RACE_KOBOROKURU: case RACE_TROLL: case RACE_CYCLOPS: case RACE_FOMORI: case RACE_GIANT: case RACE_MINOTAUR: NATURAL_VISION(ch) = THERMOGRAPHIC; break; case RACE_ORK: case RACE_HOBGOBLIN: case RACE_SATYR: case RACE_ONI: case RACE_ELF: case RACE_WAKYAMBI: case RACE_NIGHTONE: case RACE_DRYAD: NATURAL_VISION(ch) = LOWLIGHT; break; } return true; } static bool save_char(char_data *player, DBIndex::vnum_t loadroom) { FILE *fl; char outname[40], buf[MAX_STRING_LENGTH]; char bits[128]; int i; struct obj_data *char_eq[NUM_WEARS]; int wield[2]; struct obj_data *temp, *next_obj; if (IS_NPC(player)) return false; for (i = 0;(*(bits + i) = LOWER(*(GET_CHAR_NAME(player) + i))); i++) ; sprintf(outname, "%s%s%c%s%s%s", PLR_PREFIX, SLASH, *bits, SLASH, bits, PLR_SUFFIX); if (!(fl = fopen(outname, "w"))) { sprintf(buf, "SYSERR: Couldn't open player file (%s) for write", outname); mudlog(buf, NULL, LOG_SYSLOG, TRUE); return false; } /**************************************************/ /** Do In-Memory Copy **/ wield[0] = GET_WIELDED(player, 0); wield[1] = GET_WIELDED(player, 1); /* Unaffect everything a character can be affected by */ /* worn eq */ for (i = 0; i < NUM_WEARS; i++) { if (player->equipment[i]) char_eq[i] = unequip_char(player, i, FALSE); else char_eq[i] = NULL; } GET_WIELDED(player, 0) = wield[0]; GET_WIELDED(player, 1) = wield[1]; /* cyberware */ for (temp = player->cyberware; temp; temp = next_obj) { next_obj = temp->next_content; obj_from_cyberware(temp); obj_to_char(temp, player); } /* bioware */ for (temp = player->bioware; temp; temp = next_obj) { next_obj = temp->next_content; obj_from_bioware(temp); obj_to_char(temp, player); } for (struct sustain_data *sust = GET_SUSTAINED(player); sust; sust = sust->next) if (!sust->caster) spell_modify(player, sust, FALSE); /**************************************************/ if (loadroom == NOWHERE) loadroom = GET_LOADROOM(player); if (player->in_room != NOWHERE) if ( world[player->in_room].number <= 1 ) { GET_LAST_IN(player) = world[player->was_in_room].number; } else { GET_LAST_IN(player) = world[player->in_room].number; } /***************************************/ /* Code Here for the actual Save Washu */ /***************************************/ fprintf(fl, "Character:\t%s\n", player->player.char_name); fprintf(fl, "Password:\t%s\n", GET_PASSWD(player)); fprintf(fl, "Race:\t%s\n", pc_race_types[(int)GET_RACE(player)]); fprintf(fl, "Gender:\t%s\n", genders[(int)GET_SEX(player)]); fprintf(fl, "Rank:\t%s\n", status_ratings[(int)GET_LEVEL(player)]); fprintf(fl, "AffFlags:\t%s\n" "PlrFlags:\t%s\n" "PrfFlags:\t%s\n", AFF_FLAGS(player).ToString(), PLR_FLAGS(player).ToString(), PRF_FLAGS(player).ToString()); { // player text text_data *text_tab[3] = { &player->player.physical_text, &player->player.astral_text, &player->player.matrix_text }; const char *section_tab[3] = { "PHYSICAL TEXT", "ASTRAL TEXT", "MATRIX TEXT" }; for (int i = 0; i < 3; i++) { text_data *ptr = text_tab[i]; fprintf(fl, "[%s]\n", section_tab[i]); fprintf(fl, "\tKeywords:\t%s\n" "\tName:\t%s\n", ptr->keywords? ptr->keywords : player->player.char_name, ptr->name? ptr->name : player->player.char_name); if (ptr->room_desc) { strcpy(buf, ptr->room_desc); kill_ems(buf); fprintf(fl, "\tRoomDesc:$\n%s~\n", buf); } else { char race[32]; strcpy(race, pc_race_types[(int)GET_RACE(player)]); *race = tolower(*race); fprintf(fl, "\tRoomDesc:$\nA %s %s voice~\n", genders[(int)GET_SEX(player)], race); } if (ptr->look_desc) { strcpy(buf, ptr->look_desc); kill_ems(buf); fprintf(fl, "\tLookDesc:$\n%s~\n", buf); } else { char race[32]; strcpy(race, pc_race_types[(int)GET_RACE(player)]); *race = tolower(*race); fprintf(fl, "\tLookDesc:$\nYou see an unimaginative %s.~\n", race); } } } { // miscellaneous text fprintf(fl, "[MISC TEXT]\n"); if(POOFIN(player)) fprintf(fl, "\tPoofIn:\t%s\n", POOFIN(player)); if(POOFOUT(player)) fprintf(fl, "\tPoofOut:\t%s\n", POOFOUT(player)); if(GET_TITLE(player)) fprintf(fl, "\tTitle:\t%s\n", GET_TITLE(player)); if(GET_PRETITLE(player)) fprintf(fl, "\tPretitle:\t%s\n", GET_PRETITLE(player)); if(GET_WHOTITLE(player)) fprintf(fl, "\tWhotitle:\t%s\n", GET_WHOTITLE(player)); else fprintf(fl, "\tWhotitle:\t%s\n", pc_race_types[(int)GET_RACE(player)]); if (player->player.prompt) fprintf(fl, "\tPrompt:\t%s\n", player->player.prompt); if (player->player.matrixprompt) fprintf(fl, "\tMatrixPrompt:\t%s\n", player->player.matrixprompt); if (player->player.host) fprintf(fl, "\tHost:\t%s\n", player->player.host); if (player->player.background) { strcpy(buf, player->player.background); kill_ems(buf); fprintf(fl, "\tBackground:$\n%s~\n", buf); } } { // attributes fprintf(fl, "[ATTRIBUTES]\n"); fprintf(fl, "\tBod:\t%d\n" "\tQui:\t%d\n" "\tStr:\t%d\n" "\tCha:\t%d\n" "\tInt:\t%d\n" "\tWil:\t%d\n" "\tMag:\t%d\n" "\tEssenceTotal:\t%d\n" "\tEssenceHole:\t%d\n" "\tBiowarIndex:\t%d\n" "\tHighestIndex:\t%d\n" "\tPowerPoints:\t%d\n", GET_REAL_BOD(player), GET_REAL_QUI(player), GET_REAL_STR(player), GET_REAL_CHA(player), GET_REAL_INT(player), GET_REAL_WIL(player), GET_REAL_MAG(player), GET_REAL_ESS(player), player->real_abils.esshole, GET_INDEX(player), player->real_abils.highestindex, GET_PP(player)); } { fprintf(fl, "[POOLS]\n"); fprintf(fl, "\tCasting:\t%d\n" "\tSpellDefense:\t%d\n" "\tDrain:\t%d\n" "\tReflecting:\t%d\n" "\tMaxHacking:\t%d\n" "\tBody:\t%d\n" "\tDodge:\t%d\n", GET_CASTING(player), GET_SDEFENSE(player), GET_DRAIN(player), GET_REFLECT(player), GET_MAX_HACKING(player), GET_BODY(player), GET_DEFENSE(player)); } { // points fprintf(fl, "[POINTS]\n"); fprintf(fl, "\tHeight:\t%d\n", GET_HEIGHT(player)); fprintf(fl, "\tWeight:\t%d\n", GET_WEIGHT(player)); if (player->player.tradition != TRAD_MUNDANE) { fprintf(fl, "\tTradition:\t%d\n", GET_TRADITION(player)); } if (GET_TOTEM(player)) { fprintf(fl, "\tTotem:\t%d\n", GET_TOTEM(player)); fprintf(fl, "\tTotemSpirit:\t%d\n", GET_TOTEMSPIRIT(player)); } if (GET_ASPECT(player)) fprintf(fl, "\tAspect:\t%d\n", GET_ASPECT(player)); fprintf(fl, "\tCash:\t%d\n", GET_NUYEN(player)); fprintf(fl, "\tBank:\t%d\n", GET_BANK(player)); fprintf(fl, "\tKarma:\t%d\n", GET_KARMA(player)); fprintf(fl, "\tRep:\t%d\n", GET_REP(player)); fprintf(fl, "\tNotoriety:\t%d\n", GET_NOT(player)); fprintf(fl, "\tTKE:\t%d\n", GET_TKE(player)); fprintf(fl, "\tSig:\t%d\n", GET_SIG(player)); if (GET_TRADITION(player) != TRAD_MUNDANE) { fprintf(fl, "\tUsedGrade:\t%d\n", GET_GRADE(player)); fprintf(fl, "\tExtraPower:\t%d\n", player->points.extrapp); if (GET_METAMAGIC(player, META_CENTERING)) fprintf(fl, "\tCentering:\t%d\n", GET_CENTERINGSKILL(player)); } fprintf(fl, "\tPhysical:\t%d\n", GET_PHYSICAL(player)); fprintf(fl, "\tPhysicalLoss:\t%d\n", GET_PHYSICAL_LOSS(player)); fprintf(fl, "\tMental:\t%d\n", GET_MENTAL(player)); fprintf(fl, "\tMentalLoss:\t%d\n", GET_MENTAL_LOSS(player)); fprintf(fl, "\tPermBodLoss:\t%d\n", GET_PERM_BOD_LOSS(player)); if (PLR_FLAGGED(player, PLR_AUTH)) { fprintf(fl, "\tAttPoints:\t%d\n", GET_ATT_POINTS(player)); fprintf(fl, "\tSkillPoints:\t%d\n", GET_SKILL_POINTS(player)); fprintf(fl, "\tForcePoints:\t%d\n", GET_FORCE_POINTS(player)); fprintf(fl, "\tRestringPoints:\t%d\n", GET_RESTRING_POINTS(player)); } if (GET_LEVEL(player) >= LVL_BUILDER) fprintf(fl, "\tZoneNumber:\t%d\n", player->player_specials->saved.zonenum); fprintf(fl, "\tLeftHanded:\t%d\n", player->char_specials.saved.left_handed); if (player->char_specials.arrive) fprintf(fl, "\tArriveText:\t%s\n", player->char_specials.arrive); if (player->char_specials.leave) fprintf(fl, "\tLeaveText:\t%s\n", player->char_specials.leave); fprintf(fl, "\tCurLang:\t%d\n", GET_LANGUAGE(player)); fprintf(fl, "\tMasking:\t%d\n", GET_MASKING(player)); fprintf(fl, "\tWimpLevel:\t%d\n", GET_WIMP_LEV(player)); if (GET_FREEZE_LEV(player)) fprintf(fl, "\tFreezeLevel:\t%d\n", GET_FREEZE_LEV(player)); if (GET_INVIS_LEV(player)) fprintf(fl, "\tInvisLevel:\t%d\n", GET_INVIS_LEV(player)); if (GET_INCOG_LEV(player)) fprintf(fl, "\tIncogLevel:\t%d\n", GET_INCOG_LEV(player)); if (GET_BAD_PWS(player)) fprintf(fl, "\tBadPWs:\t%d\n", GET_BAD_PWS(player)); fprintf(fl, "\tLoadRoom:\t%ld\n", GET_LOADROOM(player)); fprintf(fl, "\tLastRoom:\t%ld\n", GET_LAST_IN(player)); fprintf(fl, "\tLastD:\t%ld\n", time(0)); fprintf(fl, "\tLast:\t%ld\n", player->player.time.logon); fprintf(fl, "\tBorn:\t%ld\n", player->player.time.birth); fprintf(fl, "\tPlayed:\t%d\n", player->player.time.played); } { // conditions fprintf(fl, "[CONDITIONS]\n" "\tHunger:\t%d\n" "\tThirst:\t%d\n" "\tDrunk:\t%d\n", GET_COND(player, FULL), GET_COND(player, THIRST), GET_COND(player, DRUNK)); } if (GET_LEVEL(player) == LVL_MORTAL) { fprintf(fl, "[DRUGS]\n" "\tAffect:\t%d\n" "\tStage:\t%d\n" "\tDuration:\t%d\n" "\tDose:\t%d\n", GET_DRUG_AFFECT(player), GET_DRUG_STAGE(player), GET_DRUG_DURATION(player), GET_DRUG_DOSE(player)); for (int i = 1; i < NUM_DRUGS; i++) fprintf(fl, "\t[DRUG %d]\n" "\t\tAddict:\t%d\n" "\t\tDoses:\t%d\n" "\t\tEdge:\t%d\n" "\t\tLastFix:\t%d\n" "\t\tAddtime:\t%d\n" "\t\tTolerant:\t%d\n" "\t\tLastWith:\t%d\n", i, GET_DRUG_ADDICT(player, i), GET_DRUG_DOSES(player, i), GET_DRUG_EDGE(player, i), GET_DRUG_LASTFIX(player, i), GET_DRUG_ADDTIME(player, i), GET_DRUG_TOLERANT(player, i), GET_DRUG_LASTWITH(player, i)); } { // skills fprintf(fl, "[SKILLS]\n"); for (int i = 0; i <= MAX_SKILLS; i++) if (GET_SKILL(player, i)) fprintf(fl, "\t%s:\t%d\n", skills[i].name, player->char_specials.saved.skills[i][0]); } { // adept powers if (GET_TRADITION(player) == TRAD_ADEPT) { fprintf(fl, "[POWERS]\n"); for (int i = 1; i < ADEPT_NUMPOWER; i++) if (GET_POWER_TOTAL(player, i)) fprintf(fl, "\t%s:\t%d\n", adept_powers[i], GET_POWER_TOTAL(player, i)); } } { if (GET_TRADITION(player) != TRAD_MUNDANE) { fprintf(fl, "[METAMAGIC]\n"); for (int i = 0; i < META_MAX; i++) if (GET_METAMAGIC(player, i)) fprintf(fl, "\t%s:\t%d\n", metamagic[i], GET_METAMAGIC(player, i)); } } /* add spell and eq affections back in now */ for (temp = player->carrying; temp; temp = next_obj) { next_obj = temp->next_content; if ((GET_OBJ_TYPE(temp) == ITEM_CYBERWARE)) { obj_from_char(temp); obj_to_cyberware(temp, player); } /* bioware next */ if (GET_OBJ_TYPE(temp) == ITEM_BIOWARE) { obj_from_char(temp); obj_to_bioware(temp, player); } } for (struct sustain_data *sust = GET_SUSTAINED(player); sust; sust = sust->next) if (!sust->caster) spell_modify(player, sust, TRUE); // then worn eq for (i = 0; i < NUM_WEARS; i++) { if (char_eq[i]) equip_char(player, char_eq[i], i); } affect_total(player); if (player->spells) { fprintf(fl, "[SPELL]\n"); int i = 0; for (struct spell_data *temp = player->spells; temp; temp = temp->next, i++) { fprintf(fl, "\t[SPELL %d]\n" "\t\tName:\t%s\n" "\t\tType:\t%d\n" "\t\tSubType:\t%d\n" "\t\tForce:\t%d\n", i, temp->name, temp->type, temp->subtype, temp->force); } } if (GET_SPIRIT(player) && GET_TRADITION(player) == TRAD_HERMETIC) { fprintf(fl, "[SPIRITS]\n"); int i = 0; for (struct spirit_data *spirit = GET_SPIRIT(player); spirit; spirit = spirit->next, i++) { fprintf(fl, "\t[SPIRIT %d]\n" "\t\tType:\t%d\n" "\t\tForce:\t%d\n" "\t\tServices:\t%d\n" "\t\tIdnum:\t%d\n", i, spirit->type, spirit->force, spirit->services, spirit->id); } } fprintf(fl, "[ALIASES]\n"); for (struct alias *a = GET_ALIASES(player); a; a = a->next) { fprintf(fl, "\t%s:\t%s\n", a->command, a->replacement); } fprintf(fl, "[MEMORY]\n"); for (struct remem *b = GET_MEMORY(player); b; b = b->next) if (b->idnum) fprintf(fl, "\t%s:\t%ld\n", b->mem, b->idnum); fprintf(fl, "[QUESTS]\n"); for (int i = 0; i <= QUEST_TIMER - 1; i++) fprintf(fl, "\tQuest %d:\t%d\n", i, GET_LQUEST(player, i)); struct obj_data *obj = NULL, *last_obj = NULL; int o = 0, level = 0; fprintf(fl, "[WORN]\n"); for (i = 0; i < NUM_WEARS; i++) if ((obj = GET_EQ(player, i)) && !IS_OBJ_STAT(obj, ITEM_NORENT)) break; while (obj && i < NUM_WEARS) { if (!IS_OBJ_STAT(obj, ITEM_NORENT)) { fprintf(fl, "\t[WORN %d]\n", o); fprintf(fl, "\t\tVnum:\t%ld\n", GET_OBJ_VNUM(obj)); if (level) fprintf(fl, "\t\tInside:\t%d\n", level); fprintf(fl, "\t\tWorn:\t%d\n", i); if (GET_OBJ_TYPE(obj) == ITEM_PHONE) for (int x = 0; x < 9; x++) fprintf(fl, "\t\tValue %d:\t%d\n", x, GET_OBJ_VAL(obj, x)); else for (int x = 0; x < 10; x++) fprintf(fl, "\t\tValue %d:\t%d\n", x, GET_OBJ_VAL(obj, x)); fprintf(fl, "\t\tCondition:\t%d\n", GET_OBJ_CONDITION(obj)); fprintf(fl, "\t\tCost:\t%d\n", GET_OBJ_COST(obj)); fprintf(fl, "\t\tTimer:\t%d\n", GET_OBJ_TIMER(obj)); fprintf(fl, "\t\tAttempt:\t%d\n", GET_OBJ_ATTEMPT(obj)); fprintf(fl, "\t\tExtraFlags:\t%s\n", GET_OBJ_EXTRA(obj).ToString()); if (obj->restring) fprintf(fl, "\t\tName:\t%s\n", obj->restring); if (obj->photo) fprintf(fl, "\t\tPhoto:$\n%s~\n", cleanup(buf2, obj->photo)); last_obj = GET_EQ(player, i); o++; } if (obj->contains && !IS_OBJ_STAT(obj, ITEM_NORENT) && GET_OBJ_TYPE(obj) != ITEM_PART) { obj = obj->contains; level++; continue; } else if (!obj->next_content && obj->in_obj) while (obj && !obj->next_content && level >= 0) { obj = obj->in_obj; level--; } if (!obj || !obj->next_content) while (i < NUM_WEARS) { i++; if ((obj = GET_EQ(player, i)) && !IS_OBJ_STAT(obj, ITEM_NORENT)) { level = 0; break; } } else obj = obj->next_content; } level = 0; o = 0; fprintf(fl, "[INV]\n"); for (obj = player->carrying; obj;) { if (!IS_OBJ_STAT(obj, ITEM_NORENT)) { fprintf(fl, "\t[Object %d]\n", o); o++; fprintf(fl, "\t\tVnum:\t%ld\n", GET_OBJ_VNUM(obj)); if (level) fprintf(fl, "\t\tInside:\t%d\n", level); if (GET_OBJ_TYPE(obj) == ITEM_PHONE) for (int x = 0; x < 9; x++) fprintf(fl, "\t\tValue %d:\t%d\n", x, GET_OBJ_VAL(obj, x)); else for (int x = 0; x < 10; x++) fprintf(fl, "\t\tValue %d:\t%d\n", x, GET_OBJ_VAL(obj, x)); fprintf(fl, "\t\tCondition:\t%d\n", GET_OBJ_CONDITION(obj)); fprintf(fl, "\t\tCost:\t%d\n", GET_OBJ_COST(obj)); fprintf(fl, "\t\tTimer:\t%d\n", GET_OBJ_TIMER(obj)); fprintf(fl, "\t\tAttempt:\t%d\n", GET_OBJ_ATTEMPT(obj)); fprintf(fl, "\t\tExtraFlags:\t%d\n", GET_OBJ_EXTRA(obj).ToString()); if (obj->restring) fprintf(fl, "\t\tName:\t%s\n", obj->restring); if (obj->photo) fprintf(fl, "\t\tPhoto:$\n%s\n~\n", cleanup(buf2, obj->photo)); } if (obj->contains && !IS_OBJ_STAT(obj, ITEM_NORENT) && GET_OBJ_TYPE(obj) != ITEM_PART) { obj = obj->contains; level++; continue; } else if (!obj->next_content && obj->in_obj) while (obj && !obj->next_content && level >= 0) { obj = obj->in_obj; level--; } if (obj) obj = obj->next_content; } o = 0; fprintf(fl, "[BIOWAR]\n"); for (obj = player->bioware; obj; obj = obj->next_content) { if (!IS_OBJ_STAT(obj, ITEM_NORENT)) { fprintf(fl, "\t[BIOWAR %d]\n", o); o++; fprintf(fl, "\t\tVnum:\t%ld\n", GET_OBJ_VNUM(obj)); for (int x = 0; x < 10; x++) fprintf(fl, "\t\tValue %d:\t%d\n", x, GET_OBJ_VAL(obj, x)); fprintf(fl, "\t\tCost:\t%d\n", GET_OBJ_COST(obj)); } } o = level = 0; fprintf(fl, "[CYBERWAR]\n"); for (obj = player->cyberware; obj;) { fprintf(fl, "\t[CYBER %d]\n", o); o++; fprintf(fl, "\t\tVnum:\t%ld\n", GET_OBJ_VNUM(obj)); if (obj->restring) fprintf(fl, "\t\tName:\t%s\n", obj->restring); if (obj->photo) fprintf(fl, "\t\tPhoto:$\n%s\n~\n", cleanup(buf2, obj->photo)); if (GET_OBJ_VAL(obj, 2) == 4) { fprintf(fl, "\t\tValue 3:\t%d\n", GET_OBJ_VAL(obj, 3)); fprintf(fl, "\t\tValue 6:\t%d\n", GET_OBJ_VAL(obj, 6)); fprintf(fl, "\t\tValue 7:\t%d\n", GET_OBJ_VAL(obj, 7)); fprintf(fl, "\t\tValue 8:\t%d\n", GET_OBJ_VAL(obj, 8)); } else for (int x = 0; x < 10; x++) fprintf(fl, "\t\tValue %d:\t%d\n", x, GET_OBJ_VAL(obj, x)); fprintf(fl, "\t\tCost:\t%d\n", GET_OBJ_COST(obj)); if (level) fprintf(fl, "\t\tLevel:\t%d\n", level); if (obj->contains) { obj = obj->contains; level++; continue; } else if (!obj->next_content && obj->in_obj) while (obj && !obj->next_content && level >= 0) { obj = obj->in_obj; level--; } if (obj) obj = obj->next_content; } fclose(fl); return true; } PCIndex::PCIndex() { tab = NULL; entry_cnt = entry_size = 0; needs_save = false; } PCIndex::~PCIndex() { reset(); } bool PCIndex::Save() { if (!needs_save) return true; FILE *index = fopen(INDEX_FILENAME, "w"); if (!tab) { if (entry_cnt > 0) log("--Error: no table when there should be?! That's fucked up, man."); return false; } if (!index) { log("--Error: Could not open player index file %s\n", INDEX_FILENAME); return false; } fprintf(index, "* Player index file\n" "* Generated automatically by PCIndex::Save\n\n"); for (int i = 0; i < entry_cnt; i++) { entry *ptr = tab+i; fprintf(index, "%ld %d %u %lu %s\n", ptr->id, ptr->level, ptr->flags, ptr->last, ptr->name); } fprintf(index, "END\n"); fclose(index); needs_save = false; return true; } char_data *PCIndex::CreateChar(char_data *ch) { if (entry_cnt >= entry_size) resize_table(); entry info; if (strlen(GET_CHAR_NAME(ch)) >= MAX_NAME_LENGTH) { log("--Fatal error: Could not fit name into player index..\n" " : Inrease MAX_NAME_LENGTH"); shutdown(); } // if this is the first character, make him president if (entry_cnt < 1) { log("%s promoted to president, by virtue of first-come, first-serve.", GET_CHAR_NAME(ch)); for (int i = 0; i < 3; i++) GET_COND(ch, i) = (char) -1; GET_KARMA(ch) = 0; GET_LEVEL(ch) = LVL_PRESIDENT; GET_REP(ch) = 0; GET_NOT(ch) = 0; GET_TKE(ch) = 0; PLR_FLAGS(ch).RemoveBit(PLR_NEWBIE); PLR_FLAGS(ch).RemoveBit(PLR_AUTH); PRF_FLAGS(ch).SetBits(PRF_HOLYLIGHT, PRF_CONNLOG, PRF_ROOMFLAGS, PRF_NOHASSLE, PRF_AUTOINVIS, PRF_AUTOEXIT, ENDBIT); } else { PLR_FLAGS(ch).SetBit(PLR_AUTH); } init_char(ch); init_char_strings(ch); strcpy(info.name, GET_CHAR_NAME(ch)); info.id = find_open_id(); info.level = GET_LEVEL(ch); info.flags = (PLR_FLAGGED(ch, PLR_NODELETE) ? NODELETE : 0); info.active_data = ch; info.instance_cnt = 1; // sync IDs GET_IDNUM(ch) = info.id; // update the logon time time(&info.last); // insert the new info in the correct place sorted_insert(&info); if (!needs_save) needs_save = true; Save(); return ch; } char_data *PCIndex::LoadChar(const char *name, bool logon) { rnum_t idx = get_idx_by_name(name); if (idx < 0 || idx >= entry_cnt) return NULL; entry *ptr = tab+idx; // load the character data char_data *ch = Mem->GetCh(); ch->player_specials = new player_special_data; memset(ch->player_specials, 0, sizeof(player_special_data)); load_char(name, ch, logon); // sync IDs GET_IDNUM(ch) = ptr->id; ptr->instance_cnt++; if (logon) { ptr->active_data = NULL; // set the active data thing // ptr->active_data = ch; // update the last logon time time(&ptr->last); } return ch; } bool PCIndex::SaveChar(char_data *ch, vnum_t loadroom) { if (IS_NPC(ch)) return false; bool ret = save_char(ch, loadroom); Update(ch); return ret; } bool PCIndex::StoreChar(char_data *ch, bool save) { bool result = true; if (IS_NPC(ch)) return false; if (PLR_FLAGGED(ch, PLR_DELETED)) { playerDB.DeleteChar(GET_IDNUM(ch)); return true; } /* if (save && !SaveChar(ch, GET_LOADROOM(ch))) { char msg[256]; sprintf(msg, "Error: could not save PC %s before storing", GET_CHAR_NAME(ch)); mudlog(msg, ch, LOG_SYSLOG, true); result = false; } */ rnum_t idx = get_idx_by_name(GET_CHAR_NAME(ch)); update_by_idx(idx, ch); entry *ptr = tab+idx; ptr->instance_cnt--; //if (!ptr->instance_cnt || ptr->instance_cnt < 0) ptr->active_data = NULL; if (ch->desc) free_editing_structs(ch->desc); extract_char(ch); return result; } void PCIndex::Update(char_data *ch) { rnum_t idx = get_idx_by_name(GET_CHAR_NAME(ch)); update_by_idx(idx, ch); } void PCIndex::reset() { if (tab != NULL) { delete [] tab; tab = NULL; } entry_cnt = entry_size = 0; needs_save = false; } bool PCIndex::load() { File index(INDEX_FILENAME, "r"); if (!index.IsOpen()) { log("--WARNING: Could not open player index file %s...\n" " : Starting game with NO PLAYERS!!!\n", INDEX_FILENAME); FILE *test = fopen(INDEX_FILENAME, "r"); if (test) { log("_could_ open it normally, tho"); fclose(test); } return false; } reset(); char line[512]; int line_num = 0; int idx = 0; entry_cnt = count_entries(&index); resize_table(); line_num += index.GetLine(line, 512, FALSE); while (!index.EoF() && strcmp(line, "END")) { entry *ptr = tab+idx; char temp[512]; // for paranoia if (sscanf(line, " %ld %d %u %lu %s ", &ptr->id, &ptr->level, &ptr->flags, &ptr->last, temp) != 5) { log("--Fatal error: syntax error in player index file, line %d", line_num); shutdown(); } strncpy(ptr->name, temp, MAX_NAME_LENGTH); *(ptr->name+MAX_NAME_LENGTH-1) = '\0'; ptr->active_data = NULL; line_num += index.GetLine(line, 512, FALSE); idx++; } if (entry_cnt != idx) entry_cnt = idx; log("--Successfully loaded %d entries from the player index file.", entry_cnt); sort_by_id(); clear_by_time(); return true; } int PCIndex::count_entries(File *index) { char line[512]; int count = 0; index->GetLine(line, 512, FALSE); while (!index->EoF() && strcmp(line, "END")) { count++; index->GetLine(line, 512, FALSE); } index->Rewind(); return count; } void PCIndex::sort_by_id() { qsort(tab, entry_cnt, sizeof(entry), entry_compare); } void PCIndex::resize_table(int empty_slots) { entry_size = entry_cnt + empty_slots; entry *new_tab = new entry[entry_size]; if (tab) { for (int i = 0; i < entry_cnt; i++) new_tab[i] = tab[i]; // fill empty slots with zeroes memset(new_tab+entry_cnt, 0, sizeof(entry)*(entry_size-entry_cnt)); // delete the old table delete [] tab; } else { // fill entire table with zeros memset(new_tab, 0, sizeof(entry)*entry_size); } // finally, update the pointer tab = new_tab; } void PCIndex::sorted_insert(const entry *info) { int i; // whee!! linear! // first, find the correct index for (i = 0; i < entry_cnt; i++) if (tab[i].id > info->id) break; // create an empty space for the new entry for (int j = entry_cnt; j > i; j--) tab[j] = tab[j-1]; tab[i] = *info; log("--Inserting %s's (id#%d) entry into position %d", info->name, info->id, i); // update entry_cnt, and we're done entry_cnt++; needs_save = true; } DBIndex::vnum_t PCIndex::find_open_id() { if (entry_cnt < 1) return 1; /* this won't work right now since id#s are used to store owners of foci, etc. So once there's a universal id# invalidator, this should be put in */ /* for (int i = 1; i < entry_cnt; i++) if (tab[i].id > (tab[i-1].id+1)) return (tab[i-1].id+1); */ return (tab[entry_cnt-1].id+1); } void PCIndex::clear_by_time() { for (int i = 0; i < entry_cnt; i++) { entry *ptr = tab+i; if ((time(0) - ptr->last) > (SECS_PER_REAL_DAY*30)) { playerDB.DeleteChar(ptr->id); } } } DBIndex::rnum_t PCIndex::get_idx_by_name(const char *name) { for (int i = 0; i < entry_cnt; i++) { entry *ptr = tab+i; if (!str_cmp(name, ptr->name)) return i; } return -1; } DBIndex::rnum_t PCIndex::get_idx_by_id(const vnum_t virt) { // binary search int low = 0, high = entry_cnt - 1; int mid = high / 2; while (low <= high) { entry *ptr = tab+mid; if (ptr->id == virt) return mid; if (ptr->id < virt) { low = mid+1; } else { high = mid-1; } mid = (low + high) / 2; } return -1; } DBIndex::vnum_t PCIndex::get_id_by_idx(const rnum_t idx) { if (idx >= 0 && idx < entry_cnt) return (tab[idx].id); return -1; } const char *PCIndex::get_name_by_idx(const rnum_t idx) { if (idx >= 0 && idx < entry_cnt) return (tab[idx].name); return NULL; } char_data *PCIndex::get_char_by_idx(const rnum_t idx) { if (idx >= 0 && idx < entry_cnt) return tab[idx].active_data; return NULL; } bool PCIndex::delete_by_idx(rnum_t idx) { entry *ptr = tab+idx; if (ptr->flags & NODELETE) return false; // delete the character's files log("PCLEAN: %s (ID#%d): level=%d, last=%s", ptr->name, ptr->id, ptr->level, asctime(localtime(&(ptr->last)))); char bits[128]; for (int i = 0;(*(bits + i) = LOWER(*(ptr->name + i))); i++) ; sprintf(buf, "%s%s%c%s%s%s", PLR_PREFIX, SLASH, *bits, SLASH, bits, PLR_SUFFIX); unlink(buf); for (int i = idx+1; i < entry_cnt; i++) tab[i-1] = tab[i]; entry_cnt--; entry *zero = tab+entry_cnt; memset(zero->name, 0, MAX_NAME_LENGTH); zero->id = -1; zero->level = 0; zero->last = 0; zero->active_data = NULL; zero->flags = 0; if (!needs_save) needs_save = true; Save(); return true; } void PCIndex::update_by_idx(rnum_t idx, char_data *ch) { entry *ptr = tab+idx; bool changed = false; if (ptr->id != GET_IDNUM(ch)) { char msg[256]; sprintf(msg, "Warning: %s's cached id didn't match up (%ld != %ld); fixing", GET_CHAR_NAME(ch), GET_IDNUM(ch), ptr->id); mudlog(msg, ch, LOG_SYSLOG, true); GET_IDNUM(ch) = ptr->id; } if (ptr->level != GET_LEVEL(ch)) { ptr->level = GET_LEVEL(ch); changed = true; } if ((PLR_FLAGGED(ch, PLR_NODELETE) && !(ptr->flags & NODELETE)) || (!PLR_FLAGGED(ch, PLR_NODELETE) && (ptr->flags & NODELETE))) { ptr->flags = 0; if (PLR_FLAGGED(ch, PLR_NODELETE)) ptr->flags |= NODELETE; changed = true; } if (changed && !needs_save) needs_save = true; }