summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorskotlex <skotlex@54d463be-8e91-2dee-dedb-b68131a5f0ec>2006-07-17 16:16:51 +0000
committerskotlex <skotlex@54d463be-8e91-2dee-dedb-b68131a5f0ec>2006-07-17 16:16:51 +0000
commit4a2c67dc47ffc7c33eea340ea96e3d0ba57e359e (patch)
tree1005a1e32bfedd0711c3ffb9f1b3e816cfa87d6a /src
parente378e27b012798c880f27e25c7471eb9cc537499 (diff)
downloadhercules-4a2c67dc47ffc7c33eea340ea96e3d0ba57e359e.tar.gz
hercules-4a2c67dc47ffc7c33eea340ea96e3d0ba57e359e.tar.bz2
hercules-4a2c67dc47ffc7c33eea340ea96e3d0ba57e359e.tar.xz
hercules-4a2c67dc47ffc7c33eea340ea96e3d0ba57e359e.zip
- Should have fixed the Cart Termination damage code to be scaled correctly when you change the max cart weight. Thanks to The Ultra Mage for the error clarification.
- Implemented Grandcross weird property where if there's noone on the path it'll hit twice for the skill's reported damage, and when there is (or you cant knockback the target) it'll do a splash attack that hits twice for 500% to all affected targets. - Some cleaning of the combo code. TK Rankers will now get their combo-time extended each time they trigger a kick, enabling them to do "unlimited combos". - Modified the autosave function to use a sweep across the player db instead of across connected clients. This will cause non-connected players (like autotraders) to also be saved on a regular interval, may help with possible data-loss from said characters on unclean shutdowns. - Added function map_foreachpc - Removed the code that forces aggressive mobs to go after a Homun instead of their master (no reason why there should be such a condition). git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@7721 54d463be-8e91-2dee-dedb-b68131a5f0ec
Diffstat (limited to 'src')
-rw-r--r--src/map/battle.c8
-rw-r--r--src/map/map.c7
-rw-r--r--src/map/map.h1
-rw-r--r--src/map/mob.c4
-rw-r--r--src/map/pc.c50
-rw-r--r--src/map/skill.c95
-rw-r--r--src/map/status.c3
7 files changed, 98 insertions, 70 deletions
diff --git a/src/map/battle.c b/src/map/battle.c
index 929b4494c..e47490ee6 100644
--- a/src/map/battle.c
+++ b/src/map/battle.c
@@ -1437,9 +1437,8 @@ static struct Damage battle_calc_weapon_attack(
if (i < 1) i = 1;
//Preserve damage ratio when max cart weight is changed.
if(sd && sd->cart_weight && sd->cart_max_weight)
-// FIXME: Something is wrong with this check! But what...? [Skotlex]
-// skillratio += (sd->cart_weight * 80000) / (i * sd->cart_max_weight) - 100;
- skillratio += sd->cart_weight/i - 100;
+ skillratio += sd->cart_weight/i * 80000/sd->cart_max_weight - 100;
+// skillratio += sd->cart_weight/i - 100;
else if (!sd)
skillratio += 80000 / i - 100;
flag.cardfix = 0;
@@ -2337,7 +2336,8 @@ struct Damage battle_calc_magic_attack(
if(skill_num == CR_GRANDCROSS || skill_num == NPC_GRANDDARKNESS)
{ //Apply the physical part of the skill's damage. [Skotlex]
struct Damage wd = battle_calc_weapon_attack(src,target,skill_num,skill_lv,mflag);
- ad.damage = (wd.damage + ad.damage) * (100 + 40*skill_lv)/100;
+ //When mflag, this is a no-splash attack, damage gets a bonus of 100%
+ ad.damage = (wd.damage + ad.damage) * ((mflag?200:100) + 40*skill_lv)/100;
if(src==target)
{
if (src->type == BL_PC)
diff --git a/src/map/map.c b/src/map/map.c
index a34805997..e1662fd71 100644
--- a/src/map/map.c
+++ b/src/map/map.c
@@ -1846,6 +1846,13 @@ struct map_session_data** map_getallusers(int *users) {
return all_sd;
}
+void map_foreachpc(int (*func)(DBKey,void*,va_list),...) {
+ va_list ap;
+ va_start(ap,func);
+ pc_db->foreach(pc_db,func,ap);
+ va_end(ap);
+}
+
/*==========================================
* id_db?‚Ì‘S‚Ä‚Éfunc‚ð?s
*------------------------------------------
diff --git a/src/map/map.h b/src/map/map.h
index a82f8bee1..fec279850 100644
--- a/src/map/map.h
+++ b/src/map/map.h
@@ -1342,6 +1342,7 @@ int map_eraseallipport(void);
void map_addiddb(struct block_list *);
void map_deliddb(struct block_list *bl);
struct map_session_data** map_getallusers(int *users);
+void map_foreachpc(int (*func)(DBKey,void*,va_list),...);
int map_foreachiddb(int (*)(DBKey,void*,va_list),...);
void map_addnickdb(struct map_session_data *);
struct map_session_data * map_nick2sd(char*);
diff --git a/src/map/mob.c b/src/map/mob.c
index 3e425f595..72d0a8aaa 100644
--- a/src/map/mob.c
+++ b/src/map/mob.c
@@ -762,7 +762,6 @@ int mob_target(struct mob_data *md,struct block_list *bl,int dist)
*/
static int mob_ai_sub_hard_activesearch(struct block_list *bl,va_list ap)
{
- struct map_session_data *sd;
struct mob_data *md;
struct block_list **target;
int dist;
@@ -789,9 +788,6 @@ static int mob_ai_sub_hard_activesearch(struct block_list *bl,va_list ap)
if (((TBL_PC*)bl)->state.gangsterparadise &&
!(status_get_mode(&md->bl)&MD_BOSS))
return 0; //Gangster paradise protection.
- sd = (TBL_PC*)bl; //[orn] monster target homunculus while hunting
- if (sd->hd && sd->homunculus.alive && (distance_bl(&md->bl, &sd->hd->bl ) < md->db->range2 ) ) //
- return 0; //Gangster paradise protection.
}
case BL_HOMUNCULUS: //[orn]
case BL_MOB:
diff --git a/src/map/pc.c b/src/map/pc.c
index f7c93c94f..3396de798 100644
--- a/src/map/pc.c
+++ b/src/map/pc.c
@@ -7093,25 +7093,38 @@ int pc_setsavepoint(struct map_session_data *sd, short mapindex,int x,int y)
* Ž©“®ƒZ?ƒu ŠeƒNƒ‰ƒCƒAƒ“ƒg
*------------------------------------------
*/
-static int last_save_fd,save_flag;
-static int pc_autosave_sub(struct map_session_data *sd,va_list ap)
+static int last_save_id=0,save_flag=0;
+static int pc_autosave_sub(DBKey key,void * data,va_list app)
{
- nullpo_retr(0, sd);
+ struct map_session_data *sd = (TBL_PC*)data;
+
+ if(sd->bl.id == last_save_id) {
+ save_flag = 1;
+ return 1;
+ }
- Assert((sd->status.pet_id == 0 || sd->pd == 0) || sd->pd->msd == sd);
+ if(save_flag != 1) //Not our turn to save yet.
+ return 0;
- if(save_flag==0 && sd->fd>last_save_fd && !sd->state.waitingdisconnect)
- {
- // pet
- if(sd->status.pet_id > 0 && sd->pd)
- intif_save_petdata(sd->status.account_id,&sd->pet);
+ if (sd->state.waitingdisconnect) //Invalid char to save.
+ return 0;
- chrif_save(sd,0);
- save_flag=1;
- last_save_fd = sd->fd;
- }
+ //Save char.
+ last_save_id = sd->bl.id;
+ save_flag=2;
- return 0;
+ // pet
+ if(sd->status.pet_id > 0 && sd->pd)
+ intif_save_petdata(sd->status.account_id,&sd->pet);
+
+ if(sd->state.finalsave)
+ { //Save ack hasn't returned from char-server yet? Retry.
+ ShowDebug("pc_autosave: Resending to save logging out char %d:%d (save ack from char-server hasn't arrived yet)\n", sd->status.account_id, sd->status.char_id);
+ sd->state.finalsave = 0;
+ chrif_save(sd,1);
+ } else
+ chrif_save(sd,0);
+ return 1;
}
/*==========================================
@@ -7122,10 +7135,11 @@ int pc_autosave(int tid,unsigned int tick,int id,int data)
{
int interval;
- save_flag=0;
- clif_foreachclient(pc_autosave_sub);
- if(save_flag==0)
- last_save_fd=0;
+ if(save_flag == 2) //Someone was saved on last call, normal cycle
+ save_flag = 0;
+ else
+ save_flag = 1; //Noone was saved, so save first found char.
+ map_foreachpc(pc_autosave_sub);
if (autosave_interval < 0)
return 0; //Fixed interval for saving. [Skotlex]
diff --git a/src/map/skill.c b/src/map/skill.c
index b501e9b64..6bf357910 100644
--- a/src/map/skill.c
+++ b/src/map/skill.c
@@ -1068,15 +1068,15 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, int
// Chance to trigger Taekwon kicks [Dralnu]
if(sd->sc.count && sd->sc.data[SC_COMBO].timer == -1) {
if(sd->sc.data[SC_READYSTORM].timer != -1 &&
- sc_start4(src,SC_COMBO, 15, TK_STORMKICK,0,0,0,
+ sc_start(src,SC_COMBO, 15, TK_STORMKICK,
(2000 - 4*sstatus->agi - 2*sstatus->dex)))
; //Stance triggered
else if(sd->sc.data[SC_READYDOWN].timer != -1 &&
- sc_start4(src,SC_COMBO, 15, TK_DOWNKICK,0,0,0,
+ sc_start(src,SC_COMBO, 15, TK_DOWNKICK,
(2000 - 4*sstatus->agi - 2*sstatus->dex)))
; //Stance triggered
else if(sd->sc.data[SC_READYTURN].timer != -1 &&
- sc_start4(src,SC_COMBO, 15, TK_TURNKICK,0,0,0,
+ sc_start(src,SC_COMBO, 15, TK_TURNKICK,
(2000 - 4*sstatus->agi - 2*sstatus->dex)))
; //Stance triggered
else if(sd->sc.data[SC_READYCOUNTER].timer != -1)
@@ -1764,7 +1764,7 @@ int skill_blown (struct block_list *src, struct block_list *target, int count)
if(!(count&0x20000))
clif_blown(target);
- return 0;
+ return (count&0xFFFF); //Return amount of knocked back cells.
}
/*
@@ -1895,7 +1895,6 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds
if(src == bl) type = 4; // åå‹•ã¯ãƒ€ãƒ¡ãƒ¼ã‚¸ãƒ¢ãƒ¼ã‚·ãƒ§ãƒ³ãªã—
}
-//使用者ãŒPCã®å ´åˆã®å‡¦ç†ã“ã“ã‹ã‚‰
if(sd) {
//Sorry for removing the Japanese comments, but they were actually distracting
//from the actual code and I couldn't understand a thing anyway >.< [Skotlex]
@@ -1910,7 +1909,13 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds
sd->skillid_old = skillid;
sd->skilllv_old = skilllv;
if (pc_famerank(sd->char_id,MAPID_TAEKWON))
- break; //Do not end combo state.
+ { //Extend combo time.
+ delete_timer(sc->data[SC_COMBO].timer, status_change_timer);
+ sd->sc.data[SC_COMBO].timer = add_timer(
+ tick+sd->sc.data[SC_COMBO].val4,
+ status_change_timer, src->id, SC_COMBO);
+ break;
+ }
default:
status_change_end(src,SC_COMBO,-1);
}
@@ -1920,10 +1925,9 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds
case MO_TRIPLEATTACK:
{
int delay = 1000 - 4*sstatus->agi - 2*sstatus->dex;
- if (damage < (signed int)tstatus->hp &&
- pc_checkskill(sd, MO_CHAINCOMBO) > 0)
+ if (pc_checkskill(sd, MO_CHAINCOMBO) > 0)
delay += 300 * battle_config.combo_delay_rate / 100;
- sc_start4(src,SC_COMBO,100,MO_TRIPLEATTACK,skilllv,0,0,delay);
+ sc_start(src,SC_COMBO,100,MO_TRIPLEATTACK,delay);
clif_combo_delay(src, delay);
if (sd->status.party_id>0) //bonus from SG_FRIEND [Komurka]
@@ -1933,51 +1937,51 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds
case MO_CHAINCOMBO:
{
int delay = 1000 - 4*sstatus->agi - 2*sstatus->dex;
- if(damage < (signed int)tstatus->hp &&
- (pc_checkskill(sd, MO_COMBOFINISH) > 0 && sd->spiritball > 0))
+ if(pc_checkskill(sd, MO_COMBOFINISH) > 0 && sd->spiritball > 0)
delay += 300 * battle_config.combo_delay_rate /100;
- sc_start4(src,SC_COMBO,100,MO_CHAINCOMBO,skilllv,0,0,delay);
+ sc_start(src,SC_COMBO,100,MO_CHAINCOMBO,delay);
clif_combo_delay(src,delay);
break;
}
case MO_COMBOFINISH:
{
int delay = 700 - 4*sstatus->agi - 2*sstatus->dex;
- if(damage < (signed int)tstatus->hp &&
- (
+ if (
(pc_checkskill(sd, MO_EXTREMITYFIST) > 0 && sd->spiritball >= 4 && sd->sc.data[SC_EXPLOSIONSPIRITS].timer != -1) ||
(pc_checkskill(sd, CH_TIGERFIST) > 0 && sd->spiritball > 0) ||
(pc_checkskill(sd, CH_CHAINCRUSH) > 0 && sd->spiritball > 1)
- ))
+ )
delay += 300 * battle_config.combo_delay_rate /100;
- sc_start4(src,SC_COMBO,100,MO_COMBOFINISH,skilllv,0,0,delay);
+ sc_start(src,SC_COMBO,100,MO_COMBOFINISH,delay);
clif_combo_delay(src,delay);
break;
}
case CH_TIGERFIST:
{ //Tigerfist is now a combo-only skill. [Skotlex]
int delay = 1000 - 4*sstatus->agi - 2*sstatus->dex;
- if(damage < (signed int)tstatus->hp &&
- (
+ if(
(pc_checkskill(sd, MO_EXTREMITYFIST) > 0 && sd->spiritball >= 3 && sd->sc.data[SC_EXPLOSIONSPIRITS].timer != -1) ||
(pc_checkskill(sd, CH_CHAINCRUSH) > 0)
- ))
+ )
delay += 300 * battle_config.combo_delay_rate /100;
- sc_start4(src,SC_COMBO,100,CH_TIGERFIST,skilllv,0,0,delay);
+ sc_start(src,SC_COMBO,100,CH_TIGERFIST,delay);
clif_combo_delay(src,delay);
break;
}
case CH_CHAINCRUSH:
{
int delay = 1000 - 4*sstatus->agi - 2*sstatus->dex;
- if(damage < (signed int)tstatus->hp)
+ if(pc_checkskill(sd, MO_EXTREMITYFIST) > 0 &&
+ sd->spiritball >= 1 &&
+ sd->sc.data[SC_EXPLOSIONSPIRITS].timer != -1)
delay += 300 * battle_config.combo_delay_rate /100;
- sc_start4(src,SC_COMBO,100,CH_CHAINCRUSH,skilllv,0,0,delay);
+ sc_start(src,SC_COMBO,100,CH_CHAINCRUSH,delay);
clif_combo_delay(src,delay);
break;
}
case AC_DOUBLE:
- if((tstatus->race == RC_BRUTE || tstatus->race == RC_INSECT) && damage < (signed int)tstatus->hp && pc_checkskill(sd, HT_POWER)) {
+ if((tstatus->race == RC_BRUTE || tstatus->race == RC_INSECT) &&
+ pc_checkskill(sd, HT_POWER)) {
//TODO: This code was taken from Triple Blows, is this even how it should be? [Skotlex]
sc_start4(src,SC_COMBO,100,HT_POWER,bl->id,0,0,2000);
clif_combo_delay(src,2000);
@@ -2890,34 +2894,39 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int
}
break;
- case KN_BOWLINGBASH: /* ボウリングãƒãƒƒã‚·ãƒ¥ */
+ case KN_BOWLINGBASH:
if(flag&1){
- /* 個別ã«ãƒ€ãƒ¡ãƒ¼ã‚¸ã‚’与ãˆã‚‹ */
- if(bl->id!=skill_area_temp[1])
- skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,0x0500);
+ if(bl->id==skill_area_temp[1])
+ break;
+ //Splash damage is always two hits for 500%
+ skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,0x0500);
+ skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,0x0500);
} else {
- int i,c; /* 他人ã‹ã‚‰èžã„ãŸå‹•ããªã®ã§é–“é•ã£ã¦ã‚‹å¯èƒ½æ€§å¤§ï¼†åŠ¹çŽ‡ãŒæ‚ªã„ã£ã™ï¼žï¼œ */
- /* ã¾ãšã‚¿ãƒ¼ã‚²ãƒƒãƒˆã«æ”»æ’ƒã‚’加ãˆã‚‹ */
- c = skill_get_blewcount(skillid,skilllv);
- if(map_flag_gvg(bl->m) || status_get_mexp(bl))
- c = 0;
- for(i=0;i<c;i++){
- skill_blown(src,bl,0x20000|1);
- skill_area_temp[0]=0;
- map_foreachinrange(skill_area_sub,bl,
- skill_get_splash(skillid, skilllv),BL_CHAR,
- src,skillid,skilllv,tick, flag|BCT_ENEMY,
- skill_area_sub_count);
- if(skill_area_temp[0]>1) break;
- }
- clif_blown(bl); //Update target pos.
+ int i,c;
+ c = skill_get_blewcount(skillid,skilllv);
+ for(i=0;i<c;i++){
+ if (!skill_blown(src,bl,0x20000|1))
+ break; //Can't knockback
+ skill_area_temp[0]=0;
+ map_foreachinrange(skill_area_sub,bl,
+ skill_get_splash(skillid, skilllv),BL_CHAR,
+ src,skillid,skilllv,tick, flag|BCT_ENEMY,
+ skill_area_sub_count);
+ if(skill_area_temp[0]>1) break;
+ }
+ clif_blown(bl); //Update target pos.
+ if (i==c) { //No targets found. Single attack for 600%
+ skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,1);
+ } else {
skill_area_temp[1]=bl->id;
- /* ãã®å¾Œã‚¿ãƒ¼ã‚²ãƒƒãƒˆä»¥å¤–ã®ç¯„囲内ã®æ•µå…¨ä½“ã«å‡¦ç†ã‚’行ㆠ*/
map_foreachinrange(skill_area_sub,bl,
skill_get_splash(skillid, skilllv),BL_CHAR,
src,skillid,skilllv,tick, flag|BCT_ENEMY|1,
skill_castend_damage_id);
+ //Weirdo dual-hit property, two attacks for 500%
+ skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,0);
skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,0);
+ }
}
break;
diff --git a/src/map/status.c b/src/map/status.c
index 09aed9ced..613471116 100644
--- a/src/map/status.c
+++ b/src/map/status.c
@@ -5291,6 +5291,7 @@ int status_change_start(struct block_list *bl,int type,int rate,int val1,int val
ud->attackabletime = gettick()+tick;
unit_set_walkdelay(bl, gettick(), tick, 1);
}
+ val4 = tick; //Store combo-time in val4.
}
break;
case SC_TKREST:
@@ -6347,7 +6348,7 @@ int status_change_timer(int tid, unsigned int tick, int id, int data)
case SC_DEVOTION:
{ //Check range and timeleft to preserve status [Skotlex]
- //This implementation won't work for mobs because of map_id2sd, but it's a small cost in exchange of the speed of map_id2sd over map_id2sd
+ //This implementation won't work for mobs because of map_id2sd, but it's a small cost in exchange of the speed of map_id2sd over map_id2bl
struct map_session_data *md = map_id2sd(sc->data[type].val1);
if (md && check_distance_bl(bl, &md->bl, sc->data[type].val3) && (sc->data[type].val4-=1000)>0)
{