/** * Player requesting to change map-serv * @param fd: wich fd to parse from * @return : 0 not enough data received, 1 success */ int chmapif_parse_reqchangemapserv(int fd){ if (RFIFOREST(fd) < 39) return 0; { int map_id, map_fd = -1; struct mmo_charstatus* char_data; struct mmo_charstatus char_dat; DBMap* char_db_ = char_get_chardb(); map_id = char_search_mapserver(RFIFOW(fd,18), ntohl(RFIFOL(fd,24)), ntohs(RFIFOW(fd,28))); //Locate mapserver by ip and port. if (map_id >= 0) map_fd = map_server[map_id].fd; //Char should just had been saved before this packet, so this should be safe. [Skotlex] char_data = (struct mmo_charstatus*)uidb_get(char_db_,RFIFOL(fd,14)); if (char_data == NULL) { //Really shouldn't happen. char_mmo_char_fromsql(RFIFOL(fd,14), &char_dat, true); char_data = (struct mmo_charstatus*)uidb_get(char_db_,RFIFOL(fd,14)); } if( runflag == CHARSERVER_ST_RUNNING && session_isActive(map_fd) && char_data ) { //Send the map server the auth of this player. struct online_char_data* data; struct auth_node* node; DBMap* auth_db = char_get_authdb(); DBMap* online_char_db = char_get_onlinedb(); int aid = RFIFOL(fd,2); //Update the "last map" as this is where the player must be spawned on the new map server. char_data->last_point.map = RFIFOW(fd,18); char_data->last_point.x = RFIFOW(fd,20); char_data->last_point.y = RFIFOW(fd,22); char_data->sex = RFIFOB(fd,30); // create temporary auth entry CREATE(node, struct auth_node, 1); node->account_id = aid; node->char_id = RFIFOL(fd,14); node->login_id1 = RFIFOL(fd,6); node->login_id2 = RFIFOL(fd,10); node->sex = RFIFOB(fd,30); node->expiration_time = 0; // FIXME (this thing isn't really supported we could as well purge it instead of fixing) node->ip = ntohl(RFIFOL(fd,31)); node->group_id = RFIFOL(fd,35); node->changing_mapservers = 1; idb_put(auth_db, aid, node); data = idb_ensure(online_char_db, aid, char_create_online_data); data->char_id = char_data->char_id; data->server = map_id; //Update server where char is. //Reply with an ack. chmapif_changemapserv_ack(fd,0); } else { //Reply with nak chmapif_changemapserv_ack(fd,1); } RFIFOSKIP(fd,39); }
/** [Cydh] * Find item(s) that will be obtained by player based on Item Group * @param group_id: The group ID that will be gained by player * @param nameid: The item that trigger this item group * @return val: 0:success, 1:no sd, 2:invalid item group */ char itemdb_pc_get_itemgroup(uint16 group_id, struct map_session_data *sd) { uint16 i = 0; struct s_item_group_db *group; nullpo_retr(1,sd); if (!(group = (struct s_item_group_db *) uidb_get(itemdb_group, group_id))) { ShowError("itemdb_pc_get_itemgroup: Invalid group id '%d' specified.\n",group_id); return 2; } // Get the 'must' item(s) if (group->must_qty) { for (i = 0; i < group->must_qty; i++) if (&group->must[i]) itemdb_pc_get_itemgroup_sub(sd,&group->must[i]); } // Get the 'random' item each random group for (i = 0; i < MAX_ITEMGROUP_RANDGROUP; i++) { uint16 rand; if (!(&group->random[i]) || !group->random[i].data_qty) //Skip empty random group continue; rand = rnd()%group->random[i].data_qty; if (!(&group->random[i].data[rand]) || !group->random[i].data[rand].nameid) continue; itemdb_pc_get_itemgroup_sub(sd,&group->random[i].data[rand]); } return 0; }
/** * Return a random group entry from Item Group * @param group_id * @param sub_group: 0 is 'must' item group, random groups start from 1 to MAX_ITEMGROUP_RANDGROUP+1 * @return Item group entry or NULL on fail */ struct s_item_group_entry *itemdb_get_randgroupitem(uint16 group_id, uint8 sub_group) { struct s_item_group_db *group = (struct s_item_group_db *) uidb_get(itemdb_group, group_id); struct s_item_group_entry *list = NULL; uint16 qty = 0; if (!group) { ShowError("itemdb_get_randgroupitem: Invalid group id %d\n", group_id); return NULL; } if (sub_group > MAX_ITEMGROUP_RANDGROUP+1) { ShowError("itemdb_get_randgroupitem: Invalid sub_group %d\n", sub_group); return NULL; } if (sub_group == 0) { list = group->must; qty = group->must_qty; } else { list = group->random[sub_group-1].data; qty = group->random[sub_group-1].data_qty; } if (!qty) { ShowError("itemdb_get_randgroupitem: No item entries for group id %d and sub group %d\n", group_id, sub_group); return NULL; } return &list[rnd()%qty]; }
/*========================================== * Searches for an instance name in the database *------------------------------------------*/ static struct instance_db *instance_searchname_db(const char *instance_name) { uint16 id = instance_name2id(instance_name); if(!id) return NULL; return (struct instance_db *)uidb_get(InstanceDB, id); }
/*========================================== * Loads an item from the db. If not found, it will return the dummy item. * @param nameid * @return *item_data or *dummy_item if item not found *------------------------------------------*/ struct item_data* itemdb_search(unsigned short nameid) { struct item_data* id = NULL; if (nameid == dummy_item->nameid) id = dummy_item; else if (!(id = (struct item_data*)uidb_get(itemdb, nameid))) { ShowWarning("itemdb_search: Item ID %hu does not exists in the item_db. Using dummy data.\n", nameid); id = dummy_item; } return id; }
int classdb_path(int id) { struct class_data *db=NULL; db = uidb_get(class_db, id); if (db) { return db->path; } else { return 0; } }
int setInvalidCount(unsigned int ip) { int c=uidb_get(bf_lockout,ip); if(!c) { timer_insert(10*60*1000,10*60*1000,login_clear_lockout,ip,0); } uidb_put(bf_lockout,ip,c+1); return c+1; }
unsigned int classdb_level(int path,int lvl) { struct class_data *db=NULL; db=uidb_get(class_db,path); if (db) { return db->level[lvl]; } else { return 0; } }
//character selected, insert into auth db void chrif_authok(int fd) { struct auth_node *auth_data; TBL_PC* sd; //Check if we don't already have player data in our server //(prevents data that is to be saved from being overwritten by //this received status data if this auth is later successful) [Skotlex] if ((sd = map_id2sd(RFIFOL(fd, 4))) != NULL) { struct mmo_charstatus *status = (struct mmo_charstatus *)RFIFOP(fd, 20); //Auth check is because this could be the very same sd that is waiting char-server authorization. if (sd->state.auth && sd->status.char_id == status->char_id) return; } if ((auth_data =uidb_get(auth_db, RFIFOL(fd, 4))) != NULL) { //Is the character already awaiting authorization? if (auth_data->sd) { //First, check to see if the session data still exists (avoid dangling pointers) if(session[auth_data->fd] && session[auth_data->fd]->session_data == auth_data->sd) { if (auth_data->char_dat == NULL && auth_data->account_id == RFIFOL(fd, 4) && auth_data->login_id1 == RFIFOL(fd, 8)) { //Auth Ok pc_authok(auth_data->sd, RFIFOL(fd, 16), RFIFOL(fd, 12), (struct mmo_charstatus*)RFIFOP(fd, 20)); } else { //Auth Failed pc_authfail(auth_data->sd); chrif_char_offline(auth_data->sd); //Set him offline, the char server likely has it set as online already. } } //else: Character no longer exists, just go through. } //Delete the data of this node... if (auth_data->char_dat) aFree (auth_data->char_dat); uidb_remove(auth_db, RFIFOL(fd, 4)); return; } // Awaiting for client to connect. auth_data = (struct auth_node *)aCalloc(1,sizeof(struct auth_node)); auth_data->char_dat = (struct mmo_charstatus *) aCalloc(1,sizeof(struct mmo_charstatus)); auth_data->account_id=RFIFOL(fd, 4); auth_data->login_id1=RFIFOL(fd, 8); auth_data->connect_until_time=RFIFOL(fd, 12); auth_data->login_id2=RFIFOL(fd, 16); memcpy(auth_data->char_dat,RFIFOP(fd, 20),sizeof(struct mmo_charstatus)); auth_data->node_created=gettick(); uidb_put(auth_db, RFIFOL(fd, 4), auth_data); }
struct creation_data* createdb_search(int id) { static struct creation_data *db=NULL; if (db && db->id == id) return db; db = uidb_get(create_db, id); if (db) return db; CALLOC(db, struct creation_data, 1); uidb_put(create_db, id, db); db->id = id; //strcpy(db->name, "??"); return db; }
struct class_data* classdb_search(int id) { static struct class_data *db=NULL; if (db && db->id == id) return db; db = uidb_get(class_db, id); if (db) return db; CALLOC(db, struct class_data, 1); uidb_put(class_db, id, db); db->id = id; db->chat=0; strcpy(db->rank0,"??"); //strcpy(db->rank_name[0], "??"); return db; }
/** * Return a random item id from group. (takes into account % chance giving/tot group) * NOTE: Sub group 0 will be set to default 1, since 0 isn't random group * @param group_id * @param sub_group: Default is 1 * @return nameid */ unsigned short itemdb_searchrandomid(uint16 group_id, uint8 sub_group) { struct s_item_group_db *group = (struct s_item_group_db *) uidb_get(itemdb_group, group_id); if (sub_group) sub_group -= 1; if (!group) { ShowError("itemdb_searchrandomid: Invalid group id %d\n", group_id); return UNKNOWN_ITEM_ID; } if (sub_group > MAX_ITEMGROUP_RANDGROUP) { ShowError("itemdb_searchrandomid: Invalid sub_group %d\n", sub_group+1); return UNKNOWN_ITEM_ID; } if (&group->random[sub_group] && group->random[sub_group].data_qty) return group->random[sub_group].data[rand()%group->random[sub_group].data_qty].nameid; ShowError("itemdb_searchrandomid: No item entries for group id %d and sub group %d\n", group_id, sub_group+1); return UNKNOWN_ITEM_ID; }
char *classdb_name(int id,int a) { struct class_data *db=NULL; db = uidb_get(class_db, id); switch(a) { case 0: return db->rank0; case 1: return db->rank1; case 2: return db->rank2; case 3: return db->rank3; case 4: return db->rank4; case 5: return db->rank5; case 6: return db->rank6; case 7: return db->rank7; case 8: return db->rank8; case 9: return db->rank9; case 10: return db->rank10; case 11: return db->rank11; case 12: return db->rank12; case 13: return db->rank13; case 14: return db->rank14; case 15: return db->rank15; default: return db->rank0; } }
/** [Cydh] * Return a number of item's amount that will be obtained for 'getrandgroupitem id,1;' * NOTE: Sub group 0 will be set to default 1, since 0 isn't random group * @param group_id * @param sub_group * @param nameid: The target item will be found * @return amount */ uint16 itemdb_get_randgroupitem_count(uint16 group_id, uint8 sub_group, unsigned short nameid) { uint16 i, amt = 1; struct s_item_group_db *group = (struct s_item_group_db *) uidb_get(itemdb_group, group_id); if (sub_group) sub_group -= 1; if (!group) { ShowError("itemdb_get_randgroupitem_count: Invalid group id %d\n", group_id); return amt; } if (sub_group > MAX_ITEMGROUP_RANDGROUP) { ShowError("itemdb_get_randgroupitem_count: Invalid sub_group id %d\n", group_id+1); return amt; } if (!(&group->random[sub_group]) || !group->random[sub_group].data_qty) return amt; for (i = 0; i < group->random[sub_group].data_qty; i++) { if (group->random[sub_group].data[i].nameid == nameid) return group->random[sub_group].data[i].amount; } return amt; }
/*========================================== * Read the instance_db.txt file *------------------------------------------*/ static bool instance_readdb_sub(char *str[], int columns, int current) { uint8 i; int id = atoi(str[0]); struct instance_db *db; bool isNew = false, defined = false; if(!id || id > USHRT_MAX) { ShowError("instance_readdb_sub: Cannot add instance with ID '%d'. Valid ID is 1 ~ %d.\n", id, USHRT_MAX); return false; } if(mapindex_name2id(str[3]) == 0) { ShowError("instance_readdb_sub: Invalid map '%s' as entrance map.\n", str[3]); return false; } if(!(db = (struct instance_db *)uidb_get(InstanceDB, id))) { CREATE(db, struct instance_db, 1); db->id = id; db->name = StringBuf_Malloc(); db->enter.mapname = StringBuf_Malloc(); isNew = true; } else {
/*========================================== * Searches for an instance ID in the database *------------------------------------------*/ static struct instance_db *instance_searchtype_db(unsigned short instance_id) { return (struct instance_db *)uidb_get(InstanceDB, instance_id); }
int getInvalidCount(unsigned int ip) { int c=uidb_get(bf_lockout,ip); return c; }
struct creation_data* createdb_searchexist(int id) { struct creation_data *db=NULL; db = uidb_get(create_db, id); return db; }
/** Read item group data * Structure: GroupID,ItemID,Rate{,Amount,isMust,isAnnounced,Duration,GUID,isBound,isNamed} */ static void itemdb_read_itemgroup_sub(const char* filename, bool silent) { FILE *fp; int ln = 0, entries = 0; char line[1024]; if ((fp=fopen(filename,"r")) == NULL) { if(silent == 0) ShowError("Can't read %s\n", filename); return; } while (fgets(line,sizeof(line),fp)) { DBData data; int group_id = -1; unsigned int j, prob = 1; uint8 rand_group = 1; char *str[10], *p; struct s_item_group_random *random = NULL; struct s_item_group_db *group = NULL; struct s_item_group_entry entry; bool found = false; ln++; if (line[0] == '/' && line[1] == '/') continue; if (strstr(line,"import")) { char w1[16], w2[64]; if (sscanf(line,"%15[^:]: %63[^\r\n]",w1,w2) == 2 && strcmpi(w1,"import") == 0) { itemdb_read_itemgroup_sub(w2, 0); continue; } } memset(str,0,sizeof(str)); for (j = 0, p = line; j < 9 && p;j++) { str[j] = p; p = strchr(p,','); if (p) *p++=0; } if (str[0] == NULL) //Empty Group ID continue; if (j < 3) { if (j > 1) // Or else it barks on blank lines... ShowWarning("itemdb_read_itemgroup: Insufficient fields for entry at %s:%d\n", filename, ln); continue; } memset(&entry, 0, sizeof(entry)); entry.amount = 1; entry.bound = BOUND_NONE; // Checking group_id trim(str[0]); if (ISDIGIT(str[0][0])) group_id = atoi(str[0]); else // Try reads group id by const script_get_constant(trim(str[0]), &group_id); if (group_id < 0) { ShowWarning("itemdb_read_itemgroup: Invalid Group ID '%s' (%s:%d)\n", str[0], filename, ln); continue; } // Remove from DB if (strcmpi(str[1], "clear") == 0 && itemdb_group->remove(itemdb_group, db_ui2key(group_id), &data)) { itemdb_group_free(db_ui2key(group_id), &data, 0); ShowNotice("Item Group '%s' has been cleared.\n", str[0]); continue; } // Checking sub group prob = atoi(str[2]); if (str[4] != NULL) rand_group = atoi(str[4]); if (rand_group < 0 || rand_group > MAX_ITEMGROUP_RANDGROUP) { ShowWarning("itemdb_read_itemgroup: Invalid sub group '%d' for group '%s' in %s:%d\n", rand_group, str[0], filename, ln); continue; } if (rand_group != 0 && prob < 1) { ShowWarning("itemdb_read_itemgroup: Random item must has probability. Group '%s' in %s:%d\n", str[0], filename, ln); continue; } // Checking item trim(str[1]); if (ISDIGIT(str[1][0]) && ISDIGIT(str[1][1]) && itemdb_exists((entry.nameid = atoi(str[1])))) found = true; else { struct item_data *id = itemdb_searchname(str[1]); if (id) { entry.nameid = id->nameid; found = true; } } if (!found) { ShowWarning("itemdb_read_itemgroup: Non-existant item '%s' in %s:%d\n", str[1], filename, ln); continue; } if (str[3] != NULL) entry.amount = cap_value(atoi(str[3]),1,MAX_AMOUNT); if (str[5] != NULL) entry.isAnnounced= atoi(str[5]); if (str[6] != NULL) entry.duration = cap_value(atoi(str[6]),0,UINT16_MAX); #ifdef ENABLE_ITEM_GUID if (str[7] != NULL) entry.GUID = atoi(str[7]); #endif if (str[8] != NULL) entry.bound = cap_value(atoi(str[8]),BOUND_NONE,BOUND_MAX-1); if (str[9] != NULL) entry.isNamed = atoi(str[9]); if (!(group = (struct s_item_group_db *) uidb_get(itemdb_group, group_id))) { CREATE(group, struct s_item_group_db, 1); group->id = group_id; uidb_put(itemdb_group, group->id, group); } // Must item (rand_group == 0), place it here if (!rand_group) { RECREATE(group->must, struct s_item_group_entry, group->must_qty+1); group->must[group->must_qty++] = entry; // If 'must' item isn't set as random item, skip the next process if (!prob) { entries++; continue; } rand_group = 0; }
struct class_data* classdb_searchexist(int id) { struct class_data *db=NULL; db = uidb_get(class_db, id); return db; }
/** * Open vending for Autotrader * @param sd Player as autotrader */ void vending_reopen( struct map_session_data* sd ) { struct s_autotrader *at = NULL; int8 fail = -1; nullpo_retv(sd); // Open vending for this autotrader if ((at = uidb_get(vending_autotrader_db, sd->status.char_id)) && at->count && at->entries) { uint8 *data, *p; uint16 j, count; // Init vending data for autotrader CREATE(data, uint8, at->count * 8); for (j = 0, p = data, count = at->count; j < at->count; j++) { struct s_autotrade_entry *entry = at->entries[j]; uint16 *index = (uint16*)(p + 0); uint16 *amount = (uint16*)(p + 2); uint32 *value = (uint32*)(p + 4); // Find item position in cart ARR_FIND(0, MAX_CART, entry->index, sd->status.cart[entry->index].id == entry->cartinventory_id); if (entry->index == MAX_CART) { count--; continue; } *index = entry->index + 2; *amount = itemdb_isstackable(sd->status.cart[entry->index].nameid) ? entry->amount : 1; *value = entry->price; p += 8; } sd->state.prevend = 1; // Set him into a hacked prevend state sd->state.autotrade = 1; // Make sure abort all NPCs npc_event_dequeue(sd); pc_cleareventtimer(sd); // Open the vending again if( (fail = vending_openvending(sd, at->title, data, count, at)) == 0 ) { // Make vendor look perfect pc_setdir(sd, at->dir, at->head_dir); clif_changed_dir(&sd->bl, AREA_WOS); if( at->sit ) { pc_setsit(sd); skill_sit(sd, 1); clif_sitting(&sd->bl); } // Immediate save chrif_save(sd, 3); ShowInfo("Vending loaded for '"CL_WHITE"%s"CL_RESET"' with '"CL_WHITE"%d"CL_RESET"' items at "CL_WHITE"%s (%d,%d)"CL_RESET"\n", sd->status.name, count, mapindex_id2name(sd->mapindex), sd->bl.x, sd->bl.y); } aFree(data); } if (at) { vending_autotrader_remove(at, true); if (db_size(vending_autotrader_db) == 0) vending_autotrader_db->clear(vending_autotrader_db, vending_autotrader_free); } if (fail != 0) { ShowError("vending_reopen: (Error:%d) Load failed for autotrader '"CL_WHITE"%s"CL_RESET"' (CID=%/AID=%d)\n", fail, sd->status.name, sd->status.char_id, sd->status.account_id); map_quit(sd); } }
/** Searches for the item_data. Use this to check if item exists or not. * @param nameid * @return *item_data if item is exist, or NULL if not */ struct item_data* itemdb_exists(unsigned short nameid) { return ((struct item_data*)uidb_get(itemdb,nameid)); }
/** * Check if item group exists * @param group_id * @return NULL if not exist, or s_item_group_db * */ struct s_item_group_db *itemdb_group_exists(unsigned short group_id) { return (struct s_item_group_db *)uidb_get(itemdb_group, group_id); }
/** * Open buyingstore for Autotrader * @param sd Player as autotrader */ void buyingstore_reopen( struct map_session_data* sd ){ struct s_autotrader *at = NULL; int8 fail = -1; nullpo_retv(sd); // Ready to open buyingstore for this char if ((at = (struct s_autotrader *)uidb_get(buyingstore_autotrader_db, sd->status.char_id)) && at->count && at->entries) { uint8 *data, *p; uint16 j, count; // Init buyingstore data for autotrader CREATE(data, uint8, at->count * 8); for (j = 0, p = data, count = at->count; j < at->count; j++) { struct s_autotrade_entry *entry = at->entries[j]; unsigned short *item_id = (uint16*)(p + 0); uint16 *amount = (uint16*)(p + 2); uint32 *price = (uint32*)(p + 4); *item_id = entry->item_id; *amount = entry->amount; *price = entry->price; p += 8; } sd->state.autotrade = 1; // Make sure abort all NPCs npc_event_dequeue(sd); pc_cleareventtimer(sd); // Open the buyingstore again if( (fail = buyingstore_setup( sd, (unsigned char)at->count )) == 0 && (fail = buyingstore_create( sd, at->limit, 1, at->title, data, at->count, at )) == 0 ) { // Make buyer look perfect pc_setdir(sd, at->dir, at->head_dir); clif_changed_dir(&sd->bl, AREA_WOS); if( at->sit ) { pc_setsit(sd); skill_sit(sd, 1); clif_sitting(&sd->bl); } // Immediate save chrif_save(sd, CSAVE_AUTOTRADE); ShowInfo("Buyingstore loaded for '"CL_WHITE"%s"CL_RESET"' with '"CL_WHITE"%d"CL_RESET"' items at "CL_WHITE"%s (%d,%d)"CL_RESET"\n", sd->status.name, count, mapindex_id2name(sd->mapindex), sd->bl.x, sd->bl.y); } aFree(data); } if (at) { buyingstore_autotrader_remove(at, true); if (db_size(buyingstore_autotrader_db) == 0) buyingstore_autotrader_db->clear(buyingstore_autotrader_db, buyingstore_autotrader_free); } if (fail != 0) { ShowError("buyingstore_reopen: (Error:%d) Load failed for autotrader '"CL_WHITE"%s"CL_RESET"' (CID=%/AID=%d)\n", fail, sd->status.name, sd->status.char_id, sd->status.account_id); map_quit(sd); } }
/** * Check if combo exists * @param combo_id * @return NULL if not exist, or struct item_combo* */ struct item_combo *itemdb_combo_exists(unsigned short combo_id) { return (struct item_combo *)uidb_get(itemdb_combo, combo_id); }