Преглед изворни кода

- 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 година
родитељ
комит
3efe5375f3
17 измењених фајлова са 267 додато и 204 уклоњено
  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 : "@"
 	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).
 The format of this file is as follows:
 	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.
 Locations and coordinates are stored in '/src/map/atcommand.c'.
 
+Restriction:
+	- Used from console
+
 ---------------------------------------
 
 @warp <map> {<x> <y>}
@@ -808,6 +815,9 @@ Locations and coordinates are stored in '/src/map/atcommand.c'.
 Warps to the specified map.
 If no coordinates are entered, a random location will be chosen.
 
+Restriction:
+	- Used from console
+
 ---------------------------------------
 
 @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.
 
+Restriction:
+	- Used from console
+
 ---------------------------------------
 
 @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.
 Note that jobs 22 (Wedding), 26 (Summer), 27 (Christmas), and 28 (Hanbok) are not available via @job.
 
+Restriction:
+	- Used from console
+
 ---------------------------------------
 
 @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 a player from the server.
+
+Restriction:
+	- Used from 'atcommand' or 'useatcmd' by autotrader
+
+---------------------------------------
+
 @kickall
 /killall
 
@@ -1317,7 +1341,10 @@ Affected files:
 -- questdb: quest_db.txt
 -- 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
- -- 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
 		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 )
 		{

+ 39 - 26
src/map/atcommand.c

@@ -60,12 +60,19 @@ typedef struct AliasInfo AliasInfo;
 
 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 {
 	char command[ATCOMMAND_LENGTH];
 	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 {
@@ -9136,7 +9143,7 @@ static inline void atcmd_channel_help(struct map_session_data *sd, const char *c
 {
 	int fd = sd->fd;
 	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:
 
 	//option create
@@ -9229,7 +9236,7 @@ ACMD_FUNC(channel) {
 		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'){
 			clif_displaymessage(fd, msg_txt(sd,1408)); // Channel password may not contain spaces.
 			return -1;
@@ -9277,8 +9284,8 @@ ACMD_FUNC(fontcolor)
 		sd->fontcolor = 0;
 	} else {
 		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'.
 			clif_displaymessage(fd, atcmd_output);
 			return -1;
@@ -9661,17 +9668,17 @@ ACMD_FUNC(clonestat) {
  **/
 #define ACMD_DEF(x) { #x, 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_DEF2R(x2, x, r) { x2, atcommand_ ## x, NULL, NULL, r }
 void atcommand_basecommands(void) {
 	/**
 	 * 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[] = {
 #include "../custom/atcommand_def.inc"
-		ACMD_DEF2R("warp", mapmove, 1),
+		ACMD_DEF2R("warp", mapmove, ATCMD_NOCONSOLE),
 		ACMD_DEF(where),
 		ACMD_DEF(jumpto),
 		ACMD_DEF(jump),
@@ -9689,7 +9696,7 @@ void atcommand_basecommands(void) {
 		ACMD_DEF(guildstorage),
 		ACMD_DEF(option),
 		ACMD_DEF(hide), // + /hide
-		ACMD_DEFR(jobchange, 1),
+		ACMD_DEFR(jobchange, ATCMD_NOCONSOLE),
 		ACMD_DEF(kill),
 		ACMD_DEF(alive),
 		ACMD_DEF(kami),
@@ -9705,7 +9712,7 @@ void atcommand_basecommands(void) {
 		ACMD_DEF(clearstorage),
 		ACMD_DEF(cleargstorage),
 		ACMD_DEF(clearcart),
-		ACMD_DEF2R("blvl", baselevelup, 1),
+		ACMD_DEF2R("blvl", baselevelup, ATCMD_NOCONSOLE),
 		ACMD_DEF2("jlvl", joblevelup),
 		ACMD_DEF(help),
 		ACMD_DEF(pvpoff),
@@ -9713,7 +9720,7 @@ void atcommand_basecommands(void) {
 		ACMD_DEF(gvgoff),
 		ACMD_DEF(gvgon),
 		ACMD_DEF(model),
-		ACMD_DEFR(go, 1),
+		ACMD_DEFR(go, ATCMD_NOCONSOLE),
 		ACMD_DEF(monster),
 		ACMD_DEF2("monstersmall", monster),
 		ACMD_DEF2("monsterbig", monster),
@@ -9746,7 +9753,7 @@ void atcommand_basecommands(void) {
 		ACMD_DEF(doommap),
 		ACMD_DEF(raise),
 		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(allskill),
 		ACMD_DEF(questskill),
@@ -9762,11 +9769,11 @@ void atcommand_basecommands(void) {
 		ACMD_DEF(broadcast), // + /b and /nb
 		ACMD_DEF(localbroadcast), // + /lb and /nlb
 		ACMD_DEF(recallall),
-		ACMD_DEFR(reload,2),
+		ACMD_DEFR(reload,ATCMD_NOSCRIPT),
 		ACMD_DEF2("reloaditemdb", reload),
 		ACMD_DEF2("reloadmobdb", reload),
 		ACMD_DEF2("reloadskilldb", reload),
-		ACMD_DEF2R("reloadscript", reload,2),
+		ACMD_DEF2R("reloadscript", reload, ATCMD_NOSCRIPT),
 		ACMD_DEF2("reloadatcommand", reload),
 		ACMD_DEF2("reloadbattleconf", 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);
 }
 
-/*
- *  Executes an at-command
- * \param type :
+/**
+ * Executes an at-command
+ * @param fd
+ * @param sd
+ * @param message
+ * @param type
  *  0 : script call (atcommand)
  *  1 : normal player @atcommand
- *  2 : console
+ *  2 : console (admin:@atcommand)
  *  3 : script call (useatcmd)
  */
 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 */
 					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 */
-							return false;
+						return false;
 				} else
 					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
-	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;
-		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;
 	}
 
 	// type == 1 : player invoked
 	if (type == 1) {
 		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;
 		}
 		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.
 	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.
 		clif_displaymessage(fd, output);
 		return true;

+ 72 - 63
src/map/channel.c

@@ -18,8 +18,10 @@
 #include <stdlib.h>
 
 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 {
 	int char_id;
@@ -163,12 +165,12 @@ int channel_mjoin(struct map_session_data *sd) {
 	if(!sd) return -1;
 
 	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 ) ) {
 		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));
 	}
 
@@ -219,7 +221,7 @@ int channel_gjoin(struct map_session_data *sd, int flag){
 
 	channel = g->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;
 		channel_ajoin(g);
 	}
@@ -299,7 +301,7 @@ int channel_pcquit(struct map_session_data *sd, int type){
 	if(!sd) return -1;
 
 	// 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;
 		if(type&1 && channel_haspc(g->channel,sd)==1){
 			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);
 	}
 	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 )
 			return -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) )
 			) {
 			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){
 	if(channel_chk(chname, NULL, 1))
 		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)
