/**
* @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 */
}
}