Skip to content
Permalink
Browse files

== Critical Bug fixes ==

=General:
*Merged missing changes from 3ceam rev. 556 - 557

*Rewrote some more calculation formulars. This is a critical fix, you should update ASAP!
-Thanks to rAthena for the base.
-This is another follow-up to r139(@cd0f269).
-HP, SP, ASPD and most of the damage calculations where destroyed in this commit.
-Now the calculations should be fixed, sorry for this... ^^"

*Fixed a mistake related to Banana Bomb, you're able to stand up when the bomb force you to sit.

=Skills:
*Fixed SR_CRESCENTELBOW.
-Consumes spirit spheres when is casted not when it takes damage.
-It only consumes spirit spheres if you have. Is it a bug in kRO-RE?

*Fixed SR_ASSIMILATEPOWER animation.

*Fixed SR_EARTHSHAKER animation.

*Fixed SR_CURSEDCIRCLE:
-It doesn't use OPT3_BLADESTOP.
-The effect is removed with packet 0x196.

*Optimized SR_LIGHTNINGWALK skill.
  • Loading branch information...
15peaces committed Feb 24, 2017
1 parent 5c4530b commit 0f547f90f2d494e67b817fef9107527ef855e19a
Showing with 213 additions and 150 deletions.
  1. +19 −0 Changelog-15-3athena.txt
  2. +1 −0 src/common/cbasetypes.h
  3. +18 −22 src/map/battle.c
  4. +3 −2 src/map/clif.c
  5. +69 −2 src/map/pc.c
  6. +3 −0 src/map/pc.h
  7. +38 −15 src/map/skill.c
  8. +62 −109 src/map/status.c
@@ -4,6 +4,25 @@
// * Modifications.
// - Details.
//========================================
02/24/2017
r156 [15peaces]
*Merged missing changes from 3ceam rev. 556 - 557
*Rewrote some more calculation formulars. This is a critical fix, you should update ASAP!
-Thanks to rAthena for the base.
-This is another follow-up to r139(@cd0f269).
-HP, SP, ASPD and most of the damage calculations where destroyed in this commit.
-Now the calculations should be fixed, sorry for this... ^^"
*Fixed SR_CRESCENTELBOW.
-Consumes spirit spheres when is casted not when it takes damage.
-It only consumes spirit spheres if you have. Is it a bug in kRO-RE?
*Fixed SR_ASSIMILATEPOWER animation.
*Fixed SR_EARTHSHAKER animation.
*Fixed SR_CURSEDCIRCLE:
-It doesn't use OPT3_BLADESTOP.
-The effect is removed with packet 0x196.
*Optimized SR_LIGHTNINGWALK skill.
*Fixed a mistake related to Banana Bomb, you're able to stand up when the bomb force you to sit.

02/19/2017
r155 [15peaces]
*Fixed a typo on my last commit, sorry. ^^
@@ -257,6 +257,7 @@ typedef char bool;
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#endif
static inline uint32 umax(uint32 a, uint32 b){ return (a > b) ? a : b; }

#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
@@ -696,17 +696,12 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag
status_change_end(bl, SC_KYRIE, INVALID_TIMER);
}