-			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)
 			channel_mjoin(sd);
 		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)
-			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)
 			channel_gjoin(sd,3);
 		return sd->guild->channel;
@@ -472,9 +474,6 @@ int channel_pc_haschan(struct map_session_data *sd, struct Channel *channel){
  *  -1 : fail
  */
 int channel_display_list(struct map_session_data *sd, char *options){
-	struct Channel *channel;
-	char output[128];
-	int k;
 
 	if(!sd || !options)
 		return -1;
@@ -482,10 +481,13 @@ int channel_display_list(struct map_session_data *sd, char *options){
 	//display availaible colors
 	if( options[0] != '\0' && strcmpi(options,"colors") == 0 ) {
 		char msg[40];
+		unsigned char k;
 		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
@@ -493,8 +495,12 @@ int channel_display_list(struct map_session_data *sd, char *options){
 		if(!sd->channel_count)
 			clif_displaymessage(sd->fd, msg_txt(sd,1476)); // You have not joined any channels.
 		else {
+			unsigned char k;
+			struct Channel *channel;
 			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)
 				clif_displaymessage(sd->fd, output);
 			}
@@ -503,17 +509,20 @@ int channel_display_list(struct map_session_data *sd, char *options){
 	else { //display public chanels
 		DBIterator *iter;
 		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 ----
-		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);
 		}
-		if( Channel_Config.ally_enable && sd->status.guild_id ) {
+		if( channel_config.ally_enable && sd->status.guild_id ) {
 			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);
 		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
 	}
 
-	if( !Channel_Config.closing && (channel->opt & CHAN_OPT_ANNOUNCE_JOIN) ) {
+	if( !channel_config.closing && (channel->opt & CHAN_OPT_ANNOUNCE_JOIN) ) {
 		char message[60];
 		sprintf(message, "#%s '%s' left",channel->name,sd->status.name);
 		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;
 	}
 
-	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'.
 		clif_displaymessage(sd->fd, output);
 		return -1;
 	}
 	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);
 	return 0;
 }
@@ -1031,74 +1040,74 @@ void channel_read_config(void) {
 
 		if( !config_setting_lookup_string(settings, "map_local_channel_name", &map_chname) )
 			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) )
 			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, "ally_channel_enabled", &ally_enabled);
 
 		if( local_enabled )
