示例#1
0
文件: clan.c 项目: ryantm/deimos-mud
 /* Accept an applicant into the clan */
 void do_caccept( struct char_data *ch, struct clan_type *cptr, struct char_data *vict )
 {
   int i=0;

   if (vict != NULL && (GET_CLAN(vict) < CLAN_MEMBER)) {
     GET_CLAN(vict)     = GET_CLAN(ch);
     GET_CLAN_RANK(vict) = CLAN_MEMBER;
     /* send some sort of mail to player notifying him/her of acceptance */
     sprintf(buf, "%s,\r\n\r\n"
       "   Congratulations!  You have been accepted into the ranks of\r\n"
       "%s.  The leader of our clan is %s.  Good luck.\r\n",
       GET_NAME(vict), cptr->name, cptr->leadersname);
     store_mail(GET_IDNUM(vict), GET_IDNUM(ch), -1, buf);
     /* now that the mail has been sent, let's continue. */
     GET_HOME(vict) = GET_HOME(ch);
     save_char(vict, NOWHERE);
     /* now remove the player from the petition list */
     remove_applicant(cptr, vict);

     for (i = 0; i < 100; i++)
     {
       if (cptr->members[i] == NULL)
       {
         cptr->members[i] = strdup(GET_NAME(vict));
         break;
       }
       if (strcmp(cptr->members[i], GET_NAME(vict)) == 0)
         break;  
     }

     save_clans();
   }
   return;
 }
示例#2
0
文件: clan.c 项目: ryantm/deimos-mud
 /* Dismiss a member from the clan/Resign from the clan */
 void do_dismiss( struct char_data *ch, struct clan_type *cptr, struct char_data *vict )
 {
   if (vict != ch){
     if (vict != NULL && GET_CLAN(vict) == GET_CLAN(ch)) {
       if (GET_CLAN_RANK(vict) >= GET_CLAN_RANK(ch)) {
         send_to_char("You may not dismiss those of equal or greater clan status than yourself!\r\n", ch);
         return;
       }
     /* send some sort of mail to player notifying him/her of dismissal */
     sprintf(buf, "%s,\r\n\r\n"
       "   You have been dismissed from the clan of %s.\r\n"
       "If you are unsure of the reason why, please feel\r\n"
       "free to contact the leader, %s.\r\n",
       GET_NAME(vict), cptr->name, cptr->leadersname);
     store_mail(GET_IDNUM(vict), GET_IDNUM(ch), -1, buf);
     remove_member(cptr, vict);
     }
   } else if (GET_CLAN_RANK(vict) == CLAN_LEADER) {
     GET_CLAN_RANK(vict) = CLAN_MEMBER;
     send_to_char("You have resigned as leader.\r\n", ch);
     cptr->leadersname = strdup("NoOne");
     save_clans();
     return;
   }
   GET_CLAN(vict) = CLAN_NONE;
   GET_CLAN_RANK(vict) = CLAN_NONE;
   GET_HOME(vict) = 1;

   remove_member(cptr, vict);
   save_char(vict, NOWHERE);
   save_clans();
   return;
 }
示例#3
0
// Create a brand new character
struct creature *
account_create_char(struct account *account, const char *name)
{
    struct creature *ch;
    int i;

    if (chars_available(account) <= 0)
        return NULL;

    ch = make_creature(true);

    ch->player.name = strdup(tmp_capitalize(tmp_tolower(name)));
    ch->char_specials.saved.idnum = top_player_idnum() + 1;
    account->chars =
        g_list_append(account->chars, GINT_TO_POINTER(GET_IDNUM(ch)));

    sql_exec
        ("insert into players (idnum, name, account) values (%ld, '%s', %d)",
        GET_IDNUM(ch), tmp_sqlescape(name), account->id);

    // New characters shouldn't get old mail.
    if (has_mail(GET_IDNUM(ch))) {
        if (purge_mail(GET_IDNUM(ch)) > 0) {
            errlog("Purging pre-existing mailfile for new character.(%s)",
                GET_NAME(ch));
        }
    }
    // *** if this is our first player --- he be God ***
    if (GET_IDNUM(ch) == 1) {
        GET_EXP(ch) = 160000000;
        GET_LEVEL(ch) = LVL_GRIMP;

        ch->points.max_hit = 666;
        ch->points.max_mana = 555;
        ch->points.max_move = 444;

        GET_HOME(ch) = HOME_MODRIAN;
        ch->player_specials->saved.load_room = -1;
        ch->player_specials->saved.home_room = 1204;
    } else {
        ch->points.max_hit = 100;
        ch->points.max_mana = 100;
        ch->points.max_move = 82;

        GET_HOME(ch) = HOME_NEWBIE_SCHOOL;
        ch->player_specials->saved.load_room = -1;
        ch->player_specials->saved.home_room = -1;
    }
    ch->player_specials->rentcode = RENT_CREATING;

    set_title(ch, "");

    ch->player.short_descr = NULL;
    ch->player.long_descr = NULL;
    ch->player.description = NULL;

    ch->player.time.birth = time(NULL);
    ch->player.time.death = 0;
    ch->player.time.played = 0;
    ch->player.time.logon = time(NULL);

    for (i = 0; i < MAX_SKILLS; i++)
        ch->player_specials->saved.skills[i] = 0;

    for (i = 0; i < MAX_WEAPON_SPEC; i++) {
        ch->player_specials->saved.weap_spec[i].vnum = 0;
        ch->player_specials->saved.weap_spec[i].level = 0;
    }
    ch->player_specials->saved.imm_qp = 0;
    ch->player_specials->saved.quest_id = 0;
    ch->player_specials->saved.qlog_level = 0;

    GET_REMORT_CLASS(ch) = -1;
    ch->player.weight = 100;
    ch->player.height = 100;

    ch->points.hit = GET_MAX_HIT(ch);
    ch->points.mana = GET_MAX_MANA(ch);
    ch->points.move = GET_MAX_MOVE(ch);
    ch->points.armor = 100;

    SET_BIT(PRF_FLAGS(ch),
        PRF_DISPHP | PRF_DISPMANA | PRF_DISPMOVE | PRF_AUTOEXIT | PRF_NOSPEW |
        PRF_NOPLUG);
    SET_BIT(PRF2_FLAGS(ch),
        PRF2_AUTO_DIAGNOSE | PRF2_AUTOPROMPT | PRF2_DISPALIGN |
        PRF2_NEWBIE_HELPER);

    ch->char_specials.saved.affected_by = 0;
    ch->char_specials.saved.affected2_by = 0;
    ch->char_specials.saved.affected3_by = 0;

    for (i = 0; i < 5; i++)
        GET_SAVE(ch, i) = 0;

    GET_COND(ch, FULL) = (GET_LEVEL(ch) == LVL_GRIMP ? -1 : 24);
    GET_COND(ch, THIRST) = (GET_LEVEL(ch) == LVL_GRIMP ? -1 : 24);
    GET_COND(ch, DRUNK) = (GET_LEVEL(ch) == LVL_GRIMP ? -1 : 0);

    POOFIN(ch) = NULL;
    POOFOUT(ch) = NULL;
    return ch;
}
示例#4
0
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")) {
示例#5
0
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);
}