Browse Source

- Added check to clear skill unit group that created by NPC/script before the NPC/script unloaded.
- Changed enum for NPC subtype, added prefix NPCTYPE_. See map.h::npc_subtype.
- Changed Channel_Config struct usage to -> extern struct Channel_Config channel_config.
- Added restriction for atcommand that cannot be executed when Player is in autotrade, to prevent map crash. (bugreport:9196) TODO: Check other atcommand or change this behavior.
- Added enum for atcommand restriction with prefix ATCMD_NO. See atcommand.c::e_atcmd_restict.
- Updated atcommand documentations.
- Changed dummy_sd's attributes to group_id & group_level 99, and gives all permissions (PC_PERM_ALLPERMISSION). dummy_sd is being used by 'atcommand' or 'useatcmd' script when no rid/player attached.

Signed-off-by: Cydh Ramdh <house.bad@gmail.com>

Cydh Ramdh 10 years ago
parent
commit
3efe5375f3
17 changed files with 267 additions and 204 deletions
  1. 28 1
      doc/atcommands.txt
  2. 1 1
      src/char/char_mapif.c
  3. 39 26
      src/map/atcommand.c
  4. 72 63
      src/map/channel.c
  5. 3 2
      src/map/channel.h
  6. 0 1
      src/map/chrif.c
  7. 2 2
      src/map/clif.c
  8. 3 3
      src/map/guild.c
  9. 1 1
      src/map/map.c
  10. 11 2
      src/map/map.h
  11. 2 2
      src/map/mob.c
  12. 75 73
      src/map/npc.c
  13. 0 2
      src/map/pc_groups.c
  14. 26 22
      src/map/script.c
  15. 2 2
      src/map/status.c
  16. 1 1
      src/map/unit.h
  17. 1 0
      src/map/vending.c

+ 28 - 1
doc/atcommands.txt

@@ -13,6 +13,10 @@ This file describes the usage of in-game commands and assumes that
 	atcommand_symbol : "@"
 	atcommand_symbol : "@"
 	charcommand_symbol: "#"
 	charcommand_symbol: "#"
 
 
+Some commands cannot be used from console or script command to prevent map-server crashed.
+See atcommand.c::atcommand_basecommands for restricted commands. Please tell us if any
+other atcommand that causes map-server crashed executed by console or script commands.
+
 To search for a command, write "@" before the command name (ex. @commands).
 To search for a command, write "@" before the command name (ex. @commands).
 The format of this file is as follows:
 The format of this file is as follows:
 	1. System Commands
 	1. System Commands
@@ -799,6 +803,9 @@ Warps to predefined locations in major cities.
 If no ID is given, all available maps will be displayed in the chat window.
 If no ID is given, all available maps will be displayed in the chat window.
 Locations and coordinates are stored in '/src/map/atcommand.c'.
 Locations and coordinates are stored in '/src/map/atcommand.c'.
 
 
+Restriction:
+	- Used from console
+
 ---------------------------------------
 ---------------------------------------
 
 
 @warp <map> {<x> <y>}
 @warp <map> {<x> <y>}
@@ -808,6 +815,9 @@ Locations and coordinates are stored in '/src/map/atcommand.c'.
 Warps to the specified map.
 Warps to the specified map.
 If no coordinates are entered, a random location will be chosen.
 If no coordinates are entered, a random location will be chosen.
 
 
+Restriction:
+	- Used from console
+
 ---------------------------------------
 ---------------------------------------
 
 
 @jumpto <player name/ID>
 @jumpto <player name/ID>
@@ -851,6 +861,9 @@ Allows other players to attack you outside of PvP.
 
 
 Changes base or job level by the specified amount.
 Changes base or job level by the specified amount.
 
 
+Restriction:
+	- Used from console
+
 ---------------------------------------
 ---------------------------------------
 
 
 @str <+/- amount>
 @str <+/- amount>
@@ -908,6 +921,9 @@ An 'upper' value can be specified with a job ID to produce its normal (0), advan
 If no job is given, a list of all available jobs will be returned.
 If no job is given, a list of all available jobs will be returned.
 Note that jobs 22 (Wedding), 26 (Summer), 27 (Christmas), and 28 (Hanbok) are not available via @job.
 Note that jobs 22 (Wedding), 26 (Summer), 27 (Christmas), and 28 (Hanbok) are not available via @job.
 
 
+Restriction:
+	- Used from console
+
 ---------------------------------------
 ---------------------------------------
 
 
 @speed <0-1000>
 @speed <0-1000>
@@ -1224,6 +1240,14 @@ If a time is not specified (jailfor), the player will be jailed indefinitely.
 ---------------------------------------
 ---------------------------------------
 
 
 @kick <player name/ID>
 @kick <player name/ID>
+
+Kick a player from the server.
+
+Restriction:
+	- Used from 'atcommand' or 'useatcmd' by autotrader
+
+---------------------------------------
+
 @kickall
 @kickall
 /killall
 /killall
 
 
