Browse Source

Re-worked unitwalk script command and updated documentation - Fixes bugreport:7626
Fixed issue with updating area clients when a player is forced to stand - Fixes bugreport:7635
Finished updating Crescent Elbow to official behaviour
Fixed compiler warning with pc_close_npc_timer (lighta)
Fixed Star Gladiator Miracle not using correct ratio (lighta)
Fixed character position not always updating correctly (thanks Antares) - Concerning bugreport:7492
Cleaned up unit.h comments and some other minor issues

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@17311 54d463be-8e91-2dee-dedb-b68131a5f0ec

akinari1087 12 years ago
parent
commit
11c142ed48
10 changed files with 101 additions and 71 deletions
  1. 23 10
      doc/script_commands.txt
  2. 19 18
      src/map/battle.c
  3. 2 2
      src/map/clif.c
  4. 8 4
      src/map/pc.c
  5. 1 0
      src/map/pc.h
  6. 13 12
      src/map/script.c
  7. 1 1
      src/map/skill.c
  8. 4 2
      src/map/status.c
  9. 15 1
      src/map/unit.c
  10. 15 21
      src/map/unit.h

+ 23 - 10
doc/script_commands.txt

@@ -5398,22 +5398,35 @@ summon "--ja--",-1;
 ---------------------------------------
 
 *unitwalk <GID>,<x>,<y>;
-*unitwalk <GID>,<mapid>;
+*unitwalk <GID>,<Target ID>;
 
-This is one command, but can be used in two ways. If only the first argument is given,
-the unit whose GID is given will start walking towards the map with the given mapid 
-(we believe these are the map-indexes found in db/map_index.txt).
+This command will tell a <GID> to walk to a position.  The destination can be defined
+as either set coordinates, or another object.
 
-When 2 arguments are passed, the given unit will walk to the given x,y coordinates on 
-the map where the unit currently is.
+When 2 arguments are passed, the <GID> will walk to the given x,y coordinates on 
+the map where the unit currently is.  This command returns a 1 or 0 for success and failure
+checks.  While there is no way to move across an entire map with 1 command use, there
+doesn't seem to be any reason this couldn't be used in a loop to move long distances.
+
+The second method of using this command makes the first <GID> walk to the <Target ID> (not unlike walking to attack)
+Using this method will also return a 1 or 0 for success or failure.  This is based on distance from <GID> to <Target ID>.
+It is good to note that this command uses a hard walk check, so it will calculate a walkpath with obstacles.
 
 Examples:
 
-//Will move/walk the poring we made to the coordinates 150,150
-	unitwalk .GID,150,150;
+//Move/walk NPC invoker to the coordinates 150,150
+	unitwalk getcharid(3),150,150;
+
+//Doing a conditional check with the command and reporting to player success or failure
+	if(unitwalk(getcharid(3),150,150))
+		dispbottom "Walking you there...";
+	else
+		dispbottom "That's too far away, man.";
+
+//Sends NPC invoker to another character with name WalkToMe
+	unitwalk getcharid(3),getcharid(3,"WalkToMe");
 
-//Will move the poring towards alberta (if my assumed map-indexes are correct).
-	unitwalk .GID,3;
+Note: Sending a bad target ID to this command will result in an error.
 
 ---------------------------------------
 

+ 19 - 18
src/map/battle.c

@@ -2372,7 +2372,7 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
 					flag.pdef = flag.pdef2 = 2;
 					break;
 				case MO_EXTREMITYFIST:
-					skillratio += 100*(8 + sstatus->sp/10) - 100;
+					skillratio += 100*(7 + sstatus->sp/10);
 					skillratio = min(500000,skillratio); //We stop at roughly 50k SP for overflow protection
 					break;
 				case MO_TRIPLEATTACK:
@@ -3577,6 +3577,22 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
 			status_change_end(target, SC_REJECTSWORD, INVALID_TIMER);
 	}
 
