瀏覽代碼

* Made script command 'flagemblem' and guild_emblem_change send an update of the emblem_id to the players in the area.
- known bug: ui components that are displaying the emblem at the time (emblem in flag npc and emblem over head in gvg maps) are not updated, but putting the mouse over the target shows the new emblem
* Modified script command 'guardian':
- returns the id of the guardian
- if guardian index isn't supplied, it generates a temporary guardian
* Implemented support for temporary guardians (not saved with castle).
* Added missing includes from r12520.

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

FlavioJS 17 年之前
父節點
當前提交
cd1f48cc9e
共有 13 個文件被更改,包括 168 次插入24 次删除
  1. 13 0
      Changelog-Trunk.txt
  2. 9 2
      doc/script_commands.txt
  3. 2 0
      src/common/mmo.h
  4. 16 0
      src/map/clif.c
  5. 1 0
      src/map/clif.h
  6. 52 2
      src/map/guild.c
  7. 1 0
      src/map/map.h
  8. 35 12
      src/map/mob.c
  9. 1 1
      src/map/mob.h
  10. 1 0
      src/map/npc.c
  11. 23 4
      src/map/script.c
  12. 1 0
      src/map/trade.c
  13. 13 3
      src/map/unit.c

+ 13 - 0
Changelog-Trunk.txt

@@ -4,7 +4,20 @@ AS OF SVN REV. 5091, WE ARE NOW USING TRUNK.  ALL UNTESTED BUGFIXES/FEATURES GO
 IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
 
 2008/04/07
+	* Made script command 'flagemblem' and guild_emblem_change send an update 
+	  of the emblem_id to the players in the area.
+	- known bug: ui components that are displaying the emblem at the time 
+	  (emblem in flag npc and emblem over head in gvg maps) are not updated,
+	  but putting the mouse over the target shows the new emblem
+	* Modified script command 'guardian':
+	- returns the id of the guardian
+	- if guardian index isn't supplied, it generates a temporary guardian
+	* Implemented support for temporary guardians (not saved with castle).
+	* Added missing includes from r12520. [FlavioJS]
 	* Party/guild names can no longer be less then 2 characters long. (r12521) [Kevin]
+	* Removed the 'wait close' timer that closed a session's socket after 5 seconds.
+	  This was causing random disconnects when logging in. (bugreport:1330) 
+	* Improved the Mental Sensing fix from r12507 to not start the status at all, instead of starting it and ignoring it later on.  [ultramage]
 2008/04/06
 	* Fixed a case where a dangling pointer was formed when a person was
 	- invited to a party immediately after creating their own. (r12518) [Kevin]

+ 9 - 2
doc/script_commands.txt

@@ -4,7 +4,7 @@
 //= A reference manual for the eAthena scripting language.
 //= Commands are sorted depending on their functionality.
 //===== Version ===========================================
-//= 3.18.20080327
+//= 3.19.20080407
 //=========================================================
 //= 1.0 - First release, filled will as much info as I could
 //=       remember or figure out, most likely there are errors,
@@ -108,6 +108,8 @@
 //=       Corrected cashshop description. (#FREEPOINTS->#KAFRAPOINTS) [L0ne_W0lf]
 //= 3.18.20080327
 //=       Added documentation for the 'checkcell' command [ultramage]
+//= 3.19.20080407
+//=       Extended the behaviour of 'guardian'. [FlavioJS]
 //=========================================================
 
 This document is a reference manual for all the scripting commands and functions 
@@ -5514,13 +5516,18 @@ returns a guild id:
 
 ---------------------------------------
 
-*guardian "<map name>",<x>,<y>,"<name to show>",<mob id>,<amount>{,"<event label>"}{,<guardian index>};
+*guardian("<map name>",<x>,<y>,"<name to show>",<mob id>,<amount>{,"<event label>"}{,<guardian index>})
 
 This command is roughly equivalent to 'monster', but is meant to be used with 
 castle guardian monsters and will only work with them. It will set the guardian 
 characteristics up according to the castle's investment values and otherwise 
 set the things up that only castle guardians need.
 
+Since trunk r12524:
+Returns the id of the mob or 0 if an error occurred.
+When 'guardian index' isn't supplied it produces a temporary guardian.
+Temporary guardians are not saved with the castle and can't be accessed by guardianinfo.
+
 ---------------------------------------
 
 *guardianinfo("<map name>", <guardian number>, <type>)

+ 2 - 0
src/common/mmo.h

@@ -425,6 +425,8 @@ struct guild_castle {
 		unsigned visible : 1;
 		int id; // object id
 	} guardian[MAX_GUARDIANS];