-			Channel_Config.map_enable = true;
+			channel_config.map_enable = true;
 		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, "ally_channel_autojoin", &ally_autojoin);
 
 		if( local_autojoin )
-			Channel_Config.map_autojoin = true;
+			channel_config.map_autojoin = true;
 		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);
 
 		if( allow_user_channel_creation )
-			Channel_Config.user_chenable = true;
+			channel_config.user_chenable = true;
 
 		if( (colors = config_setting_get_member(settings, "colors")) != NULL ) {
 			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++) {
 				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);
 
-		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;
 		}
 
-		if( k < Channel_Config.colors_count ) {
-			Channel_Config.map_chcolor = k;
+		if( k < channel_config.colors_count ) {
+			channel_config.map_chcolor = k;
 		} else {
 			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);
 
-		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;
 		}
 
-		if( k < Channel_Config.colors_count ) {
-			Channel_Config.ally_chcolor = k;
+		if( k < channel_config.colors_count ) {
+			channel_config.ally_chcolor = k;
 		} else {
 			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 ) {
@@ -1108,15 +1117,15 @@ void channel_read_config(void) {
 				config_setting_t *channel = config_setting_get_elem(channels, i);
 				const char *color = config_setting_get_string_elem(channels,i);
 				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;
 				}
-				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);
 					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);
 					continue;
 				}
@@ -1136,7 +1145,7 @@ void channel_read_config(void) {
  */
 void do_init_channel(void) {
 	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();
 }
 
@@ -1158,12 +1167,12 @@ void do_final_channel(void) {
 	db_destroy(channel_db);
 
 	//delete all color thing
-	if( Channel_Config.colors_count ) {
+	if( channel_config.colors_count ) {
 		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
 };
 
-struct {
+struct Channel_Config {
 	unsigned long *colors;		//color avail int list
 	char **colors_name;		//colors avail name list
 	unsigned char colors_count;	//color avail count
@@ -36,7 +36,8 @@ struct {
 	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
 	bool closing;			//server is closing
-} Channel_Config;
+};
+extern struct Channel_Config channel_config;
 
 struct Channel {
 	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);
 
 	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()) {
 			chrif_save_scdata(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,2) = msg_len + 12;
 	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);
 
 	iter = db_iterator(channel->users);
@@ -9784,7 +9784,7 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd)
 		sd->state.changemap = false;
 
 		// 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
 	} else if (sd->guild && (battle_config.guild_notice_changemap == 2 || guild_notice))
 		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 )
 			continue;
 		sd->guild = g;
-		if(Channel_Config.ally_autojoin ) {
+		if(channel_config.ally_autojoin ) {
 			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;
 		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);
 		}
 	}
