Jelajahi Sumber

- Turn Undead and Offensive Resurrection should now work on undead players.
- Fixed the range checking of Repair weapon
- Rude attacked is now also triggered when you hit a target that can't move out of their melee attack range.
- Mob ai will attempt to do a long-range attacked condition skill before unlocking a target when it is attacked and said target is out of melee range of a non-walking mob.
- Corrected mobskill event to set the target_id before triggering.
- Moved MSC_SKILLUSED trigger to mobskill_event which is triggered in battle_calc_damage. It is also triggered on skill_castend_nodamage_id
- Added party_share_loot for handling party-share loot. it should now work with autoloot as well.
- Fixed skill_break_rate breaking stuff even if the rate is 0.
- pc_stopwalking will not send a fixpos packet if you are sitting.
- mob_can_reach rude-attacked condition now uses the mob's field of view.
- SC_NOCHAT is automatically started on pc_authok if manner is negative.
- Map server now refuses to start if you try to define a label with the same name as some const.txt defined character parameter.


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

skotlex 19 tahun lalu
induk
melakukan
9321f524fc
10 mengubah file dengan 177 tambahan dan 117 penghapusan
  1. 23 0
      Changelog-Trunk.txt
  2. 9 4
      src/map/battle.c
  3. 38 21
      src/map/mob.c
  4. 1 1
      src/map/mob.h
  5. 66 3
      src/map/party.c
  6. 2 0
      src/map/party.h
  7. 6 52
      src/map/pc.c
  8. 4 0
      src/map/script.c
  9. 25 34
      src/map/skill.c
  10. 3 2
      src/map/status.c

+ 23 - 0
Changelog-Trunk.txt

@@ -5,6 +5,29 @@ IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.  EV
 GOES INTO TRUNK AND WILL BE MERGED INTO STABLE BY VALARIS AND WIZPUTER. -- VALARIS
 
 2006/03/01
+	* Turn Undead and Offensive Resurrection should now work on undead players.
+	  [Skotlex]
+	* Fixed the range checking of Repair weapon [Skotlex]
+	* Rude attacked is now also triggered when you hit a target that can't move
+	  out of their melee attack range. [Skotlex]
+	* Mob ai will attempt to do a long-range attacked condition skill before
+	  unlocking a target when it is attacked and said target is out of melee
+	  range of a non-walking mob. [Skotlex]
+	* Corrected mobskill event to set the target_id before triggering. This
+	  should fix shortrange/longrange attacked mob skill conditions. [Skotlex]
+	* Moved MSC_SKILLUSED trigger to mobskill_event which is triggered in
+	  battle_calc_damage. It is also triggered on skill_castend_nodamage_id.
+	  [Skotlex]
+	* Added party_share_loot for handling party-share loot. it should now work
+	  with autoloot as well. [Skotlex]
+	* Fixed skill_break_rate breaking stuff even if the rate is 0. [Skotlex]
+	* pc_stopwalking will not send a fixpos packet if you are sitting. [Skotlex]
+	* mob_can_reach rude-attacked condition now uses the mob's field of view.
+	  [Skotlex]
+	* SC_NOCHAT is automatically started on pc_authok if manner is negative.
+	  [Skotlex]
+	* Map server now refuses to start if you try to define a label with the
+	  same name as some const.txt defined character parameter. [Skotlex]
 	* Corrected a few Compiling Warnings [Codemaster]
 	* Added the ability to select GM loading via Login (default) or Char [Codemaster]
 	* Added script command 'setbattleflag'. [Lance]

+ 9 - 4
src/map/battle.c

@@ -755,8 +755,12 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,int damage,i
 			damage = div_;
 	}
 
-	if( md!=NULL && md->hp>0 && damage > 0 )	// ”½Œ‚‚ȂǂÌMOBƒXƒLƒ‹”»’è
-		mobskill_event(md,flag);
+	if( md && !status_isdead(bl) && src != bl) {
+	  if (damage > 0 )
+			mobskill_event(md,src,gettick(),flag);
+	  if (skill_num)
+			mobskill_event(md,src,gettick(),MSC_SKILLUSED|(skill_num<<16));
+	}
 
 	return damage;
 }
