Selaa lähdekoodia

- Added function map_search_freecell to locate an available cell around an area (for recall/warping skills)

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@5732 54d463be-8e91-2dee-dedb-b68131a5f0ec
skotlex 19 vuotta sitten
vanhempi
commit
77e57852cc
7 muutettua tiedostoa jossa 133 lisäystä ja 149 poistoa
  1. 2 0
      Changelog-Trunk.txt
  2. 67 0
      src/map/map.c
  3. 1 0
      src/map/map.h
  4. 32 94
      src/map/mob.c
  5. 1 2
      src/map/pc.c
  6. 11 36
      src/map/skill.c
  7. 19 17
      src/map/unit.c

+ 2 - 0
Changelog-Trunk.txt

@@ -5,6 +5,8 @@ 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/24
+	* Added function map_search_freecell to locate an available cell around an
+	  area (for recall/warping skills). UNTESTED. [Skotlex]
 	* Added unit.c to the VC8 project files. Thanks to Joshuaali [Skotlex]
 	* Fixed Magnum-break/GrandCross displaying multiple times the skill effect
 	  (once per target) [Skotlex]

+ 67 - 0
src/map/map.c

@@ -1364,6 +1364,73 @@ int map_searchrandfreecell(int m,int *x,int *y,int stack) {
 	return 1;
 }
 
