summaryrefslogtreecommitdiff
path: root/src/map/unit.c
diff options
context:
space:
mode:
authorskotlex <skotlex@54d463be-8e91-2dee-dedb-b68131a5f0ec>2006-05-27 18:08:30 +0000
committerskotlex <skotlex@54d463be-8e91-2dee-dedb-b68131a5f0ec>2006-05-27 18:08:30 +0000
commitcbccd8815d0db4828d40e278c999b87eeb103e67 (patch)
tree3a49b9ab73c31145b94a3ede8c8eae5eef3b0b2c /src/map/unit.c
parent763352f450c239778ab461d4e11d5469049ec0fe (diff)
downloadhercules-cbccd8815d0db4828d40e278c999b87eeb103e67.tar.gz
hercules-cbccd8815d0db4828d40e278c999b87eeb103e67.tar.bz2
hercules-cbccd8815d0db4828d40e278c999b87eeb103e67.tar.xz
hercules-cbccd8815d0db4828d40e278c999b87eeb103e67.zip
- Added structure status_data which holds status-related information (str, agi, etc, speed, amotion, adelay, dmotion, weapon-damage, race, size, etc) and weapon_atk structure with the weapon specific info (atk, atk2, element) to be used by all combat structures (TODO: Homun needs to be updated to use it)
- Cleaned up TBL_PC, TBL_MOB, TBL_PC and mob_db structures to use status_data. - Set the NPC-Change Attribute duration on Time1, updated their max to 1 in the db. - Berserk's HP cost interval is now defined as time2. - Split damage received functions into pc_damage/pc_dead and mob_damage/mob_dead - Rewrote the @heal related functions to use the new status_* healing functions. - Added status functions to deal with damage and healing (status_damage, status_heal, status_percent_change) and a bunch of defines for easier handling of them (status_percent_heal, status_percent_damage, status_fix_damage, status_kill, etc) - Splitted mob_once_spawn into two. mob_once_spawn_sub creates the mob instance without spawning it. - Added defines for Elements (ELE_*) - Modified battle_calc_(weapon/magic/misc)_attack to use the status data structure. - Rewrote and cleaned up battle_calc_misc_attack - Merged config options pc_attack_attr_none, mob_attack_attr_none, pet_attack_attr_none into attack_attr_none (type 4) - Removed config options player_defense_type, monster_defense_type, pet_defense_type in favor of weapon_defense_type - Cleaned up pet.c to stop invoking status_calc_pc when unnecessary - Modified skill_calc_heal to take into account the MEDITATION bonus. - Cleaned up code of Adjustment, Madness Cancel and other GS/NJ skills inside skill_check_condition - Added status change SC_MODECHANGE which handles mob state changes (this SC is continous until manually ended, eg: like Weight50) - Modified Slim Pitcher so it will work when casted by non-players. Will now also work with SP-healing items. - Rewrote Freedom of Cast code to use function status_freecast_switch to switch adelay/speed when cast begins/ends. - Modified Magic Power to store amplified MATK/MATK2 in val3/val4 for easier updating when used in conjunction with ground skills. - Fixed Asura Strike being usable from within a combo regardless of combo skill. - Modifed SC_DANCING to store speed-change in val3 (it is shared with skill duration...) - Added StatusChangeFlagTable to store which statuses are changed by each SC - Added SCB_* constants to specify the different stats that each sc changes. SCB_PC is the only one that means a change hardcoded in status_calc_pc, the rest are handled by status_calc_bl - Added some helper functions to simplify with basic status calculations (status_base_atk, status_calc_misc, status_base_pc_maxhp, status_base_pc_maxsp) - Added status_calc_mob which calculates initial status and special base status alterations (HP changes, stat changes due to big/small mobs, etc) - Made all the status_calc functions static. - Added status_calc_bl_sub_pc for PC related calculations that must happen after status-change adjustments. - Added status_calc_bl which does status-change related calculations using as base the base_status of the bl object and the SCB_* flag passed. - Added status_get_status_data and status_get_base_status to retrieve the bl objects current status_data and basic status_data (current never returns null, instead it returns a dummy structure with basic data) - The main switch in status_change_start now only sets the tick and val values, therefore it is skipped when loading (flag&4) - Cleaned up status_change_start and replaced many of the ex-japanese comments for english ones. - Changed Hiding to store the speed penalty on val3. val4 stores interval SP cost. - Changed Chase Walk to store Speed adjustment on val3, sp cost in val4 - Changed Cloaking to store speed penalty on val3, val4&2 signals wall-present, val4&1 is infinite cloaking. - Changed Wind walk to store speed bonus on val3 - Rewrote Marionette Control to store the status to add/substract in val3/val4, it now works on anyone (players/mobs) - Changed Improve concentration to store Card bonuses (which are not counted for total % increase) on val3/val4 - Changed SC_ADRENALINE, SC_CONCENTRATION, SC_ANGELUS, SC_IMPOSITIO, SC_MELTDOWN, SC_TRUESIGHT, SC_SUN_COMFORT, SC_MOON_COMFORT, SC_STAR_COMFORT, SC_QUAGMIRE, SC_GATLINGFEVER to store the bonus modifiers in their val values rather than calculate them in status_calc_* - Status_change_start/end will use clif_status_load rather than clif_status_change when related bl is not on a map. - Modified status_change_timer to use the status_charge function rather than directly substracting SP - Added SC_ELEMENTALCHANGE to modify someone's base defense element. - pc_clean_skilltree will now also remove item-granted skills. - Learning skills will now only invoke status_calc_pc when the skill is passive. - Cleaned up pc_steal_coin - Cleaned up pc_check_base/job_lvup to only invoke the lv-up related packets and functions ONCE regardless of skill-levls earned. - Cleaned up pc_ regen related functions. - Made player-sprite mobs have item pickup animation and walkdelay when taking items. - Cleaned up mob_dead code. - Removed paramb, parame from struct map_session_data, replaced them by param_bonus[6],param_equip[6] - mob special ai state 3 signals summon flora. - Moved petDB pet_hungry_timer vars from TBL_PC to TBL_PET - Cleaned up some pet functions, made the menu functions receive as argument both pet and master. - Clones will copy a player's base status rather than battle status (so status-change alterations are not cloned) git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@6791 54d463be-8e91-2dee-dedb-b68131a5f0ec
Diffstat (limited to 'src/map/unit.c')
-rw-r--r--src/map/unit.c132
1 files changed, 54 insertions, 78 deletions
diff --git a/src/map/unit.c b/src/map/unit.c
index 9fc3003a1..39b8c45dc 100644
--- a/src/map/unit.c
+++ b/src/map/unit.c
@@ -638,11 +638,13 @@ int unit_can_move(struct block_list *bl)
sc->data[SC_AUTOCOUNTER].timer !=-1 ||
sc->data[SC_TRICKDEAD].timer !=-1 ||
sc->data[SC_BLADESTOP].timer !=-1 ||
+ sc->data[SC_BLADESTOP_WAIT].timer !=-1 ||
sc->data[SC_SPIDERWEB].timer !=-1 ||
(sc->data[SC_DANCING].timer !=-1 && (
(sc->data[SC_DANCING].val4 && sc->data[SC_LONGING].timer == -1) ||
sc->data[SC_DANCING].val1 == CG_HERMODE //cannot move while Hermod is active.
)) ||
+ sc->data[SC_MOONLIT].timer != -1 ||
(sc->data[SC_GOSPEL].timer !=-1 && sc->data[SC_GOSPEL].val4 == BCT_SELF) || // cannot move while gospel is in effect
sc->data[SC_STOP].timer != -1 ||
sc->data[SC_CLOSECONFINE].timer != -1 ||
@@ -688,6 +690,7 @@ int unit_set_walkdelay(struct block_list *bl, unsigned int tick, int delay, int
int unit_skilluse_id2(struct block_list *src, int target_id, int skill_num, int skill_lv, int casttime, int castcancel) {
struct unit_data *ud;
+ struct status_data *tstatus;
struct status_change *sc;
struct map_session_data *sd = NULL;
struct block_list * target = NULL;
@@ -763,16 +766,17 @@ int unit_skilluse_id2(struct block_list *src, int target_id, int skill_num, int
if(!status_check_skilluse(src, target, skill_num, 0))
return 0;
+ tstatus = status_get_status_data(target);
//直前のスキル状況の記録
if(sd) {
switch(skill_num){
case SA_CASTCANCEL:
- if(ud->skillid != skill_num){ //キャストキャンセル自体は覚えない
+ if(ud->skillid != skill_num){
sd->skillid_old = ud->skillid;
sd->skilllv_old = ud->skilllv;
break;
}
- case BD_ENCORE: /* アンコール */
+ case BD_ENCORE:
//Prevent using the dance skill if you no longer have the skill in your tree.
if(!sd->skillid_dance || pc_checkskill(sd,sd->skillid_dance)<=0){
clif_skill_fail(sd,skill_num,0,0);
@@ -780,15 +784,15 @@ int unit_skilluse_id2(struct block_list *src, int target_id, int skill_num, int
}
sd->skillid_old = skill_num;
break;
- case BD_LULLABY: /* 子守歌 */
- case BD_RICHMANKIM: /* ニヨルドの宴 */
- case BD_ETERNALCHAOS: /* 永遠の?ャ沌 */
- case BD_DRUMBATTLEFIELD: /* ?太鼓の響き */
- case BD_RINGNIBELUNGEN: /* ニ?ベルングの指輪 */
- case BD_ROKISWEIL: /* ?キの叫び */
- case BD_INTOABYSS: /* ?[淵の中に */
- case BD_SIEGFRIED: /* 不死?gのジ?クフリ?ド */
- case CG_MOONLIT: /* 月明りの?に落ちる花びら */
+ case BD_LULLABY:
+ case BD_RICHMANKIM:
+ case BD_ETERNALCHAOS:
+ case BD_DRUMBATTLEFIELD:
+ case BD_RINGNIBELUNGEN:
+ case BD_ROKISWEIL:
+ case BD_INTOABYSS:
+ case BD_SIEGFRIED:
+ case CG_MOONLIT:
if (battle_config.player_skill_partner_check &&
(!battle_config.gm_skilluncond || pc_isGM(sd) < battle_config.gm_skilluncond) &&
(skill_check_pc_partner(sd, skill_num, &skill_lv, 1, 0) < 1)
@@ -825,20 +829,19 @@ int unit_skilluse_id2(struct block_list *src, int target_id, int skill_num, int
//temp: Used to signal force cast now.
temp = 0;
- /* 何か特殊な処理が必要 */
- // 失敗判定はskill_check_condition() に書くこと
+
switch(skill_num){
- case ALL_RESURRECTION: /* リザレクション */
- if(battle_check_undead(status_get_race(target),status_get_elem_type(target))){ /* 敵がアンデッドなら */
- temp=1; /* ターンアンデットと同じ詠唱時間 */
+ case ALL_RESURRECTION:
+ if(battle_check_undead(tstatus->race,tstatus->def_ele)){
+ temp=1;
casttime = skill_castfix(src, PR_TURNUNDEAD, skill_lv);
}
break;
- case MO_FINGEROFFENSIVE: /* 指弾 */
+ case MO_FINGEROFFENSIVE:
if(sd)
casttime += casttime * ((skill_lv > sd->spiritball)? sd->spiritball:skill_lv);
break;
- case MO_EXTREMITYFIST: /*阿?C羅覇鳳?*/
+ case MO_EXTREMITYFIST:
if (sc && sc->data[SC_COMBO].timer != -1 &&
(sc->data[SC_COMBO].val1 == MO_COMBOFINISH ||
sc->data[SC_COMBO].val1 == CH_TIGERFIST ||
@@ -854,37 +857,35 @@ int unit_skilluse_id2(struct block_list *src, int target_id, int skill_num, int
case SA_SPELLBREAKER:
temp =1;
break;
- case KN_CHARGEATK: //チャージアタック
+ case KN_CHARGEATK:
//Taken from jA: Casttime is increased by dist/3*100%
casttime = casttime * ((distance_bl(src,target)-1)/3+1);
break;
}
- //メモライズ状態ならキャストタイムが1/2
if (sc && sc->data[SC_MEMORIZE].timer != -1 && casttime > 0) {
casttime = casttime/2;
if ((--sc->data[SC_MEMORIZE].val2) <= 0)
status_change_end(src, SC_MEMORIZE, -1);
}
- if( casttime>0 || temp){ /* 詠唱が必要 */
+ if( casttime>0 || temp){
clif_skillcasting(src, src->id, target_id, 0,0, skill_num,casttime);
- /* 詠唱反応モンスター */
if (sd && target->type == BL_MOB)
{
TBL_MOB *md = (TBL_MOB*)target;
mobskill_event(md, src, tick, -1); //Cast targetted skill event.
//temp: used to store mob's mode now.
- if ((temp=status_get_mode(target))&MD_CASTSENSOR &&
+ if (tstatus->mode&MD_CASTSENSOR &&
battle_check_target(target, src, BCT_ENEMY) > 0)
{
switch (md->state.skillstate) {
case MSS_ANGRY:
case MSS_RUSH:
case MSS_FOLLOW:
- if (!(temp&(MD_AGGRESSIVE|MD_ANGRY)))
+ if (!(tstatus->mode&(MD_AGGRESSIVE|MD_ANGRY)))
break; //Only Aggressive mobs change target while chasing.
case MSS_IDLE:
case MSS_WALK:
@@ -906,22 +907,19 @@ int unit_skilluse_id2(struct block_list *src, int target_id, int skill_num, int
ud->skillid = skill_num;
ud->skilllv = skill_lv;
- if(sc && sc->data[SC_CLOAKING].timer != -1 && !sc->data[SC_CLOAKING].val4 && skill_num != AS_CLOAKING)
+ if(sc && sc->data[SC_CLOAKING].timer != -1 &&
+ !(sc->data[SC_CLOAKING].val4&1) && skill_num != AS_CLOAKING)
status_change_end(src,SC_CLOAKING,-1);
if(casttime > 0) {
ud->skilltimer = add_timer( tick+casttime, skill_castend_id, src->id, 0 );
- //temp: used to hold FreeCast's level
- if(sd && (temp = pc_checkskill(sd,SA_FREECAST)) > 0)
- status_quick_recalc_speed (sd, SA_FREECAST, temp, 1);
+ if(sd && pc_checkskill(sd,SA_FREECAST))
+ status_freecast_switch(sd);
else
unit_stop_walking(src,1);
}
- else {
-// if(skill_num != SA_CASTCANCEL)
-// ud->skilltimer = -1; //This check is done above...
+ else
skill_castend_id(ud->skilltimer,tick,src->id,0);
- }
return 1;
}
@@ -987,7 +985,6 @@ int unit_skilluse_pos2( struct block_list *src, int skill_x, int skill_y, int sk
unit_stop_attack(src);
ud->state.skillcastcancel = castcancel;
- //?モライズ?態ならキャストタイムが1/3
if (sc && sc->data[SC_MEMORIZE].timer != -1 && casttime > 0){
casttime = casttime/3;
if ((--sc->data[SC_MEMORIZE].val2)<=0)
@@ -995,12 +992,11 @@ int unit_skilluse_pos2( struct block_list *src, int skill_x, int skill_y, int sk
}
if( casttime>0 ) {
- /* 詠唱が必要 */
- unit_stop_walking( src, 1); // 歩行停止
+ unit_stop_walking( src, 1);
clif_skillcasting(src, src->id, 0, skill_x,skill_y, skill_num,casttime);
}
- if( casttime<=0 ) /* 詠唱の無いものはキャンセルされない */
+ if( casttime<=0 )
ud->state.skillcastcancel=0;
ud->canact_tick = tick + casttime + 100;
@@ -1010,14 +1006,14 @@ int unit_skilluse_pos2( struct block_list *src, int skill_x, int skill_y, int sk
ud->skilly = skill_y;
ud->skilltarget = 0;
- if (sc && sc->data[SC_CLOAKING].timer != -1 && !sc->data[SC_CLOAKING].val4)
+ if (sc && sc->data[SC_CLOAKING].timer != -1 &&
+ !(sc->data[SC_CLOAKING].val4&1))
status_change_end(src,SC_CLOAKING,-1);
if(casttime > 0) {
ud->skilltimer = add_timer( tick+casttime, skill_castend_pos, src->id, 0 );
- //castcancel recylced to store FREECAST lv.
- if(sd && (castcancel = pc_checkskill(sd,SA_FREECAST)) > 0)
- status_quick_recalc_speed (sd, SA_FREECAST, castcancel, 1);
+ if(sd && pc_checkskill(sd,SA_FREECAST))
+ status_freecast_switch(sd);
else
unit_stop_walking(src,1);
}
@@ -1030,7 +1026,6 @@ int unit_skilluse_pos2( struct block_list *src, int skill_x, int skill_y, int sk
static int unit_attack_timer(int tid,unsigned int tick,int id,int data);
-// 攻撃停止
int unit_stop_attack(struct block_list *bl)
{
struct unit_data *ud = unit_bl2ud(bl);
@@ -1182,6 +1177,7 @@ static int unit_attack_timer_sub(struct block_list* src, int tid, unsigned int t
{
struct block_list *target;
struct unit_data *ud;
+ struct status_data *sstatus;
struct map_session_data *sd = NULL;
struct mob_data *md = NULL;
int range;
@@ -1207,6 +1203,8 @@ static int unit_attack_timer_sub(struct block_list* src, int tid, unsigned int t
if(src->m != target->m || status_isdead(src) || status_isdead(target) || !status_check_skilluse(src, target, 0, 0))
return 0;
+ sstatus = status_get_status_data(src);
+
if(!battle_config.sdelay_attack_enable &&
DIFF_TICK(ud->canact_tick,tick) > 0 &&
(!sd || pc_checkskill(sd,SA_FREECAST) <= 0)
@@ -1224,9 +1222,9 @@ static int unit_attack_timer_sub(struct block_list* src, int tid, unsigned int t
return 1;
}
- range = status_get_range(src);
+ range = sstatus->rhw.range;
- if(!sd || sd->status.weapon != 11) range++; //Dunno why everyone but bows gets this extra range...
+ if(!sd || sd->status.weapon != W_BOW) range++; //Dunno why everyone but bows gets this extra range...
if(unit_is_walking(target)) range++; //Extra range when chasing
if(!check_distance_bl(src,target,range) ) {
@@ -1259,7 +1257,7 @@ static int unit_attack_timer_sub(struct block_list* src, int tid, unsigned int t
if(md) {
if (mobskill_use(md,tick,-1))
return 1;
- if (status_get_mode(src)&MD_ASSIST && DIFF_TICK(md->last_linktime, tick) < MIN_MOBLINKTIME)
+ if (sstatus->mode&MD_ASSIST && DIFF_TICK(md->last_linktime, tick) < MIN_MOBLINKTIME)
{ // Link monsters nearby [Skotlex]
md->last_linktime = tick;
map_foreachinrange(mob_linksearch, src, md->db->range2,
@@ -1272,17 +1270,15 @@ static int unit_attack_timer_sub(struct block_list* src, int tid, unsigned int t
map_freeblock_lock();
ud->attacktarget_lv = battle_weapon_attack(src,target,tick,0);
- if(sd && sd->status.pet_id > 0 && sd->pd && sd->petDB && battle_config.pet_attack_support)
+ if(sd && sd->status.pet_id > 0 && sd->pd && battle_config.pet_attack_support)
pet_target_check(sd,target,0);
map_freeblock_unlock();
- if(ud->skilltimer != -1 && sd && (range = pc_checkskill(sd,SA_FREECAST)) > 0 ) // フリーキャスト
- ud->attackabletime = tick + (status_get_adelay(src)*(150 - range*5)/100);
- else
- ud->attackabletime = tick + status_get_adelay(src);
+
+ud->attackabletime = tick + sstatus->adelay;
// You can't move if you can't attack neither.
- unit_set_walkdelay(src, tick, status_get_amotion(src), 1);
+ unit_set_walkdelay(src, tick, sstatus->amotion, 1);
}
if(ud->state.attack_continue)
@@ -1329,8 +1325,8 @@ int unit_skillcastcancel(struct block_list *bl,int type)
}
ud->canact_tick=tick;
- if(sd && (skill = pc_checkskill(sd,SA_FREECAST)) > 0)
- status_quick_recalc_speed(sd, SA_FREECAST, skill, 0); //Updated to use calc_speed [Skotlex]
+ if(sd && pc_checkskill(sd,SA_FREECAST))
+ status_freecast_switch(sd);
if(type&1 && sd)
skill = sd->skillid_old;
@@ -1398,7 +1394,7 @@ int unit_fixdamage(struct block_list *src,struct block_list *target,unsigned int
if(damage+damage2 <= 0)
return 0;
- return battle_damage(src,target,damage+damage2,clif_damage(target,target,tick,sdelay,ddelay,damage,div,type,damage2),0);
+ return status_fix_damage(src,target,damage+damage2,clif_damage(target,target,tick,sdelay,ddelay,damage,div,type,damage2));
}
/*==========================================
* 自分をロックしている対象の数を返す
@@ -1413,18 +1409,6 @@ int unit_counttargeted(struct block_list *bl,int target_lv)
}
/*==========================================
- * idを攻撃しているPCの攻撃を停止
- * clif_foreachclientのcallback関数
- *------------------------------------------
- */
-int unit_mobstopattacked(struct map_session_data *sd,va_list ap)
-{
- int id=va_arg(ap,int);
- if(sd->ud.target==id)
- unit_stop_attack(&sd->bl);
- return 0;
-}
-/*==========================================
* 見た目のサイズを変更する
*------------------------------------------
*/
@@ -1558,12 +1542,9 @@ int unit_remove_map(struct block_list *bl, int clrtype) {
if (md->master_id) md->master_dist = 0;
if (clrtype == 1) { //Death.
md->last_deadtime=gettick();
-// Isn't this too much? Why not let the attack-timer fail when the mob is dead? [Skotlex]
-// clif_foreachclient(unit_mobstopattacked,md->bl.id);
if(md->deletetimer!=-1)
delete_timer(md->deletetimer,mob_timer_delete);
md->deletetimer=-1;
- md->hp=0;
if(pcdb_checkid(md->vd->class_)) //Player mobs are not removed automatically by the client.
clif_clearchar_delay(gettick()+3000,bl,0);
mob_deleteslave(md);
@@ -1591,10 +1572,7 @@ int unit_remove_map(struct block_list *bl, int clrtype) {
intif_delete_petdata(sd->status.pet_id);
sd->status.pet_id = 0;
sd->pd = NULL;
- sd->petDB = NULL;
pd->msd = NULL;
- if(battle_config.pet_status_support)
- status_calc_pc(sd,2);
map_delblock(bl);
unit_free(bl);
map_freeblock_unlock();
@@ -1661,8 +1639,7 @@ int unit_free(struct block_list *bl) {
} else if( bl->type == BL_PET ) {
struct pet_data *pd = (struct pet_data*)bl;
struct map_session_data *sd = pd->msd;
- if(sd && sd->pet_hungry_timer != -1)
- pet_hungry_timer_delete(sd);
+ pet_hungry_timer_delete(pd);
if (pd->a_skill)
{
aFree(pd->a_skill);
@@ -1700,11 +1677,6 @@ int unit_free(struct block_list *bl) {
aFree (pd->loot);
pd->loot = NULL;
}
- if (pd->status)
- {
- aFree(pd->status);
- pd->status = NULL;
- }
if (sd) sd->pd = NULL;
} else if(bl->type == BL_MOB) {
struct mob_data *md = (struct mob_data*)bl;
@@ -1728,6 +1700,10 @@ int unit_free(struct block_list *bl) {
aFree(md->spawn);
md->spawn = NULL;
}
+ if(md->base_status) {
+ aFree(md->base_status);
+ md->base_status = NULL;
+ }
if(mob_is_clone(md->class_))
mob_clone_delete(md->class_);
}