void quest_quit(struct char_data *ch) { qst_rnum rnum; if (GET_QUEST(ch) == NOTHING) send_to_char(ch, "But you currently aren't on a quest!\r\n"); else if ((rnum = real_quest(GET_QUEST(ch))) == NOTHING) { clear_quest(ch); send_to_char(ch, "You are now no longer part of the quest.\r\n"); save_char(ch); } else { clear_quest(ch); if (QST_QUIT(rnum) && (str_cmp(QST_QUIT(rnum), "undefined") != 0)) send_to_char(ch, "%s", QST_QUIT(rnum)); else send_to_char(ch, "You are now no longer part of the quest.\r\n"); if (QST_PENALTY(rnum)) { GET_QUESTPOINTS(ch) -= QST_PENALTY(rnum); send_to_char(ch, "You have lost %d quest points for your cowardice.\r\n", QST_PENALTY(rnum)); } save_char(ch); } }
void account_delete_char(struct account *account, struct creature *ch) { void remove_bounties(int); int idx, count; PGresult *res; clear_clan_owner(GET_IDNUM(ch)); remove_char_clan(GET_CLAN(ch), GET_IDNUM(ch)); // TODO: Remove character from any access groups sql_exec("delete from sgroup_members where player=%ld", GET_IDNUM(ch)); // Remove character from any quests they might have joined if (GET_QUEST(ch)) { struct quest *quest = quest_by_vnum(GET_QUEST(ch)); if (quest) { remove_quest_player(quest, GET_IDNUM(ch)); save_quests(); } } // Remove character from trusted lists - we have to take the accounts // in memory into consideration when we do this, so we have to go // through each account res = sql_query("select account from trusted where player=%ld", GET_IDNUM(ch)); count = PQntuples(res); for (idx = 0; idx < count; idx++) { struct account *acct = account_by_idnum(atoi(PQgetvalue(res, idx, 0))); if (acct) account_distrust(acct, GET_IDNUM(ch)); } // Remove from the bounty list remove_bounties(GET_IDNUM(ch)); sql_exec("delete from bounty_hunters where idnum=%ld or victim=%ld", GET_IDNUM(ch), GET_IDNUM(ch)); // Disassociate author from board messages sql_exec("update board_messages set author=null where author=%ld", GET_IDNUM(ch)); // Remove character from account account->chars = g_list_remove(account->chars, GINT_TO_POINTER(GET_IDNUM(ch))); sql_exec("delete from players where idnum=%ld", GET_IDNUM(ch)); // Remove character from game if (ch->in_room) { send_to_char(ch, "A cold wind blows through your soul, and you disappear!\r\n"); creature_purge(ch, false); } }
void quest_timeout(struct char_data *ch) { if ((GET_QUEST(ch) != NOTHING) && (GET_QUEST_TIME(ch) != -1)) { clear_quest(ch); send_to_char(ch, "You have run out of time to complete the quest.\r\n"); } }
void clear_quest(struct char_data *ch) { GET_QUEST(ch) = NOTHING; GET_QUEST_TIME(ch) = -1; GET_QUEST_COUNTER(ch) = 0; REMOVE_BIT_AR(PRF_FLAGS(ch), PRF_QUEST); return; }
/*--------------------------------------------------------------------------*/ void set_quest(struct char_data *ch, qst_rnum rnum) { GET_QUEST(ch) = QST_NUM(rnum); GET_QUEST_TIME(ch) = QST_TIME(rnum); GET_QUEST_COUNTER(ch) = QST_QUANTITY(rnum); SET_BIT_AR(PRF_FLAGS(ch), PRF_QUEST); return; }
void quest_join(struct char_data *ch, struct char_data *qm, char argument[MAX_INPUT_LENGTH]) { qst_vnum vnum; qst_rnum rnum; char buf[MAX_INPUT_LENGTH]; if (!*argument) snprintf(buf, sizeof(buf), "%s What quest did you wish to join?", GET_NAME(ch)); else if (GET_QUEST(ch) != NOTHING) snprintf(buf, sizeof(buf), "%s But you are already part of a quest!", GET_NAME(ch)); else if((vnum = find_quest_by_qmnum(ch, GET_MOB_VNUM(qm), atoi(argument))) == NOTHING) snprintf(buf, sizeof(buf), "%s I don't know of such a quest!", GET_NAME(ch)); else if ((rnum = real_quest(vnum)) == NOTHING) snprintf(buf, sizeof(buf), "%s I don't know of such a quest!", GET_NAME(ch)); else if (GET_LEVEL(ch) < QST_MINLEVEL(rnum)) snprintf(buf, sizeof(buf), "%s You are not experienced enough for that quest!", GET_NAME(ch)); else if (GET_LEVEL(ch) > QST_MAXLEVEL(rnum)) snprintf(buf, sizeof(buf), "%s You are too experienced for that quest!", GET_NAME(ch)); else if (is_complete(ch, vnum)) snprintf(buf, sizeof(buf), "%s You have already completed that quest!", GET_NAME(ch)); else if ((QST_PREV(rnum) != NOTHING) && !is_complete(ch, QST_PREV(rnum))) snprintf(buf, sizeof(buf), "%s That quest is not available to you yet!", GET_NAME(ch)); else if ((QST_PREREQ(rnum) != NOTHING) && (real_object(QST_PREREQ(rnum)) != NOTHING) && (get_obj_in_list_num(real_object(QST_PREREQ(rnum)), ch->carrying) == NULL)) snprintf(buf, sizeof(buf), "%s You need to have %s first!", GET_NAME(ch), obj_proto[real_object(QST_PREREQ(rnum))].short_description); else { act("You join the quest.", TRUE, ch, NULL, NULL, TO_CHAR); act("$n has joined a quest.", TRUE, ch, NULL, NULL, TO_ROOM); snprintf(buf, sizeof(buf), "%s Listen carefully to the instructions.", GET_NAME(ch)); do_tell(qm, buf, cmd_tell, 0); set_quest(ch, rnum); send_to_char(ch, "%s", QST_INFO(rnum)); if (QST_TIME(rnum) != -1) snprintf(buf, sizeof(buf), "%s You have a time limit of %d turn%s to complete the quest.", GET_NAME(ch), QST_TIME(rnum), QST_TIME(rnum) == 1 ? "" : "s"); else snprintf(buf, sizeof(buf), "%s You can take however long you want to complete the quest.", GET_NAME(ch)); } do_tell(qm, buf, cmd_tell, 0); save_char(ch); }
void check_timed_quests(void) { struct char_data *ch; for (ch = character_list; ch; ch = ch->next) if (!IS_NPC(ch) && (GET_QUEST(ch) != NOTHING) && (GET_QUEST_TIME(ch) != -1)) if (--GET_QUEST_TIME(ch) == 0) quest_timeout(ch); }
bool is_arena_combat(struct creature *ch, struct creature *vict) { if (!vict->in_room) return false; if (ROOM_FLAGGED(vict->in_room, ROOM_ARENA)) return true; //mobs don't quest if (!IS_NPC(vict)) { if (GET_QUEST(vict)) { struct quest *quest; quest = quest_by_vnum(GET_QUEST(vict)); if (quest && QUEST_FLAGGED(quest, QUEST_ARENA)) return true; } } if (!ch || !ch->in_room) return false; if (ROOM_FLAGGED(ch->in_room, ROOM_ARENA)) return true; //mobs don't quest if (!IS_NPC(ch)) { if (GET_QUEST(ch)) { struct quest *quest; quest = quest_by_vnum(GET_QUEST(ch)); if (quest && QUEST_FLAGGED(quest, QUEST_ARENA)) return true; } } return false; }
void quest_progress(struct char_data *ch) { qst_rnum rnum; if (GET_QUEST(ch) == NOTHING) send_to_char(ch, "But you currently aren't on a quest!\r\n"); else if ((rnum = real_quest(GET_QUEST(ch))) == NOTHING) { clear_quest(ch); send_to_char(ch, "Your quest seems to no longer exist.\r\n"); } else { send_to_char(ch, "You are on the following quest:\r\n%s\r\n%s", QST_DESC(rnum), QST_INFO(rnum)); if (QST_QUANTITY(rnum) > 1) send_to_char(ch, "You still have to achieve %d out of %d goals for the quest.\r\n", GET_QUEST_COUNTER(ch), QST_QUANTITY(rnum)); if (GET_QUEST_TIME(ch) > 0) send_to_char(ch, "You have %d turn%s remaining to complete the quest.\r\n", GET_QUEST_TIME(ch), GET_QUEST_TIME(ch) == 1 ? "" : "s"); } }
void autoquest_trigger_check(struct char_data *ch, struct char_data *vict, struct obj_data *object, int type) { struct char_data *i; qst_rnum rnum; int found = TRUE; if (IS_NPC(ch)) return; if (GET_QUEST(ch) == NOTHING) /* No current quest, skip this */ return; if (GET_QUEST_TYPE(ch) != type) return; if ((rnum = real_quest(GET_QUEST(ch))) == NOTHING) return; switch (type) { case AQ_OBJ_FIND: if (QST_TARGET(rnum) == GET_OBJ_VNUM(object)) generic_complete_quest(ch); break; case AQ_ROOM_FIND: if (QST_TARGET(rnum) == world[IN_ROOM(ch)].number) generic_complete_quest(ch); break; case AQ_MOB_FIND: for (i=world[IN_ROOM(ch)].people; i; i = i->next_in_room) if (IS_NPC(i)) if (QST_TARGET(rnum) == GET_MOB_VNUM(i)) generic_complete_quest(ch); break; case AQ_MOB_KILL: if (!IS_NPC(ch) && IS_NPC(vict) && (ch != vict)) if (QST_TARGET(rnum) == GET_MOB_VNUM(vict)) generic_complete_quest(ch); break; case AQ_MOB_SAVE: if (ch == vict) found = FALSE; for (i = world[IN_ROOM(ch)].people; i && found; i = i->next_in_room) if (i && IS_NPC(i) && !MOB_FLAGGED(i, MOB_NOTDEADYET)) if ((GET_MOB_VNUM(i) != QST_TARGET(rnum)) && !AFF_FLAGGED(i, AFF_CHARM)) found = FALSE; if (found) generic_complete_quest(ch); break; case AQ_OBJ_RETURN: if (IS_NPC(vict) && (GET_MOB_VNUM(vict) == QST_RETURNMOB(rnum))) if (object && (GET_OBJ_VNUM(object) == QST_TARGET(rnum))) generic_complete_quest(ch); break; case AQ_ROOM_CLEAR: if (QST_TARGET(rnum) == world[IN_ROOM(ch)].number) { for (i = world[IN_ROOM(ch)].people; i && found; i = i->next_in_room) if (i && IS_NPC(i) && !MOB_FLAGGED(i, MOB_NOTDEADYET)) found = FALSE; if (found) generic_complete_quest(ch); } break; default: log("SYSERR: Invalid quest type passed to autoquest_trigger_check"); break; } }
void generic_complete_quest(struct char_data *ch) { qst_rnum rnum; qst_vnum vnum = GET_QUEST(ch); struct obj_data *new_obj; int happy_qp, happy_gold, happy_exp; if (--GET_QUEST_COUNTER(ch) <= 0) { rnum = real_quest(vnum); if (IS_HAPPYHOUR && IS_HAPPYQP) { happy_qp = (int)(QST_POINTS(rnum) * (((float)(100+HAPPY_QP))/(float)100)); happy_qp = MAX(happy_qp, 0); GET_QUESTPOINTS(ch) += happy_qp; send_to_char(ch, "%s\r\nYou have been awarded %d quest points for your service.\r\n", QST_DONE(rnum), happy_qp); } else { GET_QUESTPOINTS(ch) += QST_POINTS(rnum); send_to_char(ch, "%s\r\nYou have been awarded %d quest points for your service.\r\n", QST_DONE(rnum), QST_POINTS(rnum)); } if (QST_GOLD(rnum)) { if ((IS_HAPPYHOUR) && (IS_HAPPYGOLD)) { happy_gold = (int)(QST_GOLD(rnum) * (((float)(100+HAPPY_GOLD))/(float)100)); happy_gold = MAX(happy_gold, 0); increase_gold(ch, happy_gold); send_to_char(ch, "You have been awarded %d gold coins for your service.\r\n", happy_gold); } else { increase_gold(ch, QST_GOLD(rnum)); send_to_char(ch, "You have been awarded %d gold coins for your service.\r\n", QST_GOLD(rnum)); } } if (QST_EXP(rnum)) { gain_exp(ch, QST_EXP(rnum)); if ((IS_HAPPYHOUR) && (IS_HAPPYEXP)) { happy_exp = (int)(QST_EXP(rnum) * (((float)(100+HAPPY_EXP))/(float)100)); happy_exp = MAX(happy_exp, 0); send_to_char(ch, "You have been awarded %d experience for your service.\r\n", happy_exp); } else { send_to_char(ch, "You have been awarded %d experience points for your service.\r\n", QST_EXP(rnum)); } } if (QST_OBJ(rnum) && QST_OBJ(rnum) != NOTHING) { if (real_object(QST_OBJ(rnum)) != NOTHING) { if ((new_obj = read_object((QST_OBJ(rnum)),VIRTUAL)) != NULL) { obj_to_char(new_obj, ch); send_to_char(ch, "You have been presented with %s%s for your service.\r\n", GET_OBJ_SHORT(new_obj), CCNRM(ch, C_NRM)); } } } if (!IS_SET(QST_FLAGS(rnum), AQ_REPEATABLE)) add_completed_quest(ch, vnum); clear_quest(ch); if ((real_quest(QST_NEXT(rnum)) != NOTHING) && (QST_NEXT(rnum) != vnum) && !is_complete(ch, QST_NEXT(rnum))) { rnum = real_quest(QST_NEXT(rnum)); set_quest(ch, rnum); send_to_char(ch, "The next stage of your quest awaits:\r\n%s", QST_INFO(rnum)); } } save_char(ch); }
struct creature * load_player_from_file(const char *path) { struct creature *ch = NULL; char *txt; if (access(path, W_OK)) { errlog("Unable to open xml player file '%s': %s", path, strerror(errno)); return NULL; } xmlDocPtr doc = xmlParseFile(path); if (!doc) { errlog("XML parse error while loading %s", path); return NULL; } xmlNodePtr root = xmlDocGetRootElement(doc); if (!root) { xmlFreeDoc(doc); errlog("XML file %s is empty", path); return NULL; } /* to save memory, only PC's -- not MOB's -- have player_specials */ ch = make_creature(true); ch->player.name = (char *)xmlGetProp(root, (xmlChar *) "name"); ch->char_specials.saved.idnum = xmlGetIntProp(root, "idnum", 0); set_title(ch, ""); ch->player.short_descr = NULL; ch->player.long_descr = NULL; if (ch->points.max_mana < 100) ch->points.max_mana = 100; ch->char_specials.carry_weight = 0; ch->char_specials.carry_items = 0; ch->char_specials.worn_weight = 0; ch->points.armor = 100; ch->points.hitroll = 0; ch->points.damroll = 0; ch->player_specials->saved.speed = 0; // Read in the subnodes for (xmlNodePtr node = root->xmlChildrenNode; node; node = node->next) { if (xmlMatches(node->name, "points")) { ch->points.mana = xmlGetIntProp(node, "mana", 100); ch->points.max_mana = xmlGetIntProp(node, "maxmana", 100); ch->points.hit = xmlGetIntProp(node, "hit", 100); ch->points.max_hit = xmlGetIntProp(node, "maxhit", 100); ch->points.move = xmlGetIntProp(node, "move", 100); ch->points.max_move = xmlGetIntProp(node, "maxmove", 100); } else if (xmlMatches(node->name, "money")) { ch->points.gold = xmlGetIntProp(node, "gold", 0); ch->points.cash = xmlGetIntProp(node, "cash", 0); ch->points.exp = xmlGetIntProp(node, "xp", 0); } else if (xmlMatches(node->name, "stats")) { ch->player.level = xmlGetIntProp(node, "level", 0); ch->player.height = xmlGetIntProp(node, "height", 0); ch->player.weight = xmlGetIntProp(node, "weight", 0); GET_ALIGNMENT(ch) = xmlGetIntProp(node, "align", 0); /*** Temp fix for negative weights ***/ if (ch->player.weight < 0) { calculate_height_weight(ch); } GET_SEX(ch) = 0; char *sex = (char *)xmlGetProp(node, (xmlChar *) "sex"); if (sex != NULL) GET_SEX(ch) = search_block(sex, genders, false); free(sex); GET_RACE(ch) = 0; char *race_name = (char *)xmlGetProp(node, (xmlChar *) "race"); if (race_name != NULL) { struct race *race = race_by_name(race_name, true); if (race != NULL) { GET_RACE(ch) = race->idnum; } } free(race_name); } else if (xmlMatches(node->name, "class")) { GET_OLD_CLASS(ch) = GET_REMORT_CLASS(ch) = GET_CLASS(ch) = -1; char *trade = (char *)xmlGetProp(node, (xmlChar *) "name"); if (trade != NULL) { GET_CLASS(ch) = search_block(trade, class_names, false); free(trade); } trade = (char *)xmlGetProp(node, (xmlChar *) "remort"); if (trade != NULL) { GET_REMORT_CLASS(ch) = search_block(trade, class_names, false); free(trade); } if (IS_CYBORG(ch)) { char *subclass = (char *)xmlGetProp(node, (xmlChar *) "subclass"); if (subclass != NULL) { GET_OLD_CLASS(ch) = search_block(subclass, borg_subchar_class_names, false); free(subclass); } } if (GET_CLASS(ch) == CLASS_MAGE) { ch->player_specials->saved.mana_shield_low = xmlGetLongProp(node, "manash_low", 0); ch->player_specials->saved.mana_shield_pct = xmlGetLongProp(node, "manash_pct", 0); } GET_REMORT_GEN(ch) = xmlGetIntProp(node, "gen", 0); GET_TOT_DAM(ch) = xmlGetIntProp(node, "total_dam", 0); GET_BROKE(ch) = xmlGetIntProp(node, "broken", 0); } else if (xmlMatches(node->name, "time")) { ch->player.time.birth = xmlGetLongProp(node, "birth", 0); ch->player.time.death = xmlGetLongProp(node, "death", 0); ch->player.time.played = xmlGetLongProp(node, "played", 0); ch->player.time.logon = xmlGetLongProp(node, "last", 0); } else if (xmlMatches(node->name, "carnage")) { GET_PKILLS(ch) = xmlGetIntProp(node, "pkills", 0); GET_ARENAKILLS(ch) = xmlGetIntProp(node, "akills", 0); GET_MOBKILLS(ch) = xmlGetIntProp(node, "mkills", 0); GET_PC_DEATHS(ch) = xmlGetIntProp(node, "deaths", 0); RAW_REPUTATION_OF(ch) = xmlGetIntProp(node, "reputation", 0); GET_SEVERITY(ch) = xmlGetIntProp(node, "severity", 0); } else if (xmlMatches(node->name, "attr")) { ch->aff_abils.str = ch->real_abils.str = xmlGetIntProp(node, "str", 0); ch->aff_abils.str = ch->real_abils.str += xmlGetIntProp(node, "stradd", 0) / 10; ch->aff_abils.intel = ch->real_abils.intel = xmlGetIntProp(node, "int", 0); ch->aff_abils.wis = ch->real_abils.wis = xmlGetIntProp(node, "wis", 0); ch->aff_abils.dex = ch->real_abils.dex = xmlGetIntProp(node, "dex", 0); ch->aff_abils.con = ch->real_abils.con = xmlGetIntProp(node, "con", 0); ch->aff_abils.cha = ch->real_abils.cha = xmlGetIntProp(node, "cha", 0); } else if (xmlMatches(node->name, "condition")) { GET_COND(ch, THIRST) = xmlGetIntProp(node, "thirst", 0); GET_COND(ch, FULL) = xmlGetIntProp(node, "hunger", 0); GET_COND(ch, DRUNK) = xmlGetIntProp(node, "drunk", 0); } else if (xmlMatches(node->name, "player")) { GET_WIMP_LEV(ch) = xmlGetIntProp(node, "wimpy", 0); GET_LIFE_POINTS(ch) = xmlGetIntProp(node, "lp", 0); GET_CLAN(ch) = xmlGetIntProp(node, "clan", 0); } else if (xmlMatches(node->name, "home")) { GET_HOME(ch) = xmlGetIntProp(node, "town", 0); GET_HOMEROOM(ch) = xmlGetIntProp(node, "homeroom", 0); GET_LOADROOM(ch) = xmlGetIntProp(node, "loadroom", 0); } else if (xmlMatches(node->name, "quest")) { GET_QUEST(ch) = xmlGetIntProp(node, "current", 0); GET_IMMORT_QP(ch) = xmlGetIntProp(node, "points", 0); GET_QUEST_ALLOWANCE(ch) = xmlGetIntProp(node, "allowance", 0); } else if (xmlMatches(node->name, "bits")) { char *flag = (char *)xmlGetProp(node, (xmlChar *) "flag1"); ch->char_specials.saved.act = hex2dec(flag); free(flag); flag = (char *)xmlGetProp(node, (xmlChar *) "flag2"); ch->player_specials->saved.plr2_bits = hex2dec(flag); free(flag); } else if (xmlMatches(node->name, "frozen")) { ch->player_specials->thaw_time = xmlGetIntProp(node, "thaw_time", 0); ch->player_specials->freezer_id = xmlGetIntProp(node, "freezer_id", 0); } else if (xmlMatches(node->name, "prefs")) { char *flag = (char *)xmlGetProp(node, (xmlChar *) "flag1"); ch->player_specials->saved.pref = hex2dec(flag); free(flag); flag = (char *)xmlGetProp(node, (xmlChar *) "flag2"); ch->player_specials->saved.pref2 = hex2dec(flag); free(flag); flag = (char *)xmlGetProp(node, (xmlChar *) "tongue"); if (flag) GET_TONGUE(ch) = find_tongue_idx_by_name(flag); free(flag); } else if (xmlMatches(node->name, "weaponspec")) { int vnum = xmlGetIntProp(node, "vnum", -1); int level = xmlGetIntProp(node, "level", 0); if (vnum > 0 && level > 0) { for (int i = 0; i < MAX_WEAPON_SPEC; i++) { if (GET_WEAP_SPEC(ch, i).level <= 0) { GET_WEAP_SPEC(ch, i).vnum = vnum; GET_WEAP_SPEC(ch, i).level = level; break; } } } } else if (xmlMatches(node->name, "title")) { char *txt; txt = (char *)xmlNodeGetContent(node); set_title(ch, txt); free(txt); } else if (xmlMatches(node->name, "affect")) { struct affected_type af; init_affect(&af); af.type = xmlGetIntProp(node, "type", 0); af.duration = xmlGetIntProp(node, "duration", 0); af.modifier = xmlGetIntProp(node, "modifier", 0); af.location = xmlGetIntProp(node, "location", 0); af.level = xmlGetIntProp(node, "level", 0); af.aff_index = xmlGetIntProp(node, "index", 0); af.owner = xmlGetIntProp(node, "owner", 0); af.next = NULL; char *instant = (char *)xmlGetProp(node, (xmlChar *) "instant"); if (instant != NULL && strcmp(instant, "yes") == 0) { af.is_instant = 1; } free(instant); char *bits = (char *)xmlGetProp(node, (xmlChar *) "affbits"); af.bitvector = hex2dec(bits); free(bits); affect_to_char(ch, &af); } else if (xmlMatches(node->name, "affects")) { // PCs shouldn't have ANY perm affects if (IS_NPC(ch)) { char *flag = (char *)xmlGetProp(node, (xmlChar *) "flag1"); AFF_FLAGS(ch) = hex2dec(flag); free(flag); flag = (char *)xmlGetProp(node, (xmlChar *) "flag2"); AFF2_FLAGS(ch) = hex2dec(flag); free(flag); flag = (char *)xmlGetProp(node, (xmlChar *) "flag3"); AFF3_FLAGS(ch) = hex2dec(flag); free(flag); } else { AFF_FLAGS(ch) = 0; AFF2_FLAGS(ch) = 0; AFF3_FLAGS(ch) = 0; } } else if (xmlMatches(node->name, "skill")) { char *spellName = (char *)xmlGetProp(node, (xmlChar *) "name"); int index = str_to_spell(spellName); if (index >= 0) { SET_SKILL(ch, index, xmlGetIntProp(node, "level", 0)); } free(spellName); } else if (xmlMatches(node->name, "tongue")) { char *tongue = (char *)xmlGetProp(node, (xmlChar *) "name"); int index = find_tongue_idx_by_name(tongue); if (index >= 0) SET_TONGUE(ch, index, MIN(100, xmlGetIntProp(node, "level", 0))); free(tongue); } else if (xmlMatches(node->name, "alias")) { struct alias_data *alias; CREATE(alias, struct alias_data, 1); alias->type = xmlGetIntProp(node, "type", 0); alias->alias = (char *)xmlGetProp(node, (xmlChar *) "alias"); alias->replacement = (char *)xmlGetProp(node, (xmlChar *) "replace"); if (alias->alias == NULL || alias->replacement == NULL) { free(alias); } else { add_alias(ch, alias); } } else if (xmlMatches(node->name, "description")) { txt = (char *)xmlNodeGetContent(node); ch->player.description = strdup(tmp_gsub(txt, "\n", "\r\n")); free(txt); } else if (xmlMatches(node->name, "poofin")) { POOFIN(ch) = (char *)xmlNodeGetContent(node); } else if (xmlMatches(node->name, "poofout")) { POOFOUT(ch) = (char *)xmlNodeGetContent(node); } else if (xmlMatches(node->name, "immort")) { txt = (char *)xmlGetProp(node, (xmlChar *) "badge"); strncpy(BADGE(ch), txt, 7); BADGE(ch)[7] = '\0'; free(txt); GET_QLOG_LEVEL(ch) = xmlGetIntProp(node, "qlog", 0); GET_INVIS_LVL(ch) = xmlGetIntProp(node, "invis", 0); } else if (xmlMatches(node->name, "rent")) { char *txt; ch->player_specials->rentcode = xmlGetIntProp(node, "code", 0); ch->player_specials->rent_per_day = xmlGetIntProp(node, "perdiem", 0); ch->player_specials->rent_currency = xmlGetIntProp(node, "currency", 0); txt = (char *)xmlGetProp(node, (xmlChar *) "state"); if (txt) ch->player_specials->desc_mode = (enum cxn_state)search_block(txt, desc_modes, false); free(txt); } else if (xmlMatches(node->name, "recentkill")) { struct kill_record *kill; CREATE(kill, struct kill_record, 1); kill->vnum = xmlGetIntProp(node, "vnum", 0); kill->times = xmlGetIntProp(node, "times", 0); GET_RECENT_KILLS(ch) = g_list_prepend(GET_RECENT_KILLS(ch), kill); } else if (xmlMatches(node->name, "grievance")) {
void save_player_to_file(struct creature *ch, const char *path) { void expire_old_grievances(struct creature *); // Save vital statistics FILE *ouf; char *tmp_path; struct alias_data *cur_alias; int idx; int hit = GET_HIT(ch), mana = GET_MANA(ch), move = GET_MOVE(ch); tmp_path = tmp_sprintf("%s.tmp", path); ouf = fopen(tmp_path, "w"); if (!ouf) { fprintf(stderr, "Unable to open XML player file for save.[%s] (%s)\n", path, strerror(errno)); return; } struct aff_stash *aff_stash = stash_creature_affects(ch); expire_old_grievances(ch); fprintf(ouf, "<creature name=\"%s\" idnum=\"%ld\">\n", GET_NAME(ch), ch->char_specials.saved.idnum); fprintf(ouf, "<points hit=\"%d\" mana=\"%d\" move=\"%d\" maxhit=\"%d\" maxmana=\"%d\" maxmove=\"%d\"/>\n", ch->points.hit, ch->points.mana, ch->points.move, ch->points.max_hit, ch->points.max_mana, ch->points.max_move); fprintf(ouf, "<money gold=\"%" PRId64 "\" cash=\"%" PRId64 "\" xp=\"%d\"/>\n", ch->points.gold, ch->points.cash, ch->points.exp); fprintf(ouf, "<stats level=\"%d\" sex=\"%s\" race=\"%s\" height=\"%d\" weight=\"%f\" align=\"%d\"/>\n", GET_LEVEL(ch), genders[(int)GET_SEX(ch)], race_name_by_idnum(GET_RACE(ch)), GET_HEIGHT(ch), GET_WEIGHT(ch), GET_ALIGNMENT(ch)); fprintf(ouf, "<class name=\"%s\"", class_names[GET_CLASS(ch)]); if (GET_REMORT_CLASS(ch) != CLASS_UNDEFINED) fprintf(ouf, " remort=\"%s\"", class_names[GET_REMORT_CLASS(ch)]); if (GET_REMORT_GEN(ch) > 0) fprintf(ouf, " gen=\"%d\"", GET_REMORT_GEN(ch)); if (IS_CYBORG(ch)) { if (GET_OLD_CLASS(ch) != -1) fprintf(ouf, " subclass=\"%s\"", borg_subchar_class_names[GET_OLD_CLASS(ch)]); if (GET_TOT_DAM(ch)) fprintf(ouf, " total_dam=\"%d\"", GET_TOT_DAM(ch)); if (GET_BROKE(ch)) fprintf(ouf, " broken=\"%d\"", GET_BROKE(ch)); } if (GET_CLASS(ch) == CLASS_MAGE && GET_SKILL(ch, SPELL_MANA_SHIELD) > 0) { fprintf(ouf, " manash_low=\"%ld\" manash_pct=\"%ld\"", ch->player_specials->saved.mana_shield_low, ch->player_specials->saved.mana_shield_pct); } fprintf(ouf, "/>\n"); fprintf(ouf, "<time birth=\"%ld\" death=\"%ld\" played=\"%ld\" last=\"%ld\"/>\n", ch->player.time.birth, ch->player.time.death, ch->player.time.played, ch->player.time.logon); fprintf(ouf, "<carnage pkills=\"%d\" akills=\"%d\" mkills=\"%d\" deaths=\"%d\" reputation=\"%d\"", GET_PKILLS(ch), GET_ARENAKILLS(ch), GET_MOBKILLS(ch), GET_PC_DEATHS(ch), ch->player_specials->saved.reputation); fprintf(ouf, "/>\n"); fprintf(ouf, "<attr str=\"%d\" int=\"%d\" wis=\"%d\" dex=\"%d\" con=\"%d\" cha=\"%d\"/>\n", ch->real_abils.str, ch->real_abils.intel, ch->real_abils.wis, ch->real_abils.dex, ch->real_abils.con, ch->real_abils.cha); fprintf(ouf, "<condition hunger=\"%d\" thirst=\"%d\" drunk=\"%d\"/>\n", GET_COND(ch, FULL), GET_COND(ch, THIRST), GET_COND(ch, DRUNK)); fprintf(ouf, "<player wimpy=\"%d\" lp=\"%d\" clan=\"%d\"/>\n", GET_WIMP_LEV(ch), GET_LIFE_POINTS(ch), GET_CLAN(ch)); if (ch->desc) ch->player_specials->desc_mode = ch->desc->input_mode; if (ch->player_specials->rentcode == RENT_CREATING || ch->player_specials->rentcode == RENT_REMORTING) { fprintf(ouf, "<rent code=\"%d\" perdiem=\"%d\" " "currency=\"%d\" state=\"%s\"/>\n", ch->player_specials->rentcode, ch->player_specials->rent_per_day, ch->player_specials->rent_currency, desc_modes[(int)ch->player_specials->desc_mode]); } else { fprintf(ouf, "<rent code=\"%d\" perdiem=\"%d\" currency=\"%d\"/>\n", ch->player_specials->rentcode, ch->player_specials->rent_per_day, ch->player_specials->rent_currency); } fprintf(ouf, "<home town=\"%d\" homeroom=\"%d\" loadroom=\"%d\"/>\n", GET_HOME(ch), GET_HOMEROOM(ch), GET_LOADROOM(ch)); fprintf(ouf, "<quest"); if (GET_QUEST(ch)) fprintf(ouf, " current=\"%d\"", GET_QUEST(ch)); if (GET_LEVEL(ch) >= LVL_IMMORT) fprintf(ouf, " allowance=\"%d\"", GET_QUEST_ALLOWANCE(ch)); if (GET_IMMORT_QP(ch) != 0) fprintf(ouf, " points=\"%d\"", GET_IMMORT_QP(ch)); fprintf(ouf, "/>\n"); fprintf(ouf, "<bits flag1=\"%" PRIx32 "\" flag2=\"%" PRIx32 "\"/>\n", ch->char_specials.saved.act, ch->player_specials->saved.plr2_bits); if (PLR_FLAGGED(ch, PLR_FROZEN)) { fprintf(ouf, "<frozen thaw_time=\"%d\" freezer_id=\"%d\"/>\n", ch->player_specials->thaw_time, ch->player_specials->freezer_id); } fprintf(ouf, "<prefs flag1=\"%" PRIx32 "\" flag2=\"%" PRIx32 "\" tongue=\"%s\"/>\n", ch->player_specials->saved.pref, ch->player_specials->saved.pref2, tongue_name(GET_TONGUE(ch))); fprintf(ouf, "<affects flag1=\"%" PRIx32 "\" flag2=\"%" PRIx32 "\" flag3=\"%" PRIx32 "\"/>\n", ch->char_specials.saved.affected_by, ch->char_specials.saved.affected2_by, ch->char_specials.saved.affected3_by); for (idx = 0; idx < MAX_WEAPON_SPEC; idx++) { if (GET_WEAP_SPEC(ch, idx).level > 0) fprintf(ouf, "<weaponspec vnum=\"%d\" level=\"%d\"/>\n", GET_WEAP_SPEC(ch, idx).vnum, GET_WEAP_SPEC(ch, idx).level); } if (GET_TITLE(ch) && *GET_TITLE(ch)) { fprintf(ouf, "<title>%s</title>\n", xmlEncodeTmp(GET_TITLE(ch))); } if (GET_LEVEL(ch) >= 50) { fprintf(ouf, "<immort badge=\"%s\" qlog=\"%d\" invis=\"%d\"/>\n", xmlEncodeSpecialTmp(BADGE(ch)), GET_QLOG_LEVEL(ch), GET_INVIS_LVL(ch)); if (POOFIN(ch) && *POOFIN(ch)) fprintf(ouf, "<poofin>%s</poofin>\n", xmlEncodeTmp(POOFIN(ch))); if (POOFOUT(ch) && *POOFOUT(ch)) fprintf(ouf, "<poofout>%s</poofout>\n", xmlEncodeTmp(POOFOUT(ch))); } if (ch->player.description && *ch->player.description) { fprintf(ouf, "<description>%s</description>\n", xmlEncodeTmp(tmp_gsub(tmp_gsub(ch->player.description, "\r\n", "\n"), "\r", ""))); } for (cur_alias = ch->player_specials->aliases; cur_alias; cur_alias = cur_alias->next) fprintf(ouf, "<alias type=\"%d\" alias=\"%s\" replace=\"%s\"/>\n", cur_alias->type, xmlEncodeSpecialTmp(cur_alias->alias), xmlEncodeSpecialTmp(cur_alias->replacement)); for (struct affected_type *cur_aff = aff_stash->saved_affs; cur_aff; cur_aff = cur_aff->next) fprintf(ouf, "<affect type=\"%d\" duration=\"%d\" modifier=\"%d\" location=\"%d\" level=\"%d\" instant=\"%s\" affbits=\"%lx\" index=\"%d\" owner=\"%ld\"/>\n", cur_aff->type, cur_aff->duration, cur_aff->modifier, cur_aff->location, cur_aff->level, (cur_aff->is_instant) ? "yes" : "no", cur_aff->bitvector, cur_aff->aff_index, cur_aff->owner); if (!IS_IMMORT(ch)) { for (idx = 0; idx < MAX_SKILLS; idx++) if (ch->player_specials->saved.skills[idx] > 0) fprintf(ouf, "<skill name=\"%s\" level=\"%d\"/>\n", spell_to_str(idx), GET_SKILL(ch, idx)); write_tongue_xml(ch, ouf); for (GList * it = GET_RECENT_KILLS(ch); it; it = it->next) { struct kill_record *kill = it->data; fprintf(ouf, "<recentkill vnum=\"%d\" times=\"%d\"/>\n", kill->vnum, kill->times); } for (GList * it = GET_GRIEVANCES(ch); it; it = it->next) { struct grievance *grievance = it->data; fprintf(ouf, "<grievance time=\"%lu\" player=\"%d\" reputation=\"%d\" kind=\"%s\"/>\n", (long unsigned)grievance->time, grievance->player_id, grievance->rep, grievance_kind_descs[grievance->grievance]); } } if (IS_PC(ch) && ch->player_specials->tags) { GHashTableIter iter; char *key; g_hash_table_iter_init(&iter, ch->player_specials->tags); while (g_hash_table_iter_next(&iter, (gpointer *)&key, NULL)) { fprintf(ouf, "<tag tag=\"%s\"/>\n", key); } } fprintf(ouf, "</creature>\n"); fclose(ouf); // on success, move temp file on top of the old file rename(tmp_path, path); restore_creature_affects(ch, aff_stash); free(aff_stash); GET_HIT(ch) = MIN(GET_MAX_HIT(ch), hit); GET_MANA(ch) = MIN(GET_MAX_MANA(ch), mana); GET_MOVE(ch) = MIN(GET_MAX_MOVE(ch), move); }