+
+static int map_count_sub(struct block_list *bl,va_list ap)
+{
+	return 1;
+}
+
+/*==========================================
+ * Locates a random spare cell around the object given, using range as max 
+ * distance from that spot. Used for warping functions. Use range < 0 for 
+ * whole map range.
+ * Returns 1 on success. when it fails and src is available, x/y are set to src's
+ * src can be null as long as flag&1
+ * when ~flag&1, m is not needed.
+ * Flag values:
+ * &1 = random cell must be around given m,x,y, not around src
+ * &2 = the target should be able to walk to the target tile.
+ * &4 = there shouldn't be any players around the target tile (use the no_spawn_on_player setting)
+ *------------------------------------------
+ */
+int map_search_freecell(struct block_list *src, int m, int *x,int *y, int rx, int ry, int flag) {
+	int tries, spawn=0;
+	int bx, by;
+	int rx2 = 2*rx+1;
+	int ry2 = 2*ry+1;
+
+	if (!src && (!(flag&1) || flag&2))
+	{
+		ShowDebug("map_search_freecell: Incorrect usage! When src is NULL, flag has to be &1 and can't have &2\n");
+		return 0;
+	}
+
+	if (flag&1) {
+		bx = *x;
+		by = *y;
+	} else {
+		bx = src->x;
+		by = src->y;
+		m = src->m;
+	}
+	if (rx >= 0 && ry >= 0) {
+		tries = rx2*ry2;
+		if (tries > 50) tries = 50;
+	} else
+		tries = 50;
+	
+	while(tries--) {
+		*x = (rx >= 0)?(rand()%rx2-rx+bx):(rand()%(map[m].xs-2)+1);
+		*y = (ry >= 0)?(rand()%rx2-ry+by):(rand()%(map[m].ys-2)+1);
+		
+		if (map_getcell(m,*x,*y,CELL_CHKREACH))
+		{
+			if(flag&2 && !unit_can_reach(src, *x, *y))
+				continue;
+			if(flag&4 && spawn++ < battle_config.no_spawn_on_player &&
+				map_foreachinarea(map_count_sub, m,
+					*x-AREA_SIZE, *y-AREA_SIZE, *x+AREA_SIZE, *y+AREA_SIZE, BL_PC)
+			)
+				continue;
+
+			return 1;
+		}
+	}
+	*x = bx;
+	*y = by;
+	return 0;
+}
+
 /*==========================================
  * (m,x,y)を中心に3x3以?に床アイテム設置
  *

+ 1 - 0
src/map/map.h

@@ -1236,6 +1236,7 @@ int map_addobject(struct block_list *);
 int map_delobject(int);
 int map_delobjectnofree(int id);
 void map_foreachobject(int (*)(struct block_list*,va_list),int,...);
+int map_search_freecell(struct block_list *src, int m, int *x,int *y, int rx, int ry, int flag);
 //
 int map_quit(struct map_session_data *);
 // npc

+ 32 - 94
src/map/mob.c

@@ -248,7 +248,6 @@ int mob_once_spawn (struct map_session_data *sd, char *mapname,
 	struct mob_data *md = NULL;
 	struct spawn_data data;
 	int m, count, lv = 255;
-	int i, j;
 	
 	if(sd) lv = sd->status.base_level;
 
@@ -272,25 +271,12 @@ int mob_once_spawn (struct map_session_data *sd, char *mapname,
 	}
 	strncpy(data.eventname, event, 50);
 	
-	if (sd) { //even if the coords were wrong, spawn mob anyways (but look for most suitable coords first) Got from Freya [Lupus]
-		if (x <= 0 || y <= 0) {
-			if (x <= 0) x = sd->bl.x + rand() % 3 - 1;
-			if (y <= 0) y = sd->bl.y + rand() % 3 - 1;
-			if (map_getcell(m, x, y, CELL_CHKNOPASS)) {
-				x = sd->bl.x;
-				y = sd->bl.y;
-			}
-		}
-	} else if (x <= 0 || y <= 0) {
-		i = j = 0;
-		do {
-			x = rand() % (map[m].xs - 2) + 1;
-			y = rand() % (map[m].ys - 2) + 1;
-		} while ((i = map_getcell(m, x, y, CELL_CHKNOPASS)) && j++ < 64);
-		if (i) { // not solved?
-			x = 0;
-			y = 0;
-		}
+	if (x <= 0 || y <= 0) {
+		if (sd)
+			map_search_freecell(&sd->bl, 0, &x, &y, 1, 1, 0);
+		else
+		if (!map_search_freecell(NULL, m, &x, &y, -1, -1, 1))
+			return 0;	//Not solved?
 	}
 	data.x = x;
 	data.y = y;
@@ -642,11 +628,6 @@ int mob_setdelayspawn(struct mob_data *md)
 	return 0;
 }
 
-static int mob_count_sub(struct block_list *bl,va_list ap)
-{
-	return 1;
-}
-
 /*==========================================
  * Mob spawning. Initialization is also variously here.
  *------------------------------------------
@@ -674,30 +655,16 @@ int mob_spawn (struct mob_data *md)
 
 		if ((md->spawn->x == 0 && md->spawn->y == 0) || md->spawn->xs || md->spawn->ys)
 		{	//Monster can be spawned on an area.
-			int x, y;
-			while (i < 50) {
-				if (md->spawn->x == 0 && md->spawn->y == 0) {
-					x = rand()%(map[md->bl.m].xs-2)+1;
-					y = rand()%(map[md->bl.m].ys-2)+1;
-				} else {
-					x = md->spawn->x+rand()%(md->spawn->xs+1)-md->spawn->xs/2;
-					y = md->spawn->y+rand()%(md->spawn->ys+1)-md->spawn->ys/2;
-				}
-				i++;
-				if (map_getcell(md->bl.m,x,y,CELL_CHKNOPASS))
-					continue;
-
-				//Avoid spawning on the view-range of players. [Skotlex]
-				if (battle_config.no_spawn_on_player &&
-					c++ < battle_config.no_spawn_on_player &&
-					map_foreachinarea(mob_count_sub, md->bl.m,
-						x-AREA_SIZE, y-AREA_SIZE, x+AREA_SIZE, y+AREA_SIZE, BL_PC)
-				)
-					continue;
-				//Found a spot.
-				break;
+			int x, y, xs, ys;
+			if (md->spawn->x == 0 && md->spawn->y == 0)
+				xs = ys = -1;
+			else {
+				x = md->spawn->x;
+				y = md->spawn->y;
+				xs = md->spawn->xs/2;
+				ys = md->spawn->ys/2;
 			}
-			if (i >= 50) {
+			if (!map_search_freecell(NULL, md->spawn->m, &x, &y, xs, ys, battle_config.no_spawn_on_player?5:1)) {
 				// retry again later
 				add_timer(tick+5000,mob_delayspawn,md->bl.id,0);
 				return 1;
@@ -2467,23 +2434,15 @@ int mob_warpslave_sub(struct block_list *bl,va_list ap)
 {
 	struct mob_data *md=(struct mob_data *)bl;
 	struct block_list *master;
-	int x,y,range,i=0;
+	int x,y,range=0;
 	master = va_arg(ap, struct block_list*);
 	range = va_arg(ap, int);
 	
 	if(md->master_id!=master->id)
 		return 0;
 
-	do {
-		x = master->x - range/2 + rand()%range;
-		y = master->y - range/2 + rand()%range;
-	} while (map_getcell(master->m,x,y,CELL_CHKNOPASS) && i<25);
-	
-	if (i == 100)
-		unit_warp(&md->bl, master->m, master->x, master->y,2);
-	else
-		unit_warp(&md->bl, master->m, x, y,2);
-
+	map_search_freecell(master, 0, &x, &y, range, range, 0);
+	unit_warp(&md->bl, master->m, x, y,2);
 	return 1;
 }
 
@@ -2533,7 +2492,7 @@ int mob_summonslave(struct mob_data *md2,int *value,int amount,int skill_id)
 {
 	struct mob_data *md;
 	struct spawn_data data;
-	int bx,by,count = 0,k=0;
+	int count = 0,k=0;
 
 	nullpo_retr(0, md2);
 	nullpo_retr(0, value);
@@ -2543,8 +2502,6 @@ int mob_summonslave(struct mob_data *md2,int *value,int amount,int skill_id)
 	data.x = md2->bl.x;
 	data.y = md2->bl.y;
 	
-	bx=md2->bl.x;
-	by=md2->bl.y;
 
 	if(mobdb_checkid(value[0]) == 0)
 		return 0;
@@ -2556,22 +2513,18 @@ int mob_summonslave(struct mob_data *md2,int *value,int amount,int skill_id)
 		amount+=k; //Increase final value by same amount to preserve total number to summon.
 	}
 	for(;k<amount;k++) {
-		int x=0,y=0,i=0;
+		int x,y;
 		data.class_ = value[k%count]; //Summon slaves in round-robin fashion. [Skotlex]
 		if (mobdb_checkid(data.class_) == 0)
 			continue;
 
-		while((x<=0 || y<=0 || map_getcell(data.m,x,y,CELL_CHKNOPASS)) && (i++)<100){
-			x=rand()%9-4+bx;
-			y=rand()%9-4+by;
-		}
-		if(i>=100){
-			x=bx;
-			y=by;
+		if (map_search_freecell(&md2->bl, 0, &x, &y, 4, 4, 0)) {
+			data.x = x;
+			data.y = y;
+		} else {
+			data.x = md2->bl.x;
+			data.y = md2->bl.y;
 		}
-		data.x = x;
-		data.y = y;
-
 		strcpy(data.name, "--ja--");	//These two need to be loaded from the db for each slave.
 		data.level = 0;
 		if (!mob_parse_dataset(&data))
@@ -2862,27 +2815,12 @@ int mobskill_use(struct mob_data *md, unsigned int tick, int event)
 			}
 			if (x <= 0 || y <= 0)
 				continue;
-			// Ž©•ª‚ÌŽüˆÍ
-			if (ms[i].target >= MST_AROUND1) {
-				int bx = x, by = y, i = 0, m = bl->m, r = (ms[i].target-MST_AROUND1) +1;
-				do {
-					bx = x + rand() % (r*2+1) - r;
-					by = y + rand() % (r*2+1) - r;
-				} while (map_getcell(m, bx, by, CELL_CHKNOREACH) && (i++) < 1000);
-				if (i < 1000){
-					x = bx; y = by;
-				}
-			}
-			// ‘ŠŽè‚ÌŽüˆÍ
-			if (ms[i].target >= MST_AROUND5) {
-				int bx = x, by = y, i = 0, m = bl->m, r = (ms[i].target-MST_AROUND5) + 1;
-				do {
-					bx = x + rand() % (r*2+1) - r;
-					by = y + rand() % (r*2+1) - r;
-				} while (map_getcell(m, bx, by, CELL_CHKNOREACH) && (i++) < 1000);
-				if (i < 1000){
-					x = bx; y = by;
-				}
+			// Look for an area to cast the spell around...
+			if (ms[i].target >= MST_AROUND1 || ms[i].target >= MST_AROUND5) {
+				int r = ms[i].target >= MST_AROUND1?
+					(ms[i].target-MST_AROUND1) +1:
+					(ms[i].target-MST_AROUND5) +1;
+				map_search_freecell(&md->bl, md->bl.m, &x, &y, r, r, 3);
 			}
 			return unit_skilluse_pos2(&md->bl, x, y, ms[i].skill_id, ms[i].skill_lv,
 				skill_castfix(&md->bl,ms[i].skill_id, ms[i].skill_lv, ms[i].casttime), ms[i].cancel);

+ 1 - 2
src/map/pc.c

@@ -193,8 +193,6 @@ int pc_addspiritball(struct map_session_data *sd,int interval,int max) {
 
 	if(max > MAX_SKILL_LEVEL)
 		max = MAX_SKILL_LEVEL;
-	if((sd->class_&MAPID_BASEMASK)==MAPID_GUNSLINGER)
-		max = 10;
 	if(sd->spiritball < 0)
 		sd->spiritball = 0;
 
@@ -3696,6 +3694,7 @@ char * job_name(int class_) {
 		
 	case JOB_WEDDING:
 	case JOB_SUPER_NOVICE:
+
 	case JOB_XMAS:
 		return msg_txt(570 - JOB_WEDDING+class_);
 		

+ 11 - 36
src/map/skill.c

@@ -2044,9 +2044,6 @@ int skill_area_sub( struct block_list *bl,va_list ap )
 	nullpo_retr(0, bl);
 	nullpo_retr(0, ap);
 
-	if(bl->type!=BL_PC && bl->type!=BL_MOB && bl->type!=BL_SKILL)
-		return 0;
-
 	src=va_arg(ap,struct block_list *); //ここではsrcの値を??ニしていないのでNULLチェックはしない
 	skill_id=va_arg(ap,int);
 	skill_lv=va_arg(ap,int);
@@ -2292,18 +2289,8 @@ static int skill_timerskill(int tid, unsigned int tick, int id,int data )
 		switch(skl->skill_id) {
 			case RG_INTIMIDATE:
 				if (unit_warp(src,-1,-1,-1,3) == 0) {
-					int x,y,i,j;
-					for(i=0;i<16;i++) {
-						j = rand()%8;
-						x = src->x + dirx[j];
-						y = src->y + diry[j];
-						if(map_getcell(src->m,x,y,CELL_CHKPASS))
-							break;
-					}
-					if(i >= 16) {
-						x = src->x;
-						y = src->y;
-					}
+					int x,y;
+					map_search_freecell(src, 0, &x, &y, 1, 1, 0);
 					if (!status_isdead(target))
 					unit_warp(target, -1, x, y, 3);
 				}
@@ -4854,7 +4841,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
 
 	case NPC_SUMMONSLAVE:		/* 手下?「喚 */
 	case NPC_SUMMONMONSTER:		/* MOB?「喚 */