@@ -2268,7 +2272,8 @@ static struct Damage battle_calc_weapon_attack(
 				if(sc->data[SC_MAXOVERTHRUST].timer!=-1)
 					breakrate += 10;
 			}
-			skill_break_equip(src, EQP_WEAPON, breakrate, BCT_SELF);
+			if (breakrate)
+				skill_break_equip(src, EQP_WEAPON, breakrate, BCT_SELF);
 		}
 		if (battle_config.equip_skill_break_rate)
 		{	// Target equipment breaking
@@ -2471,7 +2476,7 @@ struct Damage battle_calc_magic_attack(
 				break;
 			case ALL_RESURRECTION:
 			case PR_TURNUNDEAD:
-				if(!tsd && battle_check_undead(t_race,t_ele)){
+				if(battle_check_undead(t_race,t_ele)){
 					int hp, mhp, thres;
 					hp = status_get_hp(target);
 					mhp = status_get_max_hp(target);

+ 38 - 21
src/map/mob.c

@@ -1620,12 +1620,12 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
 				(dist = distance_bl(&md->bl, abl)) >= 32 ||
 				battle_check_target(bl, abl, BCT_ENEMY) <= 0 ||
 				(battle_config.mob_ai&2 && !status_check_skilluse(bl, abl, 0, 0)) ||
-				!mob_can_reach(md, abl, dist+2, MSS_RUSH ||
+				!mob_can_reach(md, abl, md->db->range2, MSS_RUSH) ||
 				(	//Gangster Paradise check
 					abl->type == BL_PC && !(mode&MD_BOSS) &&
 					((struct map_session_data*)abl)->state.gangsterparadise
 				)
-			))	{	//Can't attack back
+			)	{	//Can't attack back
 				if (md->attacked_count++ > 3) {
 					if (mobskill_use(md, tick, MSC_RUDEATTACKED) == 0 &&
 						mode&MD_CANMOVE && mob_can_move(md))
@@ -1720,8 +1720,11 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
 			}
 			if (!battle_check_range (&md->bl, tbl, md->db->range))
 			{	//Out of range...
-				if (!(mode & MD_CANMOVE))
-				{	//Can't chase.
+				if (!(mode&MD_CANMOVE))
+				{	//Can't chase. Attempt to use a ranged skill at least?
+					if (mobskill_use(md, tick, MSC_LONGRANGEATTACKED) == 0)
+						md->attacked_count++; //Increase rude-attacked count as it can't attack back.
+					
 					mob_unlocktarget(md,tick);
 					return 0;
 				}
@@ -2074,13 +2077,16 @@ static void mob_item_drop(struct mob_data *md, unsigned int tick, struct delay_i
 	if (ditem->first_sd && ditem->first_sd->state.autoloot &&
 		(drop_rate <= ditem->first_sd->state.autoloot ||
 		ditem->first_sd->state.autoloot >= 10000) //Fetch 100% drops
-		&& pc_additem(ditem->first_sd,&ditem->item_data,ditem->item_data.amount) == 0)
-	{	//Autolooted.
-		if(log_config.pick > 0)
-			log_pick(ditem->first_sd, "P", 0, ditem->item_data.nameid, ditem->item_data.amount, &ditem->item_data);
-		aFree(ditem);
-	} else
-		add_timer(tick, mob_delay_item_drop, (int)ditem, 0);
+	) {	//Autoloot.
+		if (party_share_loot(
+			party_search(ditem->first_sd->status.party_id),
+			ditem->first_sd,&ditem->item_data)
+		) {
+			aFree(ditem);
+			return;
+		}
+	}
+	add_timer(tick, mob_delay_item_drop, (int)ditem, 0);
 }
 
 /*==========================================
@@ -3885,18 +3891,29 @@ int mobskill_use(struct mob_data *md, unsigned int tick, int event)
  * Skill use event processing
  *------------------------------------------
  */
-int mobskill_event(struct mob_data *md, int flag)
+int mobskill_event(struct mob_data *md, struct block_list *src, unsigned int tick, int flag)
 {
-	int tick = gettick();
-	nullpo_retr(0, md);
+	int target_id, res = 0;
 
-	if (flag == -1 && mobskill_use(md, tick, MSC_CASTTARGETED))
-		return 1;
-	if ((flag & BF_SHORT) && mobskill_use(md, tick, MSC_CLOSEDATTACKED))
-		return 1;
-	if ((flag & BF_LONG) && mobskill_use(md, tick, MSC_LONGRANGEATTACKED))
-		return 1;
-	return 0;
+	target_id = md->target_id;
+	if (!target_id || (battle_config.mob_changetarget_byskill &&
+		battle_check_target(&md->bl, src, BCT_ENEMY) > 0))
+		md->target_id = src->id;
+			
+	if (flag == -1)
+		res = mobskill_use(md, tick, MSC_CASTTARGETED);
+	else if ((flag&0xffff) == MSC_SKILLUSED)
+		res = mobskill_use(md,tick,flag);
+	else if (flag&BF_SHORT)
+		res = mobskill_use(md, tick, MSC_CLOSEDATTACKED);
+	else if (flag&BF_LONG)
+		res = mobskill_use(md, tick, MSC_LONGRANGEATTACKED);
+	
+	if (target_id && !res)
+	//Restore previous target only if skill condition failed to trigger. [Skotlex]
+		md->target_id = target_id;
+	
+	return res;
 }
 
 /*==========================================

+ 1 - 1
src/map/mob.h

@@ -160,7 +160,7 @@ int mob_warp(struct mob_data *md,int m,int x,int y,int type);
 int mob_warpslave(struct block_list *bl, int range);
 
 int mobskill_use(struct mob_data *md,unsigned int tick,int event);
-int mobskill_event(struct mob_data *md,int flag);
+int mobskill_event(struct mob_data *md,struct block_list *src,unsigned int tick, int flag);
 int mobskill_castend_id( int tid, unsigned int tick, int id,int data );
 int mobskill_castend_pos( int tid, unsigned int tick, int id,int data );
 int mob_summonslave(struct mob_data *md2,int *value,int amount,int skill_id);

+ 66 - 3
src/map/party.c

@@ -696,13 +696,76 @@ int party_exp_share(struct party *p,int map,unsigned int base_exp,unsigned int j
 	return 0;
 }
 
-int party_send_dot_remove(struct map_session_data *sd)
+int party_share_loot(struct party *p, TBL_PC *sd, struct item *item_data)
 {
-	if (sd->status.party_id)
-		clif_party_xy_remove(sd);
+	TBL_PC *target=NULL;
+	int i;
+	if (p && p->item&2) {
+		//item distribution to party members.
+		if (battle_config.party_share_type) { //Round Robin
+			TBL_PC *psd;
+			i = p->itemc;
+			do {
+				i++;
+				if (i >= MAX_PARTY)
+					i = 0;	// reset counter to 1st person in party so it'll stop when it reaches "itemc"
+				if ((psd=p->member[i].sd)==NULL || sd->bl.m != psd->bl.m)
+					continue;
+				
+				if (pc_additem(psd,item_data,item_data->amount))
+					continue; //Chosen char can't pick up loot.
+				//Successful pick.
+				p->itemc = i;
+				target = psd;
+				break;
+			} while (i != p->itemc);
+		} else { //Random pick
+			TBL_PC *psd[MAX_PARTY];
+			int count=0;
+			//Collect pick candidates
+			for (i = 0; i < MAX_PARTY; i++) {
+				if ((psd[count]=p->member[i].sd) && psd[count]->bl.m == sd->bl.m)
+					count++;
+			}
+			if (count > 0) { //Pick a random member.
+				do {
+					i = rand()%count;
+					if (pc_additem(psd[i],item_data,item_data->amount))
+					{	//Discard this receiver.
+						psd[i] = psd[count-1];
+						count--;
+					} else { //Successful pick.
+						target = psd[i];
+						break;
+					}
+				} while (count > 0);
+			}
+		}
+	}
+	if (!target) { //Give it to the owner.
+		target = sd;
+		if (!(i=pc_additem(sd,item_data,item_data->amount)))
+			return i;
+	}
+
+	if(log_config.pick) //Logs items, taken by (P)layers [Lupus]
+		log_pick(target, "P", 0, item_data->nameid, item_data->amount, item_data);
+	//Logs
+	if(battle_config.party_show_share_picker && target != sd){
+		char output[80];
+		sprintf(output, "%s acquired the item.",target->status.name);
+		clif_disp_onlyself(sd,output,strlen(output));
+	}
 	return 0;
 }
 
+int party_send_dot_remove(struct map_session_data *sd)
+{
+if (sd->status.party_id)
+	clif_party_xy_remove(sd);
+return 0;
+}
+
 // To use for Taekwon's "Fighting Chant"
 // int c = 0;
 // party_foreachsamemap(party_sub_count, sd, 0, &c);

+ 2 - 0
src/map/party.h

@@ -5,6 +5,7 @@
 #define _PARTY_H_
 
 #include <stdarg.h>
+#include "map.h"
 
 extern int party_share_level;
 struct party;
@@ -39,6 +40,7 @@ int party_check_conflict(struct map_session_data *sd);
 int party_skill_check(struct map_session_data *sd, int party_id, int skillid, int skilllv);
 int party_send_xy_clear(struct party *p);
 int party_exp_share(struct party *p,int map,unsigned int base_exp,unsigned int job_exp,int zeny);
+int party_share_loot(struct party *p, TBL_PC *sd, struct item *item_data);
 int party_send_dot_remove(struct map_session_data *sd);
 int party_sub_count(struct block_list *bl, va_list ap);
 int party_foreachsamemap(int (*func)(struct block_list *,va_list),struct map_session_data *sd,int type,...);

+ 6 - 52
src/map/pc.c

@@ -845,6 +845,8 @@ int pc_authok(struct map_session_data *sd, int login_id2, time_t connect_until_t
 		clif_wis_message(sd->fd, wisp_server_name, tmpstr, strlen(tmpstr)+1);
 	}
 
+	if(sd->status.manner < 0) //Needed or manner will always be negative.
+		status_change_start(&sd->bl,SC_NOCHAT,100,0,0,0,0,0,0);
 	return 0;
 }
 
@@ -2590,63 +2592,15 @@ int pc_takeitem(struct map_session_data *sd,struct flooritem_data *fitem)
 	}
 	first_sd = NULL; //First_sd will store who picked up the item.
 	if (p && p->item&2) { //item distribution to party members.
-		first_sd = NULL; 
-		if (battle_config.party_share_type) { //Round Robin
-			int i;
-			i = p->itemc;
-			do {
-				i++;
-				if (i >= MAX_PARTY)
-					i = 0;	// reset counter to 1st person in party so it'll stop when it reaches "itemc"
-				if ((second_sd=p->member[i].sd)==NULL || sd->bl.m != second_sd->bl.m)
-					continue;
-				
-				if (pc_additem(second_sd,&fitem->item_data,fitem->item_data.amount))
-					continue; //Chosen char can't pick up loot.
-				//Successful pick.
-				first_sd = second_sd;
-				break;
-			} while (i != p->itemc);
-			// Skip to the current receiver of an item, so the next pick should not go to him again.
-			p->itemc = i;
-		} else { //Random pick
-			struct map_session_data*psd[MAX_PARTY];
-			int i, count=0;
-			//Collect pick candidates
-			for (i = 0; i < MAX_PARTY; i++) {
-				if ((psd[count]=p->member[i].sd) && psd[count]->bl.m == sd->bl.m)
-					count++;
-			}
-			if (count > 0) { //Pick a random member.
-				do {
-					i = rand()%count;
-					if (pc_additem(psd[i],&fitem->item_data,fitem->item_data.amount))
-					{	//Discard this receiver.
-						psd[i] = psd[count-1];
-						count--;
-					} else { //Successful pick.
-						first_sd = psd[i];
-						break;
-					}
-				} while (count > 0);
-			}
-		}
-	}
-  	if (!first_sd) { //Noone has picked it up yet...
-		if ((flag = pc_additem(sd,&fitem->item_data,fitem->item_data.amount))) {
+		if ((flag = party_share_loot(p,sd,&fitem->item_data))) {
 			clif_additem(sd,0,0,flag);
 			return 1;
 		}
 		first_sd = sd;
-	}
+	} else
 	if(log_config.pick) //Logs items, taken by (P)layers [Lupus]
 		log_pick(first_sd, "P", 0, fitem->item_data.nameid, fitem->item_data.amount, (struct item*)&fitem->item_data);
-	//Logs
-	if(battle_config.party_show_share_picker && first_sd != sd){
-		char output[80];
-		sprintf(output, "%s acquired the item.",first_sd->status.name);
-		clif_disp_onlyself(sd,output,strlen(output));
-	}
+
 
 	//Display pickup animation.
 	if(sd->attacktimer != -1)
@@ -3698,7 +3652,7 @@ int pc_stop_walking (struct map_session_data *sd, int type)
 	sd->walkpath.path_len = 0;
 	sd->to_x = sd->bl.x;
 	sd->to_y = sd->bl.y;
-	if (type & 0x01)
+	if (type & 0x01 && !pc_issit(sd)) //Trying to fixpos while sitting makes you seem standing. [Skotlex]
 		clif_fixpos(&sd->bl);
 	if (sd->sc.data[SC_RUN].timer != -1)
 		status_change_end(&sd->bl, SC_RUN, -1);

+ 4 - 0
src/map/script.c

@@ -1755,6 +1755,10 @@ unsigned char* parse_syntax(unsigned char *p) {
 				// 関数名のラベルを付ける
 				*p = 0;
 				l=add_str(func_name);
+				if(str_data[l].type == C_PARAM) {
+					disp_error_message("invalid label name ",p);
+					exit(1);
+				}
 				if(str_data[l].type == C_NOP) {
 					str_data[l].type = C_USERFUNC;
 				}

+ 25 - 34
src/map/skill.c

@@ -1426,7 +1426,7 @@ int skill_break_equip(struct block_list *bl, unsigned short where, int rate, int
 		if (where&where_list[i]) {
 			if (sc && sc->count && sc->data[scdef[i]].timer != -1)
 				where&=~where_list[i];
-			else if (rand()%10000 > rate)
+			else if (rand()%10000 >= rate)
 				where&=~where_list[i];
 			else if (!sd) //Cause Strip effect.
 				status_change_start(bl,scatk[i],100,0,0,0,0,
@@ -1894,23 +1894,6 @@ int skill_attack( int attack_type, struct block_list* src, struct block_list *ds
 	if (dmg.dmg_lv == ATK_DEF || damage > 0) //Counter status effects [Skotlex] 
 		skill_counter_additional_effect(dsrc,bl,skillid,skilllv,attack_type,tick);
 	
-	/* ダ�??ジがあるなら追加?果判定 */	
-	if(!status_isdead(bl) && bl->type==BL_MOB && src!=bl)	/* スキル使用?件のMOBスキル */
-	{
-		struct mob_data *md=(struct mob_data *)bl;
-//		nullpo_retr(0, md); //Just so you know.. these are useless. When you cast a pointer, the pointer still is the same, so if bl is not null, the after-casted pointer will never be nulll :/ [Skotlex]
-		if(battle_config.mob_changetarget_byskill && sd)
-		{
-			int target ;
-			target=md->target_id;
-			md->target_id=src->id;
-			mobskill_use(md,tick,MSC_SKILLUSED|(skillid<<16));
-			md->target_id=target;
-		}
-		else
-			mobskill_use(md,tick,MSC_SKILLUSED|(skillid<<16));
-	}
-
 	if(sd && dmg.flag&BF_WEAPON && src != bl && src == dsrc && damage > 0) {
 		int hp = 0,sp = 0;
 		if(sd->right_weapon.hp_drain_rate && sd->right_weapon.hp_drain_per > 0 && dmg.damage > 0 && rand()%1000 < sd->right_weapon.hp_drain_rate) {
@@ -5655,6 +5638,9 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
 		return 1;
 	}
 
+	if (dstmd) //Mob skill event for no damage skills (damage ones are handled in battle_calc_damage) [Skotlex]
+		mobskill_event(dstmd, src, tick, MSC_SKILLUSED|(skillid<<16));
+	
 	map_freeblock_unlock();
 	return 0;
 }
@@ -8640,21 +8626,26 @@ int skill_use_id (struct map_session_data *sd, int target_id, int skill_num, int
 		else
 			clif_skillcasting(&sd->bl,sd->bl.id, target_id, 0,0, skill_num,casttime);
 		/* 詠?・反?モンスタ? */
-		if (bl->type == BL_MOB && (mode = status_get_mode(bl))&MD_CASTSENSOR && (md = (struct mob_data *)bl) &&
-			(!md->special_state.ai || skill_get_inf(skill_num) != INF_SUPPORT_SKILL) //Avoid having summons target master from supportive skills. [Skotlex]
-		) {
-			switch (md->state.skillstate) {
-				case MSS_ANGRY:
-				case MSS_RUSH:
-				case MSS_FOLLOW:
-					if (!(mode&(MD_AGGRESSIVE|MD_ANGRY)))
-						break; //Only Aggressive mobs change target while chasing.
-				case MSS_IDLE:
-				case MSS_WALK:
-					md->target_id = sd->bl.id;
-					md->state.targettype = ATTACKABLE;
-					md->state.aggressive = (mode&MD_ANGRY)?1:0;
-					md->min_chase = md->db->range3;
+		if (bl->type == BL_MOB)
+		{
+			md = (struct mob_data *)bl;
+			mobskill_event(md, &sd->bl, tick, -1); //Cast targetted skill event.
+			if ((mode=status_get_mode(bl))&MD_CASTSENSOR &&
+				battle_check_target(bl, &sd->bl, BCT_ENEMY) > 0)
+			{
+				switch (md->state.skillstate) {
+					case MSS_ANGRY:
+					case MSS_RUSH:
+					case MSS_FOLLOW:
+						if (!(mode&(MD_AGGRESSIVE|MD_ANGRY)))
+							break; //Only Aggressive mobs change target while chasing.
+					case MSS_IDLE:
+					case MSS_WALK:
+						md->target_id = sd->bl.id;
+						md->state.targettype = ATTACKABLE;
+						md->state.aggressive = (mode&MD_ANGRY)?1:0;
+						md->min_chase = md->db->range3;
+				}
 			}
 		}
 	}
@@ -9038,7 +9029,7 @@ void skill_repairweapon(struct map_session_data *sd, int idx)
 	if(item->nameid <= 0 || item->attribute == 0)
 		return; //Again invalid item....
 
-	if(sd!=target_sd && !battle_check_range(&sd->bl,&target_sd->bl,skill_get_range2(&sd->bl, sd->skillid,sd->skilllv))){
+	if(sd!=target_sd && !battle_check_range(&sd->bl,&target_sd->bl,skill_get_range2(&sd->bl, sd->menuskill_id,pc_checkskill(sd, sd->menuskill_id)))){
 		clif_item_repaireffect(sd,item->nameid,1);
 		return;
 	}

+ 3 - 2
src/map/status.c

@@ -4848,8 +4848,9 @@ int status_change_end( struct block_list* bl , int type,int tid )
 			case SC_NOCHAT:	//ƒ`ƒƒƒbƒg‹ÖŽ~?‘Ô
 				if (sd) {
 					if(battle_config.manner_system){
-						if (sd->status.manner >= 0) // weeee ^^ [celest]
-							sd->status.manner = 0;
+						//Why set it to 0? Can't we use good manners for something? [Skotlex]
+//						if (sd->status.manner >= 0) // weeee ^^ [celest]
+//							sd->status.manner = 0;
 						clif_updatestatus(sd,SP_MANNER);
 					}
 				}