summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Changelog-Trunk.txt26
-rw-r--r--src/map/skill.c9
-rw-r--r--src/map/status.c255
3 files changed, 153 insertions, 137 deletions
diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt
index ef057e35f..06581e7a4 100644
--- a/Changelog-Trunk.txt
+++ b/Changelog-Trunk.txt
@@ -4,6 +4,32 @@ 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.
2008/07/07
+ * First attempt at implementing the official walk speed system
+ - separated speed modifiers into bonuses, penalties and other statuses
+ - no bonuses stack, instead the maximum is taken
+ - no penalties stack, instead the maximum is taken
+ - Union, Riding and Pushcart are the only other statuses that stack
+ - both bonuses and penalties are linear modifiers of the base walk speed
+ - 'other' statuses are applied after bonuses and penalties
+ * Changed many equations to match official walk speed system
+ - Steel Body now sets a fixed walk speed of 200 (bypassing everything else)
+ - Defender now caps the walk speed to a minimum of 200
+ - Slow Grace now uses official equation for aspd/walk speed decrease
+ - Pushcart's speed penalty is now halved
+ - Free Cast now changes walk speed to a fixed value, bypassing bonuses and penalties
+ - Wedding clothes now have a penalty of +100%, not +200%
+ - rogue's Tunnel Drive and stalker's Chasewalk ignore all penalties
+ - taekwon's Running is now 5% faster
+ - Frenzy is now 5% faster
+ - Gospel's offensive slowdown is now +75% instead of +33%
+ - Quagmire now slows down by +50% instead of +100%
+ - Gatling Fever now slows down by +100% instead of +33%
+ - Cloaking modifier is now a bonus/penalty, depending on presence of wall
+ - Longing for Freedom overrides the song/dance penalty (bugreport:416)
+ - Bard/Dancer Spriit now properly affects song/dance penalty (bugreport:1019)
+ - item-granted speedup no longer stacks with speed bonuses (topic:145019)
+ - removed some status code that pre-calculated speed bonuses/penalties,
+ to make calculations more localized and less messy (see song/dance code)
* Removed stop/slowdown effect from Grimtooth (bugreport:1806)
* Players autotrading will not be able to receive whispers (bugreport:1804) [SketchyPhoenix]
2008/07/06
diff --git a/src/map/skill.c b/src/map/skill.c
index ec0abc00f..ece5ca0af 100644
--- a/src/map/skill.c
+++ b/src/map/skill.c
@@ -6324,13 +6324,12 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, short skilli
}
break;
case DC_DONTFORGETME:
- val1 = 30*skilllv+status->dex; // ASPD decrease
- val2 = 100 -2*skilllv -status->agi/10; // Movement speed adjustment.
+ val1 = status->dex/10 + 3*skilllv + 5; // ASPD decrease
+ val2 = status->agi/10 + 3*skilllv + 5; // Movement speed adjustment.
if(sd){
- val1 += pc_checkskill(sd,DC_DANCINGLESSON); //TO-DO This is a guessed value
- val2 -= pc_checkskill(sd,DC_DANCINGLESSON); //TO-DO This is a guessed value
+ val1 += pc_checkskill(sd,DC_DANCINGLESSON);
+ val2 += pc_checkskill(sd,DC_DANCINGLESSON);
}
- if (val2 < 1) val2 = 1;
break;
case BA_APPLEIDUN:
val1 = 5+2*skilllv+status->vit/10; // MaxHP percent increase
diff --git a/src/map/status.c b/src/map/status.c
index e1c504aaa..5b93b2a42 100644
--- a/src/map/status.c
+++ b/src/map/status.c
@@ -2189,22 +2189,6 @@ int status_calc_pc(struct map_session_data* sd,int first)
status->mdef = (signed char)battle_config.max_def;
}
-// ----- WALKING SPEED CALCULATION -----
-
- sd->speed_rate += sd->speed_add_rate;
- status->speed += status->speed * sd->speed_rate/100;
-
- // Relative modifiers from passive skills
- if((sd->class_&MAPID_UPPERMASK) == MAPID_ASSASSIN && (skill=pc_checkskill(sd,TF_MISS))>0)
- status->speed -= status->speed * skill/100;
- if(pc_isriding(sd) && pc_checkskill(sd,KN_RIDING)>0)
- status->speed -= status->speed * 25/100;
- if(pc_iscarton(sd) && (skill=pc_checkskill(sd,MC_PUSHCART))>0)
- status->speed += status->speed * (100-10*skill)/100;
-
- if(status->speed < battle_config.max_walk_speed)
- status->speed = battle_config.max_walk_speed;
-
// ----- ASPD CALCULATION -----
// Unlike other stats, ASPD rate modifiers from skills/SCs/items/etc are first all added together, then the final modifier is applied
@@ -3673,101 +3657,132 @@ static signed short status_calc_mdef2(struct block_list *bl, struct status_chang
static unsigned short status_calc_speed(struct block_list *bl, struct status_change *sc, int speed)
{
TBL_PC* sd = BL_CAST(BL_PC, bl);
+ int speed_rate;
- //Default speed coming in means there's no speed_rate adjustments.
- int new_speed = speed;
- bool default_speed = (speed == DEFAULT_WALK_SPEED);
+ if( sc == NULL )
+ return cap_value(speed,10,USHRT_MAX);
if( sd && sd->ud.skilltimer != -1 && pc_checkskill(sd,SA_FREECAST) > 0 )
- speed = speed * (175 - 5 * pc_checkskill(sd,SA_FREECAST))/100;
+ {
+ speed_rate = 175 - 5 * pc_checkskill(sd,SA_FREECAST);
+ }
+ else
+ {
+ speed_rate = 100;
- if(!sc || !sc->count)
- return cap_value(speed,10,USHRT_MAX);
+ //GetMoveHasteValue2()
+ {
+ int val = 0;
- if(sc->data[SC_WALKSPEED])
- new_speed = sc->data[SC_WALKSPEED]->val1;
+ if( sc->data[SC_FUSION] )
+ val = 25;
+ else
+ if( sd && pc_isriding(sd) )
+ val = 25;
- // Fixed reductions
- if(sc->data[SC_CURSE])
- new_speed += 450;
- if(sc->data[SC_SWOO])
- new_speed += 450; //Let's use Curse's slow down momentarily (exact value unknown)
- if(sc->data[SC_WEDDING])
- new_speed += 300;
-
- if(!sc->data[SC_GATLINGFEVER])
- { //These two stack with everything (but only one of either)
- if(sc->data[SC_SPEEDUP1])
- new_speed -= new_speed * 50/100;
- else if(sc->data[SC_AVOID])
- new_speed -= new_speed * sc->data[SC_AVOID]->val2/100;
-
- speed = new_speed;
-
- //These stack independently
- if(sc->data[SC_RUN])
- new_speed -= new_speed * 50/100;
- if(sc->data[SC_INCREASEAGI])
- new_speed -= new_speed * 25/100;
- if(sc->data[SC_FUSION])
- new_speed -= new_speed * 25/100;
-
- //These only apply if you don't have increase agi and/or fusion and/or sprint
- if(speed == new_speed)
+ speed_rate -= val;
+ }
+
+ //GetMoveSlowValue()
{
- //Don't allow buff from non speed potion consumables to stack with equips!
- if(sc->data[SC_SPEEDUP0] && default_speed)
- new_speed -= new_speed * 25/100;
- else if(sc->data[SC_CARTBOOST])
- new_speed -= new_speed * 20/100;
- else if(sc->data[SC_BERSERK])
- new_speed -= new_speed * 20/100;
- else if(sc->data[SC_WINDWALK])
- new_speed -= new_speed * sc->data[SC_WINDWALK]->val3/100;
+ int val = 0;
+
+ if( sd && sc->data[SC_HIDING] && pc_checkskill(sd,RG_TUNNELDRIVE) > 0 )
+ val = 120 - 6 * pc_checkskill(sd,RG_TUNNELDRIVE);
+ else
+ if( sd && sc->data[SC_CHASEWALK] && sc->data[SC_CHASEWALK]->val3 < 0 )
+ val = sc->data[SC_CHASEWALK]->val3;
+ else
+ {
+ // Longing for Freedom cancels song/dance penalty
+ if( sc->data[SC_LONGING] )
+ val = max( val, 50 - 10 * sc->data[SC_LONGING]->val1 );
+ else
+ if( sd && sc->data[SC_DANCING] )
+ val = max( val, 500 - (40 + 10 * (sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_BARDDANCER)) * pc_checkskill(sd,(sd->status.sex?BA_MUSICALLESSON:DC_DANCINGLESSON)) );
+
+ if( sc->data[SC_DECREASEAGI] )
+ val = max( val, 25 );
+ if( sc->data[SC_QUAGMIRE] )
+ val = max( val, 50 );
+ if( sc->data[SC_DONTFORGETME] )
+ val = max( val, sc->data[SC_DONTFORGETME]->val3 );
+ if( sc->data[SC_CURSE] )
+ val = max( val, 300 );
+ if( sc->data[SC_CHASEWALK] )
+ val = max( val, sc->data[SC_CHASEWALK]->val3 );
+ if( sc->data[SC_WEDDING] )
+ val = max( val, 100 );
+ if( sc->data[SC_JOINTBEAT] && sc->data[SC_JOINTBEAT]->val2&(BREAK_ANKLE|BREAK_KNEE) )
+ val = max( val, (sc->data[SC_JOINTBEAT]->val2&BREAK_ANKLE ? 50 : 0) + (sc->data[SC_JOINTBEAT]->val2&BREAK_KNEE ? 30 : 0) );
+ if( sc->data[SC_CLOAKING] && (sc->data[SC_CLOAKING]->val4&1) == 0 )
+ val = max( val, sc->data[SC_CLOAKING]->val1 < 3 ? 300 : 30 - 3 * sc->data[SC_CLOAKING]->val1 );
+ if( sc->data[SC_GOSPEL] && sc->data[SC_GOSPEL]->val4 == BCT_ENEMY )
+ val = max( val, 75 );
+ if( sc->data[SC_SLOWDOWN] ) // Slow Potion
+ val = max( val, 100 );
+ if( sc->data[SC_GATLINGFEVER] )
+ val = max( val, 100 );
+ if( sc->data[SC_SUITON] )
+ val = max( val, sc->data[SC_SUITON]->val3 );
+ if( sc->data[SC_SWOO] )
+ val = max( val, 300 );
+
+ if( sd && sd->speed_rate + sd->speed_add_rate > 0 ) // permanent item-based speedup
+ val = max( val, sd->speed_rate + sd->speed_add_rate );
+ }
+
+ speed_rate += val;
}
- }
+ //GetMoveHasteValue1()
+ {
+ int val = 0;
+
+ if( sc->data[SC_SPEEDUP1] ) //FIXME: used both by NPC_AGIUP and Speed Potion script
+ val = max( val, 50 );
+ if( sc->data[SC_INCREASEAGI] )
+ val = max( val, 25 );
+ if( sc->data[SC_WINDWALK] )
+ val = max( val, 2 * sc->data[SC_WINDWALK]->val1 );
+ if( sc->data[SC_CARTBOOST] )
+ val = max( val, 20 );
+ if( sd && (sd->class_&MAPID_UPPERMASK) == MAPID_ASSASSIN && pc_checkskill(sd,TF_MISS) > 0 )
+ val = max( val, 1 * pc_checkskill(sd,TF_MISS) );
+ if( sc->data[SC_CLOAKING] && (sc->data[SC_CLOAKING]->val4&1) == 1 )
+ val = max( val, sc->data[SC_CLOAKING]->val1 >= 10 ? 25 : 3 * sc->data[SC_CLOAKING]->val1 - 3 );
+ if( sc->data[SC_BERSERK] )
+ val = max( val, 25 );
+ if( sc->data[SC_RUN] )
+ val = max( val, 55 );
+ if( sc->data[SC_AVOID] )
+ val = max( val, 10 * sc->data[SC_AVOID]->val1 );
+
+ //FIXME: official items use a single bonus for this [ultramage]
+ if( sc->data[SC_SPEEDUP0] ) // temporary item-based speedup
+ val = max( val, 25 );
+ if( sd && sd->speed_rate + sd->speed_add_rate < 0 ) // permanent item-based speedup
+ val = max( val, -(sd->speed_rate + sd->speed_add_rate) );
+
+ speed_rate -= val;
+ }
- speed = new_speed;
+ if( speed_rate < 40 )
+ speed_rate = 40;
+ }
- //% reductions (they stack)
- if(sc->data[SC_DANCING] && sc->data[SC_DANCING]->val3&0xFFFF)
- speed += speed*(sc->data[SC_DANCING]->val3&0xFFFF)/100;
- if(sc->data[SC_DECREASEAGI])
- speed = speed * 100/75;
- if(sc->data[SC_STEELBODY])
- speed = speed * 100/75;
- if(sc->data[SC_QUAGMIRE])
- speed = speed * 100/50;
- if(sc->data[SC_SUITON] && sc->data[SC_SUITON]->val3)
- speed = speed * 100/sc->data[SC_SUITON]->val3;
- if(sc->data[SC_DONTFORGETME])
- speed = speed * 100/sc->data[SC_DONTFORGETME]->val3;
- if(sc->data[SC_DEFENDER])
- speed = speed * 100/sc->data[SC_DEFENDER]->val3;
- if(sc->data[SC_GOSPEL] && sc->data[SC_GOSPEL]->val4 == BCT_ENEMY)
- speed = speed * 100/75;
- if(sc->data[SC_JOINTBEAT] && sc->data[SC_JOINTBEAT]->val2&(BREAK_ANKLE|BREAK_KNEE)) {
- speed = speed * 100/(100
- - ( sc->data[SC_JOINTBEAT]->val2&BREAK_ANKLE ? 50 : 0 )
- - ( sc->data[SC_JOINTBEAT]->val2&BREAK_KNEE ? 30 : 0 ));
+ //GetSpeed()
+ {
+ if( sd && pc_iscarton(sd) )
+ speed += speed * (50 - 5 * pc_checkskill(sd,MC_PUSHCART)) / 100;
+ if( speed_rate != 100 )
+ speed = speed * speed_rate / 100;
+ if( sc->data[SC_STEELBODY] )
+ speed = 200;
+ if( sc->data[SC_DEFENDER] )
+ speed = max(speed, 200);
}
- if(sc->data[SC_CLOAKING])
- speed = speed * 100 /(
- (sc->data[SC_CLOAKING]->val4&1?25:0) //Wall speed bonus
- +sc->data[SC_CLOAKING]->val3); //Normal adjustment bonus->
-
- if(sc->data[SC_LONGING])
- speed = speed * 100/sc->data[SC_LONGING]->val3;
- if(sc->data[SC_HIDING] && sc->data[SC_HIDING]->val3)
- speed = speed * 100/sc->data[SC_HIDING]->val3;
- if(sc->data[SC_CHASEWALK])
- speed = speed * 100/sc->data[SC_CHASEWALK]->val3;
- if(sc->data[SC_GATLINGFEVER])
- speed = speed * 100/75;
- if(sc->data[SC_SLOWDOWN])
- speed = speed * 100/75;
-
+
return (short)cap_value(speed,10,USHRT_MAX);
}
@@ -5133,16 +5148,11 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
if (val1 == CG_MOONLIT)
clif_status_change(bl,SI_MOONLIT,1);
val1|= (val3<<16);
- val3 = 0; //Tick duration/Speed penalty.
- //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));
- val3|= ((tick/1000)<<16)&0xFFFF0000; //Store tick in upper part of val3
+ val3 = tick/1000; //Tick duration
tick = 1000;
break;
case SC_LONGING:
val2 = 500-100*val1; //Aspd penalty.
- val3 = 50+10*val1; //Walk speed adjustment.
break;
case SC_EXPLOSIONSPIRITS:
val2 = 75 + 25*val1; //Cri bonus
@@ -5231,16 +5241,14 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
case SC_HIDING:
val2 = tick/1000;
tick = 1000;
- //Store speed penalty on val3.
- if(sd && (val3 = pc_checkskill(sd,RG_TUNNELDRIVE))>0)
- val3 = 20 + 6*val3;
+ val3 = 0; // unused, previously speed adjustment
val4 = val1+3; //Seconds before SP substraction happen.
break;
case SC_CHASEWALK:
val2 = tick>0?tick:10000; //Interval at which SP is drained.
- val3 = 65+val1*5; //Speed adjustment.
+ val3 = 35 - 5 * val1; //Speed adjustment.
if (sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_ROGUE)
- val3 += 60;
+ val3 -= 40;
val4 = 10+val1*2; //SP cost.
if (map_flag_gvg(bl->m)) val4 *= 5;
break;
@@ -5248,11 +5256,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
if (!sd) //Monsters should be able to walk with no penalties. [Skotlex]
val1 = 10;
val2 = tick>0?tick:60000; //SP consumption rate.
- val3 = 0;
- if (sd && (sd->class_&MAPID_UPPERMASK) == MAPID_ASSASSIN && (val3=pc_checkskill(sd,TF_MISS))>0)
- val3 *= -1; //Substract the Dodge speed bonus.
- val3+= 70+val1*3; //Speed adjustment without a wall.
- //With a wall, it is val3 +25.
+ val3 = 0; // unused, previously walk speed adjustment
//val4&1 signals the presence of a wall.
//val4&2 makes cloak not end on normal attacks [Skotlex]
//val4&4 makes cloak not end on using skills
@@ -5308,7 +5312,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
struct map_session_data *tsd;
int i;
val2 = 5 + 15*val1; //Damage reduction
- val3 = 65 + 5*val1; //Speed adjustment
+ val3 = 0; // unused, previously speed adjustment
val4 = 250 - 50*val1; //Aspd adjustment
if (sd)
@@ -5336,7 +5340,6 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
case SC_WINDWALK:
val2 = (val1+1)/2; // Flee bonus is 1/1/2/2/3/3/4/4/5/5
- val3 = 4*val2; //movement speed % increase is 4 times that
break;
case SC_JOINTBEAT:
@@ -5717,7 +5720,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
val4 = 5+5*val1; //Def reduction.
break;
case SC_AVOID:
- val2 = 10*val1; //Speed change rate.
+ //val2 = 10*val1; //Speed change rate.
break;
case SC_DEFENCE:
val2 = 2*val1; //Def bonus
@@ -5871,15 +5874,6 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
case SC_KAAHI:
val4 = -1;
break;
- //In case the speed reduction comes loaded incorrectly, prevent division by 0.
- case SC_DONTFORGETME:
- case SC_CLOAKING:
- case SC_LONGING:
- case SC_HIDING:
- case SC_CHASEWALK:
- case SC_DEFENDER:
- if (!val3) val3 = 100;
- break;
}
//Those that make you stop attacking/walking....
@@ -6866,11 +6860,8 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr data)
{
int s = 0;
int sp = 1;
- int counter = (sce->val3)>>16;
- if (--counter <= 0)
+ if (--sce->val3 <= 0)
break;
- sce->val3&= 0xFFFF; //Remove counter
- sce->val3|=(counter<<16);//Reset it.
switch(sce->val1&0xFFFF){
case BD_RICHMANKIM:
case BD_DRUMBATTLEFIELD:
@@ -6906,7 +6897,7 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr data)
s=10;
break;
}
- if (s && (counter%s == 0))
+ if( s != 0 && sce->val3 % s == 0 )
{
if (sc->data[SC_LONGING])
sp*= 3;