/*************************************************************************** * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. * * * * Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael * * Chastain, Michael Quan, and Mitchell Tse. * * * * Envy Diku Mud improvements copyright (C) 1994 by Michael Quan, David * * Love, Guilherme 'Willie' Arnold, and Mitchell Tse. * * * * In order to use any part of this Envy Diku Mud, you must comply with * * the original Diku license in 'license.doc', the Merc license in * * 'license.txt', as well as the Envy license in 'license.nvy'. * * In particular, you may not remove either of these copyright notices. * * * * Much time and thought has gone into this software and you are * * benefitting. We hope that you share your changes too. What goes * * around, comes around. * ***************************************************************************/ /*$Id: sqldb.c,v 1.10 2005/02/22 23:55:19 ahsile Exp $*/ /* * Database Creation Script included as mud.sql (may be in mud.zip) * Turn this system on by definining SQL_SYSTEM in config.h * * File conversion from old merc format -> sql is included * built for win32 + mysql, but could be changed easily * -Ahsile */ /* * Due to a slow machine, we coded the SQL system to use memory tables * and only dump everything on a timed basis. Unfortunately we never * made a full conversion to a db system by only pulling data on demand. * Data is all stored in the db, and loaded at startup just like a * normal mud, but rather than loading from files we load from the * database. * - Ahsile - mcarpent@zenwerx.com */ /********************** * Mandatory Includes * **********************/ #ifdef RUN_AS_WIN32SERVICE #include <windows.h> #endif #if defined( macintosh ) #include <types.h> #else #include <sys/types.h> #endif #include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include "merc.h" /************************** * End Mandatory Includes * **************************/ /* * Conditional compile section * Build only if sql system is turned on */ #ifdef SQL_SYSTEM #ifdef RUN_AS_WIN32SERVICE #pragma comment(lib,"libmysql") #endif #include "/usr/local/mysql/include/mysql.h" /* prog defines */ #define LOAD_MOB 0 #define LOAD_OBJ 1 #define LOAD_ROOM 2 #define LOAD_EXIT 3 /* table name defines for functions who use the same sql for different tables */ #define TABLE_ROOM "tblroomdescriptions" #define TABLE_OBJ "tblobjectdescriptions" #define TABLE_INV "tblinventory" #define TABLE_DET "tblinventorydetail" #define DIRTY_INV "fast_inv" #define DIRTY_DET "fast_det" /* External Functions */ void area_sort ( AREA_DATA *pArea ); void religion_sort ( RELIGION_DATA* pReligion ); void clan_sort ( CLAN_DATA *pClan ); void assign_area_vnum ( int vnum ); void ch_stripbadinv ( CHAR_DATA* ch ); void link_reset ( ROOM_INDEX_DATA* pR, RESET_DATA* pReset); /* These are for creating temporary memory tables */ bool remove_fastboot_tables (); bool create_fastboot_tables (); bool remove_fast_invtable (); bool create_fast_invtable (); /* Helper SQL Functions */ MYSQL_RES* do_query ( char* query ); MYSQL_ROW get_row ( MYSQL_RES* res ); bool sql_system_init ( char* DBName, char* User, char* Pass, char* Host ); char* escape_query ( char* query ); int rowcount ( MYSQL_RES* res ); void cleanup_query ( MYSQL_RES* res ); void sql_validate_resets ( RESET_DATA* pReset ); bool sql_remove_old_inv ( int CharID, bool Dirty ); long last_id ( ); /* local variables */ MYSQL* sql; int query_count; time_t boot_time; CHAR_DATA* dirty_list; /* external globals */ extern char* help_greeting_one; extern char* help_greeting_two; extern char* help_greeting_three; extern char* help_greeting_four; extern char* help_greeting_five; extern int maxSocial; extern DISABLED_DATA* disabled_first; bool sql_system_init(char* DBName, char* User, char* Pass, char* Host) { dirty_list = NULL; query_count = 0; boot_time = time(NULL); sql = mysql_init(NULL); return (bool)mysql_real_connect(sql, Host, User, Pass, DBName, 0, NULL, 0); } bool create_fastboot_tables() { char* fast_exits = "INSERT INTO fast_exit SELECT * FROM tblroomexits"; char* fast_obj = "INSERT INTO fast_obj SELECT * FROM tblobjects"; char* fast_objaff= "INSERT INTO fast_objaf SELECT * FROM tblobjectaffects"; char* fast_mobs = "INSERT INTO fast_mob SELECT * FROM tblmobiles"; // make sure we're clean if (!remove_fastboot_tables()) { log_string("Couldn't empty fast boot tables!", CHANNEL_NONE, -1); return FALSE; } if (!do_query(fast_exits)) { log_string("Couldn't create fast_exits!", CHANNEL_NONE, -1); return FALSE; } if (!do_query(fast_obj)) { log_string("Couldn't create fast_obj!", CHANNEL_NONE, -1); return FALSE; } if (!do_query(fast_objaff)) { log_string("Couldn't create fast_objaff!", CHANNEL_NONE, -1); return FALSE; } if (!do_query(fast_mobs)) { log_string("Couldn't create fast_mobs!", CHANNEL_NONE, -1); return FALSE; } return TRUE; } bool remove_fastboot_tables() { // Free up memory char* rem_exits = "DELETE FROM fast_exit"; char* rem_objs = "DELETE FROM fast_obj"; char* rem_objaffs = "DELETE FROM fast_objaf"; char* rem_mobs = "DELETE FROM fast_mob"; if(!do_query(rem_exits)) { return FALSE; } if(!do_query(rem_objs)) { return FALSE; } if(!do_query(rem_objaffs)) { return FALSE; } if(!do_query(rem_mobs)) { return FALSE; } return TRUE; } bool create_fastinv_tables() { char* fast_inv = "INSERT INTO fast_inv SELECT * FROM tblinventory"; char* fast_det = "INSERT INTO fast_det SELECT * FROM tblinventorydetail"; // make sure we're clean if (!remove_fastinv_tables()) { char buf[MAX_STRING_LENGTH]; strcpy(buf, mysql_error(sql)); log_string(buf, CHANNEL_NONE, -1); log_string("Couldn't empty fastinv tables!", CHANNEL_NONE, -1); return FALSE; } if (!do_query(fast_inv)) { char buf[MAX_STRING_LENGTH]; strcpy(buf, mysql_error(sql)); log_string(buf, CHANNEL_NONE, -1); log_string("Couldn't create fast_inv!", CHANNEL_NONE, -1); return FALSE; } if (!do_query(fast_det)) { log_string("Couldn't create fast_det!", CHANNEL_NONE, -1); return FALSE; } return TRUE; } bool remove_fastinv_tables() { char* rem_inv = "DELETE FROM fast_inv"; char* rem_det = "DELETE FROM fast_det"; if (!do_query(rem_inv)) { return FALSE; } if (!do_query(rem_det)) { return FALSE; } return TRUE; } long last_id() { return mysql_insert_id(sql); } MYSQL_RES* do_query( char* query ) { query_count++; if (mysql_query(sql, query)) return NULL; if (strstr(query, "SELECT")!=query) return (MYSQL_RES*) 1; else return mysql_store_result( sql ); } char* escape_query( char* query ) { char* buf = NULL; if (!query) return NULL; buf = malloc(((strlen(query)*2)*sizeof(char))+sizeof(char)); mysql_real_escape_string(sql, buf, query, strlen(query)); return buf; } int rowcount( MYSQL_RES* res ) { if (res) return (int) mysql_num_rows(res); else return 0; } MYSQL_ROW get_row( MYSQL_RES* res) { return mysql_fetch_row(res); } void cleanup_query( MYSQL_RES* res ) { if (res) mysql_free_result( res ); } CHAR_DATA* sql_load_char( char* name ) { const char* FetchCharSQL = "SELECT * FROM tblcharacters WHERE Nm=\"%s\";"; char buf[MAX_STRING_LENGTH] = ""; CHAR_DATA* ch = NULL; PC_DATA* pc = NULL; MYSQL_RES* res = NULL; MYSQL_ROW row; /* check the dirty list first (we can save a DB search) */ for (ch = dirty_list; ch; ch=ch->next_dirty) { if (!str_cmp(name, ch->name)) { sprintf(buf, "Found char %s in dirty list!", ch->name); bug(buf,0); return ch; } } sprintf(buf, FetchCharSQL, name); if (!(res = do_query(buf))) { bug("sql_load_char: Query error!",0); return NULL; } if (rowcount( res ) > 1) { sprintf(buf, "Loading character %s. There were %d records found!", name, rowcount( res )); bug(buf, 0); } else if (!rowcount( res )) { // character not found. new character! return NULL; } ch = new_char(); clear_char( ch ); pc = ch->pcdata = new_pc(); if (!ch || !pc) return NULL; row = get_row( res ); ch->CharID = atoi(row[0]); ch->name = str_dup(capitalize(name)); ch->short_descr = str_dup(row[2]); ch->long_descr = str_dup(row[3]); ch->description = str_dup(row[4]); ch->prompt = str_dup(row[5]); ch->sex = atoi(row[6]); ch->class = atoi(row[7]); ch->multied = atoi(row[8]); ch->race = atoi(row[9]); ch->clan = atoi(row[10]); ch->updated = atoi(row[11]); ch->clev = atoi(row[12]); ch->ctimer = atoi(row[13]); ch->stunned[0] = atoi(row[14]); ch->stunned[1] = atoi(row[15]); ch->stunned[2] = atoi(row[16]); ch->stunned[3] = atoi(row[17]); ch->stunned[4] = atoi(row[18]); ch->damage_mods[0] = atoi(row[19]); ch->damage_mods[1] = atoi(row[20]); ch->damage_mods[2] = atoi(row[21]); ch->damage_mods[3] = atoi(row[22]); ch->damage_mods[4] = atoi(row[23]); ch->damage_mods[5] = atoi(row[24]); ch->damage_mods[6] = atoi(row[25]); ch->damage_mods[7] = atoi(row[26]); ch->damage_mods[8] = atoi(row[27]); ch->damage_mods[9] = atoi(row[28]); ch->damage_mods[10] = atoi(row[29]); ch->damage_mods[11] = atoi(row[30]); ch->damage_mods[12] = atoi(row[31]); ch->damage_mods[13] = atoi(row[32]); ch->damage_mods[14] = atoi(row[33]); ch->damage_mods[15] = atoi(row[34]); ch->damage_mods[16] = atoi(row[35]); ch->damage_mods[17] = atoi(row[36]); ch->damage_mods[18] = atoi(row[37]); ch->damage_mods[19] = atoi(row[38]); ch->wizinvis = atoi(row[39]); ch->level = atoi(row[40]); ch->pkill = atoi(row[41]); ch->antidisarm = atoi(row[42]); ch->mounted = atoi(row[43]); ch->mountcharmed = atoi(row[44]); ch->mountshort = str_dup(row[45]); ch->trust = atoi(row[46]); pc->security = atoi(row[47]); ch->wizbit = atoi(row[48]); pc->awins = atoi(row[49]); pc->alosses = atoi(row[50]); pc->mobkills = atoi(row[51]); ch->questgiver = ( atoi(row[52]) ? get_char_world( ch, get_mob_index( atoi(row[52]) )->player_name ) : NULL ); ch->played = atoi(row[53]); ch->last_note = atoi(row[54]); ch->in_room = get_room_index( atoi( row[55] ) ); ch->hit = atoi(row[56]); ch->max_hit = atoi(row[57]); ch->mana = atoi(row[58]); ch->max_mana = atoi(row[59]); ch->move = atoi(row[60]); ch->max_move = atoi(row[61]); ch->bp = atoi(row[62]); ch->max_bp = atoi(row[63]); ch->gold = atoi(row[64]); ch->guild_rank = atoi(row[65]); strcpy(buf, row[66]); // Guild. No lookup function available. Must do manually later. ch->religion = atoi(row[67]); pc->recall = atoi(row[68]); ch->rtimer = atoi(row[69]); ch->exp = atoi(row[70]); ch->act = atoi(row[71]); ch->act2 = atoi(row[72]); ch->affected_by = atoi(row[73]); ch->affected_by2 = atoi(row[74]); ch->affected_by3 = atoi(row[75]); ch->affected_by4 = atoi(row[76]); ch->affected_by_powers = atoi(row[77]); ch->affected_by_weaknesses = atoi(row[78]); ch->imm_flags = atoi(row[79]); ch->res_flags = atoi(row[80]); ch->vul_flags = atoi(row[81]); ch->shields = atoi(row[82]); ch->position = atoi(row[83]); ch->practice = atoi(row[84]); ch->saving_throw = atoi(row[85]); ch->alignment = atoi(row[86]); ch->hitroll = atoi(row[87]); ch->damroll = atoi(row[88]); ch->armor = atoi(row[89]); ch->wimpy = atoi(row[90]); ch->deaf = atoi(row[91]); pc->corpses = atoi(row[92]); ch->questpoints = atoi(row[93]); ch->nextquest = atoi(row[94]); ch->countdown = atoi(row[95]); ch->questobj = atoi(row[96]); ch->questmob = atoi(row[97]); ch->rquestpoints = atoi(row[98]); ch->rnextquest = atoi(row[99]); pc->pwd = str_dup( row[100] ); ch->speaking = atoi(row[101]); pc->learn = atoi(row[102]); pc->bamfin = str_dup( row[103] ); pc->bamfout = str_dup( row[104] ); pc->bamfsin = str_dup( row[105] ); pc->bamfsout = str_dup( row[106] ); pc->bankaccount = atoi(row[107]); pc->shares = atoi(row[108]); pc->immskll = str_dup( row[109] ); pc->title = str_dup( row[110] ); pc->who_text = str_dup( row[111] ); pc->perm_str = atoi(row[112]); pc->perm_int = atoi(row[113]); pc->perm_wis = atoi(row[114]); pc->perm_dex = atoi(row[115]); pc->perm_con = atoi(row[116]); pc->mod_str = atoi(row[117]); pc->mod_int = atoi(row[118]); pc->mod_wis = atoi(row[119]); pc->mod_dex = atoi(row[120]); pc->mod_con = atoi(row[121]); pc->condition[0] = atoi(row[122]); pc->condition[1] = atoi(row[123]); pc->condition[2] = atoi(row[124]); pc->pagelen = atoi(row[125]); ch->logon = current_time; ch->playing = TRUE; if (strcmp(buf,str_empty)) { int i; for(i = 0;guild_table[i].name[0] != '\0';i++) { if(!strcmp(guild_table[i].name, buf)) { ch->guild = &(guild_table[i]); break; } } } if ( ch->trust > L_CON && ch->level < L_IMP && !IS_CODER(ch) ) ch->trust = 0; if ( !ch->in_room ) { ch->in_room = get_room_index( ROOM_VNUM_LIMBO ); } if ( ch->in_room->vnum >= REL_VNUM_LOWER && ch->in_room->vnum <= REL_VNUM_UPPER ) { REMOVE_BIT(ch->act2, PLR_RELQUEST); // Just in case ch->rnextquest = number_range(15, 30); ch->in_room = get_room_index( ROOM_VNUM_TEMPLE ); } /* LEGACY CODE FROM FREAD_CHAR */ if ( !ch->pcdata->pagelen ) ch->pcdata->pagelen = 20; if ( !ch->prompt || ch->prompt == '\0' ) ch->prompt = str_dup ( "<%hhp %mm %vmv> " ); if ( ch->pcdata->pagelen > 60 ) ch->pcdata->pagelen = 60; /* END LEGACY CODE */ /* Load Other info */ pc->alias_list = sql_load_alias(ch->CharID ); ch->affected = sql_load_affects(ch->CharID, 1 ); ch->affected2 = sql_load_affects(ch->CharID, 2 ); ch->affected3 = sql_load_affects(ch->CharID, 3 ); ch->affected4 = sql_load_affects(ch->CharID, 4 ); sql_load_items (0, FALSE, NULL, ch ); sql_load_items (0, TRUE, NULL, ch ); sql_load_skills (ch->CharID, pc->learned ); sql_load_lang (ch->CharID, ch->language ); ch_stripbadinv( ch ); cleanup_query(res); return ch; } OBJ_DATA* sql_load_items( int InsideOf, bool Storage, OBJ_DATA* inside, CHAR_DATA* ch) { const char* objstr = "SELECT * FROM fast_inv LEFT JOIN fast_det ON fast_inv.InventoryID = fast_det.InventoryID WHERE CharacterID=%d AND Storage=%d AND InsideOf=%d"; char buf[MAX_STRING_LENGTH] = ""; OBJ_DATA* first = NULL; OBJ_DATA* cur = NULL; MYSQL_RES* res = NULL; MYSQL_ROW row; int i = 0; int c = 0; sprintf(buf, objstr, ch->CharID, Storage, InsideOf); if (!(res = do_query( buf ) ) ) { // bad query return NULL; } if (!rowcount( res )) { cleanup_query(res); // no objects found return NULL; } for (i = 0; i < rowcount( res ); i++) { OBJ_INDEX_DATA* oi = NULL; row = get_row(res); oi = get_obj_index( atoi( row[2] ) ); if (!oi) continue; // make the object cur = create_object( oi, oi->level ); if (!cur) continue; c++; // check for details if (row[6]) { free_string(cur->short_descr); free_string(cur->description); free_string(cur->name); cur->short_descr = str_dup(row[8]); cur->description = str_dup(row[9]); cur->name = str_dup(row[10]); cur->ac_charge[0] = cur->ac_charge[1] - atoi(row[11]); cur->value[2] = oi->value[1] - atoi(row[12]); } sql_load_items(atoi(row[0]), FALSE, cur, ch); cur->wear_loc = atoi(row[5]); if (InsideOf) { obj_to_obj(cur, inside); } else { if (Storage) { obj_to_storage(cur, ch); } else { obj_to_char(cur, ch); } } if (c==1) { first = cur; } } cleanup_query(res); return first; } ALIAS_DATA* sql_load_alias( int CharID ) { const char* alsstr = "SELECT * FROM tblcharacteraliases WHERE CharacterID=%d"; char buf[MAX_STRING_LENGTH] = ""; ALIAS_DATA* first = NULL; ALIAS_DATA* als = NULL; MYSQL_RES* res = NULL; MYSQL_ROW row; int i = 0; sprintf(buf, alsstr, CharID); if (!(res = do_query(buf))) { return NULL; } if (!rowcount(res)) { cleanup_query(res); return NULL; } for (i=0; i<rowcount(res);i++) { row = get_row(res); als = new_alias(); if (als) { als->old = str_dup(row[2]); als->_new = str_dup(row[3]); als->next = first; first = als; } } cleanup_query(res); return first; } AFFECT_DATA* sql_load_affects( int CharID, int AffNum ) { AFFECT_DATA* first = NULL; AFFECT_DATA* paf = NULL; const char* affstr = "SELECT * FROM tblcharacteraffects WHERE CharacterID=%d AND FlagNum=%d"; char buf[MAX_STRING_LENGTH] = ""; MYSQL_RES* res = NULL; MYSQL_ROW row; int i = 0; sprintf(buf, affstr, CharID, AffNum); if (!(res = do_query(buf))) { return NULL; } if (!rowcount(res)) { cleanup_query(res); return NULL; } for (i=0; i<rowcount(res);i++) { row = get_row(res); paf = new_affect(); if (paf) { paf->type = slot_lookup(atoi(row[3])); paf->level = atoi(row[4]); paf->duration = atoi(row[5]); paf->location = atoi(row[6]); paf->modifier = atoi(row[7]); paf->bitvector = atoi(row[8]); paf->deleted = FALSE; paf->next = first; first = paf; } } cleanup_query(res); return first; } bool sql_load_skills( int CharID, int table[]) { const char* sklstr = "SELECT * FROM tblcharacterskills WHERE CharacterID=%d"; char buf[MAX_STRING_LENGTH] = ""; MYSQL_RES* res = NULL; MYSQL_ROW row; int i = 0; sprintf(buf, sklstr, CharID); if (!(res = do_query(buf))) { return FALSE; } if (!rowcount(res)) { cleanup_query(res); return FALSE; } for (i = 0; i < rowcount(res); i++) { row = get_row(res); table[atoi(row[2])] = atoi(row[3]); } cleanup_query(res); return TRUE; } bool sql_load_lang( int CharID, int table[]) { const char* sklstr = "SELECT * FROM tblcharacterlanguages WHERE CharacterID=%d"; char buf[MAX_STRING_LENGTH] = ""; MYSQL_RES* res = NULL; MYSQL_ROW row; int i = 0; sprintf(buf, sklstr, CharID); if (!(res = do_query(buf))) { return FALSE; } if (!rowcount(res)) { cleanup_query(res); return FALSE; } for (i = 0; i < rowcount(res); i++) { row = get_row(res); table[atoi(row[2])] = atoi(row[3]); } cleanup_query(res); return TRUE; } bool sql_load_areas() { const char* areasql = "SELECT * FROM tblarea"; char buf[MAX_STRING_LENGTH] = ""; AREA_DATA* pArea = NULL; MYSQL_RES* res = NULL; MYSQL_ROW row; int i = 0; if (!create_fastboot_tables()) return FALSE; strcpy(buf, areasql); if (!(res = do_query(buf))) { return FALSE; } if (!rowcount(res)) { cleanup_query(res); return FALSE; } for (i = 0; i < rowcount(res); i++) { row = get_row(res); pArea = new_area(); if (pArea) { pArea->vnum = top_area; pArea->AreaID = atoi(row[0]); pArea->filename = str_dup( row[1]); pArea->name = str_dup( row[2] ); // debug test sprintf(buf, "Loading %s...", pArea->filename ); log_string( buf, CHANNEL_NONE , -1 ); pArea->lvnum = atoi(row[3]); pArea->uvnum = atoi(row[4]); pArea->security = atoi(row[5]); pArea->builders = str_dup( row[6] ); pArea->reset_sound = str_dup( row[7] ); pArea->area_flags = atoi(row[8]); pArea->recall = atoi(row[9]); pArea->actual_sound = str_dup( row[10] ); pArea->musicfile = str_dup( row[11] ); pArea->age = 666; // force an area update area_sort(pArea); top_area++; sql_load_rooms(pArea); sql_load_mobiles(pArea); sql_load_objects(pArea); } } cleanup_query(res); remove_fastboot_tables(); return TRUE; } bool sql_load_rooms(AREA_DATA* pArea) { const char* roomsql = "SELECT * FROM tblrooms LEFT JOIN fast_exit ON tblrooms.vnum = fast_exit.RoomVnum WHERE AreaID=%d ORDER BY tblrooms.vnum"; char buf[MAX_STRING_LENGTH] = ""; ROOM_INDEX_DATA* pRoom = NULL; MYSQL_RES* res = NULL; MYSQL_ROW row; int room_vnum = 0; int i = 0; int iHash = 0; sprintf(buf, roomsql, pArea->AreaID); if (!(res = do_query(buf))) { return FALSE; } if (!rowcount(res)) { cleanup_query(res); return FALSE; } for (i = 0; i < rowcount(res); i++) { row = get_row(res); if (room_vnum != atoi(row[0])) { pRoom = new_room_index(); if (pRoom) { pRoom->vnum = atoi(row[0]); pRoom->name = str_dup( row[2] ); pRoom->soundfile = str_dup( row[3] ); pRoom->musicfile = str_dup( row[4] ); pRoom->description = str_dup( row[5] ); pRoom->room_flags = atoi(row[6]); pRoom->sector_type = atoi(row[7]); pRoom->area = pArea; // hash stuff iHash = pRoom->vnum % MAX_KEY_HASH; pRoom->next = room_index_hash[iHash]; room_index_hash[iHash] = pRoom; top_room++; top_vnum_room = top_vnum_room < pRoom->vnum ? pRoom->vnum : top_vnum_room; if (atoi(row[8])) pRoom->traps = sql_load_traps( pRoom->vnum, LOAD_ROOM, 0); if (atoi(row[10])) { pRoom->extra_descr = sql_load_ed(pRoom->vnum, TABLE_ROOM); } room_vnum = pRoom->vnum; } } if (atoi(row[9]) && pRoom) { EXIT_DATA* e = NULL; EXIT_DATA** x = pRoom->exit; int it = 0; it = atoi(row[13]); e = x[it] = new_exit(); if (e) { e->description = str_dup( row[14] ); e->keyword = str_dup( row[15] ); e->exit_info = atoi(row[16]); e->rs_flags = atoi(row[17]); e->key = atoi(row[18]); e->vnum = atoi(row[19]); if (atoi(row[20])) { e->traps = sql_load_traps(pRoom->vnum , LOAD_EXIT, i+1); } } } } cleanup_query(res); return TRUE; } /* * Defunct. This took 180+ seconds * Memory tables + LEFT JOIN bring this down to ~5 seconds * * - Ahsile bool sql_load_exits(int vnum, EXIT_DATA* x[]) { const char* exitsql = "SELECT * FROM fast_exit WHERE vnum=%d"; char buf[MAX_STRING_LENGTH] = ""; EXIT_DATA* e = NULL; MYSQL_RES* res = NULL; MYSQL_ROW row; int i = 0; int it = 0; sprintf(buf, exitsql, vnum); if (!(res = do_query(buf))) { return FALSE; } if (!rowcount(res)) { cleanup_query(res); return FALSE; } else if (rowcount(res) > MAX_DIR) { // too many exits cleanup_query(res); return FALSE; } for (i = 0; i < rowcount(res); i++) { row = get_row(res); it = atoi(row[2]); e = x[it] = new_exit(); if (e) { e->description = str_dup( row[3] ); e->keyword = str_dup( row[4] ); e->exit_info = atoi(row[5]); e->rs_flags = atoi(row[6]); e->key = atoi(row[7]); e->vnum = atoi(row[8]); if (atoi(row[9])) { e->traps = sql_load_traps(vnum, LOAD_EXIT, i+1); } } } cleanup_query(res); return TRUE; } */ TRAP_DATA* sql_load_traps( int vnum, int ProgType, int Exit ) { const char* trapsql = "SELECT * FROM tblprograms WHERE vnum=%d AND LoadType=%d AND ExitNum=%d"; char buf[MAX_STRING_LENGTH] = ""; TRAP_DATA* trap = NULL; TRAP_DATA* first = NULL; MYSQL_RES* res = NULL; MYSQL_ROW row; int i = 0; sprintf(buf, trapsql, vnum, ProgType, Exit); if (!(res = do_query(buf))) { return NULL; } if (!rowcount(res)) { cleanup_query(res); return NULL; } for (i = 0; i<rowcount(res); i++) { row = get_row(res); trap = new_trap(); if (trap) { if (ProgType==LOAD_OBJ) { OBJ_INDEX_DATA* o = get_obj_index( vnum ); trap->on_obj = o; } else { ROOM_INDEX_DATA* r = get_room_index( vnum ); if (ProgType==LOAD_ROOM) { trap->in_room = r; } else { trap->on_exit = r->exit[Exit-1]; } } trap->type = atoi(row[4]); trap->arglist = str_dup( row[5] ); trap->comlist = str_dup( row[6] ); trap->next = trap->next_here = first; first = trap; } } cleanup_query(res); return first; } bool sql_load_mobiles(AREA_DATA* pArea) { const char* mobsql = "SELECT * FROM fast_mob WHERE AreaID=%d"; char buf[MAX_STRING_LENGTH] = ""; MOB_INDEX_DATA* pMob = NULL; MYSQL_RES* res = NULL; MYSQL_ROW row; int i = 0; int iHash = 0; sprintf(buf, mobsql, pArea->AreaID); if (!(res = do_query(buf))) { return FALSE; } if (!rowcount(res)) { cleanup_query(res); return FALSE; } for (i = 0; i < rowcount(res); i++) { row = get_row(res); pMob = new_mob_index(); if (pMob) { pMob->vnum = atoi(row[0]); pMob->player_name = str_dup( row[2] ); pMob->short_descr = str_dup( row[3] ); pMob->long_descr = str_dup( row[4] ); pMob->act = atoi(row[5]); pMob->affected_by = atoi(row[6]); pMob->affected_by2 = atoi(row[7]); pMob->affected_by3 = atoi(row[8]); pMob->affected_by4 = atoi(row[9]); pMob->alignment = atoi(row[10]); pMob->level = atoi(row[11]); pMob->hitroll = atoi(row[12]); pMob->damroll = atoi(row[13]); pMob->hitnodice = atoi(row[14]); pMob->sex = atoi(row[15]); pMob->imm_flags = atoi(row[16]); pMob->res_flags = atoi(row[17]); pMob->vul_flags = atoi(row[18]); pMob->speaking = atoi(row[19]); pMob->spec_fun = spec_lookup( str_dup( row[20] ) ); pMob->area = pArea; // Hash table and kill table iHash = pMob->vnum % MAX_KEY_HASH; pMob->next = mob_index_hash[iHash]; mob_index_hash[iHash] = pMob; top_mob_index++; top_vnum_mob = top_vnum_mob < pMob->vnum ? pMob->vnum : top_vnum_mob; /* OLC */ assign_area_vnum( pMob->vnum ); /* OLC */ kill_table[URANGE( 0, pMob->level, MAX_LEVEL-1 )].number++; if (atoi(row[21])) { MPROG_DATA* mprog; pMob->mobprogs = sql_load_mprog(pMob->vnum); for (mprog = pMob->mobprogs; mprog; mprog = mprog->next) { SET_BIT(pMob->progtypes, mprog->type); } } if (atoi(row[22])) { MYSQL_RES* det_res; MYSQL_ROW det_row; sprintf(buf, "SELECT MobileDesc FROM tblmobiledescriptions WHERE vnum=%d", pMob->vnum); det_res = do_query(buf); det_row = get_row(det_res); pMob->description = str_dup( det_row[0] ); cleanup_query(det_res); } } pMob = NULL; } cleanup_query(res); return TRUE; } MPROG_DATA* sql_load_mprog( int vnum ) { const char* mprgsql = "SELECT * FROM tblprograms WHERE vnum=%d AND LoadType=%d"; char buf[MAX_STRING_LENGTH] = ""; MPROG_DATA* mprog = NULL; MPROG_DATA* first = NULL; MYSQL_RES* res = NULL; MYSQL_ROW row; int i = 0; sprintf(buf, mprgsql, vnum, LOAD_MOB, 0); if (!(res = do_query(buf))) { return NULL; } if (!rowcount(res)) { cleanup_query(res); return NULL; } for (i = 0; i < rowcount(res); i++) { row = get_row(res); mprog = new_mprog(); if (mprog) { mprog->status = atoi(row[2]); mprog->type = atoi(row[4]); mprog->arglist = str_dup( row[5] ); mprog->comlist = str_dup( row[6] ); mprog->next = NULL; mprog->next = first; first = mprog; } } cleanup_query(res); return first; } bool sql_load_objects(AREA_DATA* pArea) { const char* objsql = "SELECT * FROM fast_obj WHERE AreaID=%d"; char buf[MAX_STRING_LENGTH] = ""; OBJ_INDEX_DATA* pObj = NULL; MYSQL_RES* res = NULL; MYSQL_ROW row; int i = 0; int iHash = 0; sprintf(buf, objsql, pArea->AreaID); if (!(res = do_query(buf))) { return FALSE; } if (!rowcount(res)) { cleanup_query(res); return FALSE; } for (i = 0; i < rowcount(res); i++) { row = get_row(res); pObj = new_obj_index(); if (pObj) { pObj->vnum = atoi(row[0]); pObj->name = str_dup(row[2]); pObj->short_descr = str_dup(row[3]); pObj->description = str_dup(row[4]); pObj->item_type = atoi(row[5]); pObj->extra_flags = atoi(row[6]); pObj->extra_flags2 = atoi(row[7]); pObj->extra_flags3 = atoi(row[8]); pObj->extra_flags4 = atoi(row[9]); pObj->wear_flags = atoi(row[10]); pObj->level = atoi(row[11]); pObj->value[0] = atoi(row[12]); pObj->value[1] = atoi(row[13]); pObj->value[2] = atoi(row[14]); pObj->value[3] = atoi(row[15]); pObj->weight = atoi(row[16]); pObj->cost = atoi(row[17]); pObj->ac_type = atoi(row[18]); pObj->ac_vnum = atoi(row[19]); pObj->ac_spell = str_dup(row[20]); pObj->ac_charge[0] = atoi(row[21]); pObj->ac_charge[1] = atoi(row[22]); pObj->join = atoi(row[23]); pObj->sep_one = atoi(row[24]); pObj->sep_two = atoi(row[25]); pObj->area = pArea; iHash = pObj->vnum % MAX_KEY_HASH; pObj->next = obj_index_hash[iHash]; obj_index_hash[iHash] = pObj; top_obj_index++; top_vnum_obj = top_vnum_obj < pObj->vnum ? pObj->vnum : top_vnum_obj; /* OLC */ assign_area_vnum( pObj->vnum ); if (atoi(row[26])) pObj->traps = sql_load_traps(pObj->vnum, LOAD_OBJ, 0); if (atoi(row[27])) pObj->extra_descr = sql_load_ed(pObj->vnum, TABLE_OBJ); if (atoi(row[28])) pObj->affected = sql_load_objaff(pObj->vnum, pObj->level); } } cleanup_query(res); return TRUE; } AFFECT_DATA* sql_load_objaff(int vnum, int level) { const char* affsql = "SELECT * FROM fast_objaf WHERE vnum=%d"; char buf[MAX_STRING_LENGTH] = ""; AFFECT_DATA* paf = NULL; AFFECT_DATA* first = NULL; MYSQL_RES* res = NULL; MYSQL_ROW row; int i = 0; sprintf(buf, affsql, vnum); if (!(res = do_query(buf))) { return NULL; } if (!rowcount(res)) { cleanup_query(res); return NULL; } for (i = 0; i < rowcount(res); i++) { row = get_row(res); paf = new_affect(); if (paf) { paf->location = atoi(row[2]); paf->modifier = atoi(row[3]); paf->level = level; paf->type = -1; paf->duration = -1; paf->next = first; first = paf; } } cleanup_query(res); return first; } EXTRA_DESCR_DATA* sql_load_ed(int vnum, char* table) { const char* edsql = "SELECT * FROM %s WHERE vnum=%d"; char buf[MAX_STRING_LENGTH] = ""; EXTRA_DESCR_DATA* ed = NULL; EXTRA_DESCR_DATA* first = NULL; MYSQL_RES* res = NULL; MYSQL_ROW row; int i = 0; sprintf(buf, edsql, table, vnum); if (!(res = do_query(buf))) { return NULL; } if (!rowcount(res)) { cleanup_query(res); return NULL; } for (i = 0; i < rowcount(res); i++) { row = get_row(res); ed = new_extra_descr(); if (ed) { ed->keyword = str_dup( row[1] ); ed->description = str_dup( row[2] ); ed->next = first; first = ed; } } cleanup_query(res); return first; } bool sql_load_disabled() { DISABLED_DATA *p = NULL; MYSQL_RES* res = NULL; MYSQL_ROW row; char *name = NULL; int i = 0; int j = 0; disabled_first = NULL; if (!(res = do_query("SELECT * FROM tbldisabled"))) { return FALSE; } if (!rowcount(res)) { cleanup_query(res); return FALSE; } for (j = 0; j < rowcount(res); j++) { row = get_row(res); name = row[1]; /* Find the command in the table */ for (i = 0; cmd_table[i].name[0] ; i++) if (!str_cmp(cmd_table[i].name, name)) break; if (!cmd_table[i].name[0]) /* command does not exist? */ { bug ("Skipping uknown command in disabled list.",0); } else /* add new disabled command */ { p = alloc_mem(sizeof(DISABLED_DATA)); p->command = &cmd_table[i]; p->uptolevel = atoi(row[2]); p->dislevel = atoi(row[3]); p->disabled_by = str_dup(row[4]); p->next = disabled_first; disabled_first = p; } } cleanup_query(res); return TRUE; } bool sql_load_bans() { BAN_DATA* pBan = NULL; MYSQL_RES* res = NULL; MYSQL_ROW row; int i = 0; if (!(res = do_query("SELECT * FROM tblbans"))) { return FALSE; } if (!rowcount(res)) { cleanup_query(res); return FALSE; } for (i = 0; i < rowcount(res); i++) { row = get_row(res); pBan = new_ban(); if (pBan) { pBan->name = str_dup(row[1]); pBan->user = str_dup(row[2]); pBan->next = ban_list; ban_list = pBan; } } return TRUE; } bool sql_load_clans() { char buf[MAX_STRING_LENGTH] = ""; CLAN_DATA* pClan = NULL; MYSQL_RES* res = NULL; MYSQL_ROW row; int i = 0; if (!(res = do_query("SELECT * FROM tblclans"))) { return FALSE; } if (!rowcount(res)) { cleanup_query(res); return FALSE; } for (i = 0; i < rowcount(res); i++) { row = get_row(res); pClan = new_clan(); if (pClan) { MYSQL_RES* det_res = NULL; MYSQL_ROW det_row; pClan->vnum = atoi(row[0]) - 1; pClan->name = str_dup( row[1] ); pClan->description = str_dup( row[2] ); pClan->deity = str_dup( row[3] ); pClan->champ = str_dup( row[4] ); pClan->leader = str_dup( row[5] ); pClan->first = str_dup( row[6] ); pClan->second = str_dup( row[7] ); pClan->ischamp = atoi(row[8]); pClan->isleader = atoi(row[9]); pClan->isfirst = atoi(row[10]); pClan->issecond = atoi(row[11]); pClan->recall = atoi(row[12]); pClan->pkills = atoi(row[13]); pClan->mkills = atoi(row[14]); pClan->members = atoi(row[15]); pClan->pdeaths = atoi(row[16]); pClan->mdeaths = atoi(row[17]); pClan->obj_vnum_1 = atoi(row[18]); pClan->obj_vnum_2 = atoi(row[19]); pClan->obj_vnum_3 = atoi(row[20]); pClan->pkill = atoi(row[21]); sprintf(buf, "SELECT COUNT(*) FROM tblcharacter WHERE Clan=%d", pClan->vnum); if ((det_res = do_query(buf))) { det_row = get_row(det_res); pClan->members = atoi(row[0]); cleanup_query(det_res); } clan_sort(pClan); top_clan++; } } return TRUE; } bool sql_load_helps() { HELP_DATA* pHelp; MYSQL_RES* res = NULL; MYSQL_ROW row; int i = 0; if (!(res = do_query("SELECT * FROM tblhelp"))) { // bad query return FALSE; } if (!rowcount(res)) { // no helps cleanup_query(res); return FALSE; } for (i = 0; i < rowcount(res); i++) { row = get_row(res); pHelp = new_help(); if (pHelp) { pHelp->keyword = str_dup(row[1]); pHelp->level = atoi(row[2]); pHelp->text = str_dup(row[3]); if ( !str_cmp( pHelp->keyword, "greeting1" ) ) help_greeting_one = pHelp->text; if ( !str_cmp( pHelp->keyword, "greeting2" ) ) help_greeting_two = pHelp->text; if ( !str_cmp( pHelp->keyword, "greeting3" ) ) help_greeting_three = pHelp->text; if ( !str_cmp( pHelp->keyword, "greeting4" ) ) help_greeting_four = pHelp->text; if ( !str_cmp( pHelp->keyword, "greeting5" ) ) help_greeting_five = pHelp->text; if ( !help_first ) help_first = pHelp; if ( help_last ) help_last->next = pHelp; help_last = pHelp; pHelp->next = NULL; top_help++; } } cleanup_query(res); return TRUE; } bool sql_load_religions() { RELIGION_DATA* pRel = NULL; char buf[MAX_STRING_LENGTH] = ""; MYSQL_RES* res = NULL; MYSQL_ROW row; int i = 0; if (!(res = do_query("SELECT * FROM tblreligions"))) { // bad query return FALSE; } if (!rowcount(res)) { // no religions cleanup_query(res); return FALSE; } for (i = 0; i < rowcount(res); i++) { row = get_row(res); pRel = new_religion(); if (pRel) { MYSQL_RES* det_res = NULL; MYSQL_ROW det_row; pRel->vnum = atoi(row[0]) - 1; pRel->name = str_dup(row[1]); pRel->shortdesc = str_dup(row[2]); pRel->deity = str_dup(row[3]); pRel->description = str_dup(row[4]); pRel->recall = atoi(row[5]); pRel->pkills = atoi(row[6]); pRel->mkills = atoi(row[7]); pRel->pdeaths = atoi(row[8]); sprintf(buf, "SELECT COUNT(*) FROM tblcharacter WHERE RNumber=%d", pRel->vnum); if ((det_res = do_query(buf))) { det_row = get_row(det_res); pRel->members = atoi(row[0]); cleanup_query(det_res); } else { pRel->members = atoi(row[9]); } religion_sort(pRel); } } relquest = FALSE; cleanup_query(res); return TRUE; } bool sql_load_resets() { RESET_DATA* pRes = NULL; MYSQL_RES* res = NULL; MYSQL_ROW row; int i = 0; if (!(res = do_query("SELECT * FROM tblresets"))) { // bad query return FALSE; } if (!rowcount(res)) { // no resets cleanup_query(res); return FALSE; } for (i = 0; i < rowcount(res); i++) { row = get_row(res); pRes = new_reset(); if (pRes) { pRes->command = row[1][0]; pRes->status = atoi(row[2]); pRes->arg1 = atoi(row[3]); pRes->arg2 = atoi(row[4]); pRes->arg3 = atoi(row[5]); sql_validate_resets(pRes); } } cleanup_query(res); return TRUE; } bool sql_load_socials() { SOCIAL_DATA* pSoc = NULL; MYSQL_RES* res = NULL; MYSQL_ROW row; int i = 0; if (!(res = do_query("SELECT * FROM tblsocials"))) { // bad query return FALSE; } if (!rowcount(res)) { // no socials cleanup_query(res); return FALSE; } maxSocial = rowcount(res); // ewww. socials suck, but I'm not going to rewrite the whole // social system. // - Ahsile social_table = malloc (sizeof(struct social_type) * (maxSocial+1)); memset(social_table, 0, sizeof(struct social_type) * (maxSocial+1)); for (i = 0; i < rowcount(res); i++) { row = get_row(res); pSoc = &social_table[i]; memset(pSoc, 0, sizeof(struct social_type)); if (pSoc) { pSoc->name = str_dup(row[1]); pSoc->char_no_arg = str_dup(row[2]); pSoc->others_no_arg = str_dup(row[3]); pSoc->char_found = str_dup(row[4]); pSoc->others_found = str_dup(row[5]); pSoc->vict_found = str_dup(row[6]); pSoc->char_auto = str_dup(row[7]); pSoc->others_auto = str_dup(row[8]); social_table[i] = *pSoc; } } social_table[maxSocial].name = str_dup(str_empty); cleanup_query(res); return TRUE; } bool sql_load_shops() { SHOP_DATA* pShop = NULL; MOB_INDEX_DATA* mob = NULL; MYSQL_RES* res = NULL; MYSQL_ROW row; int i = 0; if (!(res = do_query("SELECT * FROM tblshops"))) { // bad query return FALSE; } if (!rowcount(res)) { // no shops cleanup_query(res); return FALSE; } for (i = 0; i < rowcount(res); i++) { row = get_row(res); pShop = new_shop(); if (pShop) { mob = NULL; pShop->keeper = atoi(row[1]); pShop->profit_buy = atoi(row[2]); pShop->profit_sell = atoi(row[3]); pShop->open_hour = atoi(row[4]); pShop->close_hour = atoi(row[5]); pShop->buy_type[0] = atoi(row[6]); pShop->buy_type[1] = atoi(row[7]); pShop->buy_type[2] = atoi(row[8]); pShop->buy_type[3] = atoi(row[9]); pShop->buy_type[4] = atoi(row[10]); if ((mob = get_mob_index( pShop->keeper ))) { mob->pShop = pShop; } if ( !shop_first ) shop_first = pShop; if ( shop_last ) shop_last->next = pShop; shop_last = pShop; pShop->next = NULL; top_shop++; } } cleanup_query(res); return TRUE; } void sql_validate_resets(RESET_DATA* pReset) { /* * Validate parameters. * We're calling the index functions for the side effect. */ ROOM_INDEX_DATA* pRoomIndex = NULL; EXIT_DATA* pexit = NULL; static int iLastRoom = 0; static int iLastObj = 0; char letter = pReset->command; switch ( letter ) { default: bug( "Load_resets: bad command '%c'.", letter ); exit( 1 ); break; case 'M': get_mob_index ( pReset->arg1 ); if ( ( pRoomIndex = get_room_index ( pReset->arg3 ) ) ) { link_reset( pRoomIndex, pReset ); iLastRoom = pReset->arg3; } break; case 'O': get_obj_index ( pReset->arg1 ); if ( ( pRoomIndex = get_room_index ( pReset->arg3 ) ) ) { link_reset( pRoomIndex, pReset ); iLastObj = pReset->arg3; } break; case 'P': get_obj_index ( pReset->arg1 ); if ( ( pRoomIndex = get_room_index ( iLastObj ) ) ) { link_reset( pRoomIndex, pReset ); } break; case 'G': case 'E': get_obj_index ( pReset->arg1 ); if ( ( pRoomIndex = get_room_index ( iLastRoom ) ) ) { link_reset( pRoomIndex, pReset ); iLastObj = iLastRoom; } break; case 'D': pRoomIndex = get_room_index( pReset->arg1 ); if ( pReset->arg2 < 0 || pReset->arg2 > 5 || !pRoomIndex || !( pexit = pRoomIndex->exit[pReset->arg2] ) || !IS_SET( pexit->rs_flags, EX_ISDOOR ) ) { bug( "Load_resets: 'D': exit %d not door.", pReset->arg2 ); exit( 1 ); } switch ( pReset->arg3 ) /* OLC 1.1b */ { default: bug( "Load_resets: 'D': bad 'locks': %d." , pReset->arg3); case 0: break; case 1: SET_BIT( pexit->rs_flags, EX_CLOSED ); break; case 2: SET_BIT( pexit->rs_flags, EX_CLOSED | EX_LOCKED ); break; } break; case 'R': if ( pReset->arg2 < 0 || pReset->arg2 > 6 ) /* Last Door. */ { bug( "Load_resets: 'R': bad exit %d.", pReset->arg2 ); exit( 1 ); } if ( ( pRoomIndex = get_room_index( pReset->arg1 ) ) ) link_reset( pRoomIndex, pReset ); break; } } /* The "dirty" option here may need some explaining, and I'll do my best. We're using memory tables to do fast loading of characters, inventory, etc. The problem with these tables is they lose all their changes when the DB shuts down. The solution? Fresh updates. This takes time though. Roughly 2.5 seconds on PC being used right now (2.4 GHz P4 + 1GB Mem). Doing this for EVERY character save can make things very slow. Enter "dirty" saves. A dirty save means we're going to update the fast memory table. We take a risk here that we may lose some data, but we have a pulse defined in the update handler to do clean saves. By default this is set at roughly 5 minutes. We also keep a list of "Dirty" characters. This way we can use this list rather than hitting the DB again. Also note: The only "dirty" information is the inventory. Actual character data is never dirty. */ bool sql_save_dirty_char(CHAR_DATA* ch, bool Quit) { CHAR_DATA* search; if (!sql_save_char(ch)) return FALSE; /* Unnecessary. Causes performance hit. Save the character, but leave the inventory for a clean save. - Ahsile if (!sql_remove_old_inv(ch->CharID, TRUE)) return FALSE; if (!sql_save_inv(ch->carrying, ch->CharID, 0, FALSE, TRUE)) return FALSE; if (!sql_save_inv(ch->pcdata->storage, ch->CharID, 0, TRUE, TRUE)) return FALSE; */ if (!ch->next_dirty) { bool found_dirty = FALSE; for (search = dirty_list; search; search = search->next_dirty) { if (search==ch) { found_dirty = TRUE; break; } } if (!found_dirty) { ch->next_dirty = dirty_list; dirty_list = ch; } } if (Quit) { // TODO: This is probably where we'll handle what extract_char // was used for on PCs } return TRUE; } /* * This is where we'll force the inventory of dirty characters to save. */ bool sql_save_dirty_list(bool Refresh) { CHAR_DATA* ch = dirty_list; bool found_dirty = FALSE; while(dirty_list) { if (!sql_save_char(ch)) return FALSE; if (!sql_remove_old_inv(ch->CharID, FALSE)) return FALSE; if (!sql_save_inv(ch->carrying, ch->CharID, 0, FALSE, FALSE)) return FALSE; if (!sql_save_inv(ch->pcdata->storage, ch->CharID, 0, TRUE, FALSE)) return FALSE; dirty_list = ch->next_dirty; ch->next_dirty = NULL; if (!ch->playing) { extract_char(ch, TRUE); } found_dirty = TRUE; } if (found_dirty) { log_string("Saved \"dirty\" players.", CHANNEL_LOG, -1); if (Refresh) create_fastinv_tables(); } return TRUE; } /* * This function is common whether dirty or not. Character data * shalt always be dumped to the DB since it is more important * than inventory. */ bool sql_save_char(CHAR_DATA* ch) { char* desc_str; char* title_str; char* prompt_str; char* bamfin_str; char* bamfout_str; char* bamfsin_str; char* bamfsout_str; char* mountshort_str; char* buf = malloc( MAX_STRING_LENGTH * sizeof(char) * 20 ); const char* pcstr = "UPDATE tblcharacters SET Nm=\"%s\", ShtDsc=\"%s\", LngDsc=\"%s\", Dscr=\"%s\", Prmpt=\"%s\", Sx=%d, Cla=%d, Mlt=%d, Race=%d, \ Clan=%d, Updated=%d, Clvl=%d, Ctmr=%d, StunOne=%d, StunTwo=%d, StunThree=%d, StunFour=%d, StunFive=%d, ResAcid=%d, \ ResHoly=%d, ResMagic=%d, ResFire=%d, ResEnergy=%d, ResWind=%d, ResWater=%d, ResIllusion=%d, ResDispel=%d, ResEarth=%d, \ ResPsychic=%d, ResPoison=%d, ResBreath=%d, ResSUmmon=%d, ResPhysical=%d, ResExplosive=%d, ResSong=%d,ResNagarom=%d, ResUnholy=%d, \ ResClan=%d, WizLev=%d, Lvl=%d, Pkill=%d, Antidisarm=%d, Mounted=%d, Mountcharmed=%d, Mountshort=\"%s\", \ Trst=%d, Security=%d, Wizbt=%d, ArenaWins=%d, ArenaLoses=%d, MobKills=%d, QuestGiver=%d, Playd=%d, Note=%d, Room=%d, \ Hp=%d, MaxHP=%d, Mn=%d, MaxMn=%d, Mv=%d, MaxMv=%d, Bp=%d, MaxBp=%d, Gold=%d, \ GRank=%d, Guild=\"%s\", RNumber=%d, Recall=%d, Rtimer=%d, Exp=%d, Act=%d, Act2=%d, AffdBy=%d, AffdBy2=%d, AffdBy3=%d, \ AffdBy4=%d, AffdByp=%d,AffdByw=%d, ImmBits=%d, ResBits=%d, VulBits=%d, Shields=%d, \ Pos=%d, Prac=%d, SavThr=%d, Align=%d, Hit=%d, Dam=%d, Armr=%d, Wimp=%d, Deaf=%d, Corpses=%d, QuestPnts=%d, QuestNext=%d, \ QuestCount=%d, QuestObj=%d, QuestMob=%d, RQuestPnts=%d, RQuestNext=%d, Paswd=\"%s\", \ Speak=%d, Learn=%d, Bmfin=\"%s\", Bmfout=\"%s\", Bmfsin=\"%s\", Bmfsout=\"%s\", Bank=%d, BankShares=%d, Immskll=\"%s\", \ Ttle=\"%s\", WhoTxt=\"%s\", AtrPrmStr=%d, AtrPrmInt=%d, AtrPrmWis=%d, AtrPrmDex=%d, AtrPrmCon=%d, \ AtrMdStr=%d, AtrMdInt=%d, AtrMdWis=%d, AtrMdDex=%d, AtrMdCon=%d, CondOne=%d, CondTwo=%d, CondThree=%d, Pglen=%d \ WHERE CharacterID=%d"; const char* newpcstr = "INSERT INTO tblcharacters VALUES ( NULL, \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", %d, %d, %d, %d, \ %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, \ %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, \"%s\", \ %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, \ %d, \"%s\", %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, \ %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, \"%s\", \ %d, %d, \"%s\", \"%s\", \"%s\", \"%s\", %d, %d, \"%s\", \"%s\", \"%s\", %d, %d, %d, %d, %d, \ %d, %d, %d, %d, %d, %d, %d, %d, %d )"; memset( buf, 0, MAX_STRING_LENGTH * sizeof(char) * 20); desc_str = escape_query(ch->description); title_str = escape_query(ch->pcdata->title); prompt_str = escape_query(ch->prompt); bamfin_str = escape_query(ch->pcdata->bamfin); bamfout_str = escape_query(ch->pcdata->bamfout); bamfsin_str = escape_query(ch->pcdata->bamfsin); bamfsout_str = escape_query(ch->pcdata->bamfsout); if (ch->mountshort) mountshort_str = escape_query(ch->mountshort); else mountshort_str = strdup(""); if (!ch->new) { sprintf(buf, pcstr, ch->name, ch->short_descr, ch->long_descr, desc_str, prompt_str, ch->sex, ch->class, ch->multied, \ ch->race, ch->clan, ch->updated, ch->clev, ch->ctimer, ch->stunned[0], ch->stunned[1], ch->stunned[2], \ ch->stunned[3], ch->stunned[4], ch->damage_mods[0], ch->damage_mods[1], ch->damage_mods[2], ch->damage_mods[3], \ ch->damage_mods[4], ch->damage_mods[5], ch->damage_mods[6], ch->damage_mods[7], ch->damage_mods[8], ch->damage_mods[9], \ ch->damage_mods[10], ch->damage_mods[11], ch->damage_mods[12], ch->damage_mods[13], ch->damage_mods[14], \ ch->damage_mods[15], ch->damage_mods[16], ch->damage_mods[17], ch->damage_mods[18], ch->damage_mods[19], \ ch->wizinvis, ch->level, ch->pkill, ch->antidisarm, ch->mounted, ch->mountcharmed, mountshort_str, \ ch->trust, ch->pcdata->security, ch->wizbit, ch->pcdata->awins, ch->pcdata->alosses, ch->pcdata->mobkills, \ ch->questgiver, ch->played, ch->last_note, ( ch->in_room ? ch->in_room->vnum : ( ch->last_room ? ch->last_room->vnum : 0)), \ ch->hit, ch->max_hit, ch->mana, ch->max_mana, ch->move, \ ch->max_move, ch->bp, ch->max_bp, ch->gold, ch->guild_rank, ch->guild, ch->religion, ch->pcdata->recall, \ ch->rtimer, ch->exp, ch->act, ch->act2, ch->affected_by, ch->affected_by2, ch->affected_by3, ch->affected_by4, \ ch->affected_by_powers, ch->affected_by_weaknesses, ch->imm_flags, ch->res_flags, ch->vul_flags, \ ch->shields, ch->position, ch->practice, ch->saving_throw, ch->alignment, ch->hitroll, ch->damroll, \ ch->armor, ch->wimpy, ch->deaf, ch->pcdata->corpses, ch->questpoints, ch->nextquest, ch->countdown, \ ch->questobj, ch->questmob, ch->rquestpoints, ch->rnextquest, ch->pcdata->pwd, ch->speaking, \ ch->pcdata->learn, bamfin_str, bamfout_str, bamfsin_str, bamfsout_str, \ ch->pcdata->bankaccount, ch->pcdata->shares, ch->pcdata->immskll, title_str, ch->pcdata->who_text, \ ch->pcdata->perm_str, ch->pcdata->perm_int, ch->pcdata->perm_wis, ch->pcdata->perm_dex, \ ch->pcdata->perm_con, ch->pcdata->mod_str, ch->pcdata->mod_int, ch->pcdata->mod_wis, ch->pcdata->mod_dex, \ ch->pcdata->mod_con, ch->pcdata->condition[0], ch->pcdata->condition[1], ch->pcdata->condition[2], \ ch->pcdata->pagelen, ch->CharID); } else { sprintf(buf, newpcstr, ch->name, ch->short_descr, ch->long_descr, desc_str, prompt_str, ch->sex, ch->class, ch->multied, \ ch->race, ch->clan, ch->updated, ch->clev, ch->ctimer, ch->stunned[0], ch->stunned[1], ch->stunned[2], \ ch->stunned[3], ch->stunned[4], ch->damage_mods[0], ch->damage_mods[1], ch->damage_mods[2], ch->damage_mods[3], \ ch->damage_mods[4], ch->damage_mods[5], ch->damage_mods[6], ch->damage_mods[7], ch->damage_mods[8], ch->damage_mods[9], \ ch->damage_mods[10], ch->damage_mods[11], ch->damage_mods[12], ch->damage_mods[13], ch->damage_mods[14], \ ch->damage_mods[15], ch->damage_mods[16], ch->damage_mods[17], ch->damage_mods[18], ch->damage_mods[19], \ ch->wizinvis, ch->level, ch->pkill, ch->antidisarm, ch->mounted, ch->mountcharmed, mountshort_str, \ ch->trust, ch->pcdata->security, ch->wizbit, ch->pcdata->awins, ch->pcdata->alosses, ch->pcdata->mobkills, \ ch->questgiver, ch->played, ch->last_note, ( ch->in_room ? ch->in_room->vnum : ( ch->last_room ? ch->last_room->vnum : 0)), \ ch->hit, ch->max_hit, ch->mana, ch->max_mana, ch->move, \ ch->max_move, ch->bp, ch->max_bp, ch->gold, ch->guild_rank, ch->guild, ch->religion, ch->pcdata->recall, \ ch->rtimer, ch->exp, ch->act, ch->act2, ch->affected_by, ch->affected_by2, ch->affected_by3, ch->affected_by4, \ ch->affected_by_powers, ch->affected_by_weaknesses, ch->imm_flags, ch->res_flags, ch->vul_flags, \ ch->shields, ch->position, ch->practice, ch->saving_throw, ch->alignment, ch->hitroll, ch->damroll, \ ch->armor, ch->wimpy, ch->deaf, ch->pcdata->corpses, ch->questpoints, ch->nextquest, ch->countdown, \ ch->questobj, ch->questmob, ch->rquestpoints, ch->rnextquest, ch->pcdata->pwd, ch->speaking, \ ch->pcdata->learn, bamfin_str, bamfout_str, bamfsin_str, bamfsout_str, \ ch->pcdata->bankaccount, ch->pcdata->shares, ch->pcdata->immskll, ch->pcdata->title, ch->pcdata->who_text, \ ch->pcdata->perm_str, ch->pcdata->perm_int, ch->pcdata->perm_wis, ch->pcdata->perm_dex, \ ch->pcdata->perm_con, ch->pcdata->mod_str, ch->pcdata->mod_int, ch->pcdata->mod_wis, ch->pcdata->mod_dex, \ ch->pcdata->mod_con, ch->pcdata->condition[0], ch->pcdata->condition[1], ch->pcdata->condition[2], \ ch->pcdata->pagelen); } free(desc_str); free(title_str); free(prompt_str); free(bamfin_str); free(bamfout_str); free(bamfsin_str); free(bamfsout_str); free(mountshort_str); if (!do_query(buf)) { sprintf(buf, "Unable to save %s!", ch->name); bug(buf,0); free(buf); return FALSE; } else { const char* alsdel = "DELETE FROM tblcharacteraliases WHERE CharacterID=%d"; const char* alsstr = "INSERT INTO tblcharacteraliases VALUES (NULL, %d, \"%s\", \"%s\");"; const char* lngdel = "DELETE FROM tblcharacterlanguages WHERE CharacterID=%d"; const char* lngstr = "INSERT INTO tblcharacterlanguages VALUES (NULL, %d, %d, %d);"; const char* skldel = "DELETE FROM tblcharacterskills WHERE CharacterID=%d"; const char* sklstr = "INSERT INTO tblcharacterskills VALUES (NULL, %d, %d, %d);"; ALIAS_DATA* a; int i; if (ch->new) { ch->CharID = (int) last_id(); ch->new = FALSE; } // aliases sprintf(buf, alsdel, ch->CharID); if (do_query(buf)) { for (a = ch->pcdata->alias_list; a; a = a->next) { desc_str = escape_query(a->old); title_str = escape_query(a->_new); sprintf(buf, alsstr, ch->CharID, desc_str, title_str); do_query(buf); } } // languages sprintf(buf, lngdel, ch->CharID); if (do_query(buf)) { for(i=0; i< MAX_LANGUAGE; i++) { if (ch->language[i]) { sprintf(buf, lngstr, ch->CharID, i, ch->language[i]); do_query(buf); } } } // skills sprintf(buf, skldel, ch->CharID); if (do_query(buf)) { for (i=0; i< MAX_SKILL; i++) { if (ch->pcdata->learned[i]) { sprintf(buf, sklstr, ch->CharID, i, ch->pcdata->learned[i]); do_query(buf); } } } // affects sql_save_aff(ch->affected, ch->CharID, 1); sql_save_aff(ch->affected2, ch->CharID, 2); sql_save_aff(ch->affected3, ch->CharID, 3); sql_save_aff(ch->affected4, ch->CharID, 4); } ch->save_time = current_time; free(buf); return TRUE; } void sql_save_aff(AFFECT_DATA* aff, int CharID, int vector) { const char* affstr = "INSERT INTO tblcharacteraffects VALUES ( NULL, %d, %d, %d, %d, %d, %d, %d, %d );"; const char* delaff = "DELETE FROM tblcharacteraffects WHERE CharacterID=%d AND FlagNum=%d"; char buf[MAX_STRING_LENGTH*10]; AFFECT_DATA* a; sprintf(buf, delaff, CharID, vector); if (do_query(buf)) { for (a = aff; a; a = a->next) { if (a->deleted) continue; sprintf(buf, affstr, CharID, vector, a->type, a->level, a->duration, a->location, a->modifier, a->bitvector); do_query(buf); } } } /* * Rather than trying to search for old inventory, it's easier to * delete and re-insert. Otherwise we're doing too many record seeks * via UPDATE calls. */ bool sql_remove_old_inv(int CharID, bool Dirty) { char InvTable[100] = ""; char DetTable[100] = ""; char buf[MAX_STRING_LENGTH] = ""; char lst[MAX_STRING_LENGTH] = ""; MYSQL_RES* res = NULL; MYSQL_ROW row; int i = 0; if (Dirty) { strcpy(InvTable, DIRTY_INV); strcpy(DetTable, DIRTY_DET); } else { strcpy(InvTable, TABLE_INV); strcpy(DetTable, TABLE_DET); } sprintf(buf, "SELECT InventoryID FROM %s WHERE CharacterID=%d", InvTable, CharID ); if ((res=do_query(buf))) { int rows = rowcount(res); for (i = 0; i < rows; i++) { row = get_row(res); strcat(lst, row[0]); if ( i != (rows - 1) ) strcat(lst, ","); } } sprintf(buf, "DELETE FROM %s WHERE CharacterID=%d", InvTable, CharID); if (!do_query(buf)) return FALSE; sprintf(buf, "DELETE FROM %s WHERE InventoryID IN ( %s )", DetTable, lst); if (!do_query(buf)) return FALSE; return TRUE; } /* * Exact same function whether dirty or not. The only difference * is the table that gets updated. We probably don't need to update * the dirty table because we keep a list of dirty characters in mem * until they're dumped to the db, but this is for safety. This might * be good for something like a disconnect. */ /* * Current Algorithm: * Delete All, For Each Item (Insert, Check for Custom ) * Could be faster to: * Select All, For Each Item ( Compare, If Different, Update ) * But, this would require searching the linked list, and special cases for dleted * and new items. * * I don't feel like doing the math... * - Ahsile */ bool sql_save_inv(OBJ_DATA* obj, int CharID, int InsideOf, bool Storage, bool Dirty) { char InvTable[100] = ""; char DetTable[100] = ""; char buf[MAX_STRING_LENGTH] = ""; const char* objstr = "INSERT INTO %s VALUES ( %d, %d, %d, %d, %d, %d);"; const char* detstr = "INSERT INTO %s VALUES ( %d, %d, \"%s\", \"%s\", \"%s\", %d, %d);"; MYSQL_RES* res = NULL; MYSQL_ROW row; OBJ_DATA* o = NULL; int last_obj = 0; if (Dirty) { strcpy(InvTable, DIRTY_INV); strcpy(DetTable, DIRTY_DET); } else { strcpy(InvTable, TABLE_INV); strcpy(DetTable, TABLE_DET); } for (o = obj; o; o = o->next_content) { if (o->deleted) continue; /* clunky for now. mysql version doesn't support auto-increment for memory tables */ sprintf(buf, "SELECT MAX(InventoryID) FROM %s", InvTable); if (!(res=do_query(buf))) return FALSE; else { row = get_row(res); last_obj = atoi(row[0])+1; } sprintf(buf, objstr, InvTable, last_obj, CharID, o->pIndexData->vnum, InsideOf, Storage, o->wear_loc); if (do_query(buf)) { OBJ_INDEX_DATA* od = o->pIndexData; int det_id; // object details if ((((strcmp(o->short_descr,od->short_descr)!=0) || (o->ac_charge[0] != od->ac_charge[0]) || (o->ac_charge[1] != od->ac_charge[1]) || (o->value[1] != od->value[1]) || (o->value[2] != od->value[2]) || (strcmp(o->name,od->name)!=0) || (strcmp(o->description, od->description)!=0))) && (o->pIndexData->vnum != 1) ) { char* short_desc_buf; char* long_desc_buf; char* name_buf; int invokes_used = o->ac_charge[1] - o->ac_charge[0]; int charges_used = o->value[1] - o->value[2]; if (invokes_used < 0 || invokes_used > o->ac_charge[1]) invokes_used = 0; if (charges_used < 0 || charges_used > o->value[1]) charges_used = 0; sprintf(buf, "SELECT MAX(InventoryDetailID) FROM %s", DetTable); if (!(res=do_query(buf))) return FALSE; else { row = get_row(res); det_id = atoi(row[0])+1; } short_desc_buf = escape_query(o->short_descr); long_desc_buf = escape_query(o->description); name_buf = escape_query(o->name); sprintf(buf, detstr, DetTable, det_id, last_obj, short_desc_buf, long_desc_buf, name_buf, invokes_used, charges_used); do_query(buf); free(short_desc_buf); free(long_desc_buf); free(name_buf); } // items inside if (o->contains) { sql_save_inv(o->contains, CharID, last_obj, Storage, Dirty); } } } return TRUE; } bool sql_save_area(AREA_DATA* pArea) { char buf[MAX_STRING_LENGTH]; if (!pArea->AreaID) { const char* areastring = "INSERT INTO tblarea (AreaID, ShortName, Name, VnumLower, VnumHigh, Security, Builders, ResetString, Flags, Recall, AreaSound, MusicFile) VALUES (NULL, \"%s\", \"%s\", %d, %d, %d, \"%s\", \"%s\", %d, %d, \"%s\", \"%s\");"; sprintf(buf, areastring, pArea->filename, pArea->name, pArea->lvnum, pArea->uvnum, pArea->security, pArea->builders, pArea->reset_sound, pArea->area_flags, pArea->recall, pArea->actual_sound, pArea->musicfile); if (do_query(buf)) pArea->AreaID = (int) last_id(); else return FALSE; } else { const char* areastring = "UPDATE tblarea SET ShortName=\"%s\", Name=\"%s\", VnumLower=%d, VnumHigh=%d, Security=%d, Builders=\"%s\", ResetString=\"%s\", Flags=%d, Recall=%d, AreaSound=\"%s\", MusicFile=\"%s\" WHERE AreaID=%d"; sprintf(buf, areastring, pArea->filename, pArea->name, pArea->lvnum, pArea->uvnum, pArea->security, pArea->builders, pArea->reset_sound, pArea->area_flags, pArea->recall, pArea->actual_sound, pArea->musicfile, pArea->AreaID); if (!do_query(buf)) return FALSE; } // save rooms if (!sql_save_rooms(pArea)) return FALSE; // save mobiles if (!sql_save_mobiles(pArea)) return FALSE; // save objects if (!sql_save_objects(pArea)) return FALSE; if (!sql_save_resets(pArea)) return FALSE; return TRUE; } bool sql_save_rooms(AREA_DATA* pArea) { char buf[MAX_STRING_LENGTH*10] = ""; const char* roomstr = "INSERT INTO tblrooms VALUES( %d, %d, \"%s\", \"%s\", \"%s\", \"%s\", %d, %d, 0, 0, 0)"; const char* edstr = "INSERT INTO tblroomdescriptions VALUES(NULL, %d, \"%s\", \"%s\");"; const char* exitstr = "INSERT INTO tblroomexits VALUES (NULL, %d, %d, \"%s\", \"%s\", %d, %d, %d, %d, 0);"; ROOM_INDEX_DATA* room = NULL; int i; // delete old rooms sprintf(buf, "DELETE FROM tblrooms WHERE AreaID=%d", pArea->AreaID); if (!do_query(buf)) return FALSE; // from lowvnum to uvnum for (i=pArea->lvnum; i <= pArea->uvnum; i++) { // getroomindex room = get_room_index(i); // room exists if (room) { EXTRA_DESCR_DATA* ed; int dir; bool hasProg = FALSE; bool hasED = FALSE; bool hasExit = FALSE; char* name_str = escape_query(room->name); char* desc_str = escape_query(room->description); // insert sprintf(buf, roomstr, room->vnum, pArea->AreaID, name_str, room->soundfile, room->musicfile, desc_str, room->room_flags, room->sector_type); free(name_str); free(desc_str); if (!do_query(buf)) continue; // save progs sprintf(buf, "DELETE FROM tblprograms WHERE Vnum=%d AND LoadType=%d", room->vnum, LOAD_ROOM); if (do_query(buf)) { if (room->traps) { hasProg = TRUE; sql_save_traps(room->traps, room->vnum, LOAD_ROOM, 0); } } // save exits sprintf(buf, "DELETE FROM tblroomexits WHERE RoomVnum=%d", room->vnum); if (do_query(buf)) { for (dir = 0; dir < MAX_DIR; dir++) { if (room->exit[dir]) { EXIT_DATA* exit = room->exit[dir]; char* exit_desc_str = escape_query(exit->description); char* exit_keyw_str = escape_query(exit->keyword); sprintf(buf, exitstr, room->vnum, dir, exit_desc_str, exit_keyw_str, exit->exit_info, exit->rs_flags, exit->key, exit->vnum); free(exit_desc_str); free(exit_keyw_str); if (do_query(buf)) { hasExit = TRUE; // sigh, exits have traps (or at least the possibility to have a trap // even though not a single one exists on the mud ) if (exit->traps) { int exit_id = (int) last_id(); // have to grab id here. save_traps // may change this value sprintf(buf, "DELETE FROM tblprograms WHERE Vnum=%d And LoadType=%d", room->vnum, LOAD_EXIT); if (do_query(buf)) { if(sql_save_traps(exit->traps, room->vnum, LOAD_EXIT, dir)) { sprintf(buf, "UPDATE tblroomexits SET HasTrap=%d WHERE ExitID=%d", TRUE, exit_id); do_query(buf); } } } } } } } // save ed sprintf(buf, "DELETE FROM tblroomdescriptions WHERE vnum=%d", room->vnum); if (do_query(buf)) { for (ed = room->extra_descr; ed; ed = ed->next) { char* ed_desc_str = escape_query(ed->description); sprintf(buf, edstr, room->vnum, ed->keyword, ed_desc_str); free(ed_desc_str); if (do_query(buf)) hasED = TRUE; } } sprintf(buf, "UPDATE tblrooms SET HasTrap=%d, HasExit=%d, HasED=%d WHERE vnum=%d", hasProg, hasExit, hasED, room->vnum); do_query(buf); } } return TRUE; } bool sql_save_mobiles(AREA_DATA* pArea) { char buf[MAX_STRING_LENGTH*10] = ""; const char* mobstr = "INSERT INTO tblmobiles VALUES (%d, %d, \"%s\", \"%s\", \"%s\", %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, \"%s\", 0, 0);"; MOB_INDEX_DATA* mob = NULL; int i; // delete old mobs sprintf(buf, "DELETE FROM tblmobiles WHERE AreaID=%d", pArea->AreaID); if (!do_query(buf)) return FALSE; // from low vnum to uvnum for (i=pArea->lvnum; i<=pArea->uvnum; i++) { bool hasProg = FALSE; bool hasDesc = FALSE; // get mob index mob = get_mob_index( i ); // mob exists if (mob) { char* mob_ldesc_str = escape_query(mob->long_descr); char* mob_sdesc_str = escape_query(mob->short_descr); // insert sprintf(buf, mobstr, mob->vnum, pArea->AreaID, mob->player_name, mob_sdesc_str, mob_ldesc_str, mob->act, mob->affected_by, mob->affected_by2, mob->affected_by3, mob->affected_by4, mob->alignment, mob->level, mob->hitroll, mob->damroll, mob->hitnodice, mob->sex, mob->imm_flags, mob->res_flags, mob->vul_flags, mob->speaking, spec_string( mob->spec_fun )); free(mob_ldesc_str); free(mob_sdesc_str); if (!do_query(buf)) continue; // save progs sprintf(buf, "DELETE FROM tblprograms WHERE Vnum=%d AND LoadType=%d", mob->vnum, LOAD_MOB); if (do_query(buf)) { if (mob->mobprogs) { if (sql_save_mprogs(mob->mobprogs, mob->vnum)) { hasProg = TRUE; } } } // save desc sprintf(buf, "DELETE FROM tblmobiledescriptions WHERE Vnum=%d", mob->vnum); if (do_query(buf)) { if (str_cmp(mob->description,str_empty)) { char* mob_desc_str = escape_query(mob->description); sprintf(buf, "INSERT INTO tblmobiledescriptions VALUES (NULL, %d, %s)", mob->vnum, mob_desc_str); free(mob_desc_str); if (do_query(buf)) hasDesc = TRUE; } } sprintf(buf, "UPDATE tblmobiles SET HasProg=%d, HasDesc=%d WHERE Vnum=%d", hasProg, hasDesc, mob->vnum); do_query(buf); } } return TRUE; } bool sql_save_objects(AREA_DATA* pArea) { char buf[MAX_STRING_LENGTH*10] = ""; const char* objstr = "INSERT INTO tblobjects VALUES (%d, %d, \"%s\", \"%s\", \"%s\", %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, \"%s\", %d, %d, %d, %d, %d, 0, 0, 0);"; const char* edstr = "INSERT INTO tblobjectdescriptions VALUES ( NULL, %d, \"%s\", \"%s\" );"; const char* affstr = "INSERT INTO tblobjectaffects VALUES ( NULL, %d, %d, %d );"; OBJ_INDEX_DATA* obj = NULL; int i; // delete old objs sprintf(buf, "DELETE FROM tblobjects WHERE AreaID=%d", pArea->AreaID); if (!do_query(buf)) return FALSE; // from low vnum to uvnum for (i = pArea->lvnum; i <= pArea->uvnum; i++) { bool hasProg = FALSE; bool hasAff = FALSE; bool hasED = FALSE; // get obj index obj = get_obj_index( i ); // obj exists if (obj) { char* desc_str = escape_query(obj->description); char* short_str = escape_query(obj->short_descr); // insert sprintf( buf, objstr, obj->vnum, pArea->AreaID, obj->name, short_str, desc_str, obj->item_type, obj->extra_flags, obj->extra_flags2, obj->extra_flags3, obj->extra_flags4, obj->wear_flags, obj->level, obj->value[0], obj->value[1], obj->value[2], obj->value[3], obj->weight, obj->cost, obj->ac_type, obj->ac_vnum, obj->ac_spell, obj->ac_charge[0], obj->ac_charge[1], obj->join, obj->sep_one, obj->sep_two); free(desc_str); free(short_str); if (!do_query(buf)) continue; // save progs sprintf(buf, "DELETE FROM tblprograms WHERE Vnum=%d AND LoadType=%d", obj->vnum, LOAD_OBJ); if (do_query(buf)) { if (obj->traps) { if (sql_save_traps(obj->traps, obj->vnum, LOAD_OBJ, 0)) { hasProg = TRUE; } } } // save aff sprintf(buf, "DELETE FROM tblobjectaffects WHERE Vnum=%d", obj->vnum); if (do_query(buf)) { if (obj->affected) { AFFECT_DATA* aff; for (aff = obj->affected; aff; aff = aff->next) { sprintf(buf, affstr, obj->vnum, aff->location, aff->modifier); if (do_query(buf)) hasAff = TRUE; } } } // save ed sprintf(buf, "DELETE FROM tblobjectdescriptions WHERE Vnum=%d", obj->vnum); if (do_query(buf)) { if (obj->extra_descr) { EXTRA_DESCR_DATA* ed; for (ed = obj->extra_descr; ed; ed = ed->next) { char* ed_descr_str = escape_query(ed->description); sprintf(buf, edstr, obj->vnum, ed->keyword, ed_descr_str); free(ed_descr_str); if (do_query(buf)) hasED = TRUE; } } } } } return TRUE; } bool sql_save_traps(TRAP_DATA* traplist, int Vnum, int Type, int Exit) { char buf[MAX_STRING_LENGTH*10] = ""; const char* trapstr = "INSERT INTO tblprograms VALUES(NULL,%d, %d, %d, %d, \"%s\", \"%s\");"; TRAP_DATA* trap = NULL; for (trap = traplist; trap; trap = trap->next) { char* arglist_str = escape_query( trap->arglist ); char* comlist_str = escape_query( trap->comlist ); sprintf(buf, trapstr, Vnum, Exit, Type, trap->type, arglist_str, comlist_str); free( arglist_str ); free( comlist_str ); if (!do_query(buf)) return FALSE; } return TRUE; } bool sql_save_mprogs(MPROG_DATA* mplist, int Vnum) { char buf[MAX_STRING_LENGTH*10] = ""; const char* mpstr = "INSERT INTO tblprograms VALUES(NULL,%d, %d, %d, %d, \"%s\", \"%s\");"; MPROG_DATA* mprog = NULL; for (mprog = mplist; mprog; mprog = mprog->next) { char* arglist_str = escape_query( mprog->arglist ); char* comlist_str = escape_query( mprog->comlist ); sprintf(buf, mpstr, Vnum, mprog->status, LOAD_MOB, mprog->type, arglist_str, comlist_str); free( arglist_str ); free( comlist_str ); if (!do_query(buf)) return FALSE; } return TRUE; } bool sql_save_bans() { BAN_DATA* ban = NULL; char buf[MAX_STRING_LENGTH] = ""; if (!do_query("TRUNCATE tblbans")) return FALSE; for (ban = ban_list; ban; ban = ban->next) { sprintf(buf, "INSERT INTO tblbans VALUES (NULL, \"%s\", \"%s\");", ban->name, ban->user); do_query(buf); } return TRUE; } bool sql_save_disabled() { DISABLED_DATA* dis = NULL; char buf[MAX_STRING_LENGTH] = ""; if (!do_query("TRUNCATE tbldisabled")) return FALSE; for (dis = disabled_first; dis; dis = dis->next) { sprintf(buf, "INSERT INTO tbldisabled VALUES (NULL, \"%s\", %d, %d, \"%s\");", dis->command->name, dis->uptolevel, dis->dislevel, dis->disabled_by); do_query(buf); } return TRUE; } bool sql_save_clans() { CLAN_DATA* clan = NULL; char buf[MAX_STRING_LENGTH * 10]= ""; if (!do_query("TRUNCATE tblclans")) return FALSE; for (clan = clan_first; clan; clan = clan->next) { char* clan_descr = escape_query(clan->description); sprintf(buf, "INSERT INTO tblclans VALUES (NULL, \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d)", clan->name, clan_descr, clan->deity, clan->champ, clan->leader, clan->first, clan->second, clan->ischamp, clan->isleader, clan->isfirst, clan->issecond, clan->recall, clan->pkills, clan->mkills, clan->members, clan->pdeaths, clan->mdeaths, clan->obj_vnum_1, clan->obj_vnum_2, clan->obj_vnum_3, clan->pkill); free(clan_descr); do_query(buf); } return TRUE; } bool sql_save_religions() { RELIGION_DATA* rel = NULL; char buf[MAX_STRING_LENGTH * 10]= ""; if (!do_query("TRUNCATE tblreligions")) return FALSE; for (rel = religion_first; rel; rel = rel->next) { char* descr_str = escape_query(rel->description); sprintf(buf, "INSERT INTO tblreligions VALUES ( NULL, \"%s\", \"%s\", \"%s\", \"%s\", %d, %d, %d, %d, %d, %d );", rel->name, rel->shortdesc, rel->deity, descr_str, rel->recall, rel->pkills, rel->mkills, rel->pdeaths, rel->mdeaths, rel->members); free(descr_str); do_query(buf); } return TRUE; } bool sql_save_helps() { HELP_DATA* help = NULL; char buf[MAX_STRING_LENGTH * 10]= ""; if (!do_query("TRUNCATE tblhelp")) return FALSE; for (help = help_first; help; help = help->next) { char* help_str = escape_query(help->text); sprintf(buf, "INSERT INTO tblhelp VALUES (NULL, \"%s\", %d, \"%s\");", help->keyword, help->level, help_str); free(help_str); do_query(buf); } return TRUE; } bool sql_save_socials() { char buf[MAX_STRING_LENGTH * 10]= ""; char* socstr = "INSERT INTO tblsocials VALUES (NULL, \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\", \"%s\");"; int i = 0; if (!do_query("TRUNCATE tblsocials")) return FALSE; for (i = 0; i < maxSocial; i++) { SOCIAL_DATA* soc = &social_table[i]; char* char_no_arg_str = escape_query(soc->char_no_arg); char* others_no_arg_str = escape_query(soc->others_no_arg); char* char_found_str = escape_query(soc->char_found); char* others_found_str = escape_query(soc->others_found); char* vict_found_str = escape_query(soc->vict_found); char* char_auto_str = escape_query(soc->char_auto); char* others_auto_str = escape_query(soc->others_auto); sprintf(buf, socstr, soc->name, char_no_arg_str, others_no_arg_str, char_found_str, others_found_str, vict_found_str, char_auto_str, others_auto_str); if(char_no_arg_str) free(char_no_arg_str); if (others_no_arg_str) free(others_no_arg_str); if (char_found_str) free(char_found_str); if (others_found_str) free(others_found_str); if (vict_found_str) free(vict_found_str); if (char_auto_str) free(char_auto_str); if (others_auto_str) free(others_auto_str); do_query(buf); } return TRUE; } /* Resets are a ROYAL pain in the ass! * They need to be in the correct order to work. * Ripped original function * - Ahsile */ bool sql_save_resets(AREA_DATA* pArea) { char buf[MAX_STRING_LENGTH] = ""; int vnum = 0; RESET_DATA* pReset = NULL; ROOM_INDEX_DATA* pRoomIndex = NULL; MOB_INDEX_DATA* pLastMob = NULL; OBJ_INDEX_DATA* pLastObj = NULL; sprintf(buf, "DELETE FROM tblresets WHERE AreaID=%d", pArea->AreaID); if (!do_query(buf)) return FALSE; for( vnum = pArea->lvnum; vnum <= pArea->uvnum; vnum++ ) { if( ( pRoomIndex = get_room_index(vnum) ) ) { if ( pRoomIndex->area == pArea ) { for ( pReset = pRoomIndex->reset_first; pReset; pReset = pReset->next ) { switch ( pReset->command ) { default: bug( "Save_resets: bad command %c.", pReset->command ); continue; break; case 'M': pLastMob = get_mob_index( pReset->arg1 ); sprintf(buf, "INSERT INTO tblresets VALUES (NULL, \"M\", %d, %d, %d, %d, %d)", pReset->status, pReset->arg1, pReset->arg2, pReset->arg3, pArea->AreaID ); break; case 'O': pLastObj = get_obj_index( pReset->arg1 ); sprintf(buf, "INSERT INTO tblresets VALUES (NULL, \"O\", %d, %d, 0, %d, %d)", pReset->status, pReset->arg1, pReset->arg3, pArea->AreaID ); break; case 'P': pLastObj = get_obj_index( pReset->arg1 ); sprintf(buf, "INSERT INTO tblresets VALUES (NULL, \"P\", %d, %d, 0, %d, %d)", pReset->status, pReset->arg1, pReset->arg3, pArea->AreaID ); break; case 'G': sprintf(buf, "INSERT INTO tblresets VALUES (NULL, \"G\", %d, %d, 0, 0, %d)", pReset->status, pReset->arg1, pArea->AreaID ); if ( !pLastMob ) { sprintf( buf, "Save_resets: !NO_MOB! in [%s]", pArea->filename ); bug( buf, 0 ); } break; case 'E': sprintf(buf, "INSERT INTO tblresets VALUES (NULL, \"E\", %d, %d, 0, %d, %d", pReset->status, pReset->arg1, pReset->arg3, pArea->AreaID ); if ( !pLastMob ) { sprintf( buf, "Save_resets: !NO_MOB! in [%s]", pArea->filename ); bug( buf, 0 ); } break; case 'D': break; case 'R': sprintf(buf, "INSERT INTO tblresets VALUES (NULL, \"R\", %d, %d, %d, 0, %d)", pReset->status, pReset->arg1, pReset->arg2, pArea->AreaID ); break; } do_query(buf); } } } } return TRUE; } bool sql_save_shops() { char buf[MAX_STRING_LENGTH] = ""; SHOP_DATA* shop = NULL; if (!do_query("TRUNCATE tblshops")) return FALSE; for ( shop = shop_first; shop; shop = shop->next ) { sprintf(buf, "INSERT INTO tblshops VALUES (NULL, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d);", shop->keeper, shop->profit_buy, shop->profit_sell, shop->open_hour, shop->close_hour, shop->buy_type[0], shop->buy_type[1], shop->buy_type[2], shop->buy_type[3], shop->buy_type[4]); do_query(buf); } return TRUE; } #endif // SQL_SYSTEM