From b87d090446143bfafdc9e801f745edcb16d93767 Mon Sep 17 00:00:00 2001 From: zephyrus Date: Thu, 13 Mar 2008 04:03:37 +0000 Subject: - Added a fix for Abracadabra, this skills allways should use minimum a Yellow Gem. - Added some code "suggestion" to handle the new Barricades, please test it with: - @barricade - @killbarricade - If x and y are -1, it will use your current position. - Direction 0 Vertical 1 Horizontal. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@12352 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/map/atcommand.c | 41 +++++++++++++++ src/map/battle.c | 4 ++ src/map/clif.c | 3 ++ src/map/map.h | 9 ++++ src/map/mob.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/map/mob.h | 4 ++ src/map/skill.c | 10 +++- src/map/status.c | 5 +- 8 files changed, 216 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 702a7550d..7a202d3fd 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -7810,6 +7810,45 @@ int atcommand_showdelay(const int fd, struct map_session_data* sd, const char* c return 0; } +/*========================================== + * Barricade Build + *------------------------------------------*/ +int atcommand_barricade(const int fd, struct map_session_data* sd, const char* command, const char* message) +{ + int x = 0, y = 0, size = 1, killable = 0, dir = 0; + char event[50]; + short result; + + if( !message || !*message || (sscanf(message, "%d %d %d %d %d %50s", &x, &y, &size, &dir, &killable, event) < 6) ) + { + clif_displaymessage(fd, "usage @barricade "); + return -1; + } + + if( x == -1 ) x = sd->bl.x; + if( y == -1 ) y = sd->bl.y; + + result = mob_barricade_build(sd->bl.m, x, y, size, dir, (bool)killable, event); + + switch( result ) + { + case 0: clif_displaymessage(fd, "Barricade build."); return 0; break; + case 1: clif_displaymessage(fd, "Barricade fail. Invalid Size"); break; + case 2: clif_displaymessage(fd, "Barricade fail. Wall problem."); break; + case 3: clif_displaymessage(fd, "Barricade fail. Invalid Event"); break; + case 4: clif_displaymessage(fd, "Barricade fail. Event allready exists"); break; + } + + return -1; +} + +int atcommand_barricade_destroy(const int fd, struct map_session_data* sd, const char* command, const char* message) +{ + mob_barricade_destroy(sd->bl.m, message); + + return 0; +} + /*========================================== * Duel organizing functions [LuzZza] * @@ -8529,6 +8568,8 @@ AtCommandInfo atcommand_info[] = { { "allowks", 6, atcommand_allowks }, { "cash", 60, atcommand_cash }, { "points", 60, atcommand_cash }, + { "barricade", 60, atcommand_barricade }, + { "killbarricade", 60, atcommand_barricade_destroy }, }; diff --git a/src/map/battle.c b/src/map/battle.c index 9026ea4d4..80660510f 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -3104,6 +3104,10 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f if (!(agit_flag && map[m].flag.gvg_castle) && md->guardian_data && md->guardian_data->guild_id) return 0; //Disable guardians/emperiums owned by Guilds on non-woe times. + + if( md->class_ == MOBID_BARRICADEA && md->barricade ) + return 0; + break; } } diff --git a/src/map/clif.c b/src/map/clif.c index af4668cad..cbcada2b1 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -7958,6 +7958,7 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) //Login Event npc_script_event(sd, NPCE_LOGIN); + mob_barricade_get(sd); } else if( sd->state.changemap ) { //For some reason the client "loses" these on map-change. clif_updatestatus(sd,SP_STR); @@ -7978,6 +7979,8 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) sd->state.night = 0; clif_status_load(&sd->bl, SI_NIGHT, 0); } + + mob_barricade_get(sd); sd->state.changemap = false; } diff --git a/src/map/map.h b/src/map/map.h index 194a49304..06dd27fb4 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -49,6 +49,8 @@ #define MAX_IGNORE_LIST 20 // official is 14 #define MAX_VENDING 12 #define MOBID_EMPERIUM 1288 +#define MOBID_BARRICADEB 1905 +#define MOBID_BARRICADEA 1906 // Undestruble #define MAX_PC_BONUS 10 #define MAX_DUEL 1024 @@ -882,6 +884,7 @@ struct mob_data { struct status_data status, *base_status; //Second one is in case of leveling up mobs, or tiny/large mobs. struct status_change sc; struct mob_db *db; //For quick data access (saves doing mob_db(md->class_) all the time) [Skotlex] + struct barricade_data *barricade; char name[NAME_LENGTH]; struct { unsigned size : 2; //Small/Big monsters. @@ -1157,6 +1160,11 @@ struct mapcell #endif }; +struct barricade_data { + char npc_event[50]; + short m, x, y, count, amount, dir; +}; + struct map_data { char name[MAP_NAME_LENGTH]; unsigned short index; // The map index used by the mapindex* functions. @@ -1168,6 +1176,7 @@ struct map_data { short bxs,bys; // map dimensions (in blocks) int npc_num; int users; + int barricade_num; struct map_flag { unsigned town : 1; // [Suggestion to protect Mail System] unsigned autotrade : 1; diff --git a/src/map/mob.c b/src/map/mob.c index 4a68d8c6f..dabee94ae 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -67,6 +67,8 @@ static struct { int class_[350]; } summon[MAX_RANDOMMONSTER]; +static DBMap* barricade_db; + #define CLASSCHANGE_BOSS_NUM 21 /*========================================== @@ -493,6 +495,141 @@ int mob_once_spawn_area(struct map_session_data* sd,int m,int x0,int y0,int x1,i return id; // id of last spawned mob } +/*========================================== + * Barricades [Zephyrus] + *------------------------------------------*/ +short mob_barricade_build(short m, short x, short y, short count, short dir, bool killable, const char* event) +{ + int i, j; + short x1 = dir ? x + count - 1 : x; + short y1 = dir ? y : y + count - 1; + struct mob_data *md; + struct barricade_data *barricade; + + if( count <= 0 ) + return 1; + + if( !event ) + return 2; + + if( (barricade = (struct barricade_data *)strdb_get(barricade_db,event)) != NULL ) + return 3; // Allready a barricade with event name + + if( map_getcell(m, x, y, CELL_CHKNOREACH) ) + return 4; // Starting cell problem + + CREATE(barricade, struct barricade_data, 1); + barricade->dir = dir; + barricade->x = x; + barricade->y = y; + barricade->m = m; + safestrncpy(barricade->npc_event, event, sizeof(barricade->npc_event)); + barricade->amount = 0; + + ShowInfo("New Barricade: %s.\n", barricade->npc_event); + + for( i = 0; i < count; i++ ) + { + x1 = dir ? x + i : x; + y1 = dir ? y : y + i; + + if( map_getcell(m, x1, y1, CELL_CHKNOREACH) ) + break; // Collision + + if( i % 2 == 0 ) + { + barricade->amount++; + j = mob_once_spawn(NULL, m, x1, y1, "--ja--", killable ? MOBID_BARRICADEB : MOBID_BARRICADEA, 1, ""); + md = (struct mob_data *)map_id2bl(j); + md->barricade = barricade; + } + + map_setgatcell(m, x1, y1, 5); + clif_changemapcell(0, m, x1, y1, 5, ALL_SAMEMAP); + } + + barricade->count = i; + + strdb_put(barricade_db, barricade->npc_event, barricade); + map[m].barricade_num++; + + return 0; +} + +void mob_barricade_get(struct map_session_data *sd) +{ + struct barricade_data *barricade; + DBIterator* iter; + DBKey key; + short x1, y1; + int i; + + if( map[sd->bl.m].barricade_num <= 0 ) + return; + + iter = barricade_db->iterator(barricade_db); + for( barricade = iter->first(iter,&key); iter->exists(iter); barricade = iter->next(iter,&key) ) + { + if( sd->bl.m != barricade->m ) + continue; + + for( i = 0; i < barricade->count; i++ ) + { + x1 = barricade->dir ? barricade->x + i : barricade->x; + y1 = barricade->dir ? barricade->y : barricade->y + i; + clif_changemapcell(sd->fd, barricade->m, x1, y1, 5, SELF); + } + } + iter->destroy(iter); +} + +static void mob_barricade_break(struct barricade_data *barricade) +{ + int i; + short x1, y1; + + if( barricade == NULL ) + return; + + if( --barricade->amount > 0 ) + return; // There are still barricades + + for( i = 0; i < barricade->count; i++ ) + { + x1 = barricade->dir ? barricade->x + i : barricade->x; + y1 = barricade->dir ? barricade->y : barricade->y + i; + + map_setgatcell(barricade->m, x1, y1, 0); + clif_changemapcell(0, barricade->m, x1, y1, 0, ALL_SAMEMAP); + } + + npc_event_do(barricade->npc_event); + map[barricade->m].barricade_num--; + + strdb_remove(barricade_db, barricade->npc_event); +} + +static int mob_barricade_destroy_sub(struct block_list *bl, va_list ap) +{ + TBL_MOB* md = (TBL_MOB*)bl; + char *event = va_arg(ap,char *); + + if( md->barricade == NULL ) + return 0; + + if( strcmp(event, md->barricade->npc_event) == 0 ) + status_kill(bl); + + return 0; +} + +void mob_barricade_destroy(short m, const char *event) +{ + if( !event ) + return; + + map_foreachinmap(mob_barricade_destroy_sub, m, BL_MOB, event, 0); +} /*========================================== * Set a Guardian's guild data [Skotlex] @@ -2338,6 +2475,9 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type) npc_script_event(mvp_sd, NPCE_KILLNPC); // PCKillNPC [Lance] } + if( md->barricade != NULL ) + mob_barricade_break(md->barricade); + if(md->deletetimer!=-1) { delete_timer(md->deletetimer,mob_timer_delete); md->deletetimer=-1; @@ -4199,6 +4339,8 @@ int do_init_mob(void) item_drop_ers = ers_new(sizeof(struct item_drop)); item_drop_list_ers = ers_new(sizeof(struct item_drop_list)); + barricade_db = strdb_alloc(DB_OPT_RELEASE_DATA,2*NAME_LENGTH+2+1); + #ifndef TXT_ONLY if(db_use_sqldbs) mob_read_sqldb(); @@ -4245,5 +4387,6 @@ int do_final_mob(void) } ers_destroy(item_drop_ers); ers_destroy(item_drop_list_ers); + barricade_db->destroy(barricade_db,NULL); return 0; } diff --git a/src/map/mob.h b/src/map/mob.h index 2590c90ed..8ba5baa4e 100644 --- a/src/map/mob.h +++ b/src/map/mob.h @@ -158,6 +158,10 @@ int mob_once_spawn(struct map_session_data* sd,int m,short x,short y,const char* 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); bool mob_ksprotected (struct block_list *src, struct block_list *target); +short mob_barricade_build(short m, short x, short y, short count, short dir, bool killable, const char* event); +void mob_barricade_destroy(short m, const char *event); +void mob_barricade_get(struct map_session_data *sd); + 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] diff --git a/src/map/skill.c b/src/map/skill.c index 1c1b1ab7c..d1e230247 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -1236,10 +1236,13 @@ int skill_blown(struct block_list* src, struct block_list* target, int count, in switch (target->type) { case BL_MOB: - if (((TBL_MOB*)target)->class_ == MOBID_EMPERIUM) + { + struct mob_data* md = BL_CAST(BL_MOB, target); + if( md->class_ == MOBID_EMPERIUM || md->class_ == MOBID_BARRICADEA || md->class_ == MOBID_BARRICADEB ) return 0; if(src != target && is_boss(target)) //Bosses can't be knocked-back return 0; + } break; case BL_PC: if(src != target && ((TBL_PC*)target)->special_state.no_knockback) @@ -8111,7 +8114,12 @@ int skill_check_condition(struct map_session_data* sd, short skill, short lv, in continue; } if(sc && sc->data[SC_INTOABYSS]) + { + if( skill != SA_ABRACADABRA ) continue; + else if( --amount[i] < 1 ) + amount[i] = 1; // Hocus Pocus allways use at least 1 gem + } } if((skill == AM_POTIONPITCHER || diff --git a/src/map/status.c b/src/map/status.c index 453c0b40e..be3c2c01c 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -4624,9 +4624,10 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val if( status_isdead(bl) ) return 0; - if( bl->type == BL_MOB && ((TBL_MOB*)bl)->class_ == MOBID_EMPERIUM ) + if( bl->type == BL_MOB ) { - if( type != SC_SAFETYWALL && type != SC_PNEUMA ) + struct mob_data *md = BL_CAST(BL_MOB,bl); + if( (md->class_ == MOBID_EMPERIUM && type != SC_SAFETYWALL && type != SC_PNEUMA) || md->class_ == MOBID_BARRICADEA ) return 0; //Emperium can't be afflicted by status changes } -- cgit v1.2.3-70-g09d2