Browse Source

- Fixed indentation on int_pet.c (how did it got messed up?)
- Added mapflag "loadevent", now load-map script events will ONLY trigger on maps with this mapflag on, rather than every map.
- High Jump can now be used in all versus maps.
- Added Kaite's opt3 value, taken from jA
- Added state dirty == 2 to storages. Signals when a storage was sent for final saving. Said storage is removed from memory after the ack from the char-server, and they are sent to save if the map/char servers reconnect before the act arrives. In short: they are guaranteed to be saved after a char logs out.


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

skotlex 19 years ago
parent
commit
4f1911ae63
13 changed files with 168 additions and 120 deletions
  1. 9 0
      Changelog-Trunk.txt
  2. 1 0
      conf-tmpl/script_athena.conf
  3. 1 0
      db/const.txt
  4. 96 96
      src/char/int_pet.c
  5. 2 4
      src/map/chrif.c
  6. 10 6
      src/map/clif.c
  7. 1 0
      src/map/map.h
  8. 4 0
      src/map/npc.c
  9. 7 1
      src/map/script.c
  10. 2 2
      src/map/skill.c
  11. 8 1
      src/map/status.c
  12. 26 9
      src/map/storage.c
  13. 1 1
      src/map/storage.h

+ 9 - 0
Changelog-Trunk.txt

@@ -4,6 +4,15 @@ 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.
 
 2006/05/27
+	* Added mapflag "loadevent", now load-map script events will ONLY trigger
+	  on maps with this mapflag on, rather than every map. [Skotlex]
+	* High Jump can now be used in all versus maps. [Skotlex]
+	* Added Kaite's opt3 value, taken from jA [Skotlex]
+	* Added state dirty == 2 to storages. Signals when a storage was sent for
+	  final saving. Said storage is removed from memory after the ack from the
+	  char-server, and they are sent to save if the map/char servers reconnect
+	  before the ack arrives. In short: they are guaranteed to be saved after a
+	  char logs out. [Skotlex]
 	* Put pay_arche.gat in the "no experience lost" mapflag file. [MasterOfMuppets]
 2006/06/26
 	* Corrected the element of hunter traps. [Skotlex]

+ 1 - 0
conf-tmpl/script_athena.conf

@@ -62,6 +62,7 @@ logout_event_name: PCLogoutEvent
 login_event_name: PCLoginEvent
 
 // Name of event when a player changes map
+// NOTE: This event will only trigger on maps with the "loadmap" flag active.
 loadmap_event_name: PCLoadMapEvent
 
 // Name of event when a player levels up (base lv)

+ 1 - 0
db/const.txt

@@ -131,6 +131,7 @@ mf_nodrop	38
 mf_jexp		39
 mf_bexp		40
 mf_novending	41
+mf_loadevent 42
 
 cell_wall	1
 cell_water	3

+ 96 - 96
src/char/int_pet.c

@@ -217,8 +217,8 @@ int mapif_delete_pet_ack(int fd,int flag)
 	WFIFOB(fd,2)=flag;
 	WFIFOSET(fd,3);
 