+	int* temp_guardians; // ids of temporary guardians (mobs)
+	int temp_guardians_max;
 };
 
 // for Brandish Spear calculations

+ 16 - 0
src/map/clif.c

@@ -6327,6 +6327,22 @@ int clif_guild_emblem(struct map_session_data *sd,struct guild *g)
 	return 0;
 }
 
+/// Sends update of the guild id/emblem id to everyone in the area.
+void clif_guild_emblem_area(struct block_list* bl)
+{
+	char buf[12];
+
+	nullpo_retv(bl);
+
+	// TODO this packet doesn't force the update of ui components that have the emblem visible
+	//      (emblem in the flag npcs and emblem over the head in agit maps) [FlavioJS]
+	WBUFW(buf,0) = 0x1B4;
+	WBUFL(buf,2) = bl->id;
+	WBUFL(buf,6) = status_get_guild_id(bl);
+	WBUFW(buf,10) = status_get_emblem_id(bl);
+	clif_send(buf, 12, bl, AREA_WOS);
+}
+
 /*==========================================
  * Send guild skills
  *------------------------------------------*/

+ 1 - 0
src/map/clif.h

@@ -307,6 +307,7 @@ int clif_guild_expulsion(struct map_session_data *sd,const char *name,const char
 int clif_guild_positionchanged(struct guild *g,int idx);
 int clif_guild_memberpositionchanged(struct guild *g,int idx);
 int clif_guild_emblem(struct map_session_data *sd,struct guild *g);
+void clif_guild_emblem_area(struct block_list* bl);
 int clif_guild_notice(struct map_session_data *sd,struct guild *g);
 int clif_guild_message(struct guild *g,int account_id,const char *mes,int len);
 int clif_guild_skillup(struct map_session_data *sd,int skill_num,int lv);

+ 52 - 2
src/map/guild.c

@@ -1103,8 +1103,49 @@ int guild_emblem_changed(int len,int guild_id,int emblem_id,const char *data)
 			sd->guild_emblem_id=emblem_id;
 			clif_guild_belonginfo(sd,g);
 			clif_guild_emblem(sd,g);
+			clif_guild_emblem_area(&sd->bl);
 		}
 	}
+	{// update guardians (mobs)
+		DBIterator* iter = db_iterator(castle_db);
+		struct guild_castle* gc;
+		for( gc = (struct guild_castle*)dbi_first(iter) ; dbi_exists(iter); gc = (struct guild_castle*)dbi_next(iter) )
+		{
+			if( gc->guild_id != guild_id )
+				continue;
+			// update permanent guardians
+			for( i = 0; i < ARRAYLENGTH(gc->guardian); ++i )
+			{
+				TBL_MOB* md = (gc->guardian[i].id ? map_id2md(gc->guardian[i].id) : NULL);
+				if( md == NULL || md->guardian_data == NULL )
+					continue;
+				md->guardian_data->emblem_id = emblem_id;
+				clif_guild_emblem_area(&md->bl);
+			}
+			// update temporary guardians
+			for( i = 0; i < gc->temp_guardians_max; ++i )
+			{
+				TBL_MOB* md = (gc->temp_guardians[i] ? map_id2md(gc->temp_guardians[i]) : NULL);
+				if( md == NULL || md->guardian_data == NULL )
+					continue;
+				md->guardian_data->emblem_id = emblem_id;
+				clif_guild_emblem_area(&md->bl);
+			}
+		}
+		dbi_destroy(iter);
+	}
+	{// update npcs (flags or other npcs that used flagemblem to attach to this guild)
+		// TODO this is not efficient [FlavioJS]
+		struct s_mapiterator* iter = mapit_geteachnpc();
+		TBL_NPC* nd;
+		for( nd = (TBL_NPC*)mapit_first(iter) ; mapit_exists(iter); nd = (TBL_NPC*)mapit_next(iter) )
+		{
+			if( nd->subtype != SCRIPT || nd->u.scr.guild_id != guild_id )
+				continue;
+			clif_guild_emblem_area(&nd->bl);
+		}
+		mapit_free(iter);
+	}
 	return 0;
 }
 
@@ -1909,10 +1950,19 @@ static int guild_expcache_db_final(DBKey key,void *data,va_list ap)
 	return 0;
 }
 