@@ -1673,7 +1673,7 @@ int guild_broken(int guild_id,int flag) {
 	guild_db->foreach(guild_db,guild_broken_sub,guild_id);
 	castle_db->foreach(castle_db,castle_guild_broken_sub,guild_id);
 	guild_storage_delete(guild_id);
-	if( Channel_Config.ally_enable ) {
+	if( channel_config.ally_enable ) {
 		channel_delete(g->channel);
 	}
 	idb_remove(guild_db,guild_id);

+ 1 - 1
src/map/map.c

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

+ 11 - 2
src/map/map.h

@@ -298,10 +298,19 @@ enum bl_type {
 	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)
 
-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 {
 	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->speed = 200;
-	nd->subtype = TOMB;
+	nd->subtype = NPCTYPE_TOMB;
 
 	nd->u.tomb.md = md;
 	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;
 
-	if(nd->subtype != WARP)
+	if(nd->subtype != NPCTYPE_WARP)
 		return 0; //Not a warp
 
 	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) {
 			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;
 			}
 		}
@@ -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) {
-		case WARP:
+		case NPCTYPE_WARP:
 			xs=map[m].npc[i]->u.warp.xs;
 			ys=map[m].npc[i]->u.warp.ys;
 			break;
-		case SCRIPT:
+		case NPCTYPE_SCRIPT:
 			xs=map[m].npc[i]->u.scr.xs;
 			ys=map[m].npc[i]->u.scr.ys;
 			break;
@@ -966,14 +966,14 @@ int npc_touch_areanpc(struct map_session_data* sd, int16 m, int16 x, int16 y)
 		return 1;
 	}
 	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))
 				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);
 			break;
-		case SCRIPT:
+		case NPCTYPE_SCRIPT:
 			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;
 				}
 
@@ -1023,13 +1023,13 @@ int npc_touch_areanpc2(struct mob_data *md)
 
 		switch( map[m].npc[i]->subtype )
 		{
-			case WARP:
+			case NPCTYPE_WARP:
 				if( !( battle_config.mob_warp&1 ) )
 					continue;
 				xs = map[m].npc[i]->u.warp.xs;
 				ys = map[m].npc[i]->u.warp.ys;
 				break;
-			case SCRIPT:
+			case NPCTYPE_SCRIPT:
 				xs = map[m].npc[i]->u.scr.xs;
 				ys = map[m].npc[i]->u.scr.ys;
 				break;
@@ -1041,14 +1041,14 @@ int npc_touch_areanpc2(struct mob_data *md)
 		{ // In the npc touch area
 			switch( map[m].npc[i]->subtype )
 			{
-				case WARP:
+				case NPCTYPE_WARP:
 					xs = map_mapindex2mapid(map[m].npc[i]->u.warp.mapindex);
 					if( m < 0 )
 						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 )
 						return 1; // Warped
 					break;
-				case SCRIPT:
+				case NPCTYPE_SCRIPT:
 					if( map[m].npc[i]->bl.id == md->areanpc_id )
 						break; // Already touch this NPC
 					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)
 		{
-		case WARP:
+		case NPCTYPE_WARP:
 			if (!(flag&1))
 				continue;
 			xs=map[m].npc[i]->u.warp.xs;
 			ys=map[m].npc[i]->u.warp.ys;
 			break;
-		case SCRIPT:
+		case NPCTYPE_SCRIPT:
 			if (!(flag&2))
 				continue;
 			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;
 	
 	switch(nd->subtype) {
-		case SHOP:
-		case ITEMSHOP:
-		case POINTSHOP:
+		case NPCTYPE_SHOP:
+		case NPCTYPE_ITEMSHOP:
+		case NPCTYPE_POINTSHOP:
 			clif_npcbuysell(sd,nd->bl.id);
 			break;
-		case CASHSHOP:
+		case NPCTYPE_CASHSHOP:
 			clif_cashshop_show(sd,nd);
 			break;
-		case SCRIPT:
+		case NPCTYPE_SCRIPT:
 			run_script(nd->u.scr.script,0,sd->bl.id,nd->bl.id);
 			break;
-		case TOMB:
+		case NPCTYPE_TOMB:
 			run_tomb(sd,nd);
 			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)
 		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);
 		if (sd->npc_id == id)
 			sd->npc_id=0;
@@ -1301,7 +1301,7 @@ int npc_buysellsel(struct map_session_data* sd, int id, int type)
 		return 1;
 	}
 
