- 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.
- Added a few error messages in case something goes wrong in the new auth db system.
- Fixed logarithmic drops turning 0% drop rates into 100%.


git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@12225 54d463be-8e91-2dee-dedb-b68131a5f0ec
This commit is contained in:
skotlex 2008-02-21 10:36:26 +00:00
parent 6da0007d11
commit 9c638fa6b2
10 changed files with 47 additions and 27 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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) {

View File

@ -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);

View File

@ -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.

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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)))