Вдохновленный отсутствием алкоголя и долгим сном я решил сжалиться над народом и описать изменения в системе расчета скорости передвижения чаров чаров. Сразу обращаю ваше внимание, что значение скорости - это время, которое требуется для прохождения некого расстояния, поэтому чем выше значение переменной speed, тем медленнее вы двигаетесь. Итак, старая система расчета: Код: static unsigned short status_calc_speed(struct block_list *bl, struct status_change *sc, int speed) { //Default speed coming in means there's no speed_rate adjustments. int new_speed = speed; bool default_speed = (speed == DEFAULT_WALK_SPEED); if(!sc || !sc->count) return cap_value(speed,10,USHRT_MAX); // 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) { //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; } } speed = new_speed; //% 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 )); } 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); } Новая система: Код: 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; if( sc == NULL ) return cap_value(speed,10,USHRT_MAX); if( sd && sd->ud.skilltimer != -1 && pc_checkskill(sd,SA_FREECAST) > 0 ) { speed_rate = 175 - 5 * pc_checkskill(sd,SA_FREECAST); } else { speed_rate = 100; //GetMoveHasteValue2() { int val = 0; if( sc->data[SC_FUSION] ) val = 25; else if( sd && pc_isriding(sd) ) val = 25; speed_rate -= val; } //GetMoveSlowValue() { 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; } if( speed_rate < 40 ) speed_rate = 40; } //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); } return (short)cap_value(speed,10,USHRT_MAX); } Происхождение большинства статусов понятно, поэтому я задам сразу соответствия статусам, которые неизвестны широкой публике SC_SWOO - статус замедления, порождаемый скиллом линкера Eswoo, ES-магия не может быть применена на чаров. SC_FUSION - статус ускорения, порождаемый скиллом Star Gladiator'a Union SC_AVOID - статус ускорения, пораждаемый скиллом гомункула Lif под названием Emergency Avoid Старый код: Код: if ((skill=pc_checkskill(sd,SA_FREECAST))>0) { //Store casting walk speed for quick restoration.[Skotlex] sd->prev_speed = status->speed * (175-5*skill)/100; if(sd->ud.skilltimer != -1) { //Swap speed. skill = status->speed; status->speed = sd->prev_speed; sd->prev_speed = skill; } } } Формула расчета скорости передвижения сага при фрикасте вместе с быстрым переключением (между скоростью во время каста и вне её). Код: int speed_rate; if( sc == NULL ) return cap_value(speed,10,USHRT_MAX); if( sd && sd->ud.skilltimer != -1 && pc_checkskill(sd,SA_FREECAST) > 0 ) { speed_rate = 175 - 5 * pc_checkskill(sd,SA_FREECAST); } else { speed_rate = 100; Теперь только расчет, переключение вынесено в отдельную функцию ниже. Мелкая, но приятная оптимизация кода, изменений механики нет. Код: void status_freecast_switch(struct map_session_data *sd) { struct status_data *status; unsigned short b_speed,tmp; status = &sd->battle_status; b_speed = status->speed; tmp = status->speed; status->speed = sd->prev_speed; sd->prev_speed = tmp; tmp = status->adelay; status->adelay = sd->prev_adelay; sd->prev_adelay = tmp; if(b_speed != status->speed) clif_updatestatus(sd,SP_SPEED); } Старый код: Код: // 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; Раньше бонус спид потов и эмердженси эскейпа складывалась с любым ускорением, но либо одно, либо другое, то есть они не складывались между собой, ускорение 5-го эвойда равно ускорению спид пота. Между собой помимо этого складывались: Agi Up, Union, Run (бег у Тыквообразных). Старый код: Код: //These only apply if you don't have increase agi and/or fusion and/or sprint if(speed == new_speed) { //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; } } Если вы были лишены указанных выше бонусов (аги и т.д.), то на вас действовали Баджи, Карт Буст, Берсерк (Frenzy), ВВ. Опять-таки только что-то одно, приоритет виден из кода (по принципу сверху вниз). Плохо вам делали в полном объеме Код: speed = new_speed; //% 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 )); } 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); } Ваша скрость уменьшалась единым образом, то есть можно было замедлить вас настолько, что стоппинг ЛоВа показался бы вам утренней летней прогулкой. Замедляли вас: Квага, Стил Бади, процесс танцевания/песни, лужа Нинзи, Дефендер, Витал страйки и т.д.. К чему это приводило? К примеру, вы стоите в Слоу Грейсе, под квагой, лужей в дефендере и под дикриз аги...В общем в зависимости от статов гипси вы можете быть замедлены в 12 раз. Разумеется тогда мы начинаем плакать в теме о ГВ, что не шлось нам в прекасте и Афена шлак, читы кругом. Итак, приступим в новшествам: Код: //GetMoveHasteValue2() { int val = 0; if( sc->data[SC_FUSION] ) val = 25; else if( sd && pc_isriding(sd) ) val = 25; speed_rate -= val; } Складывается теперь с остальными видами ускорения теперь только две вещи, Union и Peco Riding. Код: //GetMoveSlowValue() { 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 ); } Казалось бы, что нас всех замедлили, но это не так, теперь на нас действует только одно замедление, сильнейшее, то есть, стоя в слоу грейсе, вы не получите пенальти от дикриз аги. Пенальти на скорость перестали складываться между собой. Кроме того, Eswoo и Curse стали снижать скорость заметно меньше. Код: //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; } Образом анологичным замедлениям поступили с ускорениями, теперь действует только что-то из списка: 1) Клок у стены 2) Аги Ап 3) ВВ 4) Спид поты 5) Вещи а-ля бладик акс, слейпниры 6) Бег тыкв 7) Эвойд Лифа 8) Карт Буст 9) Баджи И на последок: Код: //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); } Незнание пушкарта всегда снижает скорость. Монки в стилбади имеют фиксированную скорость, которая меньше нормальной в два раза. Чар под дефендером всегда двигается в два раза медленнее (сакра?) и не может двигаться быстрее, тем не менее все замедления действуют в полном объеме. Чары не могут двигаться быстрее нормы более чем в 2,5 раза. Что это меняет в игре в целом? Теперь крузы под дефендером и атакеры, которым попался подготовленный деф, не будут играть в Нэо/Макс Пейна при проходе локи, то есть выйти с локи ногами будет все-таки реально (Я имею в виду нормальный деф). С другой стороны исчезнут реактивные ЛК-лотерейщики и ГМы, которые багают реколлить со скоростью пылесоса. Тем не менее в свете ослабления замедления от кваги набор замедляющих площадок в прекасте изменится едва ли, ибо срезки дексы, аги и аспд никак не поменялись.
По привычки, как лк в душЕ, расстроился за блуди аксы. Но потом вспомнил что тут найта делать не буду и даже обрадовался. Будет больше шансов успеть добежать до импа до того, как его расколупает парочка быстроногих лордов.
на курс пфф, но за что есву порезали?...нас всех замедлили...видимо в граффити пришли работать эстонцы...
на правах нытья: в граффити падонки одни. как теперь на гв гонять от руахов и сайтов, смеясь над бестолковыми визами и пристами, которые не могут тебя найти, потому что у стен ты бох? предлагаю убрать вообще у ассасинов клок. а то чо все видимые а ососины нивидимые нипарядак. ушёл писать письмо в граффити.\
В Чейзе под линком и хайде при туннел драйве вы игнорируете все замедления, бонус ускорения чейза складывается с остальными, ибо высчитывается в части замедлений.