summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Changelog-Trunk.txt5
-rw-r--r--src/map/chrif.c15
-rw-r--r--src/map/clif.c4
-rw-r--r--src/map/clif.h1
-rw-r--r--src/map/mercenary.c2
-rw-r--r--src/map/mob.c14
-rw-r--r--src/map/pc.c3
-rw-r--r--src/map/pet.c11
-rw-r--r--src/map/status.c17
-rw-r--r--src/map/status.h2
10 files changed, 47 insertions, 27 deletions
diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt
index bb24553ff..c928ed2fd 100644
--- a/Changelog-Trunk.txt
+++ b/Changelog-Trunk.txt
@@ -4,6 +4,11 @@ AS OF SVN REV. 5091, WE ARE NOW USING TRUNK. ALL UNTESTED BUGFIXES/FEATURES GO
IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
2007/02/21
+ * Added status_calc_life to properly calculate hp/max_hp as a ratio taking
+ into accounts overflows (and for now also avoids divisions by 0). Applied
+ this function around clif.c, mob.c and pet.c
+ * Implemented the correct walk-speed bonus from the Bard/Dancer spirit.
+ * Fixed logarithmic drops turning 0% drop rates into 100%.
* Restructured the login mechanism of the map-server. The goal was to make
sure players are not found in the different dbs of the map while the
player has not yet been fully authed or while it is quitting, to avoid the
diff --git a/src/map/chrif.c b/src/map/chrif.c
index 005285da5..969157acd 100644
--- a/src/map/chrif.c
+++ b/src/map/chrif.c
@@ -169,8 +169,7 @@ bool chrif_auth_finished(TBL_PC* sd)
struct auth_node *node= chrif_search(sd->status.account_id);
if (node && node->sd == sd && node->state == ST_LOGIN) {
node->sd = NULL;
- chrif_auth_delete(node->account_id, node->char_id, ST_LOGIN);
- return true;
+ return chrif_auth_delete(node->account_id, node->char_id, ST_LOGIN);
}
return false;
}
@@ -242,7 +241,8 @@ int chrif_save(struct map_session_data *sd, int flag)
{
//FIXME: SC are lost if there's no connection at save-time because of the way its related data is cleared immediately after this function. [Skotlex]
if (chrif_isconnected()) chrif_save_scdata(sd);
- chrif_auth_logout(sd, flag==1?ST_LOGOUT:ST_MAPCHANGE);
+ if (!chrif_auth_logout(sd, flag==1?ST_LOGOUT:ST_MAPCHANGE))
+ ShowError("chrif_save: Failed to set up player %d:%d for proper quitting!\n", sd->status.account_id, sd->status.char_id);
}
if(!chrif_isconnected())
@@ -515,11 +515,12 @@ void chrif_authreq(struct map_session_data *sd)
if(node->state == ST_LOGIN &&
node->char_dat &&
- node->account_id== sd->status.account_id &&
+ node->account_id == sd->status.account_id &&
+ node->char_id == sd->status.char_id &&
node->login_id1 == sd->login_id1)
{ //auth ok
if (!pc_authok(sd, node->login_id2, node->connect_until_time, node->char_dat))
- chrif_auth_delete(sd->status.account_id, sd->status.char_id, ST_LOGIN);
+ chrif_auth_delete(node->account_id, node->char_id, ST_LOGIN);
else {
//char_dat no longer needed, but player auth is not completed yet.
aFree(node->char_dat);
@@ -587,16 +588,18 @@ void chrif_authok(int fd)
int auth_db_cleanup_sub(DBKey key,void *data,va_list ap)
{
struct auth_node *node=(struct auth_node*)data;
-
+ const char* states[] = { "Login", "Logout", "Map change" };
if(DIFF_TICK(gettick(),node->node_created)>60000) {
switch (node->state)
{
case ST_LOGOUT:
//Re-save attempt (->sd should never be null here).
+ node->node_created = gettick(); //Refresh tick (avoid char-server load if connection is really bad)
chrif_save(node->sd, 1);
break;
default:
//Clear data. any connected players should have timed out by now.
+ ShowInfo("auth_db: Node (state %s) timed out for %d:%d\n", states[node->state], node->account_id, node->char_id);
chrif_auth_delete(node->account_id, node->char_id, node->state);
break;
}
diff --git a/src/map/clif.c b/src/map/clif.c
index 5d6daaa26..07e95aed4 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -7188,9 +7188,7 @@ int clif_charnameack (int fd, struct block_list *bl)
str_p += sprintf(str_p, "HP: %u/%u | ", md->status.hp, md->status.max_hp);
if (battle_config.show_mob_info&2)
str_p += sprintf(str_p, "HP: %d%% | ",
- md->status.max_hp > 10000?
- md->status.hp/(md->status.max_hp/100):
- 100*md->status.hp/md->status.max_hp);
+ status_calc_life(md->status.hp, md->status.max_hp));
//Even thought mobhp ain't a name, we send it as one so the client
//can parse it. [Skotlex]
if (str_p != mobhp) {
diff --git a/src/map/clif.h b/src/map/clif.h
index 7000fd989..bc255097f 100644
--- a/src/map/clif.h
+++ b/src/map/clif.h
@@ -300,6 +300,7 @@ int clif_guild_allianceinfo(struct map_session_data *sd);
int clif_guild_memberlist(struct map_session_data *sd);
int clif_guild_skillinfo(struct map_session_data *sd);
int clif_guild_send_onlineinfo(struct map_session_data *sd); //[LuzZza]
+int clif_guild_masterormember(struct map_session_data *sd);
int clif_guild_memberlogin_notice(struct guild *g,int idx,int flag);
int clif_guild_invite(struct map_session_data *sd,struct guild *g);
int clif_guild_inviteack(struct map_session_data *sd,int flag);
diff --git a/src/map/mercenary.c b/src/map/mercenary.c
index 3e3d8a906..039a7f446 100644
--- a/src/map/mercenary.c
+++ b/src/map/mercenary.c
@@ -95,7 +95,7 @@ int merc_hom_vaporize(struct map_session_data *sd, int flag)
if (status_isdead(&hd->bl))
return 0; //Can't vaporize a dead homun.
- if (flag && hd->battle_status.hp < (hd->battle_status.max_hp*80/100))
+ if (flag && status_calc_life(hd->battle_status.hp, hd->battle_status.max_hp)< 80)
return 0;
hd->regen.state.block = 3; //Block regen while vaporized.
diff --git a/src/map/mob.c b/src/map/mob.c
index e66a980a3..2725f0b39 100644
--- a/src/map/mob.c
+++ b/src/map/mob.c
@@ -2451,7 +2451,7 @@ int mob_class_change (struct mob_data *md, int class_)
if (md->class_ == class_)
return 0; //Nothing to change.
- hp_rate = md->status.hp*100/md->status.max_hp;
+ hp_rate = status_calc_life(md->status.hp, md->status.max_hp);
md->class_ = class_;
md->db = mob_db(class_);
if (battle_config.override_mob_names==1)
@@ -2586,7 +2586,7 @@ int mob_summonslave(struct mob_data *md2,int *value,int amount,int skill_id)
if (!battle_config.monster_class_change_recover &&
(skill_id == NPC_TRANSFORMATION || skill_id == NPC_METAMORPHOSIS))
- hp_rate = 100*md2->status.hp/md2->status.max_hp;
+ hp_rate = status_calc_life(md2->status.hp, md2->status.max_hp);
for(;k<amount;k++) {
short x,y;
@@ -2691,7 +2691,7 @@ int mob_getfriendhprate_sub(struct block_list *bl,va_list ap)
if (battle_check_target(&md->bl,bl,BCT_ENEMY)>0)
return 0;
- rate = 100*status_get_hp(bl)/status_get_max_hp(bl);
+ rate = status_calc_life(status_get_hp(bl), status_get_max_hp(bl));
if (rate >= min_rate && rate <= max_rate)
(*fr) = bl;
@@ -2717,7 +2717,7 @@ struct block_list *mob_getmasterhpltmaxrate(struct mob_data *md,int rate)
{
if (md && md->master_id > 0) {
struct block_list *bl = map_id2bl(md->master_id);
- if (status_get_hp(bl) < status_get_max_hp(bl) * rate / 100)
+ if (bl && status_calc_life(status_get_hp(bl), status_get_max_hp(bl)) < rate);
return bl;
}
@@ -2823,11 +2823,11 @@ int mobskill_use(struct mob_data *md, unsigned int tick, int event)
case MSC_ALWAYS:
flag = 1; break;
case MSC_MYHPLTMAXRATE: // HP< maxhp%
- flag = 100*md->status.hp/md->status.max_hp;
+ flag = status_calc_life(md->status.hp, md->status.max_hp);
flag = (flag <= c2);
break;
case MSC_MYHPINRATE:
- flag = 100*md->status.hp/md->status.max_hp;
+ flag = status_calc_life(md->status.hp, md->status.max_hp);
flag = (flag >= c2 && flag <= ms[i].val[0]);
break;
case MSC_MYSTATUSON: // status[num] on
@@ -3282,7 +3282,7 @@ static unsigned int mob_drop_adjust(int baserate, int rate_adjust, unsigned shor
{
double rate = baserate;
- if (battle_config.logarithmic_drops && rate_adjust > 0) //Logarithmic drops equation by Ishizu-Chan
+ if (battle_config.logarithmic_drops && rate_adjust > 0 && baserate > 0) //Logarithmic drops equation by Ishizu-Chan
//Equation: Droprate(x,y) = x * (5 - log(x)) ^ (ln(y) / ln(5))
//x is the normal Droprate, y is the Modificator.
rate = rate * pow((5.0 - log10(rate)), (log(rate_adjust/100.) / log(5.0))) + 0.5;
diff --git a/src/map/pc.c b/src/map/pc.c
index d1bb81c3e..57f68f201 100644
--- a/src/map/pc.c
+++ b/src/map/pc.c
@@ -842,7 +842,8 @@ int pc_reg_received(struct map_session_data *sd)
map_addiddb(&sd->bl);
map_delnickdb(sd->status.char_id, sd->status.name);
- chrif_auth_finished(sd);
+ if (!chrif_auth_finished(sd))
+ ShowError("pc_reg_received: Failed to properly remove player %d:%d from logging db!\n", sd->status.account_id, sd->status.char_id);
status_calc_pc(sd,1);
chrif_scdata_request(sd->status.account_id, sd->status.char_id);
diff --git a/src/map/pet.c b/src/map/pet.c
index a792924f5..f413863a0 100644
--- a/src/map/pet.c
+++ b/src/map/pet.c
@@ -554,7 +554,8 @@ int pet_catch_process2(struct map_session_data* sd, int target_id)
return 1;
}
- pet_catch_rate = (pet_db[i].capture + (sd->status.base_level - md->level)*30 + sd->battle_status.luk*20)*(200 - md->status.hp*100/md->status.max_hp)/100;
+ pet_catch_rate = (pet_db[i].capture + (sd->status.base_level - md->level)*30 + sd->battle_status.luk*20)*(200 - status_calc_life(md->status.hp, md->status.max_hp))/100;
+
if(pet_catch_rate < 1) pet_catch_rate = 1;
if(battle_config.pet_catch_rate != 100)
pet_catch_rate = (pet_catch_rate*battle_config.pet_catch_rate)/100;
@@ -1161,8 +1162,8 @@ int pet_heal_timer(int tid,unsigned int tick,int id,int data)
status = status_get_status_data(&sd->bl);
if(pc_isdead(sd) ||
- (rate = status->sp*100/status->max_sp) > pd->s_skill->sp ||
- (rate = status->hp*100/status->max_hp) > pd->s_skill->hp ||
+ (rate = status_calc_life(status->sp, status->max_sp)) > pd->s_skill->sp ||
+ (rate = status_calc_life(status->hp, status->max_hp)) > pd->s_skill->hp ||
(rate = (pd->ud.skilltimer != -1)) //Another skill is in effect
) { //Wait (how long? 1 sec for every 10% of remaining)
pd->s_skill->timer=add_timer(gettick()+(rate>10?rate:10)*100,pet_heal_timer,sd->bl.id,0);
@@ -1204,8 +1205,8 @@ int pet_skill_support_timer(int tid,unsigned int tick,int id,int data)
}
if(pc_isdead(sd) ||
- (rate = status->sp*100/status->max_sp) > pd->s_skill->sp ||
- (rate = status->hp*100/status->max_hp) > pd->s_skill->hp ||
+ (rate = status_calc_life(status->sp, status->max_sp)) > pd->s_skill->sp ||
+ (rate = status_calc_life(status->hp, status->max_hp)) > pd->s_skill->hp ||
(rate = (pd->ud.skilltimer != -1)) //Another skill is in effect
) { //Wait (how long? 1 sec for every 10% of remaining)
pd->s_skill->timer=add_timer(tick+(rate>10?rate:10)*100,pet_skill_support_timer,sd->bl.id,0);
diff --git a/src/map/status.c b/src/map/status.c
index 10129129a..f7e3157bf 100644
--- a/src/map/status.c
+++ b/src/map/status.c
@@ -951,6 +951,17 @@ int status_revive(struct block_list *bl, unsigned char per_hp, unsigned char per
}
return 1;
}
+
+//calculates the base/max ratio as a value between 0->100 (percent), using
+//different approaches to avoid overflows.
+//NOTE: The -1 case (0 max hp) should never trigger!
+char status_calc_life(unsigned int base, unsigned int max)
+{
+ if (!max) return -1;
+ if (max < 10000) return 100*base/max;
+ return base/(max/100);
+}
+
/*==========================================
* Checks whether the src can use the skill on the target,
* taking into account status/option of both source/target. [Skotlex]
@@ -5173,11 +5184,9 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
clif_status_change(bl,SI_MOONLIT,1);
val1|= (val3<<16);
val3 = 0; //Tick duration/Speed penalty.
- if (sd) { //Store walk speed change in lower part of val3
+ //Store walk speed change in lower part of val3
+ if (sd && !(sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_BARDDANCER))
val3 = 500-40*pc_checkskill(sd,(sd->status.sex?BA_MUSICALLESSON:DC_DANCINGLESSON));
- if (sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_BARDDANCER)
- val3 -= 40; //TODO: Figure out real bonus rate.
- }
val3|= ((tick/1000)<<16)&0xFFFF0000; //Store tick in upper part of val3
tick = 1000;
break;
diff --git a/src/map/status.h b/src/map/status.h
index 23f8ec4b1..5d91fa62d 100644
--- a/src/map/status.h
+++ b/src/map/status.h
@@ -599,6 +599,8 @@ int status_set_sp(struct block_list *bl, unsigned int sp, int flag);
int status_heal(struct block_list *bl,int hp,int sp, int flag);
int status_revive(struct block_list *bl, unsigned char per_hp, unsigned char per_sp);
+char status_calc_life(unsigned int base, unsigned int max);
+
//Define for copying a status_data structure from b to a, without overwriting current Hp and Sp
#define status_cpy(a, b) \
memcpy(&((a)->max_hp), &((b)->max_hp), sizeof(struct status_data)-(sizeof((a)->hp)+sizeof((a)->sp)))