summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/map/clif.c44
-rw-r--r--src/map/clif.h1
-rw-r--r--src/map/map.c53
-rw-r--r--src/map/map.h2
-rw-r--r--src/map/mob.c3
-rw-r--r--src/map/mob.h1
-rw-r--r--src/map/pc.c2
-rw-r--r--src/map/skill.c4
-rw-r--r--src/map/status.c46
9 files changed, 148 insertions, 8 deletions
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
}