+static int guild_castle_db_final(DBKey key, void* data,va_list ap)
+{
+	struct guild_castle* gc = (struct guild_castle*)data;
+	if( gc->temp_guardians )
+		aFree(gc->temp_guardians);
+	aFree(data);
+	return 0;
+}
+
 void do_init_guild(void)
 {
 	guild_db=idb_alloc(DB_OPT_RELEASE_DATA);
-	castle_db=idb_alloc(DB_OPT_RELEASE_DATA);
+	castle_db=idb_alloc(DB_OPT_BASE);
 	guild_expcache_db=idb_alloc(DB_OPT_BASE);
 	guild_infoevent_db=idb_alloc(DB_OPT_BASE);
 	expcache_ers = ers_new(sizeof(struct guild_expcache)); 
@@ -1932,7 +1982,7 @@ void do_init_guild(void)
 void do_final_guild(void)
 {
 	guild_db->destroy(guild_db,NULL);
-	castle_db->destroy(castle_db,NULL);
+	castle_db->destroy(castle_db,guild_castle_db_final);
 	guild_expcache_db->destroy(guild_expcache_db,guild_expcache_db_final);
 	guild_infoevent_db->destroy(guild_infoevent_db,guild_infoevent_db_final);
 	guild_castleinfoevent_db->destroy(guild_castleinfoevent_db,guild_infoevent_db_final);

+ 1 - 0
src/map/map.h

@@ -584,6 +584,7 @@ bool                    mapit_exists(struct s_mapiterator* mapit);
 #define mapit_getallusers() mapit_alloc(MAPIT_NORMAL,BL_PC)
 #define mapit_geteachpc()   mapit_alloc(MAPIT_NORMAL,BL_PC)
 #define mapit_geteachmob()  mapit_alloc(MAPIT_NORMAL,BL_MOB)
+#define mapit_geteachnpc()  mapit_alloc(MAPIT_NORMAL,BL_NPC)
 #define mapit_geteachiddb() mapit_alloc(MAPIT_NORMAL,BL_ALL)
 
 // ‚»‚Ì‘¼

+ 35 - 12
src/map/mob.c

@@ -677,6 +677,7 @@ static int mob_spawn_guardian_sub(int tid,unsigned int tick,int id,int data)
 	struct block_list* bl = map_id2bl(id);
 	struct mob_data* md; 
 	struct guild* g;
+	int guardup_lv;
 
 	if (bl == NULL) //It is possible mob was already removed from map when the castle has no owner. [Skotlex]
 		return 0;
@@ -703,7 +704,7 @@ static int mob_spawn_guardian_sub(int tid,unsigned int tick,int id,int data)
 				guild_castledatasave(md->guardian_data->castle->castle_id, 1, 0);
 			}
 		} else {
-			if (md->guardian_data->castle->guardian[md->guardian_data->number].visible)
+			if( md->guardian_data->number >= 0 && md->guardian_data->number < MAX_GUARDIANS && md->guardian_data->castle->guardian[md->guardian_data->number].visible )
 			{	//Safe removal of guardian.
 				md->guardian_data->castle->guardian[md->guardian_data->number].visible = 0;
 				guild_castledatasave(md->guardian_data->castle->castle_id, 10+md->guardian_data->number,0);
@@ -712,10 +713,11 @@ static int mob_spawn_guardian_sub(int tid,unsigned int tick,int id,int data)
 		}
 		return 0;
 	}
+	guardup_lv = guild_checkskill(g,GD_GUARDUP);
 	md->guardian_data->emblem_id = g->emblem_id;
-	memcpy (md->guardian_data->guild_name, g->name, NAME_LENGTH);
-	md->guardian_data->guardup_lv = guild_checkskill(g,GD_GUARDUP);
-	if(md->guardian_data->guardup_lv)
+	memcpy(md->guardian_data->guild_name, g->name, NAME_LENGTH);
+	md->guardian_data->guardup_lv = guardup_lv;
+	if( guardup_lv )
 		status_calc_mob(md, 0); //Give bonuses.
 	return 0;
 }
@@ -723,7 +725,7 @@ static int mob_spawn_guardian_sub(int tid,unsigned int tick,int id,int data)
 /*==========================================
  * Summoning Guardians [Valaris]
  *------------------------------------------*/
