From 021b26b8409a84b4c83eb0cc1eedbd65eedfd4e0 Mon Sep 17 00:00:00 2001 From: skotlex Date: Wed, 22 Mar 2006 23:58:16 +0000 Subject: - Merged the unit_data structure from jA for handling unit-related data (attack times, walking, auto-attack timers, skill related data) - Modified unit_skillcastcancel to receive flag&2, which stands for "cancel casting only if current skill is cancellable" - Battle config options changed from yes/no to BL_TYPE settings: skillrange_by_distance, skill_noreiteration, skill_nofootset, gvg_traps_target_all, skill_log, attack_direction_change, auto_counter_type - Clif.c will disconnect sessions that send an unknown command packet above 0x30000 instead of just ignoring it. - Cleaned up/rewrite of the pet ai, same for pet_calc_pos - Implemented use of mob variable attacked_players as it is used on jA - Cleaned up error reporting during mob-skill loading to be less spamy with non-loaded mobs. - Corrected water_height reading. I forgot to give credits to LittleWolf for providing the water-reading function :X git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@5707 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/map/map.c | 312 +++++++++++++++++----------------------------------------- 1 file changed, 92 insertions(+), 220 deletions(-) (limited to 'src/map/map.c') diff --git a/src/map/map.c b/src/map/map.c index c06f7ef1b..f218572b3 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -36,6 +36,7 @@ #include "skill.h" #include "trade.h" #include "party.h" +#include "unit.h" #include "battle.h" #include "script.h" #include "guild.h" @@ -1501,191 +1502,70 @@ void map_deliddb(struct block_list *bl) { * quit?理の主?が違うような?もしてきた *------------------------------------------ */ -int map_quit(struct map_session_data *sd) { - - //nullpo_retr(0, sd); //Utterly innecessary, all invokations to this function already have an SD non-null check. - //Learn to use proper coding and stop relying on nullpo_'s for safety :P [Skotlex] - - - if(!sd->state.waitingdisconnect) { - if (sd->npc_timer_id != -1) //Cancel the event timer. - npc_timerevent_quit(sd); - if (sd->state.event_disconnect) { - if (script_config.event_script_type == 0) { - struct npc_data *npc; - if ((npc = npc_name2id(script_config.logout_event_name))) { - run_script(npc->u.scr.script,0,sd->bl.id,npc->bl.id); // PCLogoutNPC - ShowStatus("Event '"CL_WHITE"%s"CL_RESET"' executed.\n", script_config.logout_event_name); - } - } else { - ShowStatus("%d '"CL_WHITE"%s"CL_RESET"' events executed.\n", - npc_event_doall_id(script_config.logout_event_name, sd->bl.id), script_config.logout_event_name); - } - } - - if(sd->chatID) // チャットから出る - chat_leavechat(sd); - - if(sd->trade_partner) // 取引を中?する - trade_tradecancel(sd); - - if(sd->party_invite>0) // パ?ティ?誘を拒否する - party_reply_invite(sd,sd->party_invite_account,0); - - if(sd->guild_invite>0) // ギルド?誘を拒否する - guild_reply_invite(sd,sd->guild_invite,0); - if(sd->guild_alliance>0) // ギルド同盟?誘を拒否する - guild_reply_reqalliance(sd,sd->guild_alliance_account,0); - - // Force exiting from duel and rejecting - // all duel invitations when player quit [LuzZza] - if(sd->duel_group > 0) - duel_leave(sd->duel_group, sd); - - if(sd->duel_invite > 0) - duel_reject(sd->duel_invite, sd); - - party_send_logout(sd); // パ?ティのログアウトメッセ?ジ送信 - - party_send_dot_remove(sd);//minimap dot fix [Kevin] - - guild_send_memberinfoshort(sd,0); // ギルドのログアウトメッセ?ジ送信 - - guild_send_dot_remove(sd); - - pc_cleareventtimer(sd); // イベントタイマを破棄する - - // check if we've been authenticated [celest] - if (sd->state.auth) - skill_castcancel(&sd->bl,0); // 詠唱を中?する - - skill_stop_dancing(&sd->bl);// ダンス/演奏中? - - //Status that are not saved... - if(sd->sc.count) { - if(sd->sc.data[SC_HIDING].timer!=-1) - status_change_end(&sd->bl,SC_HIDING,-1); - if(sd->sc.data[SC_CLOAKING].timer!=-1) - status_change_end(&sd->bl,SC_CLOAKING,-1); - if(sd->sc.data[SC_RUN].timer!=-1) - status_change_end(&sd->bl,SC_RUN,-1); - if(sd->sc.data[SC_SPURT].timer!=-1) - status_change_end(&sd->bl,SC_SPURT,-1); - if(sd->sc.data[SC_BERSERK].timer!=-1) - status_change_end(&sd->bl,SC_BERSERK,-1); - if(sd->sc.data[SC_TRICKDEAD].timer!=-1) - status_change_end(&sd->bl,SC_TRICKDEAD,-1); - if (battle_config.debuff_on_logout) { - if(sd->sc.data[SC_STRIPWEAPON].timer!=-1) - status_change_end(&sd->bl,SC_STRIPWEAPON,-1); - if(sd->sc.data[SC_STRIPARMOR].timer!=-1) - status_change_end(&sd->bl,SC_STRIPARMOR,-1); - if(sd->sc.data[SC_STRIPSHIELD].timer!=-1) - status_change_end(&sd->bl,SC_STRIPSHIELD,-1); - if(sd->sc.data[SC_STRIPHELM].timer!=-1) - status_change_end(&sd->bl,SC_STRIPHELM,-1); - if(sd->sc.data[SC_EXTREMITYFIST].timer!=-1) - status_change_end(&sd->bl,SC_EXTREMITYFIST,-1); - if(sd->sc.data[SC_EXPLOSIONSPIRITS].timer!=-1) - status_change_end(&sd->bl,SC_EXPLOSIONSPIRITS,-1); - } - } - skill_clear_unitgroup(&sd->bl); // スキルユニットグル?プの削除 - - // check if we've been authenticated [celest] - if (sd->state.auth) { - skill_cleartimerskill(&sd->bl); - pc_stop_walking(sd,0); - pc_stopattack(sd); - pc_stop_following(sd); - pc_delinvincibletimer(sd); - } - pc_delspiritball(sd,sd->spiritball,1); - skill_gangsterparadise(sd,0); - skill_unit_move(&sd->bl,gettick(),4); - - if (sd->state.auth) - status_calc_pc(sd,4); - // skill_clear_unitgroup(&sd->bl); // [Sara-chan] - - if (!(sd->sc.option & OPTION_INVISIBLE)) - clif_clearchar_area(&sd->bl,2); - - chrif_save_scdata(sd); //Save status changes, then clear'em out from memory. [Skotlex] - status_change_clear(&sd->bl,1); - - if(sd->status.pet_id && sd->pd) { - pet_lootitem_drop(sd->pd,sd); - pet_remove_map(sd); - if(sd->pet.intimate <= 0) { - intif_delete_petdata(sd->status.pet_id); - sd->status.pet_id = 0; - sd->pd = NULL; - sd->petDB = NULL; - } - else - intif_save_petdata(sd->status.account_id,&sd->pet); - } - - if(pc_isdead(sd)) - pc_setrestartvalue(sd,2); - - pc_clean_skilltree(sd); - - //The storage closing routines will save the char if needed. [Skotlex] - if (!sd->state.storage_flag) - chrif_save(sd,1); - else if (sd->state.storage_flag == 1) - storage_storage_quit(sd,1); - else if (sd->state.storage_flag == 2) - storage_guild_storage_quit(sd,1); - - map_delblock(&sd->bl); - } else { //Try to free some data, without saving anything (this could be invoked on map server change. [Skotlex] - if (sd->bl.prev != NULL) - { //Remove from map... - if (!(sd->sc.option & OPTION_INVISIBLE)) - clif_clearchar_area(&sd->bl,2); - map_delblock(&sd->bl); - } - if (sd->pd) - pet_remove_map(sd); - } - - if (sd->stack) { - script_free_stack(sd->stack); - sd->stack= NULL; - } - -// chrif_char_offline(sd); //chrif_save handles this now. - - //Do we really need to remove the name? - idb_remove(charid_db,sd->status.char_id); - idb_remove(id_db,sd->bl.id); - idb_remove(pc_db,sd->bl.id); - - // Notify friends that this char logged out. [Skotlex] - clif_foreachclient(clif_friendslist_toggle_sub, sd->status.account_id, sd->status.char_id, 0); - - if(sd->reg) - { //Double logout already freed pointer fix... [Skotlex] - aFree(sd->reg); - sd->reg = NULL; - sd->reg_num = 0; - } - - if(sd->regstr) - { - aFree(sd->regstr); - sd->regstr = NULL; - sd->regstr_num = 0; - } - - if(!sd->fd) //There is no session connected, and as such socket.c won't free the data, we must do it. [Skotlex] - aFree(sd); - return 0; -} - +int map_quit(struct map_session_data *sd) { + + //nullpo_retr(0, sd); //Utterly innecessary, all invokations to this function already have an SD non-null check. + //Learn to use proper coding and stop relying on nullpo_'s for safety :P [Skotlex] + + if(!sd->state.waitingdisconnect) { + if (sd->npc_timer_id != -1) //Cancel the event timer. + npc_timerevent_quit(sd); + if (sd->state.event_disconnect) { + if (script_config.event_script_type == 0) { + struct npc_data *npc; + if ((npc = npc_name2id(script_config.logout_event_name))) { + run_script(npc->u.scr.script,0,sd->bl.id,npc->bl.id); // PCLogoutNPC + ShowStatus("Event '"CL_WHITE"%s"CL_RESET"' executed.\n", script_config.logout_event_name); + } + } else { + ShowStatus("%d '"CL_WHITE"%s"CL_RESET"' events executed.\n", + npc_event_doall_id(script_config.logout_event_name, sd->bl.id), script_config.logout_event_name); + } + } + if (sd->pd) unit_free(&sd->pd->bl); + unit_free(&sd->bl); + pc_clean_skilltree(sd); + status_calc_pc(sd,4); + if(sd->pet.intimate > 0) + intif_save_petdata(sd->status.account_id,&sd->pet); + chrif_save(sd,1); + } else { //Try to free some data, without saving anything (this could be invoked on map server change. [Skotlex] + if (sd->bl.prev != NULL) + { //Remove from map... + unit_remove_map(&sd->bl, 0); + if (sd->pd && sd->pd->bl.prev != NULL) + unit_remove_map(&sd->pd->bl, 0); + } + } + if (sd->stack) { + script_free_stack(sd->stack); + sd->stack= NULL; + } + + //Do we really need to remove the name? + idb_remove(charid_db,sd->status.char_id); + idb_remove(id_db,sd->bl.id); + idb_remove(pc_db,sd->bl.id); + + if(sd->reg) + { //Double logout already freed pointer fix... [Skotlex] + aFree(sd->reg); + sd->reg = NULL; + sd->reg_num = 0; + } + if(sd->regstr) + { + aFree(sd->regstr); + sd->regstr = NULL; + sd->regstr_num = 0; + } + + if(!sd->fd) //There is no session connected, and as such socket.c won't free the data, we must do it. [Skotlex] + aFree(sd); + return 0; +} + + /*========================================== * id番?のPCを探す。居なければNULL *------------------------------------------ @@ -1894,16 +1774,16 @@ void map_removenpc(void) { // allocates a struct when it there is place free in the cache, // and returns NULL otherwise // -- i'll just leave the old code in case it's needed ^^; -struct mob_list* map_addmobtolist(unsigned short m) +int map_addmobtolist(unsigned short m, struct spawn_data *spawn) { size_t i; for (i = 0; i < MAX_MOB_LIST_PER_MAP; i++) { if (map[m].moblist[i] == NULL) { - map[m].moblist[i] = (struct mob_list *) aMalloc (sizeof(struct mob_list)); - return map[m].moblist[i]; + map[m].moblist[i] = spawn; + return i; } } - return NULL; + return -1; } void map_spawnmobs(int m) @@ -1919,7 +1799,7 @@ void map_spawnmobs(int m) if(map[m].moblist[i]!=NULL) { k+=map[m].moblist[i]->num; - npc_parse_mob2(map[m].moblist[i],1); + npc_parse_mob2(map[m].moblist[i],i); } if (battle_config.etc_log && k > 0) @@ -1940,10 +1820,7 @@ int mob_cache_cleanup_sub(struct block_list *bl, va_list ap) { md->hp < md->db->max_hp) //don't use status_get_maxhp for speed (by the time you have to remove a mob, their status changes should have expired anyway) return 0; //Do not remove damaged mobs. - mob_remove_map(md, 0); - map_deliddb(&md->bl); - aFree(md); - md = NULL; + unit_free(&md->bl); return 1; } @@ -2408,15 +2285,20 @@ int map_waterheight(char *mapname) { char *rsw; float whtemp; int wh; -#ifdef _WIN32 + + //Look up for clone map. + if(waterlist){ + int i; + for(i=0;waterlist[i].mapname[0] && i < MAX_MAP_PER_SERVER;i++) + if(strcmp(waterlist[i].mapname,mapname)==0) + return map_waterheight(waterlist[i].clonemapname); + } + //Look up for the rsw sprintf(fn,"data\\%s",mapname); -#else - sprintf(fn,"data/%s",mapname); -#endif + rsw = strstr(fn, "."); - if (rsw && strstr(fn, ".rsw") == NULL) - strcat (rsw, "rsw"); - + if (rsw && strstr(fn, ".rsw") == NULL) + sprintf(rsw,".rsw"); // read & convert fn // again, might not need to be unsigned char rsw = (char *) grfio_read (fn); @@ -2427,13 +2309,7 @@ int map_waterheight(char *mapname) { aFree(rsw); return wh; } - //Look up for clone map. - if(waterlist){ - int i; - for(i=0;waterlist[i].mapname[0] && i < MAX_MAP_PER_SERVER;i++) - if(strcmp(waterlist[i].mapname,mapname)==0) - return map_waterheight(waterlist[i].clonemapname); - } + ShowWarning("Failed to find water level for (%s)\n", mapname, fn); return NO_WATER; } @@ -2930,19 +2806,11 @@ int map_readgat (struct map_data *m) if ((pt = strstr(m->name,"<")) != NULL) { // [MouseJstr] char buf[64]; *pt++ = '\0'; -#ifdef _WIN32 sprintf(buf,"data\\%s", pt); -#else - sprintf(buf,"data/%s", pt); -#endif m->alias = aStrdup(buf); } -#ifdef _WIN32 sprintf(fn,"data\\%s",m->name); -#else - sprintf(fn,"data/%s",m->name); -#endif // read & convert fn // again, might not need to be unsigned char @@ -3675,11 +3543,10 @@ int cleanup_sub(struct block_list *bl, va_list ap) { npc_unload((struct npc_data *)bl); break; case BL_MOB: - mob_unload((struct mob_data *)bl); + unit_free(bl); break; case BL_PET: - //There is no need for this, the pet is removed together with the player. [Skotlex] -// pet_remove_map(((struct pet_data *)bl)->msd); + //There is no need for this, the pet is removed together with the player. [Skotlex] break; case BL_ITEM: map_clearflooritem(bl->id); @@ -3689,9 +3556,13 @@ int cleanup_sub(struct block_list *bl, va_list ap) { break; } - return 0; + return 1; } +static int cleanup_db_sub(DBKey key,void *data,va_list va) { + return cleanup_sub((struct block_list*)data, NULL); +} + /*========================================== * map鯖終了・理 *------------------------------------------ @@ -3715,6 +3586,7 @@ void do_final(void) { for (i = 0; i < j; i++) map_quit(pl_allsd[i]); + i = id_db->foreach(id_db,cleanup_db_sub); chrif_char_reset_offline(); chrif_flush_fifo(); -- cgit v1.2.3-60-g2f50