summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/map/atcommand.c41
-rw-r--r--src/map/battle.c4
-rw-r--r--src/map/clif.c3
-rw-r--r--src/map/map.h9
-rw-r--r--src/map/mob.c143
-rw-r--r--src/map/mob.h4
-rw-r--r--src/map/skill.c10
-rw-r--r--src/map/status.c5
8 files changed, 216 insertions, 3 deletions
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
@@ -7811,6 +7811,45 @@ int atcommand_showdelay(const int fd, struct map_session_data* sd, const char* c
}
/*==========================================
+ * 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 <x> <y> <size> <dir> <killable> <event>");
+ 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]
*
* @duel [limit|nick] - create a duel
@@ -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
}