summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Changelog-Trunk.txt2
-rw-r--r--src/map/map.c67
-rw-r--r--src/map/map.h1
-rw-r--r--src/map/mob.c126
-rw-r--r--src/map/pc.c3
-rw-r--r--src/map/skill.c47
-rw-r--r--src/map/unit.c36
7 files changed, 133 insertions, 149 deletions
diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt
index 914589111..7ec67d53f 100644
--- a/Changelog-Trunk.txt
+++ b/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]
diff --git a/src/map/map.c b/src/map/map.c
index f218572b3..030ea4d02 100644
--- a/src/map/map.c
+++ b/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以?に床アイテム設置
*
diff --git a/src/map/map.h b/src/map/map.h
index 4ba04c905..b80f6f295 100644
--- a/src/map/map.h
+++ b/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
diff --git a/src/map/mob.c b/src/map/mob.c
index e907fa862..e0488bc3d 100644
--- a/src/map/mob.c
+++ b/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);
diff --git a/src/map/pc.c b/src/map/pc.c
index 03ec2c512..4063d97f0 100644
--- a/src/map/pc.c
+++ b/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_);
diff --git a/src/map/skill.c b/src/map/skill.c
index 5ae210054..786a3b17d 100644
--- a/src/map/skill.c
+++ b/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);
diff --git a/src/map/unit.c b/src/map/unit.c
index f41796d26..1e2e2268b 100644
--- a/src/map/unit.c
+++ b/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);