-	if (nd->subtype == ITEMSHOP) {
+	if (nd->subtype == NPCTYPE_ITEMSHOP) {
 		char output[CHAT_SIZE_MAX];
 		struct item_data *itd = itemdb_exists(nd->u.shop.itemshop_nameid);
 		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)
 			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];
 		memset(output,'\0',sizeof(output));
 		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;
 	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;
 
 	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 )
 		return 6;
 
-	if( !nd || nd->subtype != CASHSHOP )
+	if( !nd || nd->subtype != NPCTYPE_CASHSHOP )
 		return 1;
 
 	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));
 	if( nd == NULL )
 		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;
 
 	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);
 
 	switch(nd->subtype) {
-		case SHOP:
+		case NPCTYPE_SHOP:
 			if (z > (double)sd->status.zeny)
 				return 1;	// Not enough Zeny
 			break;
-		case ITEMSHOP:
+		case NPCTYPE_ITEMSHOP:
 			for (k = 0; k < MAX_INVENTORY; k++) {
 				if (sd->status.inventory[k].nameid == nd->u.shop.itemshop_nameid)
 					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;
 			}
 			break;
-		case POINTSHOP:
+		case NPCTYPE_POINTSHOP:
 			switch(nd->u.shop.pointshop_str[0]) {
 				case '#':
 					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
 
 	switch(nd->subtype) {
-		case SHOP:
+		case NPCTYPE_SHOP:
 			pc_payzeny(sd, (int)z, LOG_TYPE_NPC, NULL);
 			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);
 			break;
-		case POINTSHOP:
+		case NPCTYPE_POINTSHOP:
 			switch(nd->u.shop.pointshop_str[0]) {
 				case '#':
 					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
 		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);
 
 	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;
 	}
@@ -1877,6 +1877,8 @@ int npc_remove_map(struct npc_data* nd)
 	if(nd->bl.prev == NULL || nd->bl.m < 0)
 		return 1; //Not assigned to a map.
   	m = nd->bl.m;
+	if (nd->subtype == NPCTYPE_SCRIPT)
+		skill_clear_unitgroup(&nd->bl);
 	clif_clearunit_area(&nd->bl,CLR_RESPAWN);
 	npc_unsetcells(nd);
 	map_delblock(&nd->bl);
@@ -1955,9 +1957,9 @@ int npc_unload(struct npc_data* nd, bool single) {
 	if( single && nd->bl.m != -1 )
 		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);
-	else if( nd->subtype == SCRIPT ) {
+	else if( nd->subtype == NPCTYPE_SCRIPT ) {
 		struct s_mapiterator* iter;
 		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.ys = xs;
 	nd->bl.type = BL_NPC;
-	nd->subtype = WARP;
+	nd->subtype = NPCTYPE_WARP;
 	npc_setcells(nd);
 	if(map_addblock(&nd->bl))
 		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;
 	npc_warp++;
 	nd->bl.type = BL_NPC;
-	nd->subtype = WARP;
+	nd->subtype = NPCTYPE_WARP;
 	npc_setcells(nd);
 	if(map_addblock(&nd->bl)) //couldn't add on map
 		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") )
-		type = CASHSHOP;
+		type = NPCTYPE_CASHSHOP;
 	else if( !strcasecmp(w2,"itemshop") )
-		type = ITEMSHOP;
+		type = NPCTYPE_ITEMSHOP;
 	else if( !strcasecmp(w2,"pointshop") )
-		type = POINTSHOP;
+		type = NPCTYPE_POINTSHOP;
 	else
-		type = SHOP;
+		type = NPCTYPE_SHOP;
 
 	p = strchr(w4,',');
 	memset(point_str,'\0',sizeof(point_str));
 
 	switch(type) {
-		case ITEMSHOP: {
+		case NPCTYPE_ITEMSHOP: {
 			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);
 				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,',');
 			break;
 		}
-		case POINTSHOP: {
+		case NPCTYPE_POINTSHOP: {
 			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);
 				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;
 		}
 		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
 		}
-		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",
 				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",
 				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
 	}
 
-	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->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
 */
 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;
 
-	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 false;
 }