-		return 0;
-	}
+	return 0;
+}
 
 int mapif_rename_pet_ack(int fd, int account_id, int char_id, int flag, char *name){
 	WFIFOW(fd, 0) =0x3884;
@@ -231,112 +231,112 @@ int mapif_rename_pet_ack(int fd, int account_id, int char_id, int flag, char *na
 	return 0;
 }
 
-	int mapif_create_pet(int fd,int account_id,int char_id,short pet_class,short pet_lv,short pet_egg_id,
-		short pet_equip,short intimate,short hungry,char rename_flag,char incuvate,char *pet_name)
-	{
-		struct s_pet *p;
-		p= (struct s_pet *) aCalloc(sizeof(struct s_pet), 1);
-		if(p==NULL){
-			ShowFatalError("int_pet: out of memory !\n");
-			mapif_pet_created(fd,account_id,NULL);
-			return 0;
-		}
-	//	memset(p,0,sizeof(struct s_pet)); unnecessary after aCalloc [Skotlex]
-		p->pet_id = pet_newid++;
-		memcpy(p->name,pet_name,NAME_LENGTH-1);
-		if(incuvate == 1)
-			p->account_id = p->char_id = 0;
-		else {
-			p->account_id = account_id;
-			p->char_id = char_id;
-		}
-		p->class_ = pet_class;
-		p->level = pet_lv;
-		p->egg_id = pet_egg_id;
-		p->equip = pet_equip;
-		p->intimate = intimate;
-		p->hungry = hungry;
-		p->rename_flag = rename_flag;
-		p->incuvate = incuvate;
-
-		if(p->hungry < 0)
-			p->hungry = 0;
-		else if(p->hungry > 100)
-			p->hungry = 100;
-		if(p->intimate < 0)
-			p->intimate = 0;
-		else if(p->intimate > 1000)
-			p->intimate = 1000;
-
-		idb_put(pet_db,p->pet_id,p);
-
-		mapif_pet_created(fd,account_id,p);
-
+int mapif_create_pet(int fd,int account_id,int char_id,short pet_class,short pet_lv,short pet_egg_id,
+	short pet_equip,short intimate,short hungry,char rename_flag,char incuvate,char *pet_name)
+{
+	struct s_pet *p;
+	p= (struct s_pet *) aCalloc(sizeof(struct s_pet), 1);
+	if(p==NULL){
+		ShowFatalError("int_pet: out of memory !\n");
+		mapif_pet_created(fd,account_id,NULL);
 		return 0;
 	}
+//	memset(p,0,sizeof(struct s_pet)); unnecessary after aCalloc [Skotlex]
+	p->pet_id = pet_newid++;
+	memcpy(p->name,pet_name,NAME_LENGTH-1);
+	if(incuvate == 1)
+		p->account_id = p->char_id = 0;
+	else {
+		p->account_id = account_id;
+		p->char_id = char_id;
+	}
+	p->class_ = pet_class;
+	p->level = pet_lv;
+	p->egg_id = pet_egg_id;
+	p->equip = pet_equip;
+	p->intimate = intimate;
+	p->hungry = hungry;
+	p->rename_flag = rename_flag;
+	p->incuvate = incuvate;
+
+	if(p->hungry < 0)
+		p->hungry = 0;
+	else if(p->hungry > 100)
+		p->hungry = 100;
+	if(p->intimate < 0)
+		p->intimate = 0;
+	else if(p->intimate > 1000)
+		p->intimate = 1000;
+
+	idb_put(pet_db,p->pet_id,p);
+
+	mapif_pet_created(fd,account_id,p);
 
-	int mapif_load_pet(int fd,int account_id,int char_id,int pet_id)
-	{
-		struct s_pet *p;
-		p= idb_get(pet_db,pet_id);
-		if(p!=NULL) {
-			if(p->incuvate == 1) {
-				p->account_id = p->char_id = 0;
-				mapif_pet_info(fd,account_id,p);
-			}
-			else if(account_id == p->account_id && char_id == p->char_id)
-				mapif_pet_info(fd,account_id,p);
-			else
-				mapif_pet_noinfo(fd,account_id);
+	return 0;
+}
+
+int mapif_load_pet(int fd,int account_id,int char_id,int pet_id)
+{
+	struct s_pet *p;
+	p= idb_get(pet_db,pet_id);
+	if(p!=NULL) {
+		if(p->incuvate == 1) {
+			p->account_id = p->char_id = 0;
+			mapif_pet_info(fd,account_id,p);
 		}
+		else if(account_id == p->account_id && char_id == p->char_id)
+			mapif_pet_info(fd,account_id,p);
 		else
 			mapif_pet_noinfo(fd,account_id);
-
-		return 0;
 	}
+	else
+		mapif_pet_noinfo(fd,account_id);
+
+	return 0;
+}
 
-	static void* create_pet(DBKey key, va_list args) {
-		struct s_pet *p;
-		p=(struct s_pet *)aCalloc(sizeof(struct s_pet),1);
-		p->pet_id = key.i;
-		return p;
+static void* create_pet(DBKey key, va_list args) {
+	struct s_pet *p;
+	p=(struct s_pet *)aCalloc(sizeof(struct s_pet),1);
+	p->pet_id = key.i;
+	return p;
+}
+int mapif_save_pet(int fd,int account_id,struct s_pet *data)
+{
+	struct s_pet *p;
+	int pet_id, len;
+	RFIFOHEAD(fd);
+	len=RFIFOW(fd,2);
+	
+	if(sizeof(struct s_pet)!=len-8) {
+		ShowError("inter pet: data size error %d %d\n",sizeof(struct s_pet),len-8);
 	}
-	int mapif_save_pet(int fd,int account_id,struct s_pet *data)
-	{
-		struct s_pet *p;
-		int pet_id, len;
-		RFIFOHEAD(fd);
-		len=RFIFOW(fd,2);
-		
-		if(sizeof(struct s_pet)!=len-8) {
-			ShowError("inter pet: data size error %d %d\n",sizeof(struct s_pet),len-8);
-		}
-		else{
-			pet_id = data->pet_id;
-			if (pet_id == 0)
-				pet_id = data->pet_id = pet_newid++;
-			p= idb_ensure(pet_db,pet_id,create_pet);
-			if(data->hungry < 0)
-				data->hungry = 0;
-			else if(data->hungry > 100)
-				data->hungry = 100;
-			if(data->intimate < 0)
-				data->intimate = 0;
-			else if(data->intimate > 1000)
-				data->intimate = 1000;
-			memcpy(p,data,sizeof(struct s_pet));
-			if(p->incuvate == 1)
-				p->account_id = p->char_id = 0;
-
-			mapif_save_pet_ack(fd,account_id,0);
-		}
+	else{
+		pet_id = data->pet_id;
+		if (pet_id == 0)
+			pet_id = data->pet_id = pet_newid++;
+		p= idb_ensure(pet_db,pet_id,create_pet);
+		if(data->hungry < 0)
+			data->hungry = 0;
+		else if(data->hungry > 100)
+			data->hungry = 100;
+		if(data->intimate < 0)
+			data->intimate = 0;
+		else if(data->intimate > 1000)
+			data->intimate = 1000;
+		memcpy(p,data,sizeof(struct s_pet));
+		if(p->incuvate == 1)
+			p->account_id = p->char_id = 0;
 
-		return 0;
+		mapif_save_pet_ack(fd,account_id,0);
 	}
 
-	int mapif_delete_pet(int fd,int pet_id)
-	{
-		mapif_delete_pet_ack(fd,inter_pet_delete(pet_id));
+	return 0;
+}
+
+int mapif_delete_pet(int fd,int pet_id)
+{
+	mapif_delete_pet_ack(fd,inter_pet_delete(pet_id));
 
 	return 0;
 }

+ 2 - 4
src/map/chrif.c

@@ -189,7 +189,7 @@ int chrif_save(struct map_session_data *sd, int flag)
 		return -1; //Refuse to save a char already tagged for final saving. [Skotlex]
 	//For data sync
 	if (sd->state.storage_flag == 1)
-		storage_storage_save(sd->status.account_id);
+		storage_storage_save(sd->status.account_id, flag);
 	else if (sd->state.storage_flag == 2)
 		storage_guild_storagesave(sd->status.account_id, sd->status.guild_id);
 
@@ -218,10 +218,8 @@ int chrif_save(struct map_session_data *sd, int flag)
 #ifndef TXT_ONLY
 	}
 #endif
-	if (flag) {//Remove the storage from memory.
-		storage_delete(sd->status.account_id);
+	if (flag)
 		sd->state.finalsave = 1; //Mark the last save as done.
-	}
 	return 0;
 }
 

+ 10 - 6
src/map/clif.c

@@ -8207,7 +8207,7 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd)
 		sc_start(&sd->bl,SC_NOCHAT,100,0,0);
 
 // Lance
-	if(sd->state.event_loadmap){
+	if(sd->state.event_loadmap && map[sd->bl.m].flag.loadevent){
 		pc_setregstr(sd, add_str("@maploaded$"), map[sd->bl.m].name);
 		npc_script_event(sd, NPCE_LOADMAP);
 	}
@@ -9848,8 +9848,6 @@ void clif_parse_NpcStringInput(int fd,struct map_session_data *sd)
 	if(message_len >= sizeof(sd->npc_str)){
 		ShowWarning("clif: input string too long !\n");
 		message_len = sizeof(sd->npc_str);
-	} else {
-		message_len += 1; // Null character
 	}
 
 	// Exploit prevention if crafted packets (without null) is being sent. [Lance]
@@ -9972,12 +9970,18 @@ void clif_parse_ResetChar(int fd, struct map_session_data *sd) {
  */
 void clif_parse_LGMmessage(int fd, struct map_session_data *sd) {
 	unsigned char buf[512];
-	int len = RFIFOREST(fd);
+//	int len = RFIFOREST(fd);
 	int plen = RFIFOW(fd,2);
 	RFIFOHEAD(fd);
 
-	if(plen <= 0 || plen > len) // Possible hack! [Lance]
-		plen = len;
+	//This shouldn't be needed.... because the parsing code makes sure
+	//this function is not invoked until enough bytes have been received.
+	//So if the client "hacks" the packet, all that will happen is that
+	//it will not be parsed until enough data is received, on which point
+	//the following packets will be offset, causing them to fail to parse,
+	//which leads to disconnecting them :3 [Skotlex]
+//	if(plen <= 0 || plen > len) // Possible hack! [Lance]
+//		plen = len;
 
 	if ((battle_config.atc_gmonly == 0 || pc_isGM(sd)) &&
 	    (pc_isGM(sd) >= get_atcommand_level(AtCommand_LocalBroadcast))) {

+ 1 - 0
src/map/map.h

@@ -1045,6 +1045,7 @@ struct map_data {
 		unsigned nocommand : 1; //Blocks @/# commands for non-gms. [Skotlex]
 		unsigned nodrop : 1;
 		unsigned novending : 1;
+		unsigned loadevent : 1;
 	} flag;
 	struct point save;
 	struct npc_data *npc[MAX_NPC_PER_MAP];

+ 4 - 0
src/map/npc.c

@@ -2514,6 +2514,10 @@ static int npc_parse_mapflag (char *w1, char *w2, char *w3, char *w4)
 		if( map[m].bexp < 0 ) map[m].bexp = 100;
 		 map[m].flag.nobaseexp = (map[m].bexp==0)?1:0;
 	}
+	else if (strcmpi(w3,"loadevent")==0) { // Skotlex
+		map[m].flag.loadevent=state;
+	}
+ 
 	return 0;
 }
 

+ 7 - 1
src/map/script.c

@@ -6869,7 +6869,7 @@ enum {  MF_NOMEMO,MF_NOTELEPORT,MF_NOSAVE,MF_NOBRANCH,MF_NOPENALTY,MF_NOZENYPENA
 	MF_NOWARP,MF_FREE,MF_NOICEWALL,MF_SNOW,MF_FOG,MF_SAKURA,MF_LEAVES,MF_RAIN,
 	MF_INDOORS,MF_NOGO,MF_CLOUDS,MF_CLOUDS2,MF_FIREWORKS,MF_GVG_CASTLE,MF_GVG_DUNGEON,MF_NIGHTENABLED,
 	MF_NOBASEEXP, MF_NOJOBEXP, MF_NOMOBLOOT, MF_NOMVPLOOT, MF_NORETURN, MF_NOWARPTO, MF_NIGHTMAREDROP,
-	MF_RESTRICTED, MF_NOCOMMAND, MF_NODROP, MF_JEXP, MF_BEXP, MF_NOVENDING };
+	MF_RESTRICTED, MF_NOCOMMAND, MF_NODROP, MF_JEXP, MF_BEXP, MF_NOVENDING, MF_LOADEVENT };
 
 int buildin_setmapflagnosave(struct script_state *st)
 {
@@ -7028,6 +7028,9 @@ int buildin_setmapflag(struct script_state *st)
 			case MF_NOVENDING:
 				map[m].flag.novending=1;
 				break;
+			case MF_LOADEVENT:
+				map[m].flag.loadevent=1;
+				break;
 		}
 	}
 
@@ -7167,6 +7170,9 @@ int buildin_removemapflag(struct script_state *st)
 			case MF_NOVENDING:
 				map[m].flag.novending=0;
 				break;
+			case MF_LOADEVENT:
+				map[m].flag.loadevent=0;
+				break;
 		}
 	}
 

+ 2 - 2
src/map/skill.c

@@ -883,8 +883,8 @@ int skillnotok (int skillid, struct map_session_data *sd)
 			}
 			return 0;
 		case TK_HIGHJUMP:
-			if(map[sd->bl.m].flag.noteleport && !map_flag_gvg(sd->bl.m))
-		  	{	//Can't be used on noteleport maps, except for gvg maps [Skotlex]
+			if(map[sd->bl.m].flag.noteleport && !map_flag_vs(sd->bl.m))
+		  	{	//Can't be used on noteleport maps, except for vs maps [Skotlex]
 				clif_skill_fail(sd,skillid,0,0);
 				return 1;
 			}

+ 8 - 1
src/map/status.c

@@ -5278,7 +5278,10 @@ int status_change_start(struct block_list *bl,int type,int rate,int val1,int val
 			sc->opt3 |= 4096;
 			opt_flag = 0;
 			break;
-			
+		case SC_KAITE:
+			sc->opt3 |= 8192;
+			opt_flag = 0;
+			break;
 		//OPTION
 		case SC_HIDING:
 			sc->option |= OPTION_HIDE;
@@ -5764,6 +5767,10 @@ int status_change_end( struct block_list* bl , int type,int tid )
 		sc->opt3 &= ~4096;
 		opt_flag = 0;
 		break;
+	case SC_KAITE:
+		sc->opt3 &= ~8192;
+		opt_flag = 0;
+		break;
 	default:
 		opt_flag = 0;
 	}

+ 26 - 9
src/map/storage.c

@@ -82,7 +82,7 @@ static int storage_reconnect_sub(DBKey key,void *data,va_list ap)
 	{	//Account Storage
 		struct storage* stor = (struct storage*) data;
 		if (stor->dirty && stor->storage_status == 0) //Save closed storages.
-			storage_storage_save(stor->account_id);
+			storage_storage_save(stor->account_id, stor->dirty==2?1:0);
 	}
 	return 0;
 }
@@ -390,16 +390,27 @@ void storage_storage_dirty(struct map_session_data *sd)
 		stor->dirty = 1;
 }
 
