Browse Source

Cleaned up mob_once_spawn() and mob_once_spawn_area().
- now they use mapid instead of mapname as input parameter
- moved the responsibility to perform "this" -> mapid resolution to the caller
- added a pair of swap() operations to prevent working with a negative-dimensioned area (fixes bugreport:87)

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

ultramage 17 years ago
parent
commit
144afd8189
5 changed files with 121 additions and 88 deletions
  1. 3 3
      src/map/atcommand.c
  2. 66 51
      src/map/mob.c
  3. 2 5
      src/map/mob.h
  4. 48 27
      src/map/script.c
  5. 2 2
      src/map/skill.c

+ 3 - 3
src/map/atcommand.c

@@ -2454,7 +2454,7 @@ int atcommand_monster(const int fd, struct map_session_data* sd, const char* com
 	range = (int)sqrt(number) +2; // calculation of an odd number (+ 4 area around)
 	for (i = 0; i < number; i++) {
 		map_search_freecell(&sd->bl, 0, &mx,  &my, range, range, 0);
-		k = mob_once_spawn(sd, "this", mx, my, name, mob_id, 1, "");
+		k = mob_once_spawn(sd, sd->bl.m, mx, my, name, mob_id, 1, "");
 		count += (k != 0) ? 1 : 0;
 	}
 
@@ -2539,7 +2539,7 @@ int atcommand_monstersmall(const int fd, struct map_session_data* sd, const char
 			my = sd->bl.y + (rand() % 11 - 5);
 		else
 			my = y;
-		count += (mob_once_spawn((struct map_session_data*)sd, "this", mx, my, name, mob_id, 1, "2") != 0) ? 1 : 0;
+		count += (mob_once_spawn(sd, sd->bl.m, mx, my, name, mob_id, 1, "2") != 0) ? 1 : 0;
 	}
 
 	if (count != 0)
@@ -2615,7 +2615,7 @@ int atcommand_monsterbig(const int fd, struct map_session_data* sd, const char*
 			my = sd->bl.y + (rand() % 11 - 5);
 		else
 			my = y;
-		count += (mob_once_spawn((struct map_session_data*)sd, "this", mx, my, name, mob_id, 1, "4") != 0) ? 1 : 0;
+		count += (mob_once_spawn(sd, sd->bl.m, mx, my, name, mob_id, 1, "4") != 0) ? 1 : 0;
 	}
 
 	if (count != 0)

+ 66 - 51
src/map/mob.c

@@ -285,7 +285,7 @@ struct mob_data *mob_once_spawn_sub(struct block_list *bl, int m, short x, short
 	data.num = 1;
 	data.class_ = class_;
 	if (mobname)
-		strncpy(data.name, mobname, NAME_LENGTH-1);
+		safestrncpy(data.name, mobname, sizeof(data.name));
 	else
 	if(battle_config.override_mob_names==1)
 		strcpy(data.name,"--en--");
@@ -293,11 +293,13 @@ struct mob_data *mob_once_spawn_sub(struct block_list *bl, int m, short x, short
 		strcpy(data.name,"--ja--");
 
 	if (event)
-		strncpy(data.eventname, event, 50);
+		safestrncpy(data.eventname, event, sizeof(data.eventname));
 	
-	if (bl && (x < 0 || y < 0))//Locate spot around player.
+	// Locate spot next to player.
+	if (bl && (x < 0 || y < 0))
 		map_search_freecell(bl, m, &x, &y, 1, 1, 0);
 
+	// if none found, pick random position on map
 	if (x <= 0 || y <= 0 || map_getcell(m,x,y,CELL_CHKNOREACH))
 		map_search_freecell(NULL, m, &x, &y, -1, -1, 1);
 	
@@ -309,35 +311,32 @@ struct mob_data *mob_once_spawn_sub(struct block_list *bl, int m, short x, short
 
 	return mob_spawn_dataset(&data);
 }
+
 /*==========================================
- * The MOB appearance for one time (for scripts)
+ * Spawn a single mob on the specified coordinates.
  *------------------------------------------*/
-int mob_once_spawn (struct map_session_data* sd, const char* mapname, short x, short y, const char* mobname, int class_, int amount, const char* event)
+int mob_once_spawn(struct map_session_data* sd, int m, short x, short y, const char* mobname, int class_, int amount, const char* event)
 {
 	struct mob_data* md = NULL;
-	int m, count, lv = 255;
+	int count, lv;
 	
-	if(sd) lv = sd->status.base_level;
+	if (m < 0 || amount <= 0)
+		return 0; // invalid input
 
-	if(sd && strcmp(mapname,"this")==0)
-		m = sd->bl.m;
+	if(sd)
+		lv = sd->status.base_level;
 	else
-		m = map_mapname2mapid(mapname);
+		lv = 255;
 
-	if (m < 0 || amount <= 0)	// 値が異常なら召喚を止める
-		return 0;
-	
 	for (count = 0; count < amount; count++)
 	{
-		md = mob_once_spawn_sub(sd?&sd->bl:NULL, m, x, y, mobname,
-			class_<0?
-				mob_get_random_id(-class_-1, battle_config.random_monster_checklv?3:1, lv):
-				class_, event);
+		int c = ( class_ >= 0 ) ? class_ : mob_get_random_id(-class_-1, battle_config.random_monster_checklv?3:1, lv);
+		md = mob_once_spawn_sub(sd?&sd->bl:NULL, m, x, y, mobname, c, event);
 
 		if (!md) continue;
 
 		if(class_ == MOBID_EMPERIUM) {
-			struct guild_castle* gc = guild_mapname2gc(map[md->bl.m].name);
+			struct guild_castle* gc = guild_mapindex2gc(map[m].index);
 			struct guild* g = gc?guild_search(gc->guild_id):NULL;
 			if(gc) {
 				md->guardian_data = aCalloc(1, sizeof(struct guardian_data));
@@ -353,55 +352,71 @@ int mob_once_spawn (struct map_session_data* sd, const char* mapname, short x, s
 					add_timer(gettick()+5000,mob_spawn_guardian_sub,md->bl.id,md->guardian_data->guild_id);
 			}
 		}	// end addition [Valaris]
-		mob_spawn (md);
+
+		mob_spawn(md);
+
 		if (class_ < 0 && battle_config.dead_branch_active)
 			//Behold Aegis's masterful decisions yet again...
 			//"I understand the "Aggressive" part, but the "Can Move" and "Can Attack" is just stupid" - Poki#3
 			sc_start4(&md->bl, SC_MODECHANGE, 100, 1, 0, MD_AGGRESSIVE|MD_CANATTACK|MD_CANMOVE, 0, 60000);
 	}
-	return (md)?md->bl.id : 0;
+
+	return (md)?md->bl.id : 0; // id of last spawned mob
 }
+
 /*==========================================
- * The MOB appearance for one time (& area specification for scripts)
+ * Spawn mobs in the specified area.
  *------------------------------------------*/
-int mob_once_spawn_area(struct map_session_data *sd,const char *mapname,
-	int x0,int y0,int x1,int y1,
-	const char *mobname,int class_,int amount,const char *event)
+int mob_once_spawn_area(struct map_session_data* sd,int m,int x0,int y0,int x1,int y1,const char* mobname,int class_,int amount,const char* event)
 {
-	int x,y,i,max,lx=-1,ly=-1,id=0;
-	int m;
+	int i,max,id=0;
+	int lx=-1,ly=-1;
 
-	if(strcmp(mapname,"this")==0)
-		m=sd->bl.m;
-	else
-		m=map_mapname2mapid(mapname);
+	if (m < 0 || amount <= 0)
+		return 0; // invalid input
 
-	max=(y1-y0+1)*(x1-x0+1)*3;
-	if(max>1000)max=1000;
+	// normalize x/y coordinates
+	if( x0 > x1 ) swap(x0,x1);
+	if( y0 > y1 ) swap(y0,y1);
 
-	if (m < 0 || amount <= 0)	// 値が異常なら召喚を止める
-		return 0;
+	// choose a suitable max. number of attempts
+	max = (y1-y0+1)*(x1-x0+1)*3;
+	if( max > 1000 )
+		max = 1000;
 
-	for(i=0;i<amount;i++){
-		int j=0;
-		do{
-			x=rand()%(x1-x0+1)+x0;
-			y=rand()%(y1-y0+1)+y0;
-		} while (map_getcell(m,x,y,CELL_CHKNOPASS) && (++j)<max);
-		if(j>=max){
-			if(lx>=0){	// Since reference went wrong, the place which boiled before is used.
-				x=lx;
-				y=ly;
-			}else
-				return 0;	// Since reference of the place which boils first went wrong, it stops.
+	// spawn mobs, one by one
+	for( i = 0; i < amount; i++)
+	{
+		int x,y;
+		int j = 0;
+
+		// find a suitable map cell
+		do {
+			x = rand()%(x1-x0+1)+x0;
+			y = rand()%(y1-y0+1)+y0;
+			j++;
+		} while( map_getcell(m,x,y,CELL_CHKNOPASS) && j < max );
+
+		if( j == max )
+		{// attempt to find an available cell failed
+			if( lx == -1 && ly == -1 )
+				return 0; // total failure
+			
+			// fallback to last good x/y pair
+			x = lx;
+			y = ly;
 		}
-		if(x==0||y==0) ShowWarning("mob_once_spawn_area: xory=0, x=%d,y=%d,x0=%d,y0=%d\n",x,y,x0,y0);
-		id=mob_once_spawn(sd,mapname,x,y,mobname,class_,1,event);
-		lx=x;
-		ly=y;
+
+		// record last successful coordinates
+		lx = x;
+		ly = y;
+
+		id = mob_once_spawn(sd,m,x,y,mobname,class_,1,event);
 	}
-	return id;
+
+	return id; // id of last spawned mob
 }
+
 /*==========================================
  * Set a Guardian's guild data [Skotlex]
  *------------------------------------------*/

+ 2 - 5
src/map/mob.h

@@ -154,11 +154,8 @@ int mobdb_checkid(const int id);
 struct view_data* mob_get_viewdata(int class_);
 struct mob_data *mob_once_spawn_sub(struct block_list *bl, int m,
 	short x, short y, const char *mobname, int class_, const char *event);
-int mob_once_spawn(struct map_session_data *sd,const char *mapname,
-	short x,short y,const char *mobname,int class_,int amount,const char *event);
-int mob_once_spawn_area(struct map_session_data *sd,const char *mapname,
-	int x0,int y0,int x1,int y1,
-	const char *mobname,int class_,int amount,const char *event);
+int mob_once_spawn(struct map_session_data* sd,int m,short x,short y,const char* mobname,int class_,int amount,const char* event);
+int mob_once_spawn_area(struct map_session_data* sd,int m,int x0,int y0,int x1,int y1,const char* mobname,int class_,int amount,const char* event);
 
 int mob_spawn_guardian(const char* mapname, short x, short y, const char* mobname, int class_, const char* event, int guardian);	// Spawning Guardians [Valaris]
 int mob_guardian_guildchange(struct block_list *bl,va_list ap); //Change Guardian's ownership. [Skotlex]

+ 48 - 27
src/map/script.c

@@ -7334,17 +7334,20 @@ BUILDIN_FUNC(guildchangegm)
  *------------------------------------------*/
 BUILDIN_FUNC(monster)
 {
-	int class_,amount,x,y;
-	const char *str,*map,*event="";
+	const char* map   = script_getstr(st,2);
+	int x             = script_getnum(st,3);
+	int y             = script_getnum(st,4);
+	const char* str   = script_getstr(st,5);
+	int class_        = script_getnum(st,6);
+	int amount        = script_getnum(st,7);
+	const char* event = "";
+
+	struct map_session_data* sd;
+	int m;
 
-	map	=script_getstr(st,2);
-	x	=script_getnum(st,3);
-	y	=script_getnum(st,4);
-	str	=script_getstr(st,5);
-	class_=script_getnum(st,6);
-	amount=script_getnum(st,7);
-	if( script_hasdata(st,8) ){
-		event=script_getstr(st,8);
+	if( script_hasdata(st,8) )
+	{
+		event = script_getstr(st,8);
 		check_event(st, event);
 	}
 
@@ -7352,7 +7355,15 @@ BUILDIN_FUNC(monster)
 		ShowWarning("buildin_monster: Attempted to spawn non-existing monster class %d\n", class_);
 		return 1;
 	}
-	mob_once_spawn(map_id2sd(st->rid),map,x,y,str,class_,amount,event);
+
+	sd = map_id2sd(st->rid);
+
+	if( sd && strcmp(map,"this") == 0 )
+		m = sd->bl.m;
+	else
+		m = map_mapname2mapid(map);
+
+	mob_once_spawn(sd,m,x,y,str,class_,amount,event);
 	return 0;
 }
 /*==========================================
@@ -7360,23 +7371,33 @@ BUILDIN_FUNC(monster)
  *------------------------------------------*/
 BUILDIN_FUNC(areamonster)
 {
-	int class_,amount,x0,y0,x1,y1;
-	const char *str,*map,*event="";
-
-	map	=script_getstr(st,2);
-	x0	=script_getnum(st,3);
-	y0	=script_getnum(st,4);
-	x1	=script_getnum(st,5);
-	y1	=script_getnum(st,6);
-	str	=script_getstr(st,7);
-	class_=script_getnum(st,8);
-	amount=script_getnum(st,9);
-	if( script_hasdata(st,10) ){
-		event=script_getstr(st,10);
+	const char* map   = script_getstr(st,2);
+	int x0            = script_getnum(st,3);
+	int y0            = script_getnum(st,4);
+	int x1            = script_getnum(st,5);
+	int y1            = script_getnum(st,6);
+	const char* str   = script_getstr(st,7);
+	int class_        = script_getnum(st,8);
+	int amount        = script_getnum(st,9);
+	const char* event = "";
+
+	struct map_session_data* sd;
+	int m;
+
+	if( script_hasdata(st,10) )
+	{
+		event = script_getstr(st,10);
 		check_event(st, event);
 	}
 
-	mob_once_spawn_area(map_id2sd(st->rid),map,x0,y0,x1,y1,str,class_,amount,event);
+	sd = map_id2sd(st->rid);
+
+	if( sd && strcmp(map,"this") == 0 )
+		m = sd->bl.m;
+	else
+		m = map_mapname2mapid(map);
+
+	mob_once_spawn_area(sd,m,x0,y0,x1,y1,str,class_,amount,event);
 	return 0;
 }
 /*==========================================
@@ -12290,8 +12311,8 @@ BUILDIN_FUNC(mobspawn)
 	map		=script_getstr(st,4);
 	x		=script_getnum(st,5);
 	y		=script_getnum(st,6);
-		
-	id = mob_once_spawn(map_id2sd(st->rid),map,x,y,str,class_,1,"");
+
+	id = mob_once_spawn(map_id2sd(st->rid),map_mapname2mapid(map),x,y,str,class_,1,"");
 	script_pushint(st,id);
 
 	return 0;

+ 2 - 2
src/map/skill.c

@@ -3072,7 +3072,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
 		break;
 	case SA_SUMMONMONSTER:
 		clif_skill_nodamage(src,bl,skillid,skilllv,1);
-		if (sd) mob_once_spawn(sd,map[src->m].name,src->x,src->y,"--ja--",-1,1,"");
+		if (sd) mob_once_spawn(sd,src->m,src->x,src->y,"--ja--",-1,1,"");
 		break;
 	case SA_LEVELUP:
 		clif_skill_nodamage(src,bl,skillid,skilllv,1);
@@ -5804,7 +5804,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, int skillid, int sk
 			pc_delitem(sd,j,skill_db[skillid].amount[i],0);
 			clif_skill_poseffect(src,skillid,skilllv,x,y,tick);
 			if (rand()%100 < 50)
-				mob_once_spawn(sd, "this", x, y, "--ja--",(skilllv < 2 ? 1084+rand()%2 : 1078+rand()%6), 1, "");
+				mob_once_spawn(sd, sd->bl.m, x, y, "--ja--",(skilllv < 2 ? 1084+rand()%2 : 1078+rand()%6), 1, "");
 			else
 				clif_skill_fail(sd,skillid,0,0);
 		}