@@ -1317,7 +1341,10 @@ Affected files:
 -- questdb: quest_db.txt
 -- questdb: quest_db.txt
 -- script: /npc/*.txt, /npc/*.conf
 -- script: /npc/*.txt, /npc/*.conf
 -- skilldb: skill_db.txt, const.txt, skill_require_db.txt, skill_cast_db.txt, skill_castnodex_db.txt, skill_nocast_db.txt, skill_copyable_db.txt, skill_improvise_db.txt, skill_changematerial_db.txt, skill_nonearnpc_db.txt, skill_damage_db.txt, skill_unit_db.txt, abra_db.txt, create_arrow_db.txt, produce_db.txt, spellbook_db.txt, magicmushroom_db.txt
 -- skilldb: skill_db.txt, const.txt, skill_require_db.txt, skill_cast_db.txt, skill_castnodex_db.txt, skill_nocast_db.txt, skill_copyable_db.txt, skill_improvise_db.txt, skill_changematerial_db.txt, skill_nonearnpc_db.txt, skill_damage_db.txt, skill_unit_db.txt, abra_db.txt, create_arrow_db.txt, produce_db.txt, spellbook_db.txt, magicmushroom_db.txt
- -- statusdb: attr_fix.txt, size_fix.txt, refine_db.tx
+-- statusdb: attr_fix.txt, size_fix.txt, refine_db.tx
+
+Restriction:
+	- Used from 'atcommand' or 'useatcmd'. For @reload & @reloadscript
 
 
 ---------------------------------------
 ---------------------------------------
 
 

+ 1 - 1
src/char/char_mapif.c

@@ -894,7 +894,7 @@ int chmapif_parse_save_scdata(int fd){
 
 
 		// Whatever comes from the mapserver, now is the time to drop previous entries
 		// Whatever comes from the mapserver, now is the time to drop previous entries
 		if( Sql_Query( sql_handle, "DELETE FROM `%s` where `account_id` = %d and `char_id` = %d;", schema_config.scdata_db, aid, cid ) != SQL_SUCCESS ){
 		if( Sql_Query( sql_handle, "DELETE FROM `%s` where `account_id` = %d and `char_id` = %d;", schema_config.scdata_db, aid, cid ) != SQL_SUCCESS ){
-				Sql_ShowDebug( sql_handle );
+			Sql_ShowDebug( sql_handle );
 		}
 		}
 		else if( count > 0 )
 		else if( count > 0 )
 		{
 		{

+ 39 - 26
src/map/atcommand.c

@@ -60,12 +60,19 @@ typedef struct AliasInfo AliasInfo;
 
 
 int atcmd_binding_count = 0;
 int atcmd_binding_count = 0;
 
 
+/// Atcommand restriction usage
+enum e_atcmd_restict {
+	ATCMD_NOCONSOLE    = 0x1, /// Cannot be used via console (is_atcommand type 2)
+	ATCMD_NOSCRIPT     = 0x2, /// Cannot be used via script command 'atcommand' or 'useatcmd' (is_atcommand type 0 and 3)
+	ATCMD_NOAUTOTRADE  = 0x4, /// Like ATCMD_NOSCRIPT, but if the player is autotrader. Example: atcommand "@kick "+strcharinfo(0);
+};
+
 struct AtCommandInfo {
 struct AtCommandInfo {
 	char command[ATCOMMAND_LENGTH];
 	char command[ATCOMMAND_LENGTH];
 	AtCommandFunc func;
 	AtCommandFunc func;
-	char* at_groups;/* quick @commands "can-use" lookup */
-	char* char_groups;/* quick @charcommands "can-use" lookup */
-	int restriction; //prevent : 1 console, 2 script...
+	char* at_groups; /// Quick @commands "can-use" lookup
+	char* char_groups; /// Quick @charcommands "can-use" lookup
+	uint8 restriction; /// Restrictions see enum e_restict
 };
 };
 
 
 struct AliasInfo {
 struct AliasInfo {
@@ -9136,7 +9143,7 @@ static inline void atcmd_channel_help(struct map_session_data *sd, const char *c
 {
 {
 	int fd = sd->fd;
 	int fd = sd->fd;
 	bool can_delete = pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN);
 	bool can_delete = pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN);
-	bool can_create = (can_delete || Channel_Config.user_chenable);
+	bool can_create = (can_delete || channel_config.user_chenable);
 	clif_displaymessage(fd, msg_txt(sd,1414));// ---- Available options:
 	clif_displaymessage(fd, msg_txt(sd,1414));// ---- Available options:
 
 
 	//option create
 	//option create
@@ -9229,7 +9236,7 @@ ACMD_FUNC(channel) {
 		return 0;
 		return 0;
 	}
 	}
 
 
-	if( strcmpi(key,"create") == 0 && ( Channel_Config.user_chenable || pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) ) ) {
+	if( strcmpi(key,"create") == 0 && ( channel_config.user_chenable || pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) ) ) {
 		if(sub3[0] != '\0'){
 		if(sub3[0] != '\0'){
 			clif_displaymessage(fd, msg_txt(sd,1408)); // Channel password may not contain spaces.
 			clif_displaymessage(fd, msg_txt(sd,1408)); // Channel password may not contain spaces.
 			return -1;
 			return -1;
@@ -9277,8 +9284,8 @@ ACMD_FUNC(fontcolor)
 		sd->fontcolor = 0;
 		sd->fontcolor = 0;
 	} else {
 	} else {
 		unsigned char k;
 		unsigned char k;
-		ARR_FIND(0,Channel_Config.colors_count,k,( strcmpi(message,Channel_Config.colors_name[k]) == 0 ));
-		if( k == Channel_Config.colors_count ) {
+		ARR_FIND(0,channel_config.colors_count,k,( strcmpi(message,channel_config.colors_name[k]) == 0 ));
+		if( k == channel_config.colors_count ) {
 			sprintf(atcmd_output, msg_txt(sd,1411), message);// Unknown color '%s'.
 			sprintf(atcmd_output, msg_txt(sd,1411), message);// Unknown color '%s'.
 			clif_displaymessage(fd, atcmd_output);
 			clif_displaymessage(fd, atcmd_output);
 			return -1;
 			return -1;
@@ -9661,17 +9668,17 @@ ACMD_FUNC(clonestat) {
  **/
  **/
 #define ACMD_DEF(x) { #x, atcommand_ ## x, NULL, NULL, 0 }
 #define ACMD_DEF(x) { #x, atcommand_ ## x, NULL, NULL, 0 }
 #define ACMD_DEF2(x2, x) { x2, atcommand_ ## x, NULL, NULL, 0 }
 #define ACMD_DEF2(x2, x) { x2, atcommand_ ## x, NULL, NULL, 0 }
-//define with restriction
+// Define with restriction
 #define ACMD_DEFR(x, r) { #x, atcommand_ ## x, NULL, NULL, r }
 #define ACMD_DEFR(x, r) { #x, atcommand_ ## x, NULL, NULL, r }
 #define ACMD_DEF2R(x2, x, r) { x2, atcommand_ ## x, NULL, NULL, r }
 #define ACMD_DEF2R(x2, x, r) { x2, atcommand_ ## x, NULL, NULL, r }
 void atcommand_basecommands(void) {
 void atcommand_basecommands(void) {
 	/**
 	/**
 	 * Command reference list, place the base of your commands here
 	 * Command reference list, place the base of your commands here
-	 * TODO : all restricted command are crashing case, please look into it
+	 * TODO: List all commands that causing crash
 	 **/
 	 **/
 	AtCommandInfo atcommand_base[] = {
 	AtCommandInfo atcommand_base[] = {
 #include "../custom/atcommand_def.inc"
 #include "../custom/atcommand_def.inc"
-		ACMD_DEF2R("warp", mapmove, 1),
+		ACMD_DEF2R("warp", mapmove, ATCMD_NOCONSOLE),
 		ACMD_DEF(where),
 		ACMD_DEF(where),
 		ACMD_DEF(jumpto),
 		ACMD_DEF(jumpto),
 		ACMD_DEF(jump),
 		ACMD_DEF(jump),
@@ -9689,7 +9696,7 @@ void atcommand_basecommands(void) {
 		ACMD_DEF(guildstorage),
 		ACMD_DEF(guildstorage),
 		ACMD_DEF(option),
 		ACMD_DEF(option),
 		ACMD_DEF(hide), // + /hide
 		ACMD_DEF(hide), // + /hide
-		ACMD_DEFR(jobchange, 1),
+		ACMD_DEFR(jobchange, ATCMD_NOCONSOLE),
 		ACMD_DEF(kill),
 		ACMD_DEF(kill),
 		ACMD_DEF(alive),
 		ACMD_DEF(alive),
 		ACMD_DEF(kami),
 		ACMD_DEF(kami),
@@ -9705,7 +9712,7 @@ void atcommand_basecommands(void) {
 		ACMD_DEF(clearstorage),
 		ACMD_DEF(clearstorage),
 		ACMD_DEF(cleargstorage),
 		ACMD_DEF(cleargstorage),
 		ACMD_DEF(clearcart),
 		ACMD_DEF(clearcart),
-		ACMD_DEF2R("blvl", baselevelup, 1),
+		ACMD_DEF2R("blvl", baselevelup, ATCMD_NOCONSOLE),
 		ACMD_DEF2("jlvl", joblevelup),
 		ACMD_DEF2("jlvl", joblevelup),
 		ACMD_DEF(help),
 		ACMD_DEF(help),
 		ACMD_DEF(pvpoff),
 		ACMD_DEF(pvpoff),
@@ -9713,7 +9720,7 @@ void atcommand_basecommands(void) {
 		ACMD_DEF(gvgoff),
 		ACMD_DEF(gvgoff),
 		ACMD_DEF(gvgon),
 		ACMD_DEF(gvgon),
 		ACMD_DEF(model),
 		ACMD_DEF(model),
-		ACMD_DEFR(go, 1),
+		ACMD_DEFR(go, ATCMD_NOCONSOLE),
 		ACMD_DEF(monster),
 		ACMD_DEF(monster),
 		ACMD_DEF2("monstersmall", monster),
 		ACMD_DEF2("monstersmall", monster),
 		ACMD_DEF2("monsterbig", monster),
 		ACMD_DEF2("monsterbig", monster),
@@ -9746,7 +9753,7 @@ void atcommand_basecommands(void) {
 		ACMD_DEF(doommap),
 		ACMD_DEF(doommap),
 		ACMD_DEF(raise),
 		ACMD_DEF(raise),
 		ACMD_DEF(raisemap),
 		ACMD_DEF(raisemap),
-		ACMD_DEF(kick), // + right click menu for GM "(name) force to quit"
+		ACMD_DEFR(kick,ATCMD_NOAUTOTRADE), // + right click menu for GM "(name) force to quit"
 		ACMD_DEF(kickall),
 		ACMD_DEF(kickall),
 		ACMD_DEF(allskill),
 		ACMD_DEF(allskill),
 		ACMD_DEF(questskill),
 		ACMD_DEF(questskill),
@@ -9762,11 +9769,11 @@ void atcommand_basecommands(void) {
 		ACMD_DEF(broadcast), // + /b and /nb
 		ACMD_DEF(broadcast), // + /b and /nb
 		ACMD_DEF(localbroadcast), // + /lb and /nlb
 		ACMD_DEF(localbroadcast), // + /lb and /nlb
 		ACMD_DEF(recallall),
 		ACMD_DEF(recallall),
-		ACMD_DEFR(reload,2),
+		ACMD_DEFR(reload,ATCMD_NOSCRIPT),
 		ACMD_DEF2("reloaditemdb", reload),
 		ACMD_DEF2("reloaditemdb", reload),
 		ACMD_DEF2("reloadmobdb", reload),
 		ACMD_DEF2("reloadmobdb", reload),
 		ACMD_DEF2("reloadskilldb", reload),
 		ACMD_DEF2("reloadskilldb", reload),
-		ACMD_DEF2R("reloadscript", reload,2),
+		ACMD_DEF2R("reloadscript", reload, ATCMD_NOSCRIPT),
 		ACMD_DEF2("reloadatcommand", reload),
 		ACMD_DEF2("reloadatcommand", reload),
 		ACMD_DEF2("reloadbattleconf", reload),
 		ACMD_DEF2("reloadbattleconf", reload),
 		ACMD_DEF2("reloadstatusdb", reload),
 		ACMD_DEF2("reloadstatusdb", reload),
@@ -10057,12 +10064,15 @@ static void atcommand_get_suggestions(struct map_session_data* sd, const char *n
 	dbi_destroy(alias_iter);
 	dbi_destroy(alias_iter);
 }
 }
 
 
-/*
- *  Executes an at-command
- * \param type :
+/**
+ * Executes an at-command
+ * @param fd
+ * @param sd
+ * @param message
+ * @param type
  *  0 : script call (atcommand)
  *  0 : script call (atcommand)
  *  1 : normal player @atcommand
  *  1 : normal player @atcommand
- *  2 : console
+ *  2 : console (admin:@atcommand)
  *  3 : script call (useatcmd)
  *  3 : script call (useatcmd)
  */
  */
 bool is_atcommand(const int fd, struct map_session_data* sd, const char* message, int type)
 bool is_atcommand(const int fd, struct map_session_data* sd, const char* message, int type)
@@ -10143,7 +10153,7 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message
 				if( x >= 1 || y >= 1 ) { /* we have command */
 				if( x >= 1 || y >= 1 ) { /* we have command */
 					info = get_atcommandinfo_byname(atcommand_checkalias(command + 1));
 					info = get_atcommandinfo_byname(atcommand_checkalias(command + 1));
 					if( !info || info->char_groups[sd->group_pos] == 0 ) /* if we can't use or doesn't exist: don't even display the command failed message */
 					if( !info || info->char_groups[sd->group_pos] == 0 ) /* if we can't use or doesn't exist: don't even display the command failed message */
-							return false;
+						return false;
 				} else
 				} else
 					return false;/* display as normal message */
 					return false;/* display as normal message */
 			}
 			}
@@ -10211,17 +10221,20 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message
 	}
 	}
 
 
 	//check restriction
 	//check restriction
-	if(info->restriction){
-		if(info->restriction&1 && type == 2) //console prevent
+	if (info->restriction) {
+		if (info->restriction&ATCMD_NOCONSOLE && type == 2) //console prevent
+			return true;
+		if (info->restriction&ATCMD_NOSCRIPT && (type == 0 || type == 3)) //scripts prevent
 			return true;
 			return true;
-		if(info->restriction&2 && (type == 0 || type == 3) ) //scripts prevent
+		if (info->restriction&ATCMD_NOAUTOTRADE && (type == 0 || type == 3)
+			&& ((*atcmd_msg == atcommand_symbol && sd && sd->state.autotrade) || (ssd && ssd->state.autotrade)))
 			return true;
 			return true;
 	}
 	}
 
 
 	// type == 1 : player invoked
 	// type == 1 : player invoked
 	if (type == 1) {
 	if (type == 1) {
 		if ((*command == atcommand_symbol && info->at_groups[sd->group_pos] == 0) ||
 		if ((*command == atcommand_symbol && info->at_groups[sd->group_pos] == 0) ||
-		    (*command == charcommand_symbol && info->char_groups[sd->group_pos] == 0) ) {
+			(*command == charcommand_symbol && info->char_groups[sd->group_pos] == 0) ) {
 			return false;
 			return false;
 		}
 		}
 		if( pc_isdead(sd) && pc_has_permission(sd,PC_PERM_DISABLE_CMD_DEAD) ) {
 		if( pc_isdead(sd) && pc_has_permission(sd,PC_PERM_DISABLE_CMD_DEAD) ) {
@@ -10232,7 +10245,7 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message
 
 
 	// Check if target is valid only if confirmed that player can use command.
 	// Check if target is valid only if confirmed that player can use command.
 	if (*message == charcommand_symbol &&
 	if (*message == charcommand_symbol &&
-	    (ssd = map_nick2sd(charname)) == NULL && (ssd = map_nick2sd(charname2)) == NULL ) {
+		(ssd = map_nick2sd(charname)) == NULL && (ssd = map_nick2sd(charname2)) == NULL ) {
 		sprintf(output, msg_txt(sd,1389), command); // %s failed. Player not found.
 		sprintf(output, msg_txt(sd,1389), command); // %s failed. Player not found.
 		clif_displaymessage(fd, output);
 		clif_displaymessage(fd, output);
 		return true;
 		return true;

+ 72 - 63
src/map/channel.c

@@ -18,8 +18,10 @@
 #include <stdlib.h>
 #include <stdlib.h>
 
 
 static DBMap* channel_db; // channels
 static DBMap* channel_db; // channels
-DBMap* channel_get_db(void){ return channel_db; }
 
 
+struct Channel_Config channel_config;
+
+DBMap* channel_get_db(void){ return channel_db; }
 
 
 struct chan_banentry {
 struct chan_banentry {
 	int char_id;
 	int char_id;
@@ -163,12 +165,12 @@ int channel_mjoin(struct map_session_data *sd) {
 	if(!sd) return -1;
 	if(!sd) return -1;
 
 
 	if( !map[sd->bl.m].channel ) {
 	if( !map[sd->bl.m].channel ) {
-		map[sd->bl.m].channel = channel_create(Channel_Config.map_chname,NULL,Channel_Config.map_chcolor,CHAN_TYPE_MAP,sd->bl.m);
+		map[sd->bl.m].channel = channel_create(channel_config.map_chname,NULL,channel_config.map_chcolor,CHAN_TYPE_MAP,sd->bl.m);
 	}
 	}
 
 
 	if( !( map[sd->bl.m].channel->opt & CHAN_OPT_ANNOUNCE_JOIN ) ) {
 	if( !( map[sd->bl.m].channel->opt & CHAN_OPT_ANNOUNCE_JOIN ) ) {
 		char mout[60];
 		char mout[60];
-		sprintf(mout, msg_txt(sd,1435),Channel_Config.map_chname,map[sd->bl.m].name); // You're now in the '#%s' channel for '%s'.
+		sprintf(mout, msg_txt(sd,1435),channel_config.map_chname,map[sd->bl.m].name); // You're now in the '#%s' channel for '%s'.
 		clif_disp_onlyself(sd, mout, strlen(mout));
 		clif_disp_onlyself(sd, mout, strlen(mout));
 	}
 	}
 
 
@@ -219,7 +221,7 @@ int channel_gjoin(struct map_session_data *sd, int flag){
 
 
 	channel = g->channel;
 	channel = g->channel;
 	if(!channel){
 	if(!channel){
-		channel = channel_create(Channel_Config.ally_chname,NULL,Channel_Config.ally_chcolor,CHAN_TYPE_ALLY,g->guild_id);
+		channel = channel_create(channel_config.ally_chname,NULL,channel_config.ally_chcolor,CHAN_TYPE_ALLY,g->guild_id);
 		g->channel = channel;
 		g->channel = channel;
 		channel_ajoin(g);
 		channel_ajoin(g);
 	}
 	}
@@ -299,7 +301,7 @@ int channel_pcquit(struct map_session_data *sd, int type){
 	if(!sd) return -1;
 	if(!sd) return -1;
 
 
 	// Leave all chat channels.
 	// Leave all chat channels.
-	if(type&(1|2) && Channel_Config.ally_enable && sd->guild){ //quit guild and ally chan
+	if(type&(1|2) && channel_config.ally_enable && sd->guild){ //quit guild and ally chan
 		struct guild *g = sd->guild;
 		struct guild *g = sd->guild;
 		if(type&1 && channel_haspc(g->channel,sd)==1){
 		if(type&1 && channel_haspc(g->channel,sd)==1){
 			channel_clean(g->channel,sd,0); //leave guild chan
 			channel_clean(g->channel,sd,0); //leave guild chan
@@ -315,7 +317,7 @@ int channel_pcquit(struct map_session_data *sd, int type){
 			}
 			}
 		}
 		}
 	}
 	}
-	if(type&4 && Channel_Config.map_enable && channel_haspc(map[sd->bl.m].channel,sd)==1){ //quit map chan
+	if(type&4 && channel_config.map_enable && channel_haspc(map[sd->bl.m].channel,sd)==1){ //quit map chan
 		channel_clean(map[sd->bl.m].channel,sd,0);
 		channel_clean(map[sd->bl.m].channel,sd,0);
 	}
 	}
 	if(type&8 && sd->channel_count ) { //quit all chan
 	if(type&8 && sd->channel_count ) { //quit all chan
@@ -376,8 +378,8 @@ int channel_chk(char *chname, char *chpass, int type){
 		if ( strlen(chname) < 3 || strlen(chname) > CHAN_NAME_LENGTH )
 		if ( strlen(chname) < 3 || strlen(chname) > CHAN_NAME_LENGTH )
 			return -2;
 			return -2;
 		if( (type&2) && (
 		if( (type&2) && (
-			strcmpi(chname + 1,Channel_Config.map_chname) == 0
-			|| strcmpi(chname + 1,Channel_Config.ally_chname) == 0
+			strcmpi(chname + 1,channel_config.map_chname) == 0
+			|| strcmpi(chname + 1,channel_config.ally_chname) == 0
 			|| strdb_exists(channel_db, chname + 1) )
 			|| strdb_exists(channel_db, chname + 1) )
 			) {
 			) {
 			return -4;
 			return -4;
@@ -402,16 +404,16 @@ int channel_chk(char *chname, char *chpass, int type){
 struct Channel* channel_name2channel(char *chname, struct map_session_data *sd, int flag){
 struct Channel* channel_name2channel(char *chname, struct map_session_data *sd, int flag){
 	if(channel_chk(chname, NULL, 1))
 	if(channel_chk(chname, NULL, 1))
 		return NULL;
 		return NULL;
-	if(sd && strcmpi(chname + 1,Channel_Config.map_chname) == 0){
+	if(sd && strcmpi(chname + 1,channel_config.map_chname) == 0){
 		if(flag&1 && !map[sd->bl.m].channel)
 		if(flag&1 && !map[sd->bl.m].channel)
-			map[sd->bl.m].channel = channel_create(Channel_Config.map_chname,NULL,Channel_Config.map_chcolor,CHAN_TYPE_MAP,sd->bl.m);
+			map[sd->bl.m].channel = channel_create(channel_config.map_chname,NULL,channel_config.map_chcolor,CHAN_TYPE_MAP,sd->bl.m);
 		if(flag&2)
 		if(flag&2)
 			channel_mjoin(sd);
 			channel_mjoin(sd);
 		return map[sd->bl.m].channel;
 		return map[sd->bl.m].channel;
 	}
 	}
-	else if(sd && (strcmpi(chname + 1,Channel_Config.ally_chname) == 0) && sd->guild){
+	else if(sd && (strcmpi(chname + 1,channel_config.ally_chname) == 0) && sd->guild){
 		if(flag&1 && !sd->guild->channel)
 		if(flag&1 && !sd->guild->channel)
-			sd->guild->channel = channel_create(Channel_Config.ally_chname,NULL,Channel_Config.ally_chcolor,CHAN_TYPE_ALLY,sd->guild->guild_id);
+			sd->guild->channel = channel_create(channel_config.ally_chname,NULL,channel_config.ally_chcolor,CHAN_TYPE_ALLY,sd->guild->guild_id);
 		if(flag&2)
 		if(flag&2)
 			channel_gjoin(sd,3);
 			channel_gjoin(sd,3);
 		return sd->guild->channel;
 		return sd->guild->channel;
@@ -472,9 +474,6 @@ int channel_pc_haschan(struct map_session_data *sd, struct Channel *channel){
  *  -1 : fail
  *  -1 : fail
  */
  */
 int channel_display_list(struct map_session_data *sd, char *options){
 int channel_display_list(struct map_session_data *sd, char *options){
-	struct Channel *channel;
-	char output[128];
-	int k;
 
 
 	if(!sd || !options)
 	if(!sd || !options)
 		return -1;
 		return -1;
@@ -482,10 +481,13 @@ int channel_display_list(struct map_session_data *sd, char *options){
 	//display availaible colors
 	//display availaible colors
 	if( options[0] != '\0' && strcmpi(options,"colors") == 0 ) {
 	if( options[0] != '\0' && strcmpi(options,"colors") == 0 ) {
 		char msg[40];
 		char msg[40];
+		unsigned char k;
 		clif_displaymessage(sd->fd, msg_txt(sd,1444)); // ---- Available Colors ----
 		clif_displaymessage(sd->fd, msg_txt(sd,1444)); // ---- Available Colors ----
-		for( k = 0; k < Channel_Config.colors_count; k++ ) {
-			sprintf(msg, msg_txt(sd,1445),Channel_Config.colors_name[k]);// - '%s'
-			clif_colormes(sd,Channel_Config.colors[k],msg);
+		for( k = 0; k < channel_config.colors_count; k++ ) {
+			if (channel_config.colors[k]) {
+				sprintf(msg, msg_txt(sd,1445),channel_config.colors_name[k]);// - '%s'
+				clif_colormes(sd,channel_config.colors[k],msg);
+			}
 		}
 		}
 	}
 	}
 	else if( options[0] != '\0' && strcmpi(options,"mine") == 0 ) { //display chan I'm into
 	else if( options[0] != '\0' && strcmpi(options,"mine") == 0 ) { //display chan I'm into
@@ -493,8 +495,12 @@ int channel_display_list(struct map_session_data *sd, char *options){
 		if(!sd->channel_count)
 		if(!sd->channel_count)
 			clif_displaymessage(sd->fd, msg_txt(sd,1476)); // You have not joined any channels.
 			clif_displaymessage(sd->fd, msg_txt(sd,1476)); // You have not joined any channels.
 		else {
 		else {
+			unsigned char k;
+			struct Channel *channel;
 			for(k=0; k<sd->channel_count; k++){
 			for(k=0; k<sd->channel_count; k++){
-				channel = sd->channels[k];
+				char output[128];
+				if (!(channel = sd->channels[k]))
+					continue;
 				sprintf(output, msg_txt(sd,1409), channel->name, db_size(channel->users));// - #%s (%d users)
 				sprintf(output, msg_txt(sd,1409), channel->name, db_size(channel->users));// - #%s (%d users)
 				clif_displaymessage(sd->fd, output);
 				clif_displaymessage(sd->fd, output);
 			}
 			}
@@ -503,17 +509,20 @@ int channel_display_list(struct map_session_data *sd, char *options){
 	else { //display public chanels
 	else { //display public chanels
 		DBIterator *iter;
 		DBIterator *iter;
 		bool has_perm = pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) ? true : false;
 		bool has_perm = pc_has_permission(sd, PC_PERM_CHANNEL_ADMIN) ? true : false;
+		struct Channel *channel;
+		char output[128];
 
 
 		clif_displaymessage(sd->fd, msg_txt(sd,1410)); // ---- Public Channels ----
 		clif_displaymessage(sd->fd, msg_txt(sd,1410)); // ---- Public Channels ----
-		if( Channel_Config.map_enable ) {
-			sprintf(output, msg_txt(sd,1409), Channel_Config.map_chname, map[sd->bl.m].channel ? db_size(map[sd->bl.m].channel->users) : 0);// - #%s (%d users)
+		if( channel_config.map_enable && map[sd->bl.m].channel ) {
+			sprintf(output, msg_txt(sd,1409), channel_config.map_chname, map[sd->bl.m].channel ? db_size(map[sd->bl.m].channel->users) : 0);// - #%s (%d users)
 			clif_displaymessage(sd->fd, output);
 			clif_displaymessage(sd->fd, output);
 		}
 		}
-		if( Channel_Config.ally_enable && sd->status.guild_id ) {
+		if( channel_config.ally_enable && sd->status.guild_id ) {
 			struct guild *g = sd->guild;
 			struct guild *g = sd->guild;
-			if( !g ) return -1; //how can this happen if status.guild_id true ?
-			sprintf(output, msg_txt(sd,1409), Channel_Config.ally_chname, db_size(((struct Channel *)g->channel)->users));// - #%s (%d users)
-			clif_displaymessage(sd->fd, output);
+			if (g && g->channel) {
+				sprintf(output, msg_txt(sd,1409), channel_config.ally_chname, db_size(((struct Channel *)g->channel)->users));// - #%s (%d users)
+				clif_displaymessage(sd->fd, output);
+			}
 		}
 		}
 		iter = db_iterator(channel_db);
 		iter = db_iterator(channel_db);
 		for(channel = dbi_first(iter); dbi_exists(iter); channel = dbi_next(iter)) {
 		for(channel = dbi_first(iter); dbi_exists(iter); channel = dbi_next(iter)) {
@@ -618,7 +627,7 @@ int channel_pcleave(struct map_session_data *sd, char *chname){
 		return -2; //channel doesn't exist or player don't have it
 		return -2; //channel doesn't exist or player don't have it
 	}
 	}
 
 
-	if( !Channel_Config.closing && (channel->opt & CHAN_OPT_ANNOUNCE_JOIN) ) {
+	if( !channel_config.closing && (channel->opt & CHAN_OPT_ANNOUNCE_JOIN) ) {
 		char message[60];
 		char message[60];
 		sprintf(message, "#%s '%s' left",channel->name,sd->status.name);
 		sprintf(message, "#%s '%s' left",channel->name,sd->status.name);
 		clif_channel_msg(channel,sd,message,channel->color);
 		clif_channel_msg(channel,sd,message,channel->color);
@@ -726,14 +735,14 @@ int channel_pccolor(struct map_session_data *sd, char *chname, char *color){
 		return -1;
 		return -1;
 	}
 	}
 
 
-	ARR_FIND(0,Channel_Config.colors_count,k,( strcmpi(color,Channel_Config.colors_name[k]) == 0 ) );
-	if( k >= Channel_Config.colors_count ) {
+	ARR_FIND(0,channel_config.colors_count,k,( strcmpi(color,channel_config.colors_name[k]) == 0 ) );
+	if( k >= channel_config.colors_count ) {
 		sprintf(output, msg_txt(sd,1411), color);// Unknown color '%s'.
 		sprintf(output, msg_txt(sd,1411), color);// Unknown color '%s'.
 		clif_displaymessage(sd->fd, output);
 		clif_displaymessage(sd->fd, output);
 		return -1;
 		return -1;
 	}
 	}
 	channel->color = k;
 	channel->color = k;
-	sprintf(output, msg_txt(sd,1413),chname,Channel_Config.colors_name[k]);// '%s' channel color updated to '%s'.
+	sprintf(output, msg_txt(sd,1413),chname,channel_config.colors_name[k]);// '%s' channel color updated to '%s'.
 	clif_displaymessage(sd->fd, output);
 	clif_displaymessage(sd->fd, output);
 	return 0;
 	return 0;
 }
 }
@@ -1031,74 +1040,74 @@ void channel_read_config(void) {
 
 
 		if( !config_setting_lookup_string(settings, "map_local_channel_name", &map_chname) )
 		if( !config_setting_lookup_string(settings, "map_local_channel_name", &map_chname) )
 			map_chname = "map";
 			map_chname = "map";
-		safestrncpy(Channel_Config.map_chname, map_chname, CHAN_NAME_LENGTH);
+		safestrncpy(channel_config.map_chname, map_chname, CHAN_NAME_LENGTH);
 
 
 		if( !config_setting_lookup_string(settings, "ally_channel_name", &ally_chname) )
 		if( !config_setting_lookup_string(settings, "ally_channel_name", &ally_chname) )
 			ally_chname = "ally";
 			ally_chname = "ally";
-		safestrncpy(Channel_Config.ally_chname, ally_chname, CHAN_NAME_LENGTH);
+		safestrncpy(channel_config.ally_chname, ally_chname, CHAN_NAME_LENGTH);
 
 
 		config_setting_lookup_bool(settings, "map_local_channel", &local_enabled);
 		config_setting_lookup_bool(settings, "map_local_channel", &local_enabled);
 		config_setting_lookup_bool(settings, "ally_channel_enabled", &ally_enabled);
 		config_setting_lookup_bool(settings, "ally_channel_enabled", &ally_enabled);
 
 
 		if( local_enabled )
 		if( local_enabled )
-			Channel_Config.map_enable = true;
+			channel_config.map_enable = true;
 		if( ally_enabled )
 		if( ally_enabled )
-			Channel_Config.ally_enable = true;
+			channel_config.ally_enable = true;
 
 
 		config_setting_lookup_bool(settings, "map_local_channel_autojoin", &local_autojoin);
 		config_setting_lookup_bool(settings, "map_local_channel_autojoin", &local_autojoin);
 		config_setting_lookup_bool(settings, "ally_channel_autojoin", &ally_autojoin);
 		config_setting_lookup_bool(settings, "ally_channel_autojoin", &ally_autojoin);
 
 
 		if( local_autojoin )
 		if( local_autojoin )
-			Channel_Config.map_autojoin = true;
+			channel_config.map_autojoin = true;
 		if( ally_autojoin )
 		if( ally_autojoin )
-			Channel_Config.ally_autojoin = true;
+			channel_config.ally_autojoin = true;
 
 
 		config_setting_lookup_bool(settings, "allow_user_channel_creation", &allow_user_channel_creation);
 		config_setting_lookup_bool(settings, "allow_user_channel_creation", &allow_user_channel_creation);
 
 
 		if( allow_user_channel_creation )
 		if( allow_user_channel_creation )
-			Channel_Config.user_chenable = true;
+			channel_config.user_chenable = true;
 
 
 		if( (colors = config_setting_get_member(settings, "colors")) != NULL ) {
 		if( (colors = config_setting_get_member(settings, "colors")) != NULL ) {
 			int color_count = config_setting_length(colors);
 			int color_count = config_setting_length(colors);
-			CREATE( Channel_Config.colors, unsigned long, color_count );
-			CREATE( Channel_Config.colors_name, char *, color_count );
+			CREATE( channel_config.colors, unsigned long, color_count );
+			CREATE( channel_config.colors_name, char *, color_count );
 			for(i = 0; i < color_count; i++) {
 			for(i = 0; i < color_count; i++) {
 				config_setting_t *color = config_setting_get_elem(colors, i);
 				config_setting_t *color = config_setting_get_elem(colors, i);
-				CREATE( Channel_Config.colors_name[i], char, CHAN_NAME_LENGTH );
+				CREATE( channel_config.colors_name[i], char, CHAN_NAME_LENGTH );
 
 
-				safestrncpy(Channel_Config.colors_name[i], config_setting_name(color), CHAN_NAME_LENGTH);
-				Channel_Config.colors[i] = strtoul(config_setting_get_string_elem(colors,i),NULL,0);
-				Channel_Config.colors[i] = (Channel_Config.colors[i] & 0x0000FF) << 16 | (Channel_Config.colors[i] & 0x00FF00) | (Channel_Config.colors[i] & 0xFF0000) >> 16;//RGB to BGR
+				safestrncpy(channel_config.colors_name[i], config_setting_name(color), CHAN_NAME_LENGTH);
+				channel_config.colors[i] = strtoul(config_setting_get_string_elem(colors,i),NULL,0);
+				channel_config.colors[i] = (channel_config.colors[i] & 0x0000FF) << 16 | (channel_config.colors[i] & 0x00FF00) | (channel_config.colors[i] & 0xFF0000) >> 16;//RGB to BGR
 			}
 			}
-			Channel_Config.colors_count = color_count;
+			channel_config.colors_count = color_count;
 		}
 		}
 
 
 		config_setting_lookup_string(settings, "map_local_channel_color", &map_color);
 		config_setting_lookup_string(settings, "map_local_channel_color", &map_color);
 
 
-		for (k = 0; k < Channel_Config.colors_count; k++) {
-			if( strcmpi(Channel_Config.colors_name[k],map_color) == 0 )
+		for (k = 0; k < channel_config.colors_count; k++) {
+			if( strcmpi(channel_config.colors_name[k],map_color) == 0 )
 				break;
 				break;
 		}
 		}
 
 
-		if( k < Channel_Config.colors_count ) {
-			Channel_Config.map_chcolor = k;
+		if( k < channel_config.colors_count ) {
+			channel_config.map_chcolor = k;
 		} else {
 		} else {
 			ShowError("channels.conf: unknown color '%s' for 'map_local_channel_color', disabling '#%s'...\n",map_color,map_chname);
 			ShowError("channels.conf: unknown color '%s' for 'map_local_channel_color', disabling '#%s'...\n",map_color,map_chname);
-			Channel_Config.map_enable = false;
+			channel_config.map_enable = false;
 		}
 		}
 
 
 		config_setting_lookup_string(settings, "ally_channel_color", &ally_color);
 		config_setting_lookup_string(settings, "ally_channel_color", &ally_color);
 
 
-		for (k = 0; k < Channel_Config.colors_count; k++) {
-			if( strcmpi(Channel_Config.colors_name[k],ally_color) == 0 )
+		for (k = 0; k < channel_config.colors_count; k++) {
+			if( strcmpi(channel_config.colors_name[k],ally_color) == 0 )
 				break;
 				break;
 		}
 		}
 
 
-		if( k < Channel_Config.colors_count ) {
-			Channel_Config.ally_chcolor = k;
+		if( k < channel_config.colors_count ) {
+			channel_config.ally_chcolor = k;
 		} else {
 		} else {
 			ShowError("channels.conf: unknown color '%s' for 'ally_channel_color', disabling '#%s'...\n",ally_color,ally_chname);
 			ShowError("channels.conf: unknown color '%s' for 'ally_channel_color', disabling '#%s'...\n",ally_color,ally_chname);
-			Channel_Config.ally_enable = false;
+			channel_config.ally_enable = false;
 		}
 		}
 
 
 		if( (channels = config_setting_get_member(settings, "default_channels")) != NULL ) {
 		if( (channels = config_setting_get_member(settings, "default_channels")) != NULL ) {
@@ -1108,15 +1117,15 @@ void channel_read_config(void) {
 				config_setting_t *channel = config_setting_get_elem(channels, i);
 				config_setting_t *channel = config_setting_get_elem(channels, i);
 				const char *color = config_setting_get_string_elem(channels,i);
 				const char *color = config_setting_get_string_elem(channels,i);
 				char *name = config_setting_name(channel);
 				char *name = config_setting_name(channel);
-				for (k = 0; k < Channel_Config.colors_count; k++) {
-					if( strcmpi(Channel_Config.colors_name[k],color) == 0 )
+				for (k = 0; k < channel_config.colors_count; k++) {
+					if( strcmpi(channel_config.colors_name[k],color) == 0 )
 						break;
 						break;
 				}
 				}
-				if( k == Channel_Config.colors_count ) {
+				if( k == channel_config.colors_count ) {
 					ShowError("channels.conf: unknown color '%s' for channel '%s', skipping channel...\n",color,name);
 					ShowError("channels.conf: unknown color '%s' for channel '%s', skipping channel...\n",color,name);
 					continue;
 					continue;
 				}
 				}
-				if( strcmpi(name,Channel_Config.map_chname) == 0 || strcmpi(name,Channel_Config.ally_chname) == 0 || strdb_exists(channel_db, name) ) {
+				if( strcmpi(name,channel_config.map_chname) == 0 || strcmpi(name,channel_config.ally_chname) == 0 || strdb_exists(channel_db, name) ) {
 					ShowError("channels.conf: duplicate channel '%s', skipping channel...\n",name);
 					ShowError("channels.conf: duplicate channel '%s', skipping channel...\n",name);
 					continue;
 					continue;
 				}
 				}
@@ -1136,7 +1145,7 @@ void channel_read_config(void) {
  */
  */
 void do_init_channel(void) {
 void do_init_channel(void) {
 	channel_db = stridb_alloc(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA, CHAN_NAME_LENGTH);
 	channel_db = stridb_alloc(DB_OPT_DUP_KEY|DB_OPT_RELEASE_DATA, CHAN_NAME_LENGTH);
-	Channel_Config.ally_enable = Channel_Config.map_enable = Channel_Config.ally_autojoin = Channel_Config.map_autojoin = false;
+	channel_config.ally_enable = channel_config.map_enable = channel_config.ally_autojoin = channel_config.map_autojoin = false;
 	channel_read_config();
 	channel_read_config();
 }
 }
 
 
@@ -1158,12 +1167,12 @@ void do_final_channel(void) {
 	db_destroy(channel_db);
 	db_destroy(channel_db);
 
 
 	//delete all color thing
 	//delete all color thing
-	if( Channel_Config.colors_count ) {
+	if( channel_config.colors_count ) {
 		int i=0;
 		int i=0;
-		for(i = 0; i < Channel_Config.colors_count; i++) {
-			aFree(Channel_Config.colors_name[i]);
+		for(i = 0; i < channel_config.colors_count; i++) {
+			aFree(channel_config.colors_name[i]);
 		}
 		}
-		aFree(Channel_Config.colors_name);
-		aFree(Channel_Config.colors);
+		aFree(channel_config.colors_name);
+		aFree(channel_config.colors);
 	}
 	}
 }
 }

+ 3 - 2
src/map/channel.h

@@ -27,7 +27,7 @@ enum Channel_Type {
 	CHAN_TYPE_ALLY		= 3,	//guild
 	CHAN_TYPE_ALLY		= 3,	//guild
 };
 };
 
 
-struct {
+struct Channel_Config {
 	unsigned long *colors;		//color avail int list
 	unsigned long *colors;		//color avail int list
 	char **colors_name;		//colors avail name list
 	char **colors_name;		//colors avail name list
 	unsigned char colors_count;	//color avail count
 	unsigned char colors_count;	//color avail count
@@ -36,7 +36,8 @@ struct {
 	bool map_autojoin, ally_autojoin;	//do user auto join in mapchange, guildjoin ?
 	bool map_autojoin, ally_autojoin;	//do user auto join in mapchange, guildjoin ?
 	char map_chname[CHAN_NAME_LENGTH], ally_chname[CHAN_NAME_LENGTH]; //channel name for map and ally
 	char map_chname[CHAN_NAME_LENGTH], ally_chname[CHAN_NAME_LENGTH]; //channel name for map and ally
 	bool closing;			//server is closing
 	bool closing;			//server is closing
-} Channel_Config;
+};
+extern struct Channel_Config channel_config;
 
 
 struct Channel {
 struct Channel {
 	char name[CHAN_NAME_LENGTH];	//channel name
 	char name[CHAN_NAME_LENGTH];	//channel name

+ 0 - 1
src/map/chrif.c

@@ -286,7 +286,6 @@ int chrif_save(struct map_session_data *sd, int flag) {
 	pc_makesavestatus(sd);
 	pc_makesavestatus(sd);
 
 
 	if (flag && sd->state.active) { //Store player data which is quitting
 	if (flag && sd->state.active) { //Store player data which is quitting
-		//FIXME: SC are lost if there's no connection at save-time because of the way its related data is cleared immediately after this function. [Skotlex]
 		if (chrif_isconnected()) {
 		if (chrif_isconnected()) {
 			chrif_save_scdata(sd);
 			chrif_save_scdata(sd);
 			chrif_skillcooldown_save(sd);
 			chrif_skillcooldown_save(sd);

+ 2 - 2
src/map/clif.c

@@ -5657,7 +5657,7 @@ void clif_channel_msg(struct Channel *channel, struct map_session_data *sd, char
 	WFIFOW(sd->fd,0) = 0x2C1;
 	WFIFOW(sd->fd,0) = 0x2C1;
 	WFIFOW(sd->fd,2) = msg_len + 12;
 	WFIFOW(sd->fd,2) = msg_len + 12;
 	WFIFOL(sd->fd,4) = 0;
 	WFIFOL(sd->fd,4) = 0;
-	WFIFOL(sd->fd,8) = Channel_Config.colors[color];
+	WFIFOL(sd->fd,8) = channel_config.colors[color];
 	safestrncpy((char*)WFIFOP(sd->fd,12), msg, msg_len);
 	safestrncpy((char*)WFIFOP(sd->fd,12), msg, msg_len);
 
 
 	iter = db_iterator(channel->users);
 	iter = db_iterator(channel->users);
@@ -9784,7 +9784,7 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd)
 		sd->state.changemap = false;
 		sd->state.changemap = false;
 
 
 		// Instances do not need their own channels
 		// Instances do not need their own channels
-		if( Channel_Config.map_enable && Channel_Config.map_autojoin && !map[sd->bl.m].flag.chmautojoin && !map[sd->bl.m].instance_id )
+		if( channel_config.map_enable && channel_config.map_autojoin && !map[sd->bl.m].flag.chmautojoin && !map[sd->bl.m].instance_id )
 			channel_mjoin(sd); //join new map
 			channel_mjoin(sd); //join new map
 	} else if (sd->guild && (battle_config.guild_notice_changemap == 2 || guild_notice))
 	} else if (sd->guild && (battle_config.guild_notice_changemap == 2 || guild_notice))
 		clif_guild_notice(sd, sd->guild); // Displays at end
 		clif_guild_notice(sd, sd->guild); // Displays at end

+ 3 - 3
src/map/guild.c

@@ -511,7 +511,7 @@ int guild_recv_info(struct guild *sg) {
 		if( sd==NULL )
 		if( sd==NULL )
 			continue;
 			continue;
 		sd->guild = g;
 		sd->guild = g;
-		if(Channel_Config.ally_autojoin ) {
+		if(channel_config.ally_autojoin ) {
 			channel_gjoin(sd,3); //make all member join guildchan+allieschan
 			channel_gjoin(sd,3); //make all member join guildchan+allieschan
 		}
 		}
 
 
@@ -676,7 +676,7 @@ void guild_member_joined(struct map_session_data *sd) {
 		g->member[i].sd = sd;
 		g->member[i].sd = sd;
 		sd->guild = g;
 		sd->guild = g;
 
 
-		if( Channel_Config.ally_enable && Channel_Config.ally_autojoin ) {
+		if( channel_config.ally_enable && channel_config.ally_autojoin ) {
 			channel_gjoin(sd,3);
 			channel_gjoin(sd,3);
 		}
 		}
 	}
 	}
@@ -1673,7 +1673,7 @@ int guild_broken(int guild_id,int flag) {
 	guild_db->foreach(guild_db,guild_broken_sub,guild_id);
 	guild_db->foreach(guild_db,guild_broken_sub,guild_id);
 	castle_db->foreach(castle_db,castle_guild_broken_sub,guild_id);
 	castle_db->foreach(castle_db,castle_guild_broken_sub,guild_id);
 	guild_storage_delete(guild_id);
 	guild_storage_delete(guild_id);
-	if( Channel_Config.ally_enable ) {
+	if( channel_config.ally_enable ) {
 		channel_delete(g->channel);
 		channel_delete(g->channel);
 	}
 	}
 	idb_remove(guild_db,guild_id);
 	idb_remove(guild_db,guild_id);

+ 1 - 1
src/map/map.c

@@ -3832,7 +3832,7 @@ void do_final(void)
 	struct s_mapiterator* iter;
 	struct s_mapiterator* iter;
 
 
 	ShowStatus("Terminating...\n");
 	ShowStatus("Terminating...\n");
-	Channel_Config.closing = true;
+	channel_config.closing = true;
 
 
 	//Ladies and babies first.
 	//Ladies and babies first.
 	iter = mapit_getallusers();
 	iter = mapit_getallusers();

+ 11 - 2
src/map/map.h

@@ -298,10 +298,19 @@ enum bl_type {
 	BL_ALL   = 0xFFF,
 	BL_ALL   = 0xFFF,
 };
 };
 
 
-//For common mapforeach calls. Since pets cannot be affected, they aren't included here yet.
+/// For common mapforeach calls. Since pets cannot be affected, they aren't included here yet.
 #define BL_CHAR (BL_PC|BL_MOB|BL_HOM|BL_MER|BL_ELEM)
 #define BL_CHAR (BL_PC|BL_MOB|BL_HOM|BL_MER|BL_ELEM)
 
 
-enum npc_subtype { WARP, SHOP, SCRIPT, CASHSHOP, ITEMSHOP, POINTSHOP, TOMB };
+/// NPC Subtype
+enum npc_subtype {
+	NPCTYPE_WARP, /// Warp
+	NPCTYPE_SHOP, /// Shop
+	NPCTYPE_SCRIPT, /// Script
+	NPCTYPE_CASHSHOP, /// Cashshop
+	NPCTYPE_ITEMSHOP, /// Itemshop
+	NPCTYPE_POINTSHOP, /// Pointshop
+	NPCTYPE_TOMB /// Monster tomb
+};
 
 
 enum e_race {
 enum e_race {
 	RC_NONE_ = -1, //don't give us bonus
 	RC_NONE_ = -1, //don't give us bonus

+ 2 - 2
src/map/mob.c

@@ -149,7 +149,7 @@ void mvptomb_create(struct mob_data *md, char *killer, time_t time)
 
 
 	nd->class_ = 565;
 	nd->class_ = 565;
 	nd->speed = 200;
 	nd->speed = 200;
-	nd->subtype = TOMB;
+	nd->subtype = NPCTYPE_TOMB;
 
 
 	nd->u.tomb.md = md;
 	nd->u.tomb.md = md;
 	nd->u.tomb.kill_time = time;
 	nd->u.tomb.kill_time = time;
@@ -1192,7 +1192,7 @@ static int mob_warpchase_sub(struct block_list *bl,va_list ap) {
 
 
 	nd = (TBL_NPC*) bl;
 	nd = (TBL_NPC*) bl;
 
 
-	if(nd->subtype != WARP)
+	if(nd->subtype != NPCTYPE_WARP)
 		return 0; //Not a warp
 		return 0; //Not a warp
 
 
 	if(nd->u.warp.mapindex != map[target->m].index)
 	if(nd->u.warp.mapindex != map[target->m].index)

+ 75 - 73
src/map/npc.c

@@ -128,10 +128,10 @@ int npc_isnear_sub(struct block_list* bl, va_list args) {
 
 
 		if (idx > 0 && skill_db[idx].unit_nonearnpc_type) {
 		if (idx > 0 && skill_db[idx].unit_nonearnpc_type) {
 			while (1) {
 			while (1) {
-				if (skill_db[idx].unit_nonearnpc_type&1 && nd->subtype == WARP) break;
-				if (skill_db[idx].unit_nonearnpc_type&2 && nd->subtype == SHOP) break;
-				if (skill_db[idx].unit_nonearnpc_type&4 && nd->subtype == SCRIPT) break;
-				if (skill_db[idx].unit_nonearnpc_type&8 && nd->subtype == TOMB) break;
+				if (skill_db[idx].unit_nonearnpc_type&1 && nd->subtype == NPCTYPE_WARP) break;
+				if (skill_db[idx].unit_nonearnpc_type&2 && nd->subtype == NPCTYPE_SHOP) break;
+				if (skill_db[idx].unit_nonearnpc_type&4 && nd->subtype == NPCTYPE_SCRIPT) break;
+				if (skill_db[idx].unit_nonearnpc_type&8 && nd->subtype == NPCTYPE_TOMB) break;
 					return 0;
 					return 0;
 			}
 			}
 		}
 		}
@@ -944,11 +944,11 @@ int npc_touch_areanpc(struct map_session_data* sd, int16 m, int16 x, int16 y)
 		}
 		}
 
 
 		switch(map[m].npc[i]->subtype) {
 		switch(map[m].npc[i]->subtype) {
-		case WARP:
+		case NPCTYPE_WARP:
 			xs=map[m].npc[i]->u.warp.xs;
 			xs=map[m].npc[i]->u.warp.xs;
 			ys=map[m].npc[i]->u.warp.ys;
 			ys=map[m].npc[i]->u.warp.ys;
 			break;
 			break;
-		case SCRIPT:
+		case NPCTYPE_SCRIPT:
 			xs=map[m].npc[i]->u.scr.xs;
 			xs=map[m].npc[i]->u.scr.xs;
 			ys=map[m].npc[i]->u.scr.ys;
 			ys=map[m].npc[i]->u.scr.ys;
 			break;
 			break;
@@ -966,14 +966,14 @@ int npc_touch_areanpc(struct map_session_data* sd, int16 m, int16 x, int16 y)
 		return 1;
 		return 1;
 	}
 	}
 	switch(map[m].npc[i]->subtype) {
 	switch(map[m].npc[i]->subtype) {
-		case WARP:
+		case NPCTYPE_WARP:
 			if (pc_ishiding(sd) || (sd->sc.count && sd->sc.data[SC_CAMOUFLAGE]) || pc_isdead(sd))
 			if (pc_ishiding(sd) || (sd->sc.count && sd->sc.data[SC_CAMOUFLAGE]) || pc_isdead(sd))
 				break; // hidden or dead chars cannot use warps
 				break; // hidden or dead chars cannot use warps
 			pc_setpos(sd,map[m].npc[i]->u.warp.mapindex,map[m].npc[i]->u.warp.x,map[m].npc[i]->u.warp.y,CLR_OUTSIGHT);
 			pc_setpos(sd,map[m].npc[i]->u.warp.mapindex,map[m].npc[i]->u.warp.x,map[m].npc[i]->u.warp.y,CLR_OUTSIGHT);
 			break;
 			break;
-		case SCRIPT:
+		case NPCTYPE_SCRIPT:
 			for (j = i; j < map[m].npc_num; j++) {
 			for (j = i; j < map[m].npc_num; j++) {
-				if (map[m].npc[j]->subtype != WARP) {
+				if (map[m].npc[j]->subtype != NPCTYPE_WARP) {
 					continue;
 					continue;
 				}
 				}
 
 
@@ -1023,13 +1023,13 @@ int npc_touch_areanpc2(struct mob_data *md)
 
 
 		switch( map[m].npc[i]->subtype )
 		switch( map[m].npc[i]->subtype )
 		{
 		{
-			case WARP:
+			case NPCTYPE_WARP:
 				if( !( battle_config.mob_warp&1 ) )
 				if( !( battle_config.mob_warp&1 ) )
 					continue;
 					continue;
 				xs = map[m].npc[i]->u.warp.xs;
 				xs = map[m].npc[i]->u.warp.xs;
 				ys = map[m].npc[i]->u.warp.ys;
 				ys = map[m].npc[i]->u.warp.ys;
 				break;
 				break;
-			case SCRIPT:
+			case NPCTYPE_SCRIPT:
 				xs = map[m].npc[i]->u.scr.xs;
 				xs = map[m].npc[i]->u.scr.xs;
 				ys = map[m].npc[i]->u.scr.ys;
 				ys = map[m].npc[i]->u.scr.ys;
 				break;
 				break;
@@ -1041,14 +1041,14 @@ int npc_touch_areanpc2(struct mob_data *md)
 		{ // In the npc touch area
 		{ // In the npc touch area
 			switch( map[m].npc[i]->subtype )
 			switch( map[m].npc[i]->subtype )
 			{
 			{
-				case WARP:
+				case NPCTYPE_WARP:
 					xs = map_mapindex2mapid(map[m].npc[i]->u.warp.mapindex);
 					xs = map_mapindex2mapid(map[m].npc[i]->u.warp.mapindex);
 					if( m < 0 )
 					if( m < 0 )
 						break; // Cannot Warp between map servers
 						break; // Cannot Warp between map servers
 					if( unit_warp(&md->bl, xs, map[m].npc[i]->u.warp.x, map[m].npc[i]->u.warp.y, CLR_OUTSIGHT) == 0 )
 					if( unit_warp(&md->bl, xs, map[m].npc[i]->u.warp.x, map[m].npc[i]->u.warp.y, CLR_OUTSIGHT) == 0 )
 						return 1; // Warped
 						return 1; // Warped
 					break;
 					break;
-				case SCRIPT:
+				case NPCTYPE_SCRIPT:
 					if( map[m].npc[i]->bl.id == md->areanpc_id )
 					if( map[m].npc[i]->bl.id == md->areanpc_id )
 						break; // Already touch this NPC
 						break; // Already touch this NPC
 					snprintf(eventname, ARRAYLENGTH(eventname), "%s::OnTouchNPC", map[m].npc[i]->exname);
 					snprintf(eventname, ARRAYLENGTH(eventname), "%s::OnTouchNPC", map[m].npc[i]->exname);
@@ -1102,13 +1102,13 @@ int npc_check_areanpc(int flag, int16 m, int16 x, int16 y, int16 range)
 
 
 		switch(map[m].npc[i]->subtype)
 		switch(map[m].npc[i]->subtype)
 		{
 		{
-		case WARP:
+		case NPCTYPE_WARP:
 			if (!(flag&1))
 			if (!(flag&1))
 				continue;
 				continue;
 			xs=map[m].npc[i]->u.warp.xs;
 			xs=map[m].npc[i]->u.warp.xs;
 			ys=map[m].npc[i]->u.warp.ys;
 			ys=map[m].npc[i]->u.warp.ys;
 			break;
 			break;
-		case SCRIPT:
+		case NPCTYPE_SCRIPT:
 			if (!(flag&2))
 			if (!(flag&2))
 				continue;
 				continue;
 			xs=map[m].npc[i]->u.scr.xs;
 			xs=map[m].npc[i]->u.scr.xs;
@@ -1218,18 +1218,18 @@ int npc_click(struct map_session_data* sd, struct npc_data* nd)
 		return 1;
 		return 1;
 	
 	
 	switch(nd->subtype) {
 	switch(nd->subtype) {
-		case SHOP:
-		case ITEMSHOP:
-		case POINTSHOP:
+		case NPCTYPE_SHOP:
+		case NPCTYPE_ITEMSHOP:
+		case NPCTYPE_POINTSHOP:
 			clif_npcbuysell(sd,nd->bl.id);
 			clif_npcbuysell(sd,nd->bl.id);
 			break;
 			break;
-		case CASHSHOP:
+		case NPCTYPE_CASHSHOP:
 			clif_cashshop_show(sd,nd);
 			clif_cashshop_show(sd,nd);
 			break;
 			break;
-		case SCRIPT:
+		case NPCTYPE_SCRIPT:
 			run_script(nd->u.scr.script,0,sd->bl.id,nd->bl.id);
 			run_script(nd->u.scr.script,0,sd->bl.id,nd->bl.id);
 			break;
 			break;
-		case TOMB:
+		case NPCTYPE_TOMB:
 			run_tomb(sd,nd);
 			run_tomb(sd,nd);
 			break;
 			break;
 	}
 	}
@@ -1289,7 +1289,7 @@ int npc_buysellsel(struct map_session_data* sd, int id, int type)
 	if ((nd = npc_checknear(sd,map_id2bl(id))) == NULL)
 	if ((nd = npc_checknear(sd,map_id2bl(id))) == NULL)
 		return 1;
 		return 1;
 
 
-	if (nd->subtype != SHOP && nd->subtype != ITEMSHOP && nd->subtype != POINTSHOP) {
+	if (nd->subtype != NPCTYPE_SHOP && nd->subtype != NPCTYPE_ITEMSHOP && nd->subtype != NPCTYPE_POINTSHOP) {
 		ShowError("no such shop npc : %d\n",id);
 		ShowError("no such shop npc : %d\n",id);
 		if (sd->npc_id == id)
 		if (sd->npc_id == id)
 			sd->npc_id=0;
 			sd->npc_id=0;
@@ -1301,7 +1301,7 @@ int npc_buysellsel(struct map_session_data* sd, int id, int type)
 		return 1;
 		return 1;
 	}
 	}
 
 
-	if (nd->subtype == ITEMSHOP) {
+	if (nd->subtype == NPCTYPE_ITEMSHOP) {
 		char output[CHAT_SIZE_MAX];
 		char output[CHAT_SIZE_MAX];
 		struct item_data *itd = itemdb_exists(nd->u.shop.itemshop_nameid);
 		struct item_data *itd = itemdb_exists(nd->u.shop.itemshop_nameid);
 		memset(output,'\0',sizeof(output));
 		memset(output,'\0',sizeof(output));
@@ -1309,7 +1309,7 @@ int npc_buysellsel(struct map_session_data* sd, int id, int type)
 			sprintf(output,msg_txt(sd,714),itd->jname,itd->nameid); // Item Shop List: %s (%hu)
 			sprintf(output,msg_txt(sd,714),itd->jname,itd->nameid); // Item Shop List: %s (%hu)
 			clif_broadcast(&sd->bl,output,strlen(output) + 1,BC_BLUE,SELF);
 			clif_broadcast(&sd->bl,output,strlen(output) + 1,BC_BLUE,SELF);
 		}
 		}
-	} else if (nd->subtype == POINTSHOP) {
+	} else if (nd->subtype == NPCTYPE_POINTSHOP) {
 		char output[CHAT_SIZE_MAX];
 		char output[CHAT_SIZE_MAX];
 		memset(output,'\0',sizeof(output));
 		memset(output,'\0',sizeof(output));
 		sprintf(output,msg_txt(sd,715),nd->u.shop.pointshop_str); // Point Shop List: '%s'
 		sprintf(output,msg_txt(sd,715),nd->u.shop.pointshop_str); // Point Shop List: '%s'
@@ -1336,7 +1336,7 @@ int npc_cashshop_buylist(struct map_session_data *sd, int points, int count, uns
 	unsigned short nameid;
 	unsigned short nameid;
 	struct npc_data *nd = (struct npc_data *)map_id2bl(sd->npc_shopid);
 	struct npc_data *nd = (struct npc_data *)map_id2bl(sd->npc_shopid);
 
 
-	if( !nd || nd->subtype != CASHSHOP )
+	if( !nd || nd->subtype != NPCTYPE_CASHSHOP )
 		return 1;
 		return 1;
 
 
 	if( sd->state.trading )
 	if( sd->state.trading )
@@ -1453,7 +1453,7 @@ int npc_cashshop_buy(struct map_session_data *sd, unsigned short nameid, int amo
 	if( points < 0 )
 	if( points < 0 )
 		return 6;
 		return 6;
 
 
-	if( !nd || nd->subtype != CASHSHOP )
+	if( !nd || nd->subtype != NPCTYPE_CASHSHOP )
 		return 1;
 		return 1;
 
 
 	if( sd->state.trading )
 	if( sd->state.trading )
@@ -1538,7 +1538,7 @@ int npc_buylist(struct map_session_data* sd, int n, unsigned short* item_list)
 	nd = npc_checknear(sd,map_id2bl(sd->npc_shopid));
 	nd = npc_checknear(sd,map_id2bl(sd->npc_shopid));
 	if( nd == NULL )
 	if( nd == NULL )
 		return 3;
 		return 3;
-	if( nd->subtype != SHOP && nd->subtype != ITEMSHOP && nd->subtype != POINTSHOP )
+	if( nd->subtype != NPCTYPE_SHOP && nd->subtype != NPCTYPE_ITEMSHOP && nd->subtype != NPCTYPE_POINTSHOP )
 		return 3;
 		return 3;
 
 
 	z = 0;
 	z = 0;
@@ -1602,11 +1602,11 @@ int npc_buylist(struct map_session_data* sd, int n, unsigned short* item_list)
 		return npc_buylist_sub(sd,n,item_list,nd->master_nd);
 		return npc_buylist_sub(sd,n,item_list,nd->master_nd);
 
 
 	switch(nd->subtype) {
 	switch(nd->subtype) {
-		case SHOP:
+		case NPCTYPE_SHOP:
 			if (z > (double)sd->status.zeny)
 			if (z > (double)sd->status.zeny)
 				return 1;	// Not enough Zeny
 				return 1;	// Not enough Zeny
 			break;
 			break;
-		case ITEMSHOP:
+		case NPCTYPE_ITEMSHOP:
 			for (k = 0; k < MAX_INVENTORY; k++) {
 			for (k = 0; k < MAX_INVENTORY; k++) {
 				if (sd->status.inventory[k].nameid == nd->u.shop.itemshop_nameid)
 				if (sd->status.inventory[k].nameid == nd->u.shop.itemshop_nameid)
 					count += sd->status.inventory[k].amount;
 					count += sd->status.inventory[k].amount;
@@ -1619,7 +1619,7 @@ int npc_buylist(struct map_session_data* sd, int n, unsigned short* item_list)
 				return 1;
 				return 1;
 			}
 			}
 			break;
 			break;
-		case POINTSHOP:
+		case NPCTYPE_POINTSHOP:
 			switch(nd->u.shop.pointshop_str[0]) {
 			switch(nd->u.shop.pointshop_str[0]) {
 				case '#':
 				case '#':
 					if (nd->u.shop.pointshop_str[1] == '#')
 					if (nd->u.shop.pointshop_str[1] == '#')
@@ -1646,13 +1646,13 @@ int npc_buylist(struct map_session_data* sd, int n, unsigned short* item_list)
 		return 3;	// Not enough space to store items
 		return 3;	// Not enough space to store items
 
 
 	switch(nd->subtype) {
 	switch(nd->subtype) {
-		case SHOP:
+		case NPCTYPE_SHOP:
 			pc_payzeny(sd, (int)z, LOG_TYPE_NPC, NULL);
 			pc_payzeny(sd, (int)z, LOG_TYPE_NPC, NULL);
 			break;
 			break;
-		case ITEMSHOP:
+		case NPCTYPE_ITEMSHOP:
 			pc_delitem(sd, pc_search_inventory(sd, nd->u.shop.itemshop_nameid), (int)z, 0, 0, LOG_TYPE_NPC);
 			pc_delitem(sd, pc_search_inventory(sd, nd->u.shop.itemshop_nameid), (int)z, 0, 0, LOG_TYPE_NPC);
 			break;
 			break;
-		case POINTSHOP:
+		case NPCTYPE_POINTSHOP:
 			switch(nd->u.shop.pointshop_str[0]) {
 			switch(nd->u.shop.pointshop_str[0]) {
 				case '#':
 				case '#':
 					if (nd->u.shop.pointshop_str[1] == '#')
 					if (nd->u.shop.pointshop_str[1] == '#')
@@ -1701,7 +1701,7 @@ int npc_buylist(struct map_session_data* sd, int n, unsigned short* item_list)
 		}
 		}
 	}
 	}
 
 
-	if (nd->subtype == POINTSHOP) {
+	if (nd->subtype == NPCTYPE_POINTSHOP) {
 		sprintf(output,msg_txt(sd,716),nd->u.shop.pointshop_str,count - (int)z); // Your '%s' now: %d
 		sprintf(output,msg_txt(sd,716),nd->u.shop.pointshop_str,count - (int)z); // Your '%s' now: %d
 		clif_disp_onlyself(sd,output,strlen(output)+1);
 		clif_disp_onlyself(sd,output,strlen(output)+1);
 	}
 	}
@@ -1782,7 +1782,7 @@ int npc_selllist(struct map_session_data* sd, int n, unsigned short* item_list)
 	nullpo_retr(1, item_list);
 	nullpo_retr(1, item_list);
 
 
 	if( ( nd = npc_checknear(sd, map_id2bl(sd->npc_shopid)) ) == NULL 
 	if( ( nd = npc_checknear(sd, map_id2bl(sd->npc_shopid)) ) == NULL 
-			|| ( nd->subtype != SHOP && nd->subtype != ITEMSHOP && nd->subtype != POINTSHOP ) )
+			|| ( nd->subtype != NPCTYPE_SHOP && nd->subtype != NPCTYPE_ITEMSHOP && nd->subtype != NPCTYPE_POINTSHOP ) )
 	{
 	{
 		return 1;
 		return 1;
 	}
 	}
@@ -1877,6 +1877,8 @@ int npc_remove_map(struct npc_data* nd)
 	if(nd->bl.prev == NULL || nd->bl.m < 0)
 	if(nd->bl.prev == NULL || nd->bl.m < 0)
 		return 1; //Not assigned to a map.
 		return 1; //Not assigned to a map.
   	m = nd->bl.m;
   	m = nd->bl.m;
+	if (nd->subtype == NPCTYPE_SCRIPT)
+		skill_clear_unitgroup(&nd->bl);
 	clif_clearunit_area(&nd->bl,CLR_RESPAWN);
 	clif_clearunit_area(&nd->bl,CLR_RESPAWN);
 	npc_unsetcells(nd);
 	npc_unsetcells(nd);
 	map_delblock(&nd->bl);
 	map_delblock(&nd->bl);
@@ -1955,9 +1957,9 @@ int npc_unload(struct npc_data* nd, bool single) {
 	if( single && nd->bl.m != -1 )
 	if( single && nd->bl.m != -1 )
 		map_remove_questinfo(nd->bl.m, nd);
 		map_remove_questinfo(nd->bl.m, nd);
 
 
-	if( (nd->subtype == SHOP || nd->subtype == CASHSHOP || nd->subtype == ITEMSHOP || nd->subtype == POINTSHOP) && nd->src_id == 0) //src check for duplicate shops [Orcao]
+	if( (nd->subtype == NPCTYPE_SHOP || nd->subtype == NPCTYPE_CASHSHOP || nd->subtype == NPCTYPE_ITEMSHOP || nd->subtype == NPCTYPE_POINTSHOP) && nd->src_id == 0) //src check for duplicate shops [Orcao]
 		aFree(nd->u.shop.shop_item);
 		aFree(nd->u.shop.shop_item);
-	else if( nd->subtype == SCRIPT ) {
+	else if( nd->subtype == NPCTYPE_SCRIPT ) {
 		struct s_mapiterator* iter;
 		struct s_mapiterator* iter;
 		struct block_list* bl;
 		struct block_list* bl;
 
 
@@ -2267,7 +2269,7 @@ struct npc_data* npc_add_warp(char* name, short from_mapid, short from_x, short
 	nd->u.warp.xs = xs;
 	nd->u.warp.xs = xs;
 	nd->u.warp.ys = xs;
 	nd->u.warp.ys = xs;
 	nd->bl.type = BL_NPC;
 	nd->bl.type = BL_NPC;
-	nd->subtype = WARP;
+	nd->subtype = NPCTYPE_WARP;
 	npc_setcells(nd);
 	npc_setcells(nd);
 	if(map_addblock(&nd->bl))
 	if(map_addblock(&nd->bl))
 		return NULL;
 		return NULL;
@@ -2344,7 +2346,7 @@ static const char* npc_parse_warp(char* w1, char* w2, char* w3, char* w4, const
 	nd->u.warp.ys = ys;
 	nd->u.warp.ys = ys;
 	npc_warp++;
 	npc_warp++;
 	nd->bl.type = BL_NPC;
 	nd->bl.type = BL_NPC;
-	nd->subtype = WARP;
+	nd->subtype = NPCTYPE_WARP;
 	npc_setcells(nd);
 	npc_setcells(nd);
 	if(map_addblock(&nd->bl)) //couldn't add on map
 	if(map_addblock(&nd->bl)) //couldn't add on map
 		return strchr(start,'\n');
 		return strchr(start,'\n');
@@ -2405,19 +2407,19 @@ static const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const
 	}
 	}
 
 
 	if( !strcasecmp(w2,"cashshop") )
 	if( !strcasecmp(w2,"cashshop") )
-		type = CASHSHOP;
+		type = NPCTYPE_CASHSHOP;
 	else if( !strcasecmp(w2,"itemshop") )
 	else if( !strcasecmp(w2,"itemshop") )
-		type = ITEMSHOP;
+		type = NPCTYPE_ITEMSHOP;
 	else if( !strcasecmp(w2,"pointshop") )
 	else if( !strcasecmp(w2,"pointshop") )
-		type = POINTSHOP;
+		type = NPCTYPE_POINTSHOP;
 	else
 	else
-		type = SHOP;
+		type = NPCTYPE_SHOP;
 
 
 	p = strchr(w4,',');
 	p = strchr(w4,',');
 	memset(point_str,'\0',sizeof(point_str));
 	memset(point_str,'\0',sizeof(point_str));
 
 
 	switch(type) {
 	switch(type) {
-		case ITEMSHOP: {
+		case NPCTYPE_ITEMSHOP: {
 			if (sscanf(p,",%hu:%d,",&nameid,&is_discount) < 1) {
 			if (sscanf(p,",%hu:%d,",&nameid,&is_discount) < 1) {
 				ShowError("npc_parse_shop: Invalid item cost definition in file '%s', line '%d'. Ignoring the rest of the line...\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4);
 				ShowError("npc_parse_shop: Invalid item cost definition in file '%s', line '%d'. Ignoring the rest of the line...\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4);
 				return strchr(start,'\n'); // skip and continue
 				return strchr(start,'\n'); // skip and continue
@@ -2429,7 +2431,7 @@ static const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const
 			p = strchr(p+1,',');
 			p = strchr(p+1,',');
 			break;
 			break;
 		}
 		}
-		case POINTSHOP: {
+		case NPCTYPE_POINTSHOP: {
 			if (sscanf(p, ",%32[^,:]:%d,",point_str,&is_discount) < 1) {
 			if (sscanf(p, ",%32[^,:]:%d,",point_str,&is_discount) < 1) {
 				ShowError("npc_parse_shop: Invalid item cost definition in file '%s', line '%d'. Ignoring the rest of the line...\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4);
 				ShowError("npc_parse_shop: Invalid item cost definition in file '%s', line '%d'. Ignoring the rest of the line...\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4);
 				return strchr(start,'\n'); // skip and continue
 				return strchr(start,'\n'); // skip and continue
@@ -2473,14 +2475,14 @@ static const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const
 			continue;
 			continue;
 		}
 		}
 		if( value < 0 ) {
 		if( value < 0 ) {
-			if( type == SHOP ) value = id->value_buy;
+			if( type == NPCTYPE_SHOP ) value = id->value_buy;
 			else value = 0; // Cashshop doesn't have a "buy price" in the item_db
 			else value = 0; // Cashshop doesn't have a "buy price" in the item_db
 		}
 		}
-		if( (type == SHOP || type == ITEMSHOP || type == POINTSHOP) && value == 0 ) { // NPC selling items for free!
+		if( (type == NPCTYPE_SHOP || type == NPCTYPE_ITEMSHOP || type == NPCTYPE_POINTSHOP) && value == 0 ) { // NPC selling items for free!
 			ShowWarning("npc_parse_shop: Item %s [%hu] is being sold for FREE in file '%s', line '%d'.\n",
 			ShowWarning("npc_parse_shop: Item %s [%hu] is being sold for FREE in file '%s', line '%d'.\n",
 				id->name, nameid2, filepath, strline(buffer,start-buffer));
 				id->name, nameid2, filepath, strline(buffer,start-buffer));
 		}
 		}
-		if( type == SHOP && value*0.75 < id->value_sell*1.24 ) { // Exploit possible: you can buy and sell back with profit
+		if( type == NPCTYPE_SHOP && value*0.75 < id->value_sell*1.24 ) { // Exploit possible: you can buy and sell back with profit
 			ShowWarning("npc_parse_shop: Item %s [%hu] discounted buying price (%d->%d) is less than overcharged selling price (%d->%d) at file '%s', line '%d'.\n",
 			ShowWarning("npc_parse_shop: Item %s [%hu] discounted buying price (%d->%d) is less than overcharged selling price (%d->%d) at file '%s', line '%d'.\n",
 				id->name, nameid2, value, (int)(value*0.75), id->value_sell, (int)(id->value_sell*1.24), filepath, strline(buffer,start-buffer));
 				id->name, nameid2, value, (int)(value*0.75), id->value_sell, (int)(id->value_sell*1.24), filepath, strline(buffer,start-buffer));
 		}
 		}
@@ -2504,9 +2506,9 @@ static const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const
 		return strchr(start,'\n');// continue
 		return strchr(start,'\n');// continue
 	}
 	}
 
 
-	if (type != SHOP) {
-		if (type == ITEMSHOP) nd->u.shop.itemshop_nameid = nameid; // Item shop currency
-		else if (type == POINTSHOP) safestrncpy(nd->u.shop.pointshop_str,point_str,strlen(point_str)+1); // Point shop currency
+	if (type != NPCTYPE_SHOP) {
+		if (type == NPCTYPE_ITEMSHOP) nd->u.shop.itemshop_nameid = nameid; // Item shop currency
+		else if (type == NPCTYPE_POINTSHOP) safestrncpy(nd->u.shop.pointshop_str,point_str,strlen(point_str)+1); // Point shop currency
 		nd->u.shop.discount = is_discount;
 		nd->u.shop.discount = is_discount;
 	}
 	}
 	nd->bl.prev = nd->bl.next = NULL;
 	nd->bl.prev = nd->bl.next = NULL;
@@ -2547,11 +2549,11 @@ static const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const
 * @return bool 'true' is discountable, 'false' otherwise
 * @return bool 'true' is discountable, 'false' otherwise
 */
 */
 bool npc_shop_discount(enum npc_subtype type, bool discount) {
 bool npc_shop_discount(enum npc_subtype type, bool discount) {
-	if (type == SHOP || (type != SHOP && discount))
+	if (type == NPCTYPE_SHOP || (type != NPCTYPE_SHOP && discount))
 		return true;
 		return true;
 
 
-	if( (type == ITEMSHOP && battle_config.discount_item_point_shop&1) ||
-		(type == POINTSHOP && battle_config.discount_item_point_shop&2) )
+	if( (type == NPCTYPE_ITEMSHOP && battle_config.discount_item_point_shop&1) ||
+		(type == NPCTYPE_POINTSHOP && battle_config.discount_item_point_shop&2) )
 		return true;
 		return true;
 	return false;
 	return false;
 }
 }
@@ -2754,7 +2756,7 @@ static const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, cons
 
 
 	++npc_script;
 	++npc_script;
 	nd->bl.type = BL_NPC;
 	nd->bl.type = BL_NPC;
-	nd->subtype = SCRIPT;
+	nd->subtype = NPCTYPE_SCRIPT;
 
 
 	if( m >= 0 )
 	if( m >= 0 )
 	{
 	{
@@ -2847,7 +2849,7 @@ const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const ch
 	type = dnd->subtype;
 	type = dnd->subtype;
 
 
 	// get placement
 	// get placement
-	if( (type == SHOP || type == CASHSHOP || type == ITEMSHOP || type == POINTSHOP || type == SCRIPT) && strcmp(w1, "-") == 0 ) {// floating shop/chashshop/itemshop/pointshop/script
+	if( (type == NPCTYPE_SHOP || type == NPCTYPE_CASHSHOP || type == NPCTYPE_ITEMSHOP || type == NPCTYPE_POINTSHOP || type == NPCTYPE_SCRIPT) && strcmp(w1, "-") == 0 ) {// floating shop/chashshop/itemshop/pointshop/script
 		x = y = dir = 0;
 		x = y = dir = 0;
 		m = -1;
 		m = -1;
 	} else {
 	} else {
@@ -2864,9 +2866,9 @@ const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const ch
 		ShowError("npc_parse_duplicate: coordinates %d/%d are out of bounds in map %s(%dx%d), in file '%s', line '%d'\n", x, y, map[m].name, map[m].xs, map[m].ys,filepath,strline(buffer,start-buffer));
 		ShowError("npc_parse_duplicate: coordinates %d/%d are out of bounds in map %s(%dx%d), in file '%s', line '%d'\n", x, y, map[m].name, map[m].xs, map[m].ys,filepath,strline(buffer,start-buffer));
 	}
 	}
 
 
-	if( type == WARP && sscanf(w4, "%d,%d", &xs, &ys) == 2 );// <spanx>,<spany>
-	else if( type == SCRIPT && sscanf(w4, "%*[^,],%d,%d", &xs, &ys) == 2);// <sprite id>,<triggerX>,<triggerY>
-	else if( type == WARP ) {
+	if( type == NPCTYPE_WARP && sscanf(w4, "%d,%d", &xs, &ys) == 2 );// <spanx>,<spany>
+	else if( type == NPCTYPE_SCRIPT && sscanf(w4, "%*[^,],%d,%d", &xs, &ys) == 2);// <sprite id>,<triggerX>,<triggerY>
+	else if( type == NPCTYPE_WARP ) {
 		ShowError("npc_parse_duplicate: Invalid span format for duplicate warp in file '%s', line '%d'. Skipping line...\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4);
 		ShowError("npc_parse_duplicate: Invalid span format for duplicate warp in file '%s', line '%d'. Skipping line...\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4);
 		return end;// next line, try to continue
 		return end;// next line, try to continue
 	}
 	}
@@ -2885,7 +2887,7 @@ const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const ch
 	nd->bl.type = BL_NPC;
 	nd->bl.type = BL_NPC;
 	nd->subtype = (enum npc_subtype)type;
 	nd->subtype = (enum npc_subtype)type;
 	switch( type ) {
 	switch( type ) {
-		case SCRIPT:
+		case NPCTYPE_SCRIPT:
 			++npc_script;
 			++npc_script;
 			nd->u.scr.xs = xs;
 			nd->u.scr.xs = xs;
 			nd->u.scr.ys = ys;
 			nd->u.scr.ys = ys;
@@ -2894,16 +2896,16 @@ const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const ch
 			nd->u.scr.label_list_num = dnd->u.scr.label_list_num;
 			nd->u.scr.label_list_num = dnd->u.scr.label_list_num;
 			break;
 			break;
 
 
-		case SHOP:
-		case CASHSHOP:
-		case ITEMSHOP:
-		case POINTSHOP:
+		case NPCTYPE_SHOP:
+		case NPCTYPE_CASHSHOP:
+		case NPCTYPE_ITEMSHOP:
+		case NPCTYPE_POINTSHOP:
 			++npc_shop;
 			++npc_shop;
 			nd->u.shop.shop_item = dnd->u.shop.shop_item;
 			nd->u.shop.shop_item = dnd->u.shop.shop_item;
 			nd->u.shop.count = dnd->u.shop.count;
 			nd->u.shop.count = dnd->u.shop.count;
 			break;
 			break;
 
 
-		case WARP:
+		case NPCTYPE_WARP:
 			++npc_warp;
 			++npc_warp;
 			if( !battle_config.warp_point_debug )
 			if( !battle_config.warp_point_debug )
 				nd->class_ = WARP_CLASS;
 				nd->class_ = WARP_CLASS;
@@ -2937,7 +2939,7 @@ const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const ch
 	}
 	}
 	strdb_put(npcname_db, nd->exname, nd);
 	strdb_put(npcname_db, nd->exname, nd);
 
 
-	if( type != SCRIPT )
+	if( type != NPCTYPE_SCRIPT )
 		return end;
 		return end;
 
 
 	//-----------------------------------------
 	//-----------------------------------------
@@ -2970,7 +2972,7 @@ int npc_duplicate4instance(struct npc_data *snd, int16 m) {
 		return 1;
 		return 1;
 	}
 	}
 
 
-	if( snd->subtype == WARP ) { // Adjust destination, if instanced
+	if( snd->subtype == NPCTYPE_WARP ) { // Adjust destination, if instanced
 		struct npc_data *wnd = NULL; // New NPC
 		struct npc_data *wnd = NULL; // New NPC
 		struct instance_data *im = &instance_data[map[m].instance_id];
 		struct instance_data *im = &instance_data[map[m].instance_id];
 		int dm = map_mapindex2mapid(snd->u.warp.mapindex), imap = 0, i;
 		int dm = map_mapindex2mapid(snd->u.warp.mapindex), imap = 0, i;
@@ -3007,7 +3009,7 @@ int npc_duplicate4instance(struct npc_data *snd, int16 m) {
 		wnd->u.warp.xs = snd->u.warp.xs;
 		wnd->u.warp.xs = snd->u.warp.xs;
 		wnd->u.warp.ys = snd->u.warp.ys;
 		wnd->u.warp.ys = snd->u.warp.ys;
 		wnd->bl.type = BL_NPC;
 		wnd->bl.type = BL_NPC;
-		wnd->subtype = WARP;
+		wnd->subtype = NPCTYPE_WARP;
 		npc_setcells(wnd);
 		npc_setcells(wnd);
 		if(map_addblock(&wnd->bl))
 		if(map_addblock(&wnd->bl))
 			return 1;
 			return 1;
@@ -3057,11 +3059,11 @@ void npc_setcells(struct npc_data* nd)
 
 
 	switch(nd->subtype)
 	switch(nd->subtype)
 	{
 	{
-	case WARP:
+	case NPCTYPE_WARP:
 		xs = nd->u.warp.xs;
 		xs = nd->u.warp.xs;
 		ys = nd->u.warp.ys;
 		ys = nd->u.warp.ys;
 		break;
 		break;
-	case SCRIPT:
+	case NPCTYPE_SCRIPT:
 		xs = nd->u.scr.xs;
 		xs = nd->u.scr.xs;
 		ys = nd->u.scr.ys;
 		ys = nd->u.scr.ys;
 		break;
 		break;
@@ -3095,7 +3097,7 @@ void npc_unsetcells(struct npc_data* nd)
 	int16 m = nd->bl.m, x = nd->bl.x, y = nd->bl.y, xs, ys;
 	int16 m = nd->bl.m, x = nd->bl.x, y = nd->bl.y, xs, ys;
 	int i,j, x0, x1, y0, y1;
 	int i,j, x0, x1, y0, y1;
 
 
-	if (nd->subtype == WARP) {
+	if (nd->subtype == NPCTYPE_WARP) {
 		xs = nd->u.warp.xs;
 		xs = nd->u.warp.xs;
 		ys = nd->u.warp.ys;
 		ys = nd->u.warp.ys;
 	} else {
 	} else {
@@ -4167,7 +4169,7 @@ void do_final_npc(void) {
 static void npc_debug_warps_sub(struct npc_data* nd)
 static void npc_debug_warps_sub(struct npc_data* nd)
 {
 {
 	int16 m;
 	int16 m;
-	if (nd->bl.type != BL_NPC || nd->subtype != WARP || nd->bl.m < 0)
+	if (nd->bl.type != BL_NPC || nd->subtype != NPCTYPE_WARP || nd->bl.m < 0)
 		return;
 		return;
 
 
 	m = map_mapindex2mapid(nd->u.warp.mapindex);
 	m = map_mapindex2mapid(nd->u.warp.mapindex);
@@ -4256,7 +4258,7 @@ void do_init_npc(void){
 
 
 	npc_script++;
 	npc_script++;
 	fake_nd->bl.type = BL_NPC;
 	fake_nd->bl.type = BL_NPC;
-	fake_nd->subtype = SCRIPT;
+	fake_nd->subtype = NPCTYPE_SCRIPT;
 
 
 	strdb_put(npcname_db, fake_nd->exname, fake_nd);
 	strdb_put(npcname_db, fake_nd->exname, fake_nd);
 	fake_nd->u.scr.timerid = INVALID_TIMER;
 	fake_nd->u.scr.timerid = INVALID_TIMER;

+ 0 - 2
src/map/pc_groups.c

@@ -467,6 +467,4 @@ void pc_groups_reload(void) {
 		pc_group_pc_load(sd);
 		pc_group_pc_load(sd);
 	}
 	}
 	mapit_free(iter);
 	mapit_free(iter);
-
-	
 }
 }

+ 26 - 22
src/map/script.c

@@ -11814,7 +11814,7 @@ BUILDIN_FUNC(flagemblem)
 	nd = (TBL_NPC*)map_id2nd(st->oid);
 	nd = (TBL_NPC*)map_id2nd(st->oid);
 	if( nd == NULL ) {
 	if( nd == NULL ) {
 		ShowError("script:flagemblem: npc %d not found\n", st->oid);
 		ShowError("script:flagemblem: npc %d not found\n", st->oid);
-	} else if( nd->subtype != SCRIPT ) {
+	} else if( nd->subtype != NPCTYPE_SCRIPT ) {
 		ShowError("script:flagemblem: unexpected subtype %d for npc %d '%s'\n", nd->subtype, st->oid, nd->exname);
 		ShowError("script:flagemblem: unexpected subtype %d for npc %d '%s'\n", nd->subtype, st->oid, nd->exname);
 	} else {
 	} else {
 		bool changed = ( nd->u.scr.guild_id != g_id )?true:false;
 		bool changed = ( nd->u.scr.guild_id != g_id )?true:false;
@@ -13242,10 +13242,9 @@ BUILDIN_FUNC(nude)
 }
 }
 
 
 int atcommand_sub(struct script_state* st,int type) {
 int atcommand_sub(struct script_state* st,int type) {
-	TBL_PC dummy_sd;
-	TBL_PC* sd;
+	TBL_PC *sd, dummy_sd;
 	int fd;
 	int fd;
-	const char* cmd;
+	const char *cmd;
 
 
 	cmd = script_getstr(st,2);
 	cmd = script_getstr(st,2);
 
 
@@ -13257,19 +13256,23 @@ int atcommand_sub(struct script_state* st,int type) {
 		fd = 0;
 		fd = 0;
 
 
 		memset(&dummy_sd, 0, sizeof(TBL_PC));
 		memset(&dummy_sd, 0, sizeof(TBL_PC));
-		if (st->oid)
-		{
+		if (st->oid) {
 			struct block_list* bl = map_id2bl(st->oid);
 			struct block_list* bl = map_id2bl(st->oid);
 			memcpy(&dummy_sd.bl, bl, sizeof(struct block_list));
 			memcpy(&dummy_sd.bl, bl, sizeof(struct block_list));
 			if (bl->type == BL_NPC)
 			if (bl->type == BL_NPC)
 				safestrncpy(dummy_sd.status.name, ((TBL_NPC*)bl)->name, NAME_LENGTH);
 				safestrncpy(dummy_sd.status.name, ((TBL_NPC*)bl)->name, NAME_LENGTH);
+			sd->mapindex = (bl->m > 0) ? bl->m : mapindex_name2id(MAP_DEFAULT);
 		}
 		}
+
+		// Init Group ID, Level, & permissions
+		sd->group_id = sd->group_level = 99;
+		sd->permissions |= PC_PERM_ALLPERMISSION;
 	}
 	}
 
 
 	if (!is_atcommand(fd, sd, cmd, type)) {
 	if (!is_atcommand(fd, sd, cmd, type)) {
-		ShowWarning("script: buildin_atcommand: failed to execute command '%s'\n", cmd);
+		ShowWarning("buildin_atcommand: failed to execute command '%s'\n", cmd);
 		script_reportsrc(st);
 		script_reportsrc(st);
-		return 1;
+		return SCRIPT_CMD_FAILURE;
 	}
 	}
 	return SCRIPT_CMD_SUCCESS;
 	return SCRIPT_CMD_SUCCESS;
 }
 }
@@ -15473,14 +15476,14 @@ BUILDIN_FUNC(callshop)
 	if( script_hasdata(st,3) )
 	if( script_hasdata(st,3) )
 		flag = script_getnum(st,3);
 		flag = script_getnum(st,3);
 	nd = npc_name2id(shopname);
 	nd = npc_name2id(shopname);
-	if( !nd || nd->bl.type != BL_NPC || (nd->subtype != SHOP && nd->subtype != CASHSHOP && nd->subtype != ITEMSHOP && nd->subtype != POINTSHOP) )
+	if( !nd || nd->bl.type != BL_NPC || (nd->subtype != NPCTYPE_SHOP && nd->subtype != NPCTYPE_CASHSHOP && nd->subtype != NPCTYPE_ITEMSHOP && nd->subtype != NPCTYPE_POINTSHOP) )
 	{
 	{
 		ShowError("buildin_callshop: Shop [%s] not found (or NPC is not shop type)\n", shopname);
 		ShowError("buildin_callshop: Shop [%s] not found (or NPC is not shop type)\n", shopname);
 		script_pushint(st,0);
 		script_pushint(st,0);
 		return 1;
 		return 1;
 	}
 	}
 
 
-	if( nd->subtype == SHOP || nd->subtype == ITEMSHOP || nd->subtype == POINTSHOP )
+	if( nd->subtype == NPCTYPE_SHOP || nd->subtype == NPCTYPE_ITEMSHOP || nd->subtype == NPCTYPE_POINTSHOP )
 	{
 	{
 		// flag the user as using a valid script call for opening the shop (for floating NPCs)
 		// flag the user as using a valid script call for opening the shop (for floating NPCs)
 		sd->state.callshop = 1;
 		sd->state.callshop = 1;
@@ -15507,7 +15510,7 @@ BUILDIN_FUNC(npcshopitem)
 	int n, i;
 	int n, i;
 	int amount;
 	int amount;
 
 
-	if( !nd || ( nd->subtype != SHOP && nd->subtype != CASHSHOP && nd->subtype != ITEMSHOP && nd->subtype != POINTSHOP ) )
+	if( !nd || ( nd->subtype != NPCTYPE_SHOP && nd->subtype != NPCTYPE_CASHSHOP && nd->subtype != NPCTYPE_ITEMSHOP && nd->subtype != NPCTYPE_POINTSHOP ) )
 	{	//Not found.
 	{	//Not found.
 		script_pushint(st,0);
 		script_pushint(st,0);
 		return 0;
 		return 0;
@@ -15536,7 +15539,7 @@ BUILDIN_FUNC(npcshopadditem)
 	int n, i;
 	int n, i;
 	int amount;
 	int amount;
 
 
-	if( !nd || ( nd->subtype != SHOP && nd->subtype != CASHSHOP && nd->subtype != ITEMSHOP && nd->subtype != POINTSHOP ) )
+	if( !nd || ( nd->subtype != NPCTYPE_SHOP && nd->subtype != NPCTYPE_CASHSHOP && nd->subtype != NPCTYPE_ITEMSHOP && nd->subtype != NPCTYPE_POINTSHOP ) )
 	{	//Not found.
 	{	//Not found.
 		script_pushint(st,0);
 		script_pushint(st,0);
 		return 0;
 		return 0;
@@ -15567,7 +15570,7 @@ BUILDIN_FUNC(npcshopdelitem)
 	int amount;
 	int amount;
 	int size;
 	int size;
 
 
-	if( !nd || ( nd->subtype != SHOP && nd->subtype != CASHSHOP && nd->subtype != ITEMSHOP && nd->subtype != POINTSHOP ) )
+	if( !nd || ( nd->subtype != NPCTYPE_SHOP && nd->subtype != NPCTYPE_CASHSHOP && nd->subtype != NPCTYPE_ITEMSHOP && nd->subtype != NPCTYPE_POINTSHOP ) )
 	{	//Not found.
 	{	//Not found.
 		script_pushint(st,0);
 		script_pushint(st,0);
 		return 0;
 		return 0;
@@ -15606,7 +15609,7 @@ BUILDIN_FUNC(npcshopattach)
 	if( script_hasdata(st,3) )
 	if( script_hasdata(st,3) )
 		flag = script_getnum(st,3);
 		flag = script_getnum(st,3);
 
 
-	if( !nd || ( nd->subtype != SHOP && nd->subtype != CASHSHOP && nd->subtype != ITEMSHOP && nd->subtype != POINTSHOP ) )
+	if( !nd || ( nd->subtype != NPCTYPE_SHOP && nd->subtype != NPCTYPE_CASHSHOP && nd->subtype != NPCTYPE_ITEMSHOP && nd->subtype != NPCTYPE_POINTSHOP ) )
 	{	//Not found.
 	{	//Not found.
 		script_pushint(st,0);
 		script_pushint(st,0);
 		return 0;
 		return 0;
@@ -16426,7 +16429,7 @@ BUILDIN_FUNC(getvariableofnpc)
 	}
 	}
 
 
 	nd = npc_name2id(script_getstr(st,3));
 	nd = npc_name2id(script_getstr(st,3));
-	if( nd == NULL || nd->subtype != SCRIPT || nd->u.scr.script == NULL )
+	if( nd == NULL || nd->subtype != NPCTYPE_SCRIPT || nd->u.scr.script == NULL )
 	{// NPC not found or has no script
 	{// NPC not found or has no script
 		ShowError("script:getvariableofnpc: can't find npc %s\n", script_getstr(st,3));
 		ShowError("script:getvariableofnpc: can't find npc %s\n", script_getstr(st,3));
 		script_pushnil(st);
 		script_pushnil(st);
@@ -16455,10 +16458,9 @@ BUILDIN_FUNC(warpportal)
 	struct block_list* bl;
 	struct block_list* bl;
 
 
 	bl = map_id2bl(st->oid);
 	bl = map_id2bl(st->oid);
-	if( bl == NULL )
-	{
-		ShowError("script:warpportal: npc is needed\n");
-		return 1;
+	if( bl == NULL ) {
+		ShowError("buildin_warpportal: NPC is needed\n");
+		return SCRIPT_CMD_FAILURE;
 	}
 	}
 
 
 	spx = script_getnum(st,2);
 	spx = script_getnum(st,2);
@@ -16467,12 +16469,14 @@ BUILDIN_FUNC(warpportal)
 	tpx = script_getnum(st,5);
 	tpx = script_getnum(st,5);
 	tpy = script_getnum(st,6);
 	tpy = script_getnum(st,6);
 
 
-	if( mapindex == 0 )
-		return 0;// map not found
+	if( mapindex == 0 ) {
+		ShowError("buildin_warpportal: Target map not found %s.\n", script_getstr(st, 4));
+		return SCRIPT_CMD_FAILURE;
+	}
 
 
 	group = skill_unitsetting(bl, AL_WARP, 4, spx, spy, 0);
 	group = skill_unitsetting(bl, AL_WARP, 4, spx, spy, 0);
 	if( group == NULL )
 	if( group == NULL )
-		return 0;// failed
+		return SCRIPT_CMD_FAILURE;// failed
 	group->val1 = (group->val1<<16)|(short)0;
 	group->val1 = (group->val1<<16)|(short)0;
 	group->val2 = (tpx<<16) | tpy;
 	group->val2 = (tpx<<16) | tpy;
 	group->val3 = mapindex;
 	group->val3 = mapindex;

+ 2 - 2
src/map/status.c

@@ -6734,7 +6734,7 @@ int status_get_guild_id(struct block_list *bl)
 				return ((TBL_MER*)bl)->master->status.guild_id;
 				return ((TBL_MER*)bl)->master->status.guild_id;
 			break;
 			break;
 		case BL_NPC:
 		case BL_NPC:
-			if (((TBL_NPC*)bl)->subtype == SCRIPT)
+			if (((TBL_NPC*)bl)->subtype == NPCTYPE_SCRIPT)
 				return ((TBL_NPC*)bl)->u.scr.guild_id;
 				return ((TBL_NPC*)bl)->u.scr.guild_id;
 			break;
 			break;
 		case BL_SKILL:
 		case BL_SKILL:
@@ -6781,7 +6781,7 @@ int status_get_emblem_id(struct block_list *bl)
 				return ((TBL_MER*)bl)->master->guild_emblem_id;
 				return ((TBL_MER*)bl)->master->guild_emblem_id;
 			break;
 			break;
 		case BL_NPC:
 		case BL_NPC:
-			if (((TBL_NPC*)bl)->subtype == SCRIPT && ((TBL_NPC*)bl)->u.scr.guild_id > 0) {
+			if (((TBL_NPC*)bl)->subtype == NPCTYPE_SCRIPT && ((TBL_NPC*)bl)->u.scr.guild_id > 0) {
 				struct guild *g = guild_search(((TBL_NPC*)bl)->u.scr.guild_id);
 				struct guild *g = guild_search(((TBL_NPC*)bl)->u.scr.guild_id);
 				if (g)
 				if (g)
 					return g->emblem_id;
 					return g->emblem_id;

+ 1 - 1
src/map/unit.h

@@ -18,7 +18,7 @@ extern const short dirx[8]; ///lookup to know where will move to x according dir
 extern const short diry[8]; ///lookup to know where will move to y according dir
 extern const short diry[8]; ///lookup to know where will move to y according dir
 
 
 struct unit_data {
 struct unit_data {
-	struct block_list *bl; ///link to owner object BL_CHAR (BL_PC|BL_HOM|BL_PET|BL_ELE|BL_MER)
+	struct block_list *bl; ///link to owner object BL_PC|BL_MOB|BL_PET|BL_NPC|BL_HOM|BL_MER|BL_ELEM
 	struct walkpath_data walkpath; 
 	struct walkpath_data walkpath; 
 	struct skill_timerskill *skilltimerskill[MAX_SKILLTIMERSKILL];
 	struct skill_timerskill *skilltimerskill[MAX_SKILLTIMERSKILL];
 	struct skill_unit_group *skillunit[MAX_SKILLUNITGROUP];
 	struct skill_unit_group *skillunit[MAX_SKILLUNITGROUP];

+ 1 - 0
src/map/vending.c

@@ -297,6 +297,7 @@ void vending_purchasereq(struct map_session_data* sd, int aid, int uid, const ui
  * @param data : itemlist data \n
  * @param data : itemlist data \n
  *	data := {<index>.w <amount>.w <value>.l}[count]
  *	data := {<index>.w <amount>.w <value>.l}[count]
  * @param count : number of different items
  * @param count : number of different items
+ * @return 0 If success, 1 - Cannot open (die, not state.prevend, trading), 2 - No cart, 3 - Count issue, 4 - Cart data isn't saved yet, 5 - No valid item found
  */
  */
 char vending_openvending(struct map_session_data* sd, const char* message, const uint8* data, int count) {
 char vending_openvending(struct map_session_data* sd, const char* message, const uint8* data, int count) {
 	int i, j;
 	int i, j;