-int storage_storage_save(int account_id)
+int storage_storage_save(int account_id, int final)
 {
 	struct storage *stor;
 
 	stor=account2storage2(account_id);
-	if(stor && stor->dirty)
+	if(!stor) return 0;
+
+	if(stor->dirty)
 	{
+		if (final) {
+			stor->dirty = 2;
+			stor->storage_status = 0; //To prevent further manipulation of it.
+		}
 		intif_send_storage(stor);
 		return 1;
 	}
+	if (final) 
+	{	//Clear storage from memory. Nothing to save.
+		storage_delete(account_id);
+		return 1;
+	}
 
 	return 0;
 }
@@ -409,13 +420,19 @@ int storage_storage_saved(int account_id)
 {
 	struct storage *stor;
 	
-	if((stor=account2storage2(account_id)) != NULL)
+	if((stor=account2storage2(account_id)) == NULL)
+		return 0;
+
+	if (stor->dirty == 2)
+	{	//Final save of storage. Remove from memory.
+	  	storage_delete(account_id);
+		return 1;
+	}
+
+	if (stor->dirty && stor->storage_status == 0)
 	{	//Only mark it clean if it's not in use. [Skotlex]
-		if (stor->dirty && stor->storage_status == 0)
-		{
-			stor->dirty = 0;
-			sortage_sortitem(stor);
-		}
+		stor->dirty = 0;
+		sortage_sortitem(stor);
 		return 1;
 	}
 	return 0;

+ 1 - 1
src/map/storage.h

@@ -19,7 +19,7 @@ struct storage *account2storage(int account_id);
 struct storage *account2storage2(int account_id);
 int storage_delete(int account_id);
 int storage_storage_quit(struct map_session_data *sd, int flag);
-int storage_storage_save(int account_id);
+int storage_storage_save(int account_id, int final);
 int storage_storage_saved(int account_id); //Ack from char server that guild store was saved.
 void storage_storage_dirty(struct map_session_data *sd);