/** * @file character.c * @ingroup character * * Character based code * * @author Geoff Davis <geoff@circlemudsquared.org> * @author Greg Buxton <greg@circlemudsquared.org> * * @par Copyright: * Copyright (C) 2006 Geoff Davis <geoff@circlemudsquared.org><br> * Greg Buxton <greg@circlemudsquared.org> * * @par * Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University<br> * CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991. * * @par * All rights reserved. See license.doc for complete information. * * @package cs * @version 1.0 */ #define __CHARACTER_C__ #include "base.h" #include "structs.h" #include "utils.h" #include "comm.h" #include "command.h" #include "constants.h" #include "db.h" #include "handler.h" #include "interpreter.h" #include "log.h" #include "dao.h" #include "character.h" #include "item.h" #include "room.h" /* * Global variables. */ /** * The number of pending character extractions. * @var unsigned long */ unsigned long extractions_pending = 0UL; /* * External variables. */ extern charData_t *combat_list; extern const char *MENU; extern const char *genders[]; extern const char *npc_class_types[]; extern const char *pc_class_types[]; extern const char *save_types[]; extern const char *preference_bits[]; extern const char *player_bits[]; extern const char *action_bits[]; /* * External functions. */ int apply_ac(charData_t *ch, int eq_pos); void clearMemory(charData_t *ch); bool invalid_align(charData_t *ch, itemData_t *obj); bool invalid_class(charData_t *ch, itemData_t *obj); /** * Equips an item in a wear slot. * @param ch the character to be equipped * @param obj the item with which the character is to be equipped * @param pos the wear slot (WEAR_xxx) where the item is to be worn * @return none */ void char_equipItem(charData_t *ch, itemData_t *obj, int pos) { if (ch == NULL) { log("char_equipItem(): invalid 'ch' charData_t."); } else if (obj == NULL) { log("char_equipItem(): invalid 'obj' itemData_t."); } else if (pos < 0 || pos >= NUM_WEARS) { log("char_equipItem(): invalid 'pos' value %d.", pos); } else if (obj->carriedBy != NULL) { log("char_equipItem(): itemData_t 'obj' is being carried."); } else if (obj->wornBy != NULL) { log("char_equipItem(): itemData_t 'obj' is being worn."); } else if (IN_ROOM(obj) != NULL) { log("char_equipItem(): itemData_t 'obj' is in room #%s:%d.", IN_ROOM(obj)->zone->keyword, IN_ROOM(obj)->number); } else { int j; if (GET_EQ(ch, pos) != NULL) { itemData_toChar(char_unequipItem(ch, pos), ch); } if (invalid_align(ch, obj) || invalid_class(ch, obj)) { act("You are zapped by $p and instantly let go of it.", FALSE, ch, obj, 0, TO_CHAR); act("$n is zapped by $p and instantly lets go of it.", FALSE, ch, obj, 0, TO_ROOM); /* Changed to drop in inventory instead of the ground. */ itemData_toChar(obj, ch); } else { GET_EQ(ch, pos) = obj; obj->wornBy = ch; obj->wornOn = pos; if (GET_ITEM_TYPE(obj) == ITEM_ARMOR) { GET_AC(ch) -= apply_ac(ch, pos); } if (IN_ROOM(ch) != NULL) { if (pos == WEAR_LIGHT && GET_ITEM_TYPE(obj) == ITEM_LIGHT) { if (GET_ITEM_VAL(obj, 2)) { /* if light is ON */ ch->room->light++; } } } for (j = 0; j < MAX_ITEM_AFFECT; j++) { effectData_modify(ch, obj->affected[j].location, obj->affected[j].modifier, GET_ITEM_AFFECT(obj), TRUE); } effectData_total(ch); } } } /** * Removes a character from its room. * @param ch the character to be removed * @return none */ void char_fromRoom(charData_t *ch) { if (ch == NULL) { log("char_fromRoom(): invalid 'ch' charData_t."); } else { if (IN_ROOM(ch) == NULL) { log("char_fromRoom(): charData_t 'ch' in nowhere."); } else { /* Declare an iterator variable. */ register charData_t *temp; /* Stop the character from fighting. */ if (FIGHTING(ch) != NULL) { charData_stopFighting(ch); } /* Remove any lighting supplied by the character. */ if (GET_EQ(ch, WEAR_LIGHT) != NULL) { if (GET_ITEM_TYPE(GET_EQ(ch, WEAR_LIGHT)) == ITEM_LIGHT) { if (GET_ITEM_VAL(GET_EQ(ch, WEAR_LIGHT), 2)) { /* Light is ON */ (IN_ROOM(ch))->light--; } } } /* Unlink the character from the room. */ REMOVE_FROM_LIST(ch, (IN_ROOM(ch))->people, next_in_room); IN_ROOM(ch) = NULL; ch->next_in_room = NULL; } } } /** * Places a character into a room. * @param ch the character to be placed * @param room the room the place the character into * @return none */ void char_toRoom(charData_t *ch, roomData_t *room) { if (ch == NULL) { log("char_toRoom(): invalid 'ch' charData_t."); } else if (room == NULL) { log("char_toRoom(): invalid 'room' roomData_t."); } else { /* Remove the character from its current room. */ if (IN_ROOM(ch) != NULL) { char_fromRoom(ch); } /* Link the character into the room. */ ch->next_in_room = room->people; room->people = ch; IN_ROOM(ch) = room; /* Adjust the room's lighting. */ if (GET_EQ(ch, WEAR_LIGHT)) { if (GET_ITEM_TYPE(GET_EQ(ch, WEAR_LIGHT)) == ITEM_LIGHT) { if (GET_ITEM_VAL(GET_EQ(ch, WEAR_LIGHT), 2)) { /* Light ON */ room->light++; } } } /* Stop fighting now, if we left. */ if (FIGHTING(ch) && IN_ROOM(ch) != IN_ROOM(FIGHTING(ch))) { charData_stopFighting(FIGHTING(ch)); charData_stopFighting(ch); } } } /** * Removes the item equipped in a wear slot. * @param ch the character to be unequipped * @param pos the wear slot (WEAR_xxx) to be unequipped * @return the item unequipped from the wear slot, or NULL */ itemData_t *char_unequipItem(charData_t *ch, int pos) { itemData_t *obj = NULL; if (ch == NULL) { log("char_unequipItem(): invalid 'ch' charData_t."); } else if (pos < 0 || pos >= NUM_WEARS) { log("char_unequipItem(): invalid 'pos' value %d.", pos); } else if (GET_EQ(ch, pos) != NULL) { register int j = 0; obj = GET_EQ(ch, pos); obj->wornBy = NULL; obj->wornOn = -1; if (GET_ITEM_TYPE(obj) == ITEM_ARMOR) { GET_AC(ch) += apply_ac(ch, pos); } if (IN_ROOM(ch) != NULL) { if (pos == WEAR_LIGHT && GET_ITEM_TYPE(obj) == ITEM_LIGHT) { if (GET_ITEM_VAL(obj, 2)) { /* if light is ON */ ch->room->light--; } } } GET_EQ(ch, pos) = NULL; for (j = 0; j < MAX_ITEM_AFFECT; j++) { effectData_modify(ch, obj->affected[j].location, obj->affected[j].modifier, GET_ITEM_AFFECT(obj), FALSE); } effectData_total(ch); } return (obj); } /** * Extracts a character. * @param ch the character to be extracted * @return none */ void char_extract(charData_t *ch) { /* * Q: Why do we do this? * A: Because trying to iterate over the character * list with 'ch = ch->next' does bad things if * the current character happens to die. The * trivial workaround of 'vict = next_vict' * doesn't work if the _next_ person in the list * gets killed, for example, by an area spell. * * Q: Why do we leave them on the character_list? * A: Because code doing 'vict = vict->next' would * get really confused otherwise. */ if (ch == NULL) { log("char_extract(): inalid 'ch' charData_t."); } else { if (IS_NPC(ch)) { SET_BIT(MOB_FLAGS(ch), MOB_NOTDEADYET); } else { SET_BIT(PLR_FLAGS(ch), PLR_NOTDEADYET); } extractions_pending++; } } /** * Extracts a character. * @param ch the character to be extracted * @return none */ void char_extractFinal(charData_t *ch) { if (ch == NULL) { log("char_extractFinal(): invalid 'ch' charData_t."); } else if (IN_ROOM(ch) == NULL) { log("char_extractFinal(): charData_t 'ch' nowhere."); } else { charData_t *k = NULL, *temp = NULL; descriptorData_t *d = NULL; itemData_t *obj = NULL; int i = 0; /* * We're booting the character of someone who has switched so first we * need to stuff them back into their own body. This will set ch->desc * we're checking below this loop to the proper value. */ if (!IS_NPC(ch) && !ch->desc) { for (d = descriptor_list; d; d = d->next) { if (d->original == ch) { do_return(d->character, NULL, 0); break; } } } if (ch->desc) { /* * This time we're extracting the body someone has switched into * (not the body of someone switching as above) so we need to put * the switcher back to their own body. * * If this body is not possessed, the owner won't have a * body after the removal so dump them to the main menu. */ if (ch->desc->original) { do_return(ch, NULL, 0); } else { /* * Now we boot anybody trying to log in with the same character, to * help guard against duping. CON_DISCONNECT is used to close a * descriptor without extracting the d->character associated with it, * for being link-dead, so we want CON_CLOSE to clean everything up. * If we're here, we know it's a player so no IS_NPC check required. */ for (d = descriptor_list; d; d = d->next) { if (d == ch->desc) { continue; } if (d->character && GET_IDNUM(ch) == GET_IDNUM(d->character)) { STATE(d) = CON_CLOSE; } } STATE(ch->desc) = CON_MENU; write_to_output(ch->desc, "%s", MENU); } } /* On with the character's assets... */ if (ch->followers || ch->master) { die_follower(ch); } /* transfer objects to room, if any */ while (ch->carrying) { obj = ch->carrying; itemData_fromChar(obj); itemData_toRoom(obj, IN_ROOM(ch)); } /* transfer equipment to room, if any */ for (i = 0; i < NUM_WEARS; i++) { if (GET_EQ(ch, i)) { itemData_toRoom(char_unequipItem(ch, i), IN_ROOM(ch)); } } if (FIGHTING(ch)) { charData_stopFighting(ch); } for (k = combat_list; k; k = temp) { temp = k->next_fighting; if (FIGHTING(k) == ch) { charData_stopFighting(k); } } /* we can't forget the hunters either... */ for (temp = character_list; temp; temp = temp->next) { if (HUNTING(temp) == ch) { HUNTING(temp) = NULL; } } char_fromRoom(ch); if (IS_NPC(ch)) { if (ch->prototype) { /* prototyped */ ch->prototype->number--; } clearMemory(ch); } else { save_char(ch); Crash_delete_crashfile(ch); } /* If there's a descriptor, they're in the menu now. */ if (IS_NPC(ch) || ch->desc == NULL) { free_char(ch); } } } /** * Extracts any characters with a pending extraction. * @return none */ void char_extractPendingChars(void) { /* Declare some iterator variables. */ register charData_t *ch = NULL, *nextCh = NULL, *prevCh = NULL; /* Iterate over the character list. */ for (ch = character_list; ch && extractions_pending > 0; ch = nextCh) { /* Save off the next character in the character list. */ nextCh = ch->next; if (MOB_FLAGGED(ch, MOB_NOTDEADYET)) { REMOVE_BIT(MOB_FLAGS(ch), MOB_NOTDEADYET); } else if (PLR_FLAGGED(ch, PLR_NOTDEADYET)) { REMOVE_BIT(PLR_FLAGS(ch), PLR_NOTDEADYET); } else { /* Last non-free'd character to continue chain from. */ prevCh = ch; continue; } char_extractFinal(ch); extractions_pending--; if (prevCh) { prevCh->next = nextCh; } else { character_list = nextCh; } } extractions_pending = 0; } /** * Convert a charPlayerData_t to it's DAO representation * * @param parentDao the container DAO to contain the item's DAO * @param cpData the charPlayerData_t to be converted * @param isPlayer TRUE if being called for a Player, FALSE if being called for a Mobile * @return none */ void charPlayerData_toDao(daoData_t *parentDao, charPlayerData_t *cpData, bool isPlayer) { if (parentDao == NULL) { log("charPlayerData_toDao(): invalid 'parentDao' daoData_t."); } else if (cpData == NULL) { log("charPlayerData_toDao(): invalid 'cpData' charPlayerData_t."); } else { /* Declare some working DAO pointers */ daoData_t *cpDao = NULL; /* Declare some temporary buffer space. */ char temp[MAX_STRING_LENGTH] = {'\0'}; cpDao = dao_newChild(parentDao, "playerData"); if (isPlayer) { /* Save PC specific data */ dao_newScalar(cpDao, "password", "%s", cpData->passwd); dao_newScalar(cpDao, "birth", "%ld", cpData->time.birth); dao_newScalar(cpDao, "logon", "%ld", cpData->time.logon); dao_newScalar(cpDao, "timePlayed", "%ld", cpData->time.played); sprinttype(cpData->chclass, pc_class_types, temp, sizeof(temp)); if (cpData->name && *(cpData->name) != '\0') { dao_newScalar(cpDao, "name", "%s", cpData->name); } } else { /* Save Mob specific data */ sprinttype(cpData->chclass, npc_class_types, temp, sizeof(temp)); if (cpData->short_descr && *(cpData->short_descr) != '\0') { dao_newScalar(cpDao, "shortDescription", "%s", cpData->short_descr); } if (cpData->name && *(cpData->name) != '\0') { dao_newScalar(cpDao, "keywords", "%s", cpData->name); } } dao_newScalar(cpDao, "class", "%s", temp); /* Data in common to both PCs and NPCs */ if (cpData->long_descr && *(cpData->long_descr) != '\0') { dao_newScalar(cpDao, "longDescription", "%s", cpData->long_descr); } if (cpData->description && *(cpData->description) != '\0') { dao_newScalar(cpDao, "description", "%s", cpData->description); } if (cpData->title && *(cpData->title) != '\0') { dao_newScalar(cpDao, "title", "%s", cpData->title); } dao_newScalar(cpDao, "level", "%d", cpData->level); sprinttype(cpData->sex, genders, temp, sizeof(temp)); dao_newScalar(cpDao, "sex", "%s", temp); sprinttype(cpData->auth, auth_types, temp, sizeof(temp)); dao_newScalar(cpDao, "auth", "%s", temp); dao_newScalar(cpDao, "homeTown", "%d", cpData->hometown); dao_newScalar(cpDao, "weight", "%d", cpData->weight); dao_newScalar(cpDao, "height", "%d", cpData->height); } } /** * Convert a charAbilities_t to it's DAO representation * * @param parentDao the container DAO to contain the item's DAO * @param caData the charAbilities_t to be converted * @return none */ void charAbilities_toDao(daoData_t *parentDao, charAbilities_t *caData) { if (parentDao == NULL) { log("charAbilities_toDao(): invalid 'parentDao' daoData_t."); } else if (caData == NULL) { log("charAbilities_toDao(): invalid 'caData' charAbilities_t."); } else { dao_newScalar(parentDao, "strength", "%d", caData->str); dao_newScalar(parentDao, "strengthAdd", "%d", caData->str_add); dao_newScalar(parentDao, "intelligence", "%d", caData->intel); dao_newScalar(parentDao, "wisdom", "%d", caData->wis); dao_newScalar(parentDao, "dexterity", "%d", caData->dex); dao_newScalar(parentDao, "constitution", "%d", caData->con); dao_newScalar(parentDao, "charisma", "%d", caData->cha); } } /** * Convert a charPointData_t to it's DAO representation * * @param parentDao the container DAO to contain the item's DAO * @param cpData the charPointData_t to be converted * @return none */ void charPointData_toDao(daoData_t *parentDao, charPointData_t *cpData, bool isPlayer) { if (parentDao == NULL) { log("charPointData_toDao(): invalid 'parentDao' daoData_t."); } else if (cpData == NULL) { log("charPointData_toDao(): invalid 'cpData' charPointData_t."); } else { /* Declare a DAO pointer */ daoData_t *subContainerDao = NULL; if (isPlayer == TRUE) { /* Save points for a Player */ subContainerDao = dao_newChild(parentDao, "hitPoints"); dao_newScalar(subContainerDao, "current", "%d", cpData->hit); dao_newScalar(subContainerDao, "maximum", "%d", cpData->max_hit); subContainerDao = NULL; subContainerDao = dao_newChild(parentDao, "manaPoints"); dao_newScalar(subContainerDao, "current", "%d", cpData->mana); dao_newScalar(subContainerDao, "maximum", "%d", cpData->max_mana); subContainerDao = NULL; subContainerDao = dao_newChild(parentDao, "movePoints"); dao_newScalar(subContainerDao, "current", "%d", cpData->move); dao_newScalar(subContainerDao, "maximum", "%d", cpData->max_move); subContainerDao = NULL; } else { /* Save points for a Mobile Prototype. No currents, just maxes so we can trim things down */ if (cpData->max_hit == 0) { subContainerDao = dao_newChild(parentDao, "hitPoints"); dao_newScalar(subContainerDao, "diceNumber", "%d", cpData->hit); dao_newScalar(subContainerDao, "diceSize", "%d", cpData->mana); dao_newScalar(subContainerDao, "diceAdd", "%d", cpData->move); subContainerDao = NULL; } else { dao_newScalar(parentDao, "hitPoints", "%d", cpData->hit); dao_newScalar(parentDao, "manaPoints", "%d", cpData->mana); dao_newScalar(parentDao, "maxHitPoints", "%d", cpData->max_hit); } dao_newScalar(parentDao, "maxManaPoints", "%d", cpData->max_mana); dao_newScalar(parentDao, "maxMovePoints", "%d", cpData->max_move); } /* Common data between players and mobiles */ subContainerDao = dao_newChild(parentDao, "gold"); dao_newScalar(subContainerDao, "inHand", "%d", cpData->gold); dao_newScalar(subContainerDao, "inBank", "%d", cpData->bank_gold); subContainerDao = NULL; dao_newScalar(parentDao, "armor", "%d", cpData->armor); dao_newScalar(parentDao, "experience", "%d", cpData->exp); dao_newScalar(parentDao, "hitRoll", "%d", cpData->hitroll); dao_newScalar(parentDao, "damRoll", "%d", cpData->damroll); } } /** * Convert a playerSpecials_t to it's DAO representation * * @param parentDao the container DAO to contain the item's DAO * @param psData the playerSpecials_t to be converted * @return none */ void playerSpecials_toDao(daoData_t *parentDao, playerSpecials_t *psData) { if (parentDao == NULL) { log("playerSpecials_toDao(): invalid 'parentDao' daoData_t."); } else if (psData == NULL) { log("playerSpecials_toDao(): invalid 'psData' playerSpecials_t."); } else { /* Declare a DAO pointer */ daoData_t *subContainerDao = NULL; subContainerDao = dao_newChild(parentDao, "poofs"); dao_newScalar(parentDao, "in", "%s", psData->poofin); dao_newScalar(parentDao, "out", "%s", psData->poofout); subContainerDao = NULL; /* Now for the savedPlayerSpecials */ subContainerDao = dao_newChild(parentDao, "savedPlayerSpecials"); savedPlayerSpecials_toDao(subContainerDao, &(psData->saved)); subContainerDao = NULL; /* Aliases */ /** @todo Code alias saving */ subContainerDao = dao_newChild(parentDao, "aliases"); subContainerDao = NULL; } } /** * Convert a savedPlayerSpecials_t to it's DAO representation * * @param parentDao the container DAO to contain the item's DAO * @param psData the savedPlayerSpecials_t to be converted * @return none */ void savedPlayerSpecials_toDao(daoData_t *parentDao, savedPlayerSpecials_t *psData) { if (parentDao == NULL) { log("savedPlayerSpecials_toDao(): invalid 'parentDao' daoData_t."); } else if (psData == NULL) { log("savedPlayerSpecials_toDao(): invalid 'psData' savedPlayerSpecials_t."); } else { /* Declare a DAO pointer */ daoData_t *subContainerDao = NULL; /* Declare an iterator variable. */ register int i = 0; /* Declare some temporary buffer space. */ char temp[MAX_STRING_LENGTH] = {'\0'}; if (psData->wimp_level > 0) { dao_newScalar(parentDao, "wimpLevel", "%d", psData->wimp_level); } if (psData->freeze_auth > AUTH_NONE) { sprinttype(psData->freeze_auth, auth_types, temp, sizeof(temp)); dao_newScalar(parentDao, "freezeAuth", "%s", temp); } if (psData->invis_auth > AUTH_NONE) { sprinttype(psData->invis_auth, auth_types, temp, sizeof(temp)); dao_newScalar(parentDao, "invisAuth", "%s", temp); } dao_newScalar(parentDao, "loadRoom", "%d", psData->load_room); dao_newScalar(parentDao, "badPWAttempts", "%d", psData->bad_pws); dao_newScalar(parentDao, "spellsToLearn", "%d", psData->spells_to_learn); subContainerDao = dao_newChild(parentDao, "skills"); for (i = 0; i <= MAX_SKILLS; i++) { if (psData->skills[i] > 0) { snprintf(temp, sizeof(temp), "%d", i); dao_newScalar(subContainerDao, temp, "%d", psData->skills[i]); } } subContainerDao = NULL; /* Saving these for now, but it doesn't appear they're actually used anywhere */ subContainerDao = dao_newChild(parentDao, "talks"); for (i = 0; i <= MAX_TONGUE; i++) { snprintf(temp, sizeof(temp), "%d", i); if (psData->talks[i]) { dao_newScalar(subContainerDao, temp, "%s", "Yes"); } else { dao_newScalar(subContainerDao, temp, "%s", "No"); } } subContainerDao = NULL; if (psData->pref != 0UL) { subContainerDao = dao_newChild(parentDao, "preferences"); dao_newScalar(subContainerDao, "brief", YESNO(IS_SET(psData->pref, PRF_BRIEF))); dao_newScalar(subContainerDao, "compact", YESNO(IS_SET(psData->pref, PRF_COMPACT))); dao_newScalar(subContainerDao, "deaf", YESNO(IS_SET(psData->pref, PRF_DEAF))); dao_newScalar(subContainerDao, "noTell", YESNO(IS_SET(psData->pref, PRF_NOTELL))); dao_newScalar(subContainerDao, "displayHP", YESNO(IS_SET(psData->pref, PRF_DISPHP))); dao_newScalar(subContainerDao, "displayMana", YESNO(IS_SET(psData->pref, PRF_DISPMANA))); dao_newScalar(subContainerDao, "displayMove", YESNO(IS_SET(psData->pref, PRF_DISPMOVE))); dao_newScalar(subContainerDao, "autoExits", YESNO(IS_SET(psData->pref, PRF_AUTOEXIT))); dao_newScalar(subContainerDao, "noHassle", YESNO(IS_SET(psData->pref, PRF_NOHASSLE))); dao_newScalar(subContainerDao, "quest", YESNO(IS_SET(psData->pref, PRF_QUEST))); dao_newScalar(subContainerDao, "summon", YESNO(IS_SET(psData->pref, PRF_SUMMONABLE))); dao_newScalar(subContainerDao, "noRepeat", YESNO(IS_SET(psData->pref, PRF_NOREPEAT))); dao_newScalar(subContainerDao, "holyLight", YESNO(IS_SET(psData->pref, PRF_HOLYLIGHT))); dao_newScalar(subContainerDao, "color1", YESNO(IS_SET(psData->pref, PRF_COLOR_1))); dao_newScalar(subContainerDao, "color2", YESNO(IS_SET(psData->pref, PRF_COLOR_2))); dao_newScalar(subContainerDao, "noWiznet", YESNO(IS_SET(psData->pref, PRF_NOWIZ))); dao_newScalar(subContainerDao, "log1", YESNO(IS_SET(psData->pref, PRF_LOG1))); dao_newScalar(subContainerDao, "log2", YESNO(IS_SET(psData->pref, PRF_LOG2))); dao_newScalar(subContainerDao, "noAuction", YESNO(IS_SET(psData->pref, PRF_NOAUCT))); dao_newScalar(subContainerDao, "noGossip", YESNO(IS_SET(psData->pref, PRF_NOGOSS))); dao_newScalar(subContainerDao, "noGrats", YESNO(IS_SET(psData->pref, PRF_NOGRATZ))); dao_newScalar(subContainerDao, "roomFlags", YESNO(IS_SET(psData->pref, PRF_ROOMFLAGS))); dao_newScalar(subContainerDao, "displayAuto", YESNO(IS_SET(psData->pref, PRF_DISPAUTO))); subContainerDao = NULL; } subContainerDao = dao_newChild(parentDao, "conditions"); dao_newScalar(subContainerDao, "drunk", "%d", psData->conditions[DRUNK]); dao_newScalar(subContainerDao, "hunger", "%d", psData->conditions[FULL]); dao_newScalar(subContainerDao, "thirst", "%d", psData->conditions[THIRST]); subContainerDao = NULL; } } /** * Convert a savedCharSpecials_t to it's DAO representation * * @param parentDao the container DAO to contain the item's DAO * @param csData the savedCharSpecials_t to be converted * @param isPlayer TRUE if being called for a Player, FALSE if being called for a Mobile * @return none */ void savedCharSpecials_toDao(daoData_t *parentDao, savedCharSpecials_t *csData, bool isPlayer) { if (parentDao == NULL) { log("savedCharSpecials_toDao(): invalid 'parentDao' daoData_t."); } else if (csData == NULL) { log("savedCharSpecials_toDao(): invalid 'csData' savedCharSpecials_t."); } else { /* Declare a DAO pointer */ daoData_t *subContainerDao = NULL; /* Declare an iterator variable. */ register int i = 0; /* Declare some temporary buffer space. */ char temp[MAX_STRING_LENGTH] = {'\0'}; if (isPlayer) { /* PC Data */ dao_newScalar(parentDao, "idnum", "%d", csData->idnum); subContainerDao = dao_newChild(parentDao, "playerFlags"); dao_newScalar(subContainerDao, "killer", YESNO(IS_SET(csData->act, PLR_KILLER))); dao_newScalar(subContainerDao, "thief", YESNO(IS_SET(csData->act, PLR_THIEF))); dao_newScalar(subContainerDao, "frozen", YESNO(IS_SET(csData->act, PLR_FROZEN))); dao_newScalar(subContainerDao, "writing", YESNO(IS_SET(csData->act, PLR_WRITING))); dao_newScalar(subContainerDao, "mailing", YESNO(IS_SET(csData->act, PLR_MAILING))); dao_newScalar(subContainerDao, "crash", YESNO(IS_SET(csData->act, PLR_CRASH))); dao_newScalar(subContainerDao, "siteOK", YESNO(IS_SET(csData->act, PLR_SITEOK))); dao_newScalar(subContainerDao, "noShout", YESNO(IS_SET(csData->act, PLR_NOSHOUT))); dao_newScalar(subContainerDao, "noTitle", YESNO(IS_SET(csData->act, PLR_NOTITLE))); dao_newScalar(subContainerDao, "deleted", YESNO(IS_SET(csData->act, PLR_DELETED))); dao_newScalar(subContainerDao, "loadRoom", YESNO(IS_SET(csData->act, PLR_LOADROOM))); dao_newScalar(subContainerDao, "noWizlist", YESNO(IS_SET(csData->act, PLR_NOWIZLIST))); dao_newScalar(subContainerDao, "noDelete", YESNO(IS_SET(csData->act, PLR_NODELETE))); dao_newScalar(subContainerDao, "invisStart", YESNO(IS_SET(csData->act, PLR_INVSTART))); dao_newScalar(subContainerDao, "cryoSaved", YESNO(IS_SET(csData->act, PLR_CRYO))); dao_newScalar(subContainerDao, "Dead", YESNO(IS_SET(csData->act, PLR_NOTDEADYET))); subContainerDao = NULL; } else { /* NPC Data */ subContainerDao = dao_newChild(parentDao, "mobileFlags"); dao_newScalar(subContainerDao, "spec", YESNO(IS_SET(csData->act, MOB_SPEC))); dao_newScalar(subContainerDao, "sentinel", YESNO(IS_SET(csData->act, MOB_SENTINEL))); dao_newScalar(subContainerDao, "scavenger", YESNO(IS_SET(csData->act, MOB_SCAVENGER))); dao_newScalar(subContainerDao, "isNPC", YESNO(IS_SET(csData->act, MOB_ISNPC))); dao_newScalar(subContainerDao, "aware", YESNO(IS_SET(csData->act, MOB_AWARE))); dao_newScalar(subContainerDao, "aggressive", YESNO(IS_SET(csData->act, MOB_AGGRESSIVE))); dao_newScalar(subContainerDao, "stayZone", YESNO(IS_SET(csData->act, MOB_STAY_ZONE))); dao_newScalar(subContainerDao, "wimpy", YESNO(IS_SET(csData->act, MOB_WIMPY))); dao_newScalar(subContainerDao, "aggroEvil", YESNO(IS_SET(csData->act, MOB_AGGR_EVIL))); dao_newScalar(subContainerDao, "aggroGood", YESNO(IS_SET(csData->act, MOB_AGGR_GOOD))); dao_newScalar(subContainerDao, "aggroNeutral", YESNO(IS_SET(csData->act, MOB_AGGR_NEUTRAL))); dao_newScalar(subContainerDao, "memory", YESNO(IS_SET(csData->act, MOB_MEMORY))); dao_newScalar(subContainerDao, "helper", YESNO(IS_SET(csData->act, MOB_HELPER))); dao_newScalar(subContainerDao, "noCharm", YESNO(IS_SET(csData->act, MOB_NOCHARM))); dao_newScalar(subContainerDao, "noSummon", YESNO(IS_SET(csData->act, MOB_NOSUMMON))); dao_newScalar(subContainerDao, "noSleep", YESNO(IS_SET(csData->act, MOB_NOSLEEP))); dao_newScalar(subContainerDao, "noBash", YESNO(IS_SET(csData->act, MOB_NOBASH))); dao_newScalar(subContainerDao, "noBlind", YESNO(IS_SET(csData->act, MOB_NOBLIND))); dao_newScalar(subContainerDao, "Dead", YESNO(IS_SET(csData->act, MOB_NOTDEADYET))); subContainerDao = NULL; } dao_newScalar(parentDao, "alignment", "%d", csData->alignment); subContainerDao = dao_newChild(parentDao, "savingThrows"); for (i = 0; i < 5; i++) { snprintf(temp, sizeof(temp), "%s", save_types[i]); dao_newScalar(subContainerDao, temp, "%d", csData->apply_saving_throw[i]); } subContainerDao = NULL; } } /* ************************************************************************ */ /* Load Character Data from DAO */ /* ************************************************************************ */ /** * Load a charPlayerData_t from it's dao representation * * NOTE: This will re-set all string variables, so should only be used for players * or mobile prototypes * * @param cpData charPlayerData_t to populate * @param isPlayer TRUE or FALSE if player character * @param dao charPlayerData_t in dao format */ void charPlayerData_fromDao(charPlayerData_t *cpData, bool isPlayer, daoData_t *dao) { if (cpData == NULL) { log("charPlayerData_fromDao(): invalid 'charPlayerData_t' cpData."); } else if (dao == NULL) { log("charPlayerData_fromDao(): invalid 'daoData_t' dao."); } else { char *sTemp = NULL; if (isPlayer) { /* Load data that's player specific */ /* Password */ sTemp = (char *)dao_queryString(dao, "password", NULL); if (sTemp) { strncpy(cpData->passwd, sTemp, MAX(strlen(sTemp), MAX_PWD_LENGTH)); } sTemp = NULL; /* Age */ cpData->time.birth = dao_queryLong(dao, "birth", time(0)); cpData->time.logon = dao_queryLong(dao, "logon", time(0)); cpData->time.played = dao_queryLong(dao, "timePlayed", 0); /* Class */ cpData->chclass = dao_queryType(dao, "class", pc_class_types, 0); /* Name */ cpData->name = stringReplace(cpData->name, (char *)dao_queryString(dao, "name", NULL)); } else { /* Load data that's mobile specific */ /* Class */ cpData->chclass = dao_queryType(dao, "class", npc_class_types, 0); /* Short Description */ cpData->short_descr = stringReplace(cpData->short_descr, (char *)dao_queryString(dao, "shortDescription", NULL)); /* Keywords */ cpData->name = stringReplace(cpData->name, (char *)dao_queryString(dao, "keywords", NULL)); } /* Load data shared by PCs and Mobiles */ /* Long Description */ cpData->long_descr = stringReplace(cpData->long_descr, (char *)dao_queryString(dao, "longDescription", NULL)); /* Description */ cpData->description = stringReplace(cpData->description, (char *)dao_queryString(dao, "description", NULL)); /* Title */ cpData->title = stringReplace(cpData->title, (char *)dao_queryString(dao, "title", NULL)); /* Level */ cpData->level = dao_queryInt(dao, "level", 0); /* Gender */ cpData->sex = dao_queryType(dao, "sex", genders, 0); /* Home Town */ cpData->hometown = dao_queryInt(dao, "homeTown", 0); /* Weight */ cpData->weight = dao_queryInt(dao, "weight", 0); /* Height */ cpData->height = dao_queryInt(dao, "height", 0); } } /** * Load a charAbilities_t from it's dao representation * * @param caData charAbilities_t to populate * @param dao charPlayerData_t in dao format */ void charAbilities_fromDao(charAbilities_t *caData, daoData_t *dao) { if (caData == NULL) { log("charAbilities_fromDao(): invalid 'charAbilities_t' caData."); } else if (dao == NULL) { log("charAbilities_fromDao(): invalid 'daoData_t' dao."); } else { caData->str = dao_queryInt(dao, "strength", 0); caData->str_add = dao_queryInt(dao, "strengthAdd", 0); caData->intel = dao_queryInt(dao, "intelligence", 0); caData->wis = dao_queryInt(dao, "wisdom", 0); caData->dex = dao_queryInt(dao, "dexterity", 0); caData->con = dao_queryInt(dao, "constitution", 0); caData->cha = dao_queryInt(dao, "charisma", 0); } } /** * Load a charPointData_t from it's dao representation * * @param cpData charPointData_t to populate * @param isPlayer TRUE or FLASE if player character * @param dao charPointData_t in dao format */ void charPointData_fromDao(charPointData_t *cpData, bool isPlayer, daoData_t *dao) { if (cpData == NULL) { log("charPointData_fromDao(): invalid 'charPointData_t' cpData."); } else if (dao == NULL) { log("charPointData_fromDao(): invalid 'daoData_t' dao."); } else { /* HP, MP, MV */ if (isPlayer) { /* Load data that's player specific */ cpData->hit = dao_queryInt(dao, "hitPoints/current", 0); cpData->max_hit = dao_queryInt(dao, "hitPoints/maximum", 0); cpData->mana = dao_queryInt(dao, "manaPoints/current", 0); cpData->max_mana = dao_queryInt(dao, "manaPoints/maximum", 0); cpData->move = dao_queryInt(dao, "movePoints/current", 0); cpData->max_move = dao_queryInt(dao, "movePoints/maximum", 0); } else { /* Load data that's mobile specific */ /* Declare a holder variable, and init off query */ int max_hit = dao_queryInt(dao, "maxHitPoints", 0); if (max_hit == 0) { cpData->hit = dao_queryInt(dao, "hitPoints/diceNumber", 0); cpData->mana = dao_queryInt(dao, "hitPoints/diceSize", 0); cpData->move = dao_queryInt(dao, "hitPoints/diceAdd", 0); } else { cpData->hit = dao_queryInt(dao, "hitPoints", 0); cpData->mana = dao_queryInt(dao, "manaPoints", 0); cpData->max_hit = max_hit; } cpData->max_mana = dao_queryInt(dao, "maxManaPoints", 0); cpData->max_move = dao_queryInt(dao, "maxMovePoints", 0); } /* Load data that's shared by PCs and Mobiles */ /* Gold */ cpData->gold = dao_queryInt(dao, "gold/inHand", 0); cpData->bank_gold = dao_queryInt(dao, "gold/inBank", 0); /* Armor, XP, Hit/Dam */ cpData->armor = dao_queryInt(dao, "armor", 0); cpData->exp = dao_queryInt(dao, "experience", 0); cpData->hitroll = dao_queryInt(dao, "hitRoll", 0); cpData->damroll = dao_queryInt(dao, "damRoll", 0); } } /** * Load a playerSpecials_t from it's dao representation * * @param psData playerSpecials_t to populate * @param dao playerSpecials_t in dao format */ void playerSpecials_fromDao(playerSpecials_t *psData, daoData_t *dao) { if (psData == NULL) { log("playerSpecials_fromDao(): invalid 'playerSpecials_t' psData."); } else if (dao == NULL) { log("playerSpecials_fromDao(): invalid 'daoData_t' dao."); } else { daoData_t *subDao = NULL; /* Poofin */ psData->poofin = stringReplace(psData->poofin, (char *)dao_queryString(dao, "poofs/in", NULL)); /* Poofout */ psData->poofin = stringReplace(psData->poofout, (char *)dao_queryString(dao, "poofs/out", NULL)); /* savedPlayerSpecials */ subDao = dao_query(dao, "savedPlayerSpecials"); if (subDao) { savedPlayerSpecials_fromDao(&(psData->saved), subDao); } subDao = NULL; /* Aliases */ /** @todo Code alias loading */ } } /** * Load a savedPlayerSpecials_t from it's dao representation * * @param psData savedPlayerSpecials_t to populate * @param dao savedPlayerSpecials_t in dao format */ void savedPlayerSpecials_fromDao(savedPlayerSpecials_t *psData, daoData_t *dao) { if (psData == NULL) { log("savedPlayerSpecials_fromDao(): invalid 'savedPlayerSpecials_t' psData."); } else if (dao == NULL) { log("savedPlayerSpecials_fromDao(): invalid 'daoData_t' dao."); } else { /* Declare some DAO pointers */ daoData_t *subDao = NULL, *childDao = NULL; /* Load the main data */ psData->wimp_level = dao_queryInt(dao, "wimpLevel", 0); psData->freeze_auth = dao_queryInt(dao, "freezeLevel", 0); psData->invis_auth = dao_queryInt(dao, "invisLevel", 0); psData->load_room = dao_queryInt(dao, "loadRoom", 0); psData->bad_pws = dao_queryInt(dao, "badPWAttempts", 0); psData->spells_to_learn = dao_queryInt(dao, "spellsToLearn", 0); /* Skills */ subDao = dao_query(dao, "skills"); if (subDao) { /* Loop through the entries for skills and set the values as needed */ for (childDao = subDao->children; childDao; childDao = childDao->next) { register int sNum = dao_keyInt(childDao, -1); /* Sanity check */ if (sNum >= 0 && sNum <= MAX_SKILLS) { psData->skills[sNum] = dao_valueInt(childDao, 0); } } childDao = NULL; } subDao = NULL; /* Talks/Tongues/Languages */ /* Not used in the code, but we're saving 'em anyway * Even though we don't have pfiles saving to DAO yet. * Yes, we're odd. */ subDao = dao_query(dao, "talks"); if (subDao) { /* Loop through the entries for the languages/talks and set the values */ for (childDao = subDao->children; childDao; childDao = childDao->next) { register int lNum = dao_keyInt(childDao, -1); /* Sanity */ if (lNum >= 0 && lNum <= MAX_TONGUE) { if (strcasecmp(dao_valueString(childDao, "No"), "Yes") == 0) { psData->talks[lNum] = 1; } } } childDao = NULL; } subDao = NULL; /* Preferences */ psData->pref = dao_queryBits(dao, "preferences", preference_bits, 0); /* Conditions */ psData->conditions[DRUNK] = dao_queryInt(dao, "conditions/drunk", 0); psData->conditions[FULL] = dao_queryInt(dao, "conditions/hunger", 0); psData->conditions[THIRST] = dao_queryInt(dao, "conditions/thirst", 0); /* Done */ } } /** * Load a savedCharSpecials_t from it's dao representation * * @param csData savedCharSpecials_t to populate * @param isPlayer TRUE or FALSE if player character * @param dao savedCharSpecials_t in dao format */ void savedCharSpecials_fromDao(savedCharSpecials_t *csData, bool isPlayer, daoData_t *dao) { if (csData == NULL) { log("savedCharSpecials_fromDao(): invalid 'savedCharSpecials_t' csData."); } else if (dao == NULL) { log("savedCharSpecials_fromDao(): invalid 'daoData_t' dao."); } else { /* Declare some DAO pointers */ daoData_t *subDao = NULL, *childDao = NULL; if (isPlayer) { /* Player Specific Data */ /* IDNum */ csData->idnum = dao_queryInt(dao, "idnum", -1); /* Player Flags */ csData->act = dao_queryBits(dao, "playerFlags", player_bits, 0); } else { /* Mobile Specific Data */ /* Mobile Flags */ csData->act = dao_queryBits(dao, "mobileFlags", action_bits, 0); } /* Shared Data */ /* Alignment */ csData->alignment = dao_queryInt(dao, "alignment", 0); /* Saving Throws */ /* This is ugly, but it works ... I think */ subDao = dao_query(dao, "savingThrows"); if (subDao) { /* Loop over the contents */ for (childDao = subDao->children; childDao; childDao = childDao->next) { /* Declare an iterator var */ register int n = 0; /* Declare and init a string pointer */ char *sTemp = (char *)dao_keyString(childDao, NULL); /* Find the value in the save_types[] array if possible */ for (n = 0; n < 5; n++) { if (sTemp && *sTemp && strcasecmp(sTemp, save_types[n]) == 0) { /* Set the value */ csData->apply_saving_throw[n] = dao_valueInt(childDao, 0); break; } } /* Sanity */ sTemp = NULL; } } subDao = NULL; /* Done */ } }