@@ -2754,7 +2756,7 @@ static const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, cons
 
 	++npc_script;
 	nd->bl.type = BL_NPC;
-	nd->subtype = SCRIPT;
+	nd->subtype = NPCTYPE_SCRIPT;
 
 	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;
 
 	// 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;
 		m = -1;
 	} 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));
 	}
 
-	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);
 		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->subtype = (enum npc_subtype)type;
 	switch( type ) {
-		case SCRIPT:
+		case NPCTYPE_SCRIPT:
 			++npc_script;
 			nd->u.scr.xs = xs;
 			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;
 			break;
 
-		case SHOP:
-		case CASHSHOP:
-		case ITEMSHOP:
-		case POINTSHOP:
+		case NPCTYPE_SHOP:
+		case NPCTYPE_CASHSHOP:
+		case NPCTYPE_ITEMSHOP:
+		case NPCTYPE_POINTSHOP:
 			++npc_shop;
 			nd->u.shop.shop_item = dnd->u.shop.shop_item;
 			nd->u.shop.count = dnd->u.shop.count;
 			break;
 
-		case WARP:
+		case NPCTYPE_WARP:
 			++npc_warp;
 			if( !battle_config.warp_point_debug )
 				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);
 
-	if( type != SCRIPT )
+	if( type != NPCTYPE_SCRIPT )
 		return end;
 
 	//-----------------------------------------
