summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Changelog-Trunk.txt16
-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
8 files changed, 114 insertions, 70 deletions
diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt
index fe1cc4e12..9fcb896d8 100644
--- a/Changelog-Trunk.txt
+++ b/Changelog-Trunk.txt
@@ -4,6 +4,22 @@ 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.
2006/07/17
+ * 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. [Skotlex]
+ * 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
+ can't knockback the target) it'll do a splash attack that hits twice for
+ 500% to all affected targets. [Skotlex]
+ * 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". [Skotlex]
+ * 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. [Skotlex]
+ * 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). [Skotlex]
* Some sign quest map flag updates [MasterOfMuppets]
* atcommand_follow is now more verbose. [Adam]
* Manually added int_homun.c to the VS8 char_sql project, *should* work [DracoRPG]
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)
{