-int mob_spawn_guardian(const char* mapname, short x, short y, const char* mobname, int class_, const char* event, int guardian)
+int mob_spawn_guardian(const char* mapname, short x, short y, const char* mobname, int class_, const char* event, int guardian, bool has_index)
 {
 	struct mob_data *md=NULL;
 	struct spawn_data data;
@@ -749,7 +751,11 @@ int mob_spawn_guardian(const char* mapname, short x, short y, const char* mobnam
 
 	data.class_ = class_;
 
-	if(guardian < 0 || guardian >= MAX_GUARDIANS)
+	if( !has_index )
+	{
+		guardian = -1;
+	}
+	else if( guardian < 0 || guardian >= MAX_GUARDIANS )
 	{
 		ShowError("mob_spawn_guardian: Invalid guardian index %d for guardian %d (castle map %s)\n", guardian, class_, map[m].name);
 		return 0;
@@ -778,7 +784,7 @@ int mob_spawn_guardian(const char* mapname, short x, short y, const char* mobnam
 	else
 		g = guild_search(gc->guild_id);
 
-	if (gc->guardian[guardian].id)
+	if( has_index && gc->guardian[guardian].id )
   	{	//Check if guardian already exists, refuse to spawn if so.
 		struct mob_data *md2 = (TBL_MOB*)map_id2bl(gc->guardian[guardian].id);
 		if (md2 && md2->bl.type == BL_MOB &&
@@ -794,7 +800,21 @@ int mob_spawn_guardian(const char* mapname, short x, short y, const char* mobnam
 	md->guardian_data->number = guardian;
 	md->guardian_data->guild_id = gc->guild_id;
 	md->guardian_data->castle = gc;
-	gc->guardian[guardian].id = md->bl.id;
+	if( has_index )
+	{// permanent guardian
+		gc->guardian[guardian].id = md->bl.id;
+	}
+	else
+	{// temporary guardian
+		int i;
+		ARR_FIND(0, gc->temp_guardians_max, i, gc->temp_guardians[i] == 0);
+		if( i == gc->temp_guardians_max )
+		{
+			++(gc->temp_guardians_max);
+			RECREATE(gc->temp_guardians, int, gc->temp_guardians_max);
+		}
+		gc->temp_guardians[i] = md->bl.id;
+	}
 	if (g)
 	{
 		md->guardian_data->emblem_id = g->emblem_id;
@@ -2077,7 +2097,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
 
 	status = &md->status;
 		
-	if(md->guardian_data && md->guardian_data->number < MAX_GUARDIANS)
+	if( md->guardian_data && md->guardian_data->number >= 0 && md->guardian_data->number < MAX_GUARDIANS )
 		guild_castledatasave(md->guardian_data->castle->castle_id, 10+md->guardian_data->number,0);
 
 	md->state.skillstate = MSS_DEAD;	
@@ -2588,7 +2608,7 @@ int mob_guardian_guildchange(struct block_list *bl,va_list ap)
 			md->guardian_data->emblem_id = 0;
 			md->guardian_data->guild_name[0] = '\0';
 		} else {
-			if (md->guardian_data->castle->guardian[md->guardian_data->number].visible)
+			if( md->guardian_data->number >= 0 && md->guardian_data->number < MAX_GUARDIANS && md->guardian_data->castle->guardian[md->guardian_data->number].visible )
 			{	//Safe removal of guardian.
 				md->guardian_data->castle->guardian[md->guardian_data->number].visible = 0;
 				guild_castledatasave(md->guardian_data->castle->castle_id, 10+md->guardian_data->number,0);
@@ -2602,8 +2622,11 @@ int mob_guardian_guildchange(struct block_list *bl,va_list ap)
 	if (g == NULL)
 	{	//Properly remove guardian info from Castle data.
 		ShowError("mob_guardian_guildchange: New Guild (id %d) does not exists!\n", md->guardian_data->guild_id);
-		md->guardian_data->castle->guardian[md->guardian_data->number].visible = 0;
-		guild_castledatasave(md->guardian_data->castle->castle_id, 10+md->guardian_data->number,0);
+		if( md->guardian_data->number >= 0 && md->guardian_data->number < MAX_GUARDIANS )
+		{
+			md->guardian_data->castle->guardian[md->guardian_data->number].visible = 0;
+			guild_castledatasave(md->guardian_data->castle->castle_id, 10+md->guardian_data->number,0);
+		}
 		unit_free(&md->bl,0);
 		return 0;
 	}

+ 1 - 1
src/map/mob.h

@@ -227,7 +227,7 @@ void mob_barricade_destroy(short m, const char *event);
 void mob_barricade_get(struct map_session_data *sd);
 void mod_barricade_clearall(void);
 
-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_spawn_guardian(const char* mapname, short x, short y, const char* mobname, int class_, const char* event, int guardian, bool has_index);	// Spawning Guardians [Valaris]
 int mob_guardian_guildchange(struct block_list *bl,va_list ap); //Change Guardian's ownership. [Skotlex]
 
 int mob_randomwalk(struct mob_data *md,unsigned int tick);

+ 1 - 0
src/map/npc.c

@@ -10,6 +10,7 @@
 #include "../common/utils.h"
 #include "../common/ers.h"
 #include "../common/db.h"
+#include "../common/socket.h"
 #include "map.h"
 #include "log.h"
 #include "clif.h"

+ 23 - 4
src/map/script.c

@@ -9165,14 +9165,30 @@ BUILDIN_FUNC(agitcheck)
 	return 0;
 }
 
+/// Sets the guild_id of this npc.
+///
+/// flagemblem <guild_id>;
 BUILDIN_FUNC(flagemblem)
 {
+	TBL_NPC* nd;
 	int g_id=script_getnum(st,2);
 
 	if(g_id < 0) return 0;
 
-//	ShowMessage("Script.c: [FlagEmblem] GuildID=%d, Emblem=%d.\n", g->guild_id, g->emblem_id);
-	((struct npc_data *)map_id2bl(st->oid))->u.scr.guild_id = g_id;
+	nd = (TBL_NPC*)map_id2nd(st->oid);
+	if( nd == NULL )
+	{
+		ShowError("script:flagemblem: npc %d not found\n", st->oid);
+	}
+	else if( nd->subtype != SCRIPT )
+	{
+		ShowError("script:flagemblem: unexpected subtype %d for npc %d '%s'\n", nd->subtype, st->oid, nd->exname);
+	}
+	else
+	{
+		nd->u.scr.guild_id = g_id;
+		clif_guild_emblem_area(&nd->bl);
+	}
 	return 0;
 }
 
@@ -9743,13 +9759,14 @@ BUILDIN_FUNC(strmobinfo)
 
 /*==========================================
  * Summon guardians [Valaris]
- * guardian "<map name>",<x>,<y>,"<name to show>",<mob id>,{,"<event label>"}{,<guardian index>};
+ * guardian("<map name>",<x>,<y>,"<name to show>",<mob id>{,"<event label>"}{,<guardian index>}) -> <id>
  *------------------------------------------*/
 BUILDIN_FUNC(guardian)
 {
 	int class_=0,x=0,y=0,guardian=0;
 	const char *str,*map,*evt="";
 	struct script_data *data;
+	bool has_index = false;
 
 	map	  =script_getstr(st,2);
 	x	  =script_getnum(st,3);
@@ -9761,6 +9778,7 @@ BUILDIN_FUNC(guardian)
 	{// "<event label>",<guardian index>
 		evt=script_getstr(st,7);
 		guardian=script_getnum(st,8);
+		has_index = true;
 	} else if( script_hasdata(st,7) ){
 		data=script_getdata(st,7);
 		get_val(st,data);
@@ -9770,6 +9788,7 @@ BUILDIN_FUNC(guardian)
 		} else if( data_isint(data) )
 		{// <guardian index>
 			guardian=script_getnum(st,7);
+			has_index = true;
 		} else {
 			ShowError("script:guardian: invalid data type for argument #6 (from 1)\n");
 			script_reportdata(data);
@@ -9778,7 +9797,7 @@ BUILDIN_FUNC(guardian)
 	}
 
 	check_event(st, evt);
-	mob_spawn_guardian(map,x,y,str,class_,evt,guardian);
+	script_pushint(st, mob_spawn_guardian(map,x,y,str,class_,evt,guardian,has_index));
 
 	return 0;
 }

+ 1 - 0
src/map/trade.c

@@ -2,6 +2,7 @@
 // For more information, see LICENCE in the main folder
 
 #include "../common/nullpo.h"
+#include "../common/socket.h"
 #include "clif.h"
 #include "itemdb.h"
 #include "map.h"

+ 13 - 3
src/map/unit.c

@@ -1950,10 +1950,20 @@ int unit_free(struct block_list *bl, int clrtype)
 			aFree(md->lootitem);
 			md->lootitem=NULL;
 		}
-		if(md->guardian_data)
+		if( md->guardian_data )
 		{
-			if (md->guardian_data->number < MAX_GUARDIANS)
-				md->guardian_data->castle->guardian[md->guardian_data->number].id = 0;
+			struct guild_castle* gc = md->guardian_data->castle;
+			if( md->guardian_data->number >= 0 && md->guardian_data->number < MAX_GUARDIANS )
+			{
+				gc->guardian[md->guardian_data->number].id = 0;
+			}
+			else
+			{
+				int i;
+				ARR_FIND(0, gc->temp_guardians_max, i, gc->temp_guardians[i] == md->bl.id);
+				if( i < gc->temp_guardians_max )
+					gc->temp_guardians[i] = 0;
+			}
 			aFree(md->guardian_data);
 			md->guardian_data = NULL;
 		}