if( (sce = sc->data[SC_LIGHTNINGWALK]) && flag&BF_LONG && damage > 0 ){
if( rand()%100 < 88 + 2 * sce->val1 ){
short x, y;
damage = 0;
map_search_freecell(src, 0, &x, &y, 1, 1, 0);
unit_movepos(bl, x, y, 1, 1);
clif_slide(bl, x, y);
clif_fixpos(bl);
map_moveblock(bl, x, y, gettick());
status_change_end(bl, SC_LIGHTNINGWALK, -1);
}
if ((sce = sc->data[SC_LIGHTNINGWALK]) && flag&BF_LONG && damage > 0 && rand()%100 < sce->val1)
{
skill_blown(src, bl, 1, -2, 0);
d->div_ = ATK_DEF;
status_change_end(bl, SC_LIGHTNINGWALK, INVALID_TIMER);
return 0;
}

if (!damage) return 0;
@@ -4138,13 +4133,15 @@ int battle_calc_return_damage(struct block_list *src, struct block_list *bl, int
rdamage += (*damage) / 100;
rdamage = cap_value(rdamage,1,max_damage);
}
if( sc && sc->data[SC_CRESCENTELBOW] && !is_boss(bl) && sd && sd->spiritball >= 2 &&
rand()%100 < 94 + sc->data[SC_CRESCENTELBOW]->val1 )
if (sc && sc->data[SC_CRESCENTELBOW] && !is_boss(bl) && rand()%100 < sc->data[SC_CRESCENTELBOW]->val2)
{ // Stimated formula from test
rdamage += (int)((*damage) + (*damage) * status_get_hp(src) * 2.15 / 100000);
if( rdamage < 1 ) rdamage = 1;
if (rdamage < 1)
rdamage = 1;
}
} else {
}
else
{
if (sd && sd->long_weapon_damage_return)
{
rdamage += (*damage) * sd->long_weapon_damage_return / 100;
@@ -4429,14 +4426,13 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t
}
else
{
if( tsc && tsc->data[SC_CRESCENTELBOW] )
if (tsc && tsc->data[SC_CRESCENTELBOW])
{ // Deal rdamage to src and 10% damage back to target.
clif_skill_nodamage(target,target,SR_CRESCENTELBOW_AUTOSPELL,tsc->data[SC_CRESCENTELBOW]->val1,1);
skill_blown(target,src,skill_get_blewcount(SR_CRESCENTELBOW_AUTOSPELL,tsc->data[SC_CRESCENTELBOW]->val1),unit_getdir(src),0);
status_damage(src,target,rdamage/10,0,0,1);
clif_damage(src, target, tick, wd.amotion, wd.dmotion, rdamage/10, wd.div_ , wd.type, wd.damage2);
status_change_end(target,SC_CRESCENTELBOW,-1);
if( tsd ) pc_delspiritball(tsd,2,0); // remove 2 spiritballs here.
clif_skill_nodamage(target, target, SR_CRESCENTELBOW_AUTOSPELL, tsc->data[SC_CRESCENTELBOW]->val1, 1);
skill_blown(target, src,skill_get_blewcount(SR_CRESCENTELBOW_AUTOSPELL, tsc->data[SC_CRESCENTELBOW]->val1), unit_getdir(src), 0);
status_damage(NULL, target, rdamage / 10, 0, 0, 1);
clif_damage(target, target, tick, wd.amotion, wd.dmotion, rdamage/10, wd.div_ , wd.type, wd.damage2);
status_change_end(target, SC_CRESCENTELBOW, INVALID_TIMER);
}
rdelay = clif_damage(src, src, tick, wd.amotion, sstatus->dmotion, rdamage, 1, 4, 0);
//Use Reflect Shield to signal this kind of skill trigger. [Skotlex]
@@ -10836,10 +10836,11 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type,
break;
}

if( sd->sc.data[SC_SITDOWN_FORCE] || sd->sc.data[SC_BANANA_BOMB_SITDOWN_POSTDELAY] )
if (sd->sc.data[SC_SITDOWN_FORCE])
return;

if(pc_issit(sd)) {
if (pc_issit(sd))
{
//Bugged client? Just refresh them.
clif_sitting(&sd->bl);
return;
@@ -43,6 +43,7 @@

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <time.h>

@@ -9340,6 +9341,61 @@ static bool pc_readdb_job2(char* fields[], int columns, int current)
return true;
}

// [Cydh]
// Calculates base hp of player. Reference: http://irowiki.org/wiki/Max_HP
// @param level Base level of player
// @param class_ Job ID @see enum e_job
// @return base_hp
static unsigned int pc_calc_basehp(uint16 level, uint16 class_)
{
double base_hp;
uint16 i, idx = pc_class2idx(class_);

base_hp = 35 + level * (job_info[idx].hp_multiplicator/100.);

if(level >= 10 && (class_ == JOB_NINJA || class_ == JOB_GUNSLINGER)) base_hp += 90;

for (i = 2; i <= level; i++)
base_hp += floor(((job_info[idx].hp_factor/100.) * i) + 0.5); //Don't have round()
/*if (class_ == JOB_SUMMONER)
base_hp += floor((base_hp / 2) + 0.5);*/
return (unsigned int)base_hp;
}

// [Playtester]
// Calculates base sp of player.
// @param level Base level of player
// @param class_ Job ID @see enum e_job
// @return base_sp
static unsigned int pc_calc_basesp(uint16 level, uint16 class_)
{
double base_sp;
uint16 idx = pc_class2idx(class_);

base_sp = 10 + floor(level * (job_info[idx].sp_factor / 100.));

switch (class_)
{
case JOB_NINJA:
if (level >= 10)
base_sp -= 22;
else
base_sp = 11 + 3*level;
break;
case JOB_GUNSLINGER:
if (level > 10)
base_sp -= 18;
else
base_sp = 9 + 3*level;
break;
/*case JOB_SUMMONER:
base_sp -= floor(base_sp / 2);
break;*/
}

return (unsigned int)base_sp;
}

//Reading job_exp.txt line
//Max Level,Class list,Type (0 - Base Exp; 1 - Job Exp),Exp/lvl...
static bool pc_readdb_exp(char* fields[], int columns, int current)
@@ -9490,7 +9546,7 @@ void pc_readdb(void) {
sv_readdb(db_path, "exp.txt",',',4,1000+3,CLASS_COUNT*2,&pc_readdb_exp);
sv_readdb(db_path, "job_noenter.txt", ',', 3, 3, CLASS_COUNT, &pc_readdb_job_noenter);

// Reset and read skilltree - needs to be read after pc_readdb_job_exp to get max base and job levels
// Reset and read skilltree
memset(skill_tree, 0, sizeof(skill_tree));
sv_readdb(db_path, "skill_tree.txt", ',', 3 + MAX_PC_SKILL_REQUIRE * 2, 5 + MAX_PC_SKILL_REQUIRE * 2, -1, &pc_readdb_skilltree);

@@ -9503,8 +9559,10 @@ void pc_readdb(void) {
battle_config.use_statpoint_table = k; //restore setting

//Checking if all class have their data
for (i = 0; i < JOB_MAX; i++) {
for (i = 0; i < JOB_MAX; i++)
{
int idx;
uint16 j;
if (!pcdb_checkid(i))
continue;
if (i == JOB_WEDDING || i == JOB_XMAS || i == JOB_SUMMER || i == JOB_HANBOK || i == JOB_OKTOBERFEST)
@@ -9514,6 +9572,15 @@ void pc_readdb(void) {
ShowWarning("Class %s (%d) does not have a base exp table.\n", job_name(i), i);
if (!job_info[idx].max_level[1])
ShowWarning("Class %s (%d) does not have a job exp table.\n", job_name(i), i);

//Init and checking the empty value of Base HP/SP [Cydh]
for (j = 0; j < (job_info[idx].max_level[0] ? job_info[idx].max_level[0] : MAX_LEVEL); j++)
{
if (job_info[idx].base_hp[j] == 0)
job_info[idx].base_hp[j] = pc_calc_basehp(j+1,i);
if (job_info[idx].base_sp[j] == 0)
job_info[idx].base_sp[j] = pc_calc_basesp(j+1,i);
}
}
}

@@ -956,4 +956,7 @@ void pc_show_questinfo_reinit(struct map_session_data *sd);

bool pc_job_can_entermap(enum e_job jobid, int m, int group_lv);

/// Check if player is Taekwon Ranker and the level is >= 90 (battle_config.taekwon_ranker_min_lv)
#define pc_is_taekwon_ranker(sd) (((sd)->class_&MAPID_UPPERMASK) == MAPID_TAEKWON && pc_famerank((sd)->status.char_id,MAPID_TAEKWON))

#endif /* _PC_H_ */
@@ -2140,7 +2140,8 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds
dmg.dmotion = clif_skill_damage(dsrc,bl,tick, dmg.amotion, dmg.dmotion, damage, dmg.div_, skillid, -2, 5); // needs -2(!) as skill level
break;
case WL_HELLINFERNO:
dmg.dmotion = clif_skill_damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,1,skillid,-2,6);
case SR_EARTHSHAKER:
dmg.dmotion = clif_skill_damage(src, bl, tick, dmg.amotion, dmg.dmotion, damage, 1, skillid, -2, 6);
break;
case WL_SOULEXPANSION:
case WL_COMET:
@@ -7923,21 +7924,28 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
break;

case SR_CURSEDCIRCLE:
if( flag&1 ){
if( is_boss(bl) ) break;
if (flag&1)
{
if (is_boss(bl))
break;
if (sc_start2(bl, type, 100, skilllv, src->id, skill_get_time(skillid, skilllv)))
{
unit_stop_attack(bl);
clif_bladestop(src, bl->id, 1);
map_freeblock_unlock();
return 1;
}
}else{
}
else
{
int count = 0;
clif_skill_nodamage(src, src, skillid, skilllv, sc_start(src, SC_CURSEDCIRCLE_ATKER, 100, skilllv, skill_get_time(skillid,skilllv)));
clif_skill_damage(src, bl, tick, status_get_amotion(src), 0, -30000, 1, skillid, skilllv, 6);
count = map_forcountinrange(skill_area_sub, src, skill_get_splash(skillid,skilllv), (sd)?sd->spiritball_old:15, // Assume 15 spiritballs in non-charactors
BL_CHAR, src, skillid, skilllv, tick, flag|BCT_ENEMY|1, skill_castend_nodamage_id);
if( sd ) pc_delspiritball(sd, count, 0);
if(sd)
pc_delspiritball(sd, count, 0);
clif_skill_nodamage(src, src, skillid, skilllv, sc_start2(src, SC_CURSEDCIRCLE_ATKER, 100, skilllv, count, skill_get_time(skillid,skilllv)));

}
break;

@@ -7953,16 +7961,23 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
break;

case SR_ASSIMILATEPOWER:
if( flag&1 ){
if (flag&1)
{
i = 0;
if( dstsd && dstsd->spiritball && (sd == dstsd || map_flag_vs(src->m)) && (dstsd->class_&MAPID_BASEMASK)!=MAPID_GUNSLINGER ){
if (dstsd && dstsd->spiritball && (sd == dstsd || map_flag_vs(src->m)) && (dstsd->class_&MAPID_BASEMASK) != MAPID_GUNSLINGER)
{
i = dstsd->spiritball; //1%sp per spiritball.
pc_delspiritball(dstsd, dstsd->spiritball, 0);
}
if( i ) status_percent_heal(src, 0, i);
if (i)
status_percent_heal(src, 0, i);
clif_skill_nodamage(src, bl, skillid, skilllv, i ? 1:0);
}else
}
else
{
clif_skill_damage(src, bl, tick, status_get_amotion(src), 0, -30000, 1, skillid, skilllv, 6);
map_foreachinrange(skill_area_sub, bl, skill_get_splash(skillid, skilllv), splash_target(src), src, skillid, skilllv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill_castend_nodamage_id);
}
break;

case SR_POWERVELOCITY:
@@ -9017,11 +9032,15 @@ int skill_castend_pos2(struct block_list* src, int x, int y, int skillid, int sk
type = status_skill2sc(skillid);
sce = (sc && type != -1)?sc->data[type]:NULL;

if( sc ){ //Status end during cast end.
if( sc->data[SC_CAMOUFLAGE] )
status_change_end(src,SC_CAMOUFLAGE,INVALID_TIMER);
if( sc->data[SC_CURSEDCIRCLE_ATKER] )
status_change_end(src,SC_CURSEDCIRCLE_ATKER,INVALID_TIMER);
if (sc)
{ //Status end during cast end.
if (sc->data[SC_CAMOUFLAGE])
status_change_end(src, SC_CAMOUFLAGE, INVALID_TIMER);
if (sc->data[SC_CURSEDCIRCLE_ATKER])
{
sc->data[SC_CURSEDCIRCLE_ATKER]->val3 = 1;
status_change_end(src, SC_CURSEDCIRCLE_ATKER, INVALID_TIMER);
}
}

switch (skillid) { //Skill effect.
@@ -12848,6 +12867,10 @@ struct skill_condition skill_get_requirement(struct map_session_data* sd, short
case LG_RAGEBURST:
req.spiritball = sd->rageball?sd->rageball:1;
break;
case SR_CRESCENTELBOW:
if (sd->spiritball <= 0)
req.spiritball = 0; // Only consumes spirit spheres if these are pressent. Is a bug?
break;
case SR_RAMPAGEBLASTER:
req.spiritball = sd->spiritball?sd->spiritball:15;
break;
Oops, something went wrong.

0 comments on commit 0f547f9

Please sign in to comment.
You can’t perform that action at this time.