@@ -2970,7 +2972,7 @@ int npc_duplicate4instance(struct npc_data *snd, int16 m) {
 		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 instance_data *im = &instance_data[map[m].instance_id];
 		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.ys = snd->u.warp.ys;
 		wnd->bl.type = BL_NPC;
-		wnd->subtype = WARP;
+		wnd->subtype = NPCTYPE_WARP;
 		npc_setcells(wnd);
 		if(map_addblock(&wnd->bl))
 			return 1;
@@ -3057,11 +3059,11 @@ void npc_setcells(struct npc_data* nd)
 
 	switch(nd->subtype)
 	{
-	case WARP:
+	case NPCTYPE_WARP:
 		xs = nd->u.warp.xs;
 		ys = nd->u.warp.ys;
 		break;
-	case SCRIPT:
+	case NPCTYPE_SCRIPT:
 		xs = nd->u.scr.xs;
 		ys = nd->u.scr.ys;
 		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;
 	int i,j, x0, x1, y0, y1;
 
-	if (nd->subtype == WARP) {
+	if (nd->subtype == NPCTYPE_WARP) {
 		xs = nd->u.warp.xs;
 		ys = nd->u.warp.ys;
 	} else {
@@ -4167,7 +4169,7 @@ void do_final_npc(void) {
 static void npc_debug_warps_sub(struct npc_data* nd)
 {
 	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;
 
 	m = map_mapindex2mapid(nd->u.warp.mapindex);
@@ -4256,7 +4258,7 @@ void do_init_npc(void){
 
 	npc_script++;
 	fake_nd->bl.type = BL_NPC;
-	fake_nd->subtype = SCRIPT;
+	fake_nd->subtype = NPCTYPE_SCRIPT;
 
 	strdb_put(npcname_db, fake_nd->exname, fake_nd);
 	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);
 	}
 	mapit_free(iter);
-
-	
 }

+ 26 - 22
src/map/script.c

@@ -11814,7 +11814,7 @@ BUILDIN_FUNC(flagemblem)
 	nd = (TBL_NPC*)map_id2nd(st->oid);
 	if( nd == NULL ) {
 		ShowError("script:flagemblem: npc %d not found\n", st->oid);
-	} else if( nd->subtype != SCRIPT ) {
+	} else if( nd->subtype != NPCTYPE_SCRIPT ) {
 		ShowError("script:flagemblem: unexpected subtype %d for npc %d '%s'\n", nd->subtype, st->oid, nd->exname);
 	} else {
 		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) {
-	TBL_PC dummy_sd;
-	TBL_PC* sd;
+	TBL_PC *sd, dummy_sd;
 	int fd;
-	const char* cmd;
+	const char *cmd;
 
 	cmd = script_getstr(st,2);
 
@@ -13257,19 +13256,23 @@ int atcommand_sub(struct script_state* st,int type) {
 		fd = 0;
 
 		memset(&dummy_sd, 0, sizeof(TBL_PC));
-		if (st->oid)
-		{
+		if (st->oid) {
 			struct block_list* bl = map_id2bl(st->oid);
 			memcpy(&dummy_sd.bl, bl, sizeof(struct block_list));
 			if (bl->type == BL_NPC)
 				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)) {
-		ShowWarning("script: buildin_atcommand: failed to execute command '%s'\n", cmd);
+		ShowWarning("buildin_atcommand: failed to execute command '%s'\n", cmd);
 		script_reportsrc(st);
-		return 1;
+		return SCRIPT_CMD_FAILURE;
 	}
 	return SCRIPT_CMD_SUCCESS;
 }
@@ -15473,14 +15476,14 @@ BUILDIN_FUNC(callshop)
 	if( script_hasdata(st,3) )
 		flag = script_getnum(st,3);
 	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);
 		script_pushint(st,0);
 		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)
 		sd->state.callshop = 1;
@@ -15507,7 +15510,7 @@ BUILDIN_FUNC(npcshopitem)
 	int n, i;
 	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.
 		script_pushint(st,0);
 		return 0;
@@ -15536,7 +15539,7 @@ BUILDIN_FUNC(npcshopadditem)
 	int n, i;
 	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.
 		script_pushint(st,0);
 		return 0;
@@ -15567,7 +15570,7 @@ BUILDIN_FUNC(npcshopdelitem)
 	int amount;
 	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.
 		script_pushint(st,0);
 		return 0;
@@ -15606,7 +15609,7 @@ BUILDIN_FUNC(npcshopattach)
 	if( script_hasdata(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.
 		script_pushint(st,0);
 		return 0;
@@ -16426,7 +16429,7 @@ BUILDIN_FUNC(getvariableofnpc)
 	}
 
 	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
 		ShowError("script:getvariableofnpc: can't find npc %s\n", script_getstr(st,3));
 		script_pushnil(st);
@@ -16455,10 +16458,9 @@ BUILDIN_FUNC(warpportal)
 	struct block_list* bl;
 
 	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);
@@ -16467,12 +16469,14 @@ BUILDIN_FUNC(warpportal)
 	tpx = script_getnum(st,5);
 	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);
 	if( group == NULL )
-		return 0;// failed
+		return SCRIPT_CMD_FAILURE;// failed
 	group->val1 = (group->val1<<16)|(short)0;
 	group->val2 = (tpx<<16) | tpy;
 	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;
 			break;
 		case BL_NPC:
-			if (((TBL_NPC*)bl)->subtype == SCRIPT)
+			if (((TBL_NPC*)bl)->subtype == NPCTYPE_SCRIPT)
 				return ((TBL_NPC*)bl)->u.scr.guild_id;
 			break;
 		case BL_SKILL:
@@ -6781,7 +6781,7 @@ int status_get_emblem_id(struct block_list *bl)
 				return ((TBL_MER*)bl)->master->guild_emblem_id;
 			break;
 		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);
 				if (g)
 					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
 
 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 skill_timerskill *skilltimerskill[MAX_SKILLTIMERSKILL];
 	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
  *	data := {<index>.w <amount>.w <value>.l}[count]
  * @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) {
 	int i, j;