+	if( tsc && tsc->data[SC_CRESCENTELBOW] && !is_boss(src) && rnd()%100 < tsc->data[SC_CRESCENTELBOW]->val2 ) {
+		//ATK [{(Target HP / 100) x Skill Level} x Caster Base Level / 125] % + [Received damage x {1 + (Skill Level x 0.2)}]
+		int rdamage = 0;
+		int ratio = (int64)(status_get_hp(src) / 100) * tsc->data[SC_CRESCENTELBOW]->val1 * status_get_lv(target) / 125;
+		if (ratio > 5000) ratio = 5000; // Maximum of 5000% ATK
+		rdamage = battle_calc_base_damage(tstatus,&tstatus->rhw,tsc,sstatus->size,tsd,0);
+		rdamage = (int64)rdamage * ratio / 100 + wd.damage * (10 + tsc->data[SC_CRESCENTELBOW]->val1 * 20 / 10) / 10;
+		skill_blown(target, src, skill_get_blewcount(SR_CRESCENTELBOW_AUTOSPELL, tsc->data[SC_CRESCENTELBOW]->val1), unit_getdir(src), 0);
+		clif_skill_damage(target, src, gettick(), status_get_amotion(src), 0, rdamage,
+			1, SR_CRESCENTELBOW_AUTOSPELL, tsc->data[SC_CRESCENTELBOW]->val1, 6); // This is how official does
+		clif_damage(src, target, gettick(), status_get_amotion(src)+1000, 0, rdamage/10, 1, 0, 0);
+		status_damage(target, src, rdamage, 0, 0, 0);
+		status_damage(src, target, rdamage/10, 0, 0, 1);
+		status_change_end(target, SC_CRESCENTELBOW, INVALID_TIMER);
+	}
+
 	if( sc ) {
 		//SG_FUSION hp penalty [Komurka]
 		if (sc->data[SC_FUSION]) {
@@ -4615,27 +4631,12 @@ int battle_calc_return_damage(struct block_list* bl, struct block_list *src, int
 
 	if( sc && sc->data[SC_REFLECTDAMAGE] ) {
 		if( rnd()%100 <= sc->data[SC_REFLECTDAMAGE]->val1*10 + 30 ){
-			max_damage *= status_get_lv(bl) / 100;
+			max_damage = (int64)max_damage * status_get_lv(bl) / 100;
 			rdamage = (int64)(*dmg) * sc->data[SC_REFLECTDAMAGE]->val2 / 100;
 			if( --(sc->data[SC_REFLECTDAMAGE]->val3) < 1)
 				status_change_end(bl,SC_REFLECTDAMAGE,INVALID_TIMER);
 		}
-	}else if( sc && sc->data[SC_CRESCENTELBOW] && !is_boss(src) && rnd()%100 < sc->data[SC_CRESCENTELBOW]->val2 ){ //TODO: This is a counter-attack skill, put it by Reject Sword
-		//ATK [{(Target HP / 100) x Skill Level} x Caster Base Level / 125] % + [Received damage x {1 + (Skill Level x 0.2)}]
-		struct status_data *status = status_get_status_data(bl);
-		struct status_data *tstatus = status_get_status_data(src);
-		int ratio = (int64)(status_get_hp(src) / 100) * sc->data[SC_CRESCENTELBOW]->val1 * status_get_lv(bl) / 125;
-		if (ratio > 5000) ratio = 5000; // Maximum of 5000% ATK
-		rdamage = battle_calc_base_damage(status,&status->rhw,sc,tstatus->size,sd,0);
-		rdamage = (int64)rdamage * ratio / 100 + (*dmg) * (10 + sc->data[SC_CRESCENTELBOW]->val1 * 20 / 10) / 10;
-		skill_blown(bl, src, skill_get_blewcount(SR_CRESCENTELBOW_AUTOSPELL, sc->data[SC_CRESCENTELBOW]->val1), unit_getdir(src), 0);
-		clif_skill_damage(bl, src, gettick(), status_get_amotion(src), 0, rdamage,
-			1, SR_CRESCENTELBOW_AUTOSPELL, sc->data[SC_CRESCENTELBOW]->val1, 6); // This is how official does
-		clif_damage(src, bl, gettick(), status_get_amotion(src)+1000, 0, rdamage/10, 1, 0, 0);
-		status_damage(src, bl, status_damage(bl, src, rdamage, 0, 0, 1)/10, 0, 0, 1);
-		status_change_end(bl, SC_CRESCENTELBOW, INVALID_TIMER);
-		return 0; // Just put here to minimize redundancy
-	}else if (flag & BF_SHORT) {//Bounces back part of the damage.
+	} else if (flag & BF_SHORT) {//Bounces back part of the damage.
 		if ( sd && sd->bonus.short_weapon_damage_return ) {
 			rdamage += (int64)damage * sd->bonus.short_weapon_damage_return / 100;
 			if(rdamage < 1) rdamage = 1;

+ 2 - 2
src/map/clif.c

@@ -1686,10 +1686,10 @@ void clif_changemapserver(struct map_session_data* sd, unsigned short map_index,
 }
 
 
-void clif_blown(struct block_list *bl)
+void clif_blown(struct block_list *bl) //FIXME: This needs a better behaviour than just sending 2 position fixes
 {
 //Aegis packets says fixpos, but it's unsure whether slide works better or not.
-//	clif_fixpos(bl);
+	clif_fixpos(bl);
 	clif_slide(bl, bl->x, bl->y);
 }
 

+ 8 - 4
src/map/pc.c

@@ -6569,16 +6569,19 @@ void pc_damage(struct map_session_data *sd,struct block_list *src,unsigned int h
 	sd->canlog_tick = gettick();
 }
 
-void pc_close_npc_timer(int tid, unsigned int tick, int id, intptr_t data){
-    TBL_PC *sd = map_id2sd(id);
-    if(sd) pc_close_npc(sd,data);
+int pc_close_npc_timer(int tid, unsigned int tick, int id, intptr_t data)
+{
+	TBL_PC *sd = map_id2sd(id);
+	if(sd) pc_close_npc(sd,data);
+	return 0;
 }
 /*
  *  Method to properly close npc for player and clear anything related
  * @flag == 1 : produce close button
  * @flag == 2 : directly close it
  */
-void pc_close_npc(struct map_session_data *sd,int flag) {
+void pc_close_npc(struct map_session_data *sd,int flag)
+{
 	nullpo_retv(sd);
 
 	if (sd->npc_id) {
@@ -9278,6 +9281,7 @@ void pc_setstand(struct map_session_data *sd){
 
 	status_change_end(&sd->bl, SC_TENSIONRELAX, INVALID_TIMER);
 	clif_status_load(&sd->bl,SI_SIT,0);
+	clif_standing(&sd->bl); //Inform area PC is standing
 	//Reset sitting tick.
 	sd->ssregen.tick.hp = sd->ssregen.tick.sp = 0;
 	sd->state.dead_sit = sd->vd.dead_sit = 0;

+ 1 - 0
src/map/pc.h

@@ -718,6 +718,7 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim
 void pc_authfail(struct map_session_data *);
 int pc_reg_received(struct map_session_data *sd);
 void pc_close_npc(struct map_session_data *sd,int flag);
+int pc_close_npc_timer(int tid, unsigned int tick, int id, intptr_t data);
 
 int pc_isequip(struct map_session_data *sd,int n);
 int pc_equippoint(struct map_session_data *sd,int n);

+ 13 - 12
src/map/script.c

@@ -15359,32 +15359,33 @@ BUILDIN_FUNC(pcstopfollow)
 }
 // <--- [zBuffer] List of player cont commands
 // [zBuffer] List of mob control commands --->
-//## TODO always return if the request/whatever was successfull [FlavioJS]
 
 /// Makes the unit walk to target position or map
 /// Returns if it was successfull
 ///
 /// unitwalk(<unit_id>,<x>,<y>) -> <bool>
-/// unitwalk(<unit_id>,<map_id>) -> <bool>
+/// unitwalk(<unit_id>,<target_id>) -> <bool>
 BUILDIN_FUNC(unitwalk)
 {
 	struct block_list* bl;
 
 	bl = map_id2bl(script_getnum(st,2));
 	if( bl == NULL )
-	{
 		script_pushint(st, 0);
-	}
-	else if( script_hasdata(st,4) )
-	{
+	else if( script_hasdata(st,4) ) {
 		int x = script_getnum(st,3);
 		int y = script_getnum(st,4);
-		script_pushint(st, unit_walktoxy(bl,x,y,0));// We'll use harder calculations.
-	}
-	else
-	{
-		int map_id = script_getnum(st,3);
-		script_pushint(st, unit_walktobl(bl,map_id2bl(map_id),65025,1));
+		if( script_pushint(st, unit_can_reach_pos(bl,x,y,0)) ) 
+			add_timer(gettick()+50, unit_delay_walktoxy_timer, bl->id, (x<<16)|(y&0xFFFF)); // Need timer to avoid mismatches
+	} else {
+		struct block_list* tbl = map_id2bl(script_getnum(st,3));
+		if( tbl == NULL ) {
+			ShowError("script:unitwalk: bad target destination\n");
+			script_pushint(st, 0);
+			return 1;
+		}
+		else if (script_pushint(st, unit_can_reach_bl(bl, tbl, distance_bl(bl, tbl)+1, 0, NULL, NULL)))
+			add_timer(gettick()+50, unit_delay_walktobl_timer, bl->id, tbl->id); // Need timer to avoid mismatches
 	}
 
 	return 0;

+ 1 - 1
src/map/skill.c

@@ -1827,7 +1827,7 @@ int skill_counter_additional_effect (struct block_list* src, struct block_list *
 
 	if(sd && (sd->class_&MAPID_UPPERMASK) == MAPID_STAR_GLADIATOR &&
 		map[sd->bl.m].flag.nosumstarmiracle == 0)	//SG_MIRACLE [Komurka]
-		sc_start(src,src,SC_MIRACLE,battle_config.sg_miracle_skill_ratio,1,battle_config.sg_miracle_skill_duration);
+		status_change_start(src,src,SC_MIRACLE,battle_config.sg_miracle_skill_ratio,1,0,0,0,battle_config.sg_miracle_skill_duration,0);
 
 	if(sd && skill_id && attack_type&BF_MAGIC && status_isdead(bl) &&
 	 	!(skill_get_inf(skill_id)&(INF_GROUND_SKILL|INF_SELF_SKILL)) &&

+ 4 - 2
src/map/status.c

@@ -6730,7 +6730,8 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 
 	case SC_INCREASEAGI:
 		 if(sd && pc_issit(sd)){
-			 pc_setstand(sd);
+			pc_setstand(sd);
+			skill_sit(sd,0);
 		 }
 
 	case SC_CONCENTRATE:
@@ -8560,7 +8561,8 @@ int status_change_start(struct block_list* src, struct block_list* bl,enum sc_ty
 			val_flag |= 1|2|4;
 			break;
 		case SC_CRESCENTELBOW:
-			val2 = 94 + val1;
+			if( sd )
+				val2 = (sd->status.job_level / 2) + (50 + 5 * val1);
 			val_flag |= 1|2;
 			break;
 		case SC_LIGHTNINGWALK: //  [(Job Level / 2) + (40 + 5 * Skill Level)] %

+ 15 - 1
src/map/unit.c

@@ -298,7 +298,7 @@ static int unit_walktoxy_timer(int tid, unsigned int tick, int id, intptr_t data
 	return 0;
 }
 
-static int unit_delay_walktoxy_timer(int tid, unsigned int tick, int id, intptr_t data)
+int unit_delay_walktoxy_timer(int tid, unsigned int tick, int id, intptr_t data)
 {
 	struct block_list *bl = map_id2bl(id);
 
@@ -308,6 +308,19 @@ static int unit_delay_walktoxy_timer(int tid, unsigned int tick, int id, intptr_
 	return 1;
 }
 
+int unit_delay_walktobl_timer(int tid, unsigned int tick, int id, intptr_t data)
+{
+	struct block_list *bl = map_id2bl(id);
+
+	if (!bl || bl->prev == NULL || !data)
+		return 0;
+
+	struct unit_data* ud = unit_bl2ud(bl);
+	unit_walktobl(bl, map_id2bl(data), 0, 0);
+	ud->target_to = 0;
+	return 1;
+}
+
 //flag parameter:
 //&1 -> 1/0 = easy/hard
 //&2 -> force walking
@@ -2513,6 +2526,7 @@ int do_init_unit(void)
 	add_timer_func_list(unit_walktoxy_timer,"unit_walktoxy_timer");
 	add_timer_func_list(unit_walktobl_sub, "unit_walktobl_sub");
 	add_timer_func_list(unit_delay_walktoxy_timer,"unit_delay_walktoxy_timer");
+	add_timer_func_list(unit_delay_walktobl_timer,"unit_delay_walktobl_timer");
 	return 0;
 }
 

+ 15 - 21
src/map/unit.h

@@ -68,61 +68,57 @@ struct view_data {
 	unsigned dead_sit : 2;
 };
 
-// PC, MOB, PET に共通する処理を1つにまとめる計画
+// PC, MOB, PET
 
-// 歩行開始
-//     戻り値は、0 ( 成功 ), 1 ( 失敗 )
+// Does walk action for unit
 int unit_walktoxy( struct block_list *bl, short x, short y, int easy);
 int unit_walktobl( struct block_list *bl, struct block_list *target, int range, int easy);
 int unit_run(struct block_list *bl);
 int unit_calc_pos(struct block_list *bl, int tx, int ty, uint8 dir);
+int unit_delay_walktoxy_timer(int tid, unsigned int tick, int id, intptr_t data);
+int unit_delay_walktobl_timer(int tid, unsigned int tick, int id, intptr_t data);
 
-// 歩行停止
-// typeは以下の組み合わせ :
-//     1: 位置情報の送信( この関数の後に位置情報を送信する場合は不要 )
-//     2: ダメージディレイ有り
-//     4: 不明(MOBのみ?)
+// Causes the target object to stop moving.
 int unit_stop_walking(struct block_list *bl,int type);
 int unit_can_move(struct block_list *bl);
 int unit_is_walking(struct block_list *bl);
 int unit_set_walkdelay(struct block_list *bl, unsigned int tick, int delay, int type);
 
 int unit_escape(struct block_list *bl, struct block_list *target, short dist);
-// 位置の強制移動(吹き飛ばしなど)
+
+// Instant unit changes
 int unit_movepos(struct block_list *bl, short dst_x, short dst_y, int easy, bool checkpath);
 int unit_warp(struct block_list *bl, short map, short x, short y, clr_type type);
 int unit_setdir(struct block_list *bl,unsigned char dir);
 uint8 unit_getdir(struct block_list *bl);
 int unit_blown(struct block_list* bl, int dx, int dy, int count, int flag);
 
-// そこまで歩行でたどり着けるかの判定
+// Can-reach checks
 bool unit_can_reach_pos(struct block_list *bl,int x,int y,int easy);
 bool unit_can_reach_bl(struct block_list *bl,struct block_list *tbl, int range, int easy, short *x, short *y);
 
-// 攻撃関連
+// Unit attack functions
 int unit_stop_attack(struct block_list *bl);
 int unit_attack(struct block_list *src,int target_id,int continuous);
 int unit_cancel_combo(struct block_list *bl);
 
-// スキル使用
+// Cast on a unit
 int unit_skilluse_id(struct block_list *src, int target_id, uint16 skill_id, uint16 skill_lv);
 int unit_skilluse_pos(struct block_list *src, short skill_x, short skill_y, uint16 skill_id, uint16 skill_lv);
-
-// スキル使用( 補正済みキャスト時間、キャンセル不可設定付き )
 int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill_id, uint16 skill_lv, int casttime, int castcancel);
 int unit_skilluse_pos2( struct block_list *src, short skill_x, short skill_y, uint16 skill_id, uint16 skill_lv, int casttime, int castcancel);
 
-// 詠唱キャンセル
+// Cancel unit cast
 int unit_skillcastcancel(struct block_list *bl,int type);
 
 int unit_counttargeted(struct block_list *bl);
 int unit_set_target(struct unit_data* ud, int target_id);
 
-// unit_data の初期化処理
+// unit_data
 void unit_dataset(struct block_list *bl);
 
 int unit_fixdamage(struct block_list *src,struct block_list *target,unsigned int tick,int sdelay,int ddelay,int damage,int div,int type,int damage2);
-// その他
+// Remove unit
 struct unit_data* unit_bl2ud(struct block_list *bl);
 void unit_remove_map_pc(struct map_session_data *sd, clr_type clrtype);
 void unit_free_pc(struct map_session_data *sd);
@@ -131,12 +127,10 @@ int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file,
 int unit_free(struct block_list *bl, clr_type clrtype);
 int unit_changeviewsize(struct block_list *bl,short size);
 
-// 初期化ルーチン
 int do_init_unit(void);
 int do_final_unit(void);
-/**
- * Ranger
- **/
+
+// Ranger
 int unit_wugdash(struct block_list *bl, struct map_session_data *sd);
 
 extern const short dirx[8];