-		if(md)
+		if(md && md->skillidx >= 0)
 			mob_summonslave(md,md->db->skill[md->skillidx].val,skilllv,skillid);
 		break;
 
@@ -4904,11 +4891,11 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
 
 	case NPC_TRANSFORMATION:
 	case NPC_METAMORPHOSIS:
-		if(md) {
+		if(md && md->skillidx >= 0) {
 			if (skilllv > 1)
 			{	//Multiply skilllv times, the original instance must be silently killed. [Skotlex] 
 				mob_summonslave(md,md->db->skill[md->skillidx].val,skilllv,skillid);
-				unit_free(src);
+				unit_remove_map(src,1);
 			}
 			else
 			{	//Transform into another class.
@@ -5523,7 +5510,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
 		if(sd) {
 			clif_skill_nodamage(src,bl,skillid,skilllv,1);
 			if(rand()%100 < (50+10*skilllv))
-				pc_addspiritball(sd,skill_get_time(skillid,skilllv),skilllv);
+				pc_addspiritball(sd,skill_get_time(skillid,skilllv),10);
 			else if(sd->spiritball > 0)
 				pc_delspiritball(sd,1,0);
 		}
@@ -5822,7 +5809,7 @@ int skill_castend_pos2( struct block_list *src, int x,int y,int skillid,int skil
 {
 	struct map_session_data *sd=NULL;
 	struct status_change *sc;
-	int i,tmpx = 0,tmpy = 0, x1 = 0, y1 = 0;
+	int i;
 
 	//if(skilllv <= 0) return 0;
 	if(skillid > 0 && skilllv <= 0) return 0;	// celest
@@ -5930,25 +5917,13 @@ int skill_castend_pos2( struct block_list *src, int x,int y,int skillid,int skil
 	case WZ_METEOR:				//�?テオスト?ム
 		{
 			int flag=0, area = skill_get_splash(skillid, skilllv);
+			int tmpx, tmpy, x1 = 0, y1 = 0;
 			if (sc && sc->data[SC_MAGICPOWER].timer != -1)
 				flag = flag|2; //Store the magic power flag for future use. [Skotlex]
 			for(i=0;i<2+(skilllv>>1);i++) {
-				int j=0;
-				do {
-					
-					tmpx = x + (rand()%area - area/2);
-					tmpy = y + (rand()%area - area/2);
-					if(tmpx < 0)
-						tmpx = 0;
-					else if(tmpx >= map[src->m].xs)
-						tmpx = map[src->m].xs - 1;
-					if(tmpy < 0)
-						tmpy = 0;
-					else if(tmpy >= map[src->m].ys)
-						tmpy = map[src->m].ys - 1;
-					j++;
-				} while((map_getcell(src->m,tmpx,tmpy,CELL_CHKNOPASS)) && j<100);
-				if(j >= 100)
+				tmpx = x;
+				tmpy = y;
+				if (!map_search_freecell(NULL, src->m, &tmpx, &tmpy, area, area, 1))
 					continue;
 				if(!(flag&1)){
 					clif_skill_poseffect(src,skillid,skilllv,tmpx,tmpy,tick);

+ 19 - 17
src/map/unit.c

@@ -393,7 +393,6 @@ int unit_getdir(struct block_list *bl)
 //it respects the no warp flags, so it is safe to call this without doing nowarpto/nowarp checks.
 int unit_warp(struct block_list *bl,int m,int x,int y,int type)
 {
-	int i=0,xs=9,ys=9,bx=x,by=y;
 	struct unit_data *ud;
 	nullpo_retr(0, bl);
 	ud = unit_bl2ud(bl);
@@ -419,25 +418,28 @@ int unit_warp(struct block_list *bl,int m,int x,int y,int type)
 			break;
 	}
 	
-	if(bx>0 && by>0)
-		xs=ys=9;
-
-	while( ( x<0 || y<0 || map_getcell(m,x,y,CELL_CHKNOPASS)) && (i++)<1000 ){
-		if( xs>0 && ys>0 && i<250 ){
-			x=bx+rand()%xs-xs/2;
-			y=by+rand()%ys-ys/2;
-		}else{
-			x=rand()%(map[m].xs-2)+1;
-			y=rand()%(map[m].ys-2)+1;
+	if (x<0 || y<0)
+  	{	//Random map position.
+		
+		if (!map_search_freecell(NULL, m, &x, &y, -1, -1, 1)) {
+			if(battle_config.error_log)
+				ShowWarning("unit_warp failed. Unit Id:%d/Type:%d, target position map %d (%s) at [%d,%d]\n", bl->id, bl->type, m, map[m].name, x, y);
+			return 2;
+			
 		}
-	}
-
-	if(i>=1000){
+	} else if (map_getcell(m,x,y,CELL_CHKNOREACH))
+	{	//Invalid target cell
 		if(battle_config.error_log)
-			ShowWarning("unit_warp failed. Unit Id:%d/Type:%d, target position map %d (%s) at [%d,%d]\n", bl->id, bl->type, m, map[m].name, bx,by);
-		return 2;
+			ShowWarning("unit_warp: Specified non-walkable target cell: %d (%s) at [%d,%d]\n", m, map[m].name, x,y);
+		
+		if (!map_search_freecell(NULL, m, &x, &y, 4, 4, 1))
+	 	{	//Can't find a nearby cell
+			if(battle_config.error_log)
+				ShowWarning("unit_warp failed. Unit Id:%d/Type:%d, target position map %d (%s) at [%d,%d]\n", bl->id, bl->type, m, map[m].name, x, y);
+			return 2;
+		}
 	}
-
+			
 	if (bl->type == BL_PC) //Use pc_setpos
 		return pc_setpos((TBL_PC*)bl, map[m].index, x, y, type);