瀏覽代碼

- 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 <x> <y> <size> <direction> <killable> <Event Name>
- @killbarricade <Event Name>
- If x and y are -1, it will use your current position.
- Direction 0 Vertical 1 Horizontal.

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

zephyrus 17 年之前
父節點
當前提交
0588524caa
共有 8 個文件被更改,包括 216 次插入3 次删除
  1. 41 0
      src/map/atcommand.c
  2. 4 0
      src/map/battle.c
  3. 3 0
      src/map/clif.c
  4. 9 0
      src/map/map.h
  5. 143 0
      src/map/mob.c
  6. 4 0
      src/map/mob.h
  7. 9 1
      src/map/skill.c
  8. 3 2
      src/map/status.c

+ 41 - 0
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 <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]
  *
@@ -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 },
 };
 
 

+ 4 - 0
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;
 		}
 	}

+ 3 - 0
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;
 	}
 	

+ 9 - 0
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;

+ 143 - 0
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;
 }

+ 4 - 0
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]
 

+ 9 - 1
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 ||

+ 3 - 2
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
 	}