diff options
-rw-r--r-- | db/item_db.txt | 2 | ||||
-rw-r--r-- | src/map/clif.c | 44 | ||||
-rw-r--r-- | src/map/clif.h | 1 | ||||
-rw-r--r-- | src/map/map.c | 53 | ||||
-rw-r--r-- | src/map/map.h | 2 | ||||
-rw-r--r-- | src/map/mob.c | 3 | ||||
-rw-r--r-- | src/map/mob.h | 1 | ||||
-rw-r--r-- | src/map/pc.c | 2 | ||||
-rw-r--r-- | src/map/skill.c | 4 | ||||
-rw-r--r-- | src/map/status.c | 46 |
10 files changed, 149 insertions, 9 deletions
diff --git a/db/item_db.txt b/db/item_db.txt index 84d6a31c3..00ef24db9 100644 --- a/db/item_db.txt +++ b/db/item_db.txt @@ -3451,7 +3451,7 @@ 12211,Kafra_Card,Kafra Card,2,,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ callfunc "F_CashStore"; },{},{} 12212,Giant_Fly_Wing,Giant Fly Wing,2,,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ callfunc "F_CashPartyCall"; },{},{} 12213,Neuralizer,Neuralizer,2,,,0,,,,,0xFFFFFFFF,7,2,,,,,,{ callfunc "F_CashReset"; },{},{} -12214,Convex_Mirror,Convex Mirror,3,20,,10,,,,,,,,,,,,,{},{},{} +12214,Convex_Mirror,Convex Mirror,2,,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ sc_start SC_BOSSMAPINFO,600000,0;},{},{} 12215,Blessing_10_Scroll,LV10 Blessing Scroll,2,,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ skilleffect "AL_BLESSING",0; sc_start SC_BLESSING,240000,10; },{},{} 12216,Inc_Agi_10_Scroll,LV10 Agil Scroll,2,,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ if (Hp > 15) { skilleffect "AL_INCAGI",0; sc_start SC_INCREASEAGI,240000,10; heal -15,0; } },{},{} 12217,Aspersio_5_Scroll,LV5 Aspersio Scroll,2,,,10,,,,,0xFFFFFFFF,7,2,,,,,,{ if (countitem(523) > 0) { skilleffect "PR_ASPERSIO",0; sc_start SC_ASPERSIO,180000,5; delitem 523,1; } },{},{} diff --git a/src/map/clif.c b/src/map/clif.c index 103994a76..6752a9699 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -12153,6 +12153,50 @@ void clif_parse_Adopt_reply(int fd, struct map_session_data *sd) } /*========================================== + * Convex Mirror + * S 0293 <flag>.b <x>.l <y>.l <Hours>.w <Minutes>.w <unknown>.l <monster name>.40B <unknown>.11B + *==========================================*/ +void clif_bossmapinfo(int fd, struct mob_data *md, short flag) +{ + WFIFOHEAD(fd,70); + memset(WFIFOP(fd,0),0,70); + WFIFOW(fd,0) = 0x0293; + + if( md != NULL ) + { + if( md->bl.prev != NULL ) + { // Boss on This Map + if( flag ) + { + WFIFOB(fd,2) = 1; + WFIFOL(fd,3) = md->bl.x; + WFIFOL(fd,7) = md->bl.y; + } + else + WFIFOB(fd,2) = 2; // First Time + } + else + { // Boss is Dead + const struct TimerData * timer_data = get_timer(md->spawn_timer); + unsigned int seconds; + int hours, minutes; + + seconds = DIFF_TICK(timer_data->tick, gettick()) / 1000; + hours = seconds / (60 * 60); + seconds = seconds - (60 * 60 * hours); + minutes = seconds / 60; + + WFIFOB(fd,2) = 3; + WFIFOW(fd,11) = hours; // Hours + WFIFOW(fd,13) = minutes; // Minutes + } + safestrncpy((char*)WFIFOP(fd,19), md->db->jname, NAME_LENGTH); + } + + WFIFOSET(fd,70); +} + +/*========================================== * Requesting equip of a player *------------------------------------------*/ void clif_parse_ViewPlayerEquip(int fd, struct map_session_data* sd) diff --git a/src/map/clif.h b/src/map/clif.h index f3ad31fbe..8c8a40211 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -433,6 +433,7 @@ void clif_Auction_close(int fd, unsigned char flag); void clif_parse_Auction_cancelreg(int fd, struct map_session_data *sd); #endif +void clif_bossmapinfo(int fd, struct mob_data *md, short flag); void clif_cashshop_show(struct map_session_data *sd, struct npc_data *nd); // ADOPTION diff --git a/src/map/map.c b/src/map/map.c index f4b5edfe6..eab6a9f7a 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -99,6 +99,7 @@ char *GRF_PATH_FILENAME; static DBMap* id_db=NULL; // int id -> struct block_list* static DBMap* pc_db=NULL; // int id -> struct map_session_data* static DBMap* mobid_db=NULL; // int id -> struct mob_data* +static DBMap* bossid_db=NULL; // int id -> struct mob_data* (MVP db) static DBMap* map_db=NULL; // unsigned int mapindex -> struct map_data* static DBMap* nick_db=NULL; // int char_id -> struct charid2nick* (requested names of offline characters) static DBMap* charid_db=NULL; // int char_id -> struct map_session_data* @@ -1525,14 +1526,21 @@ void map_addiddb(struct block_list *bl) { nullpo_retv(bl); - if (bl->type == BL_PC) + if( bl->type == BL_PC ) { TBL_PC* sd = (TBL_PC*)bl; idb_put(pc_db,sd->bl.id,sd); idb_put(charid_db,sd->status.char_id,sd); - } else if (bl->type == BL_MOB) + } + else if( bl->type == BL_MOB ) + { + struct mob_data* md = BL_CAST(BL_MOB, bl); idb_put(mobid_db,bl->id,bl); + if( md && (md->db->status.mode&MD_BOSS) && md->db->mexp > 0 ) + idb_put(bossid_db, bl->id, bl); + } + idb_put(id_db,bl->id,bl); } @@ -1543,13 +1551,17 @@ void map_deliddb(struct block_list *bl) { nullpo_retv(bl); - if (bl->type == BL_PC) + if( bl->type == BL_PC ) { TBL_PC* sd = (TBL_PC*)bl; idb_remove(pc_db,sd->bl.id); idb_remove(charid_db,sd->status.char_id); - } else if (bl->type == BL_MOB) + } + else if( bl->type == BL_MOB ) + { idb_remove(mobid_db,bl->id); + idb_remove(bossid_db,bl->id); + } idb_remove(id_db,bl->id); } @@ -1578,6 +1590,8 @@ int map_quit(struct map_session_data *sd) //(changing map-servers invokes unit_free but bypasses map_quit) if(sd->sc.count) { //Status that are not saved... + if(sd->sc.data[SC_BOSSMAPINFO]) + status_change_end(&sd->bl,SC_BOSSMAPINFO,-1); if(sd->sc.data[SC_AUTOTRADE]) status_change_end(&sd->bl,SC_AUTOTRADE,-1); if(sd->sc.data[SC_SPURT]) @@ -1744,6 +1758,35 @@ struct block_list * map_id2bl(int id) return bl; } +/*========================================== + * Convext Mirror + *------------------------------------------*/ +struct mob_data * map_getmob_boss(int m) +{ + DBIterator* iter; + struct mob_data *md = NULL; + bool found = false; + + iter = db_iterator(bossid_db); + for( md = (struct mob_data*)dbi_first(iter); dbi_exists(iter); md = (struct mob_data*)dbi_next(iter) ) + { + if( md->bl.m != m || !md->spawn ) + continue; + + found = true; + break; + } + dbi_destroy(iter); + + return (found)? md : NULL; +} + +struct mob_data * map_id2boss(int id) +{ + if (id <= 0) return NULL; + return (struct mob_data*)idb_get(bossid_db,id); +} + /// Applies func to all the players in the db. /// Stops iterating if func returns -1. void map_foreachpc(int (*func)(struct map_session_data* sd, va_list args), ...) @@ -3179,6 +3222,7 @@ void do_final(void) id_db->destroy(id_db, NULL); pc_db->destroy(pc_db, NULL); mobid_db->destroy(mobid_db, NULL); + bossid_db->destroy(bossid_db, NULL); nick_db->destroy(nick_db, nick_db_final); charid_db->destroy(charid_db, NULL); @@ -3351,6 +3395,7 @@ int do_init(int argc, char *argv[]) id_db = idb_alloc(DB_OPT_BASE); pc_db = idb_alloc(DB_OPT_BASE); //Added for reliable map_id2sd() use. [Skotlex] mobid_db = idb_alloc(DB_OPT_BASE); //Added to lower the load of the lazy mob ai. [Skotlex] + bossid_db = idb_alloc(DB_OPT_BASE); // Used for Convex Mirror quick MVP search map_db = uidb_alloc(DB_OPT_BASE); nick_db = idb_alloc(DB_OPT_BASE); charid_db = idb_alloc(DB_OPT_BASE); diff --git a/src/map/map.h b/src/map/map.h index afa63c182..2f46c4e3e 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -569,6 +569,8 @@ void map_foreachmob(int (*func)(struct mob_data* md, va_list args), ...); void map_foreachnpc(int (*func)(struct npc_data* bl, va_list args), ...); void map_foreachiddb(int (*func)(struct block_list* bl, va_list args), ...); struct map_session_data * map_nick2sd(const char*); +struct mob_data * map_getmob_boss(int m); +struct mob_data * map_id2boss(int id); /// Bitfield of flags for the iterator. enum e_mapitflags diff --git a/src/map/mob.c b/src/map/mob.c index 9abdd54e7..270b9ebd4 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -951,7 +951,7 @@ int mob_setdelayspawn(struct mob_data *md) if (spawntime < 5000) //Min respawn time (is it needed?) spawntime = 5000; - add_timer(gettick()+spawntime, mob_delayspawn, md->bl.id, 0); + md->spawn_timer = add_timer(gettick()+spawntime, mob_delayspawn, md->bl.id, 0); return 0; } @@ -1007,6 +1007,7 @@ int mob_spawn (struct mob_data *md) md->attacked_id = 0; md->target_id = 0; md->move_fail_count = 0; + md->spawn_timer = -1; // md->master_id = 0; md->master_dist = 0; diff --git a/src/map/mob.h b/src/map/mob.h index 13b9c346a..0136b6c98 100644 --- a/src/map/mob.h +++ b/src/map/mob.h @@ -121,6 +121,7 @@ struct mob_data { unsigned flag : 1; //0: Normal. 1: Homunc exp } dmglog[DAMAGELOG_SIZE]; struct spawn_data *spawn; //Spawn data. + int spawn_timer; //Required for Convex Mirror struct item *lootitem; short class_; unsigned int tdmg; //Stores total damage given to the mob, for exp calculations. [Skotlex] diff --git a/src/map/pc.c b/src/map/pc.c index 95c265fad..823d8aaa8 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -3528,6 +3528,8 @@ int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y { //Cancel some map related stuff. if (sd->sc.data[SC_JAILED]) return 1; //You may not get out! + if (sd->sc.data[SC_BOSSMAPINFO]) + status_change_end(&sd->bl,SC_BOSSMAPINFO,-1); if (sd->sc.data[SC_WARM]) status_change_end(&sd->bl,SC_WARM,-1); if (sd->sc.data[SC_SUN_COMFORT]) diff --git a/src/map/skill.c b/src/map/skill.c index d817e5eba..178a946c1 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -1471,8 +1471,8 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds if( (skillid == AL_INCAGI || skillid == AL_BLESSING) && tsd->sc.data[SC_CHANGEUNDEAD] ) damage = 1; - if (damage > 0 && dmg.flag&BF_WEAPON && src != bl && src == dsrc && - skillid != WS_CARTTERMINATION) // FIXME(?): Quick and dirty check, but HSCR does bypass Shield Reflect... so I make it bypass the whole reflect thing [DracoRPG] + if( damage > 0 && dmg.flag&BF_WEAPON && src != bl && ( src == dsrc || ( dsrc->type == BL_SKILL && ( skillid == SG_SUN_WARM || skillid == SG_MOON_WARM || skillid == SG_STAR_WARM ) ) ) + && skillid != WS_CARTTERMINATION ) rdamage = battle_calc_return_damage(bl, damage, dmg.flag); //Skill hit type diff --git a/src/map/status.c b/src/map/status.c index aacdf2fc8..bbc22363e 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -4586,6 +4586,8 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val struct view_data *vd; int opt_flag, calc_flag, undead_flag; + struct mob_data *boss_md = NULL; + nullpo_retr(0, bl); sc = status_get_sc(bl); status = status_get_status_data(bl); @@ -4912,6 +4914,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val break; case SC_HPREGEN: case SC_SPREGEN: + case SC_BOSSMAPINFO: case SC_STUN: case SC_SLEEP: case SC_POISON: @@ -5238,6 +5241,22 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val val4 = 1; tick = val2 * 1000; // val2 = Seconds between heals break; + case SC_BOSSMAPINFO: + if( sd != NULL ) + { + boss_md = map_getmob_boss(bl->m); // Search for Boss on this Map + if( boss_md == NULL || boss_md->bl.prev == NULL ) + { // No MVP on this map - MVP is dead + clif_bossmapinfo(sd->fd, boss_md, 1); + return 0; // No need to start SC + } + + val1 = boss_md->bl.id; + if( (val4 = tick/1000) < 1 ) + val4 = 1; + tick = 1000; + } + break; case SC_HIDING: val2 = tick/1000; tick = 1000; @@ -6102,6 +6121,10 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val if (ud) ud->state.running = unit_run(bl); } + + if( boss_md != NULL ) + clif_bossmapinfo(sd->fd, boss_md, 0); // First Message + return 1; } /*========================================== @@ -6683,6 +6706,9 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr data) struct status_change *sc; struct status_change_entry *sce; + struct mob_data *boss_md = NULL; + int result; + bl = map_id2bl(id); if(!bl) { @@ -6856,6 +6882,19 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr data) } break; + case SC_BOSSMAPINFO: + if( sd && --(sce->val4) >= 0 ) + { + boss_md = map_id2boss(sce->val1); + if( boss_md && boss_md->bl.prev != NULL && sd->bl.m == boss_md->bl.m ) + { + clif_bossmapinfo(sd->fd, boss_md, 1); // Update X - Y on minimap + sc_timer_next(5000 + tick, status_change_timer, bl->id, data); + return 0; + } + } + break; + case SC_DANCING: //ダンススキルの時間SP消費 { int s = 0; @@ -7007,7 +7046,12 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr data) } // default for all non-handled control paths is to end the status - return status_change_end( bl,type,tid ); + result = status_change_end( bl,type,tid ); + + if( sd && boss_md && boss_md->bl.prev == NULL ) + clif_bossmapinfo(sd->fd, boss_md, 1); // Killed MVP - Show next spawn info + + return result; #undef sc_timer_next } |