From dc3d23e60aaad210be711844ab24b3a0a2b113aa Mon Sep 17 00:00:00 2001 From: skotlex Date: Fri, 24 Mar 2006 18:20:55 +0000 Subject: - Added function map_search_freecell to locate an available cell around an area (for recall/warping skills) git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@5732 54d463be-8e91-2dee-dedb-b68131a5f0ec --- Changelog-Trunk.txt | 2 + src/map/map.c | 67 ++++++++++++++++++++++++++++ src/map/map.h | 1 + src/map/mob.c | 126 +++++++++++++--------------------------------------- src/map/pc.c | 3 +- src/map/skill.c | 47 +++++--------------- src/map/unit.c | 36 ++++++++------- 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=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); -- cgit v1.2.3-70-g09d2