- 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>
This commit is contained in:
Cydh Ramdh 2014-08-18 19:59:16 +07:00
parent 880903bdab
commit 3efe5375f3
17 changed files with 267 additions and 204 deletions

View File

@ -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
--------------------------------------- ---------------------------------------

View File

@ -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 )
{ {

View File

@ -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* at_groups; /// Quick @commands "can-use" lookup
char* char_groups;/* quick @charcommands "can-use" lookup */ char* char_groups; /// Quick @charcommands "can-use" lookup
int restriction; //prevent : 1 console, 2 script... 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 )); ARR_FIND(0,channel_config.colors_count,k,( strcmpi(message,channel_config.colors_name[k]) == 0 ));
if( k == Channel_Config.colors_count ) { 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 * Executes an at-command
* \param type : * @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) {
if(info->restriction&1 && type == 2) //console prevent if (info->restriction&ATCMD_NOCONSOLE && type == 2) //console prevent
return true; return true;
if(info->restriction&2 && (type == 0 || type == 3) ) //scripts prevent if (info->restriction&ATCMD_NOSCRIPT && (type == 0 || type == 3)) //scripts prevent
return true;
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;

View File

@ -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.map_chname) == 0
|| strcmpi(chname + 1,Channel_Config.ally_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++ ) { for( k = 0; k < channel_config.colors_count; k++ ) {
sprintf(msg, msg_txt(sd,1445),Channel_Config.colors_name[k]);// - '%s' if (channel_config.colors[k]) {
clif_colormes(sd,Channel_Config.colors[k],msg); 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 ) { 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) 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 ? if (g && g->channel) {
sprintf(output, msg_txt(sd,1409), Channel_Config.ally_chname, db_size(((struct Channel *)g->channel)->users));// - #%s (%d users) 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); 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 ) ); ARR_FIND(0,channel_config.colors_count,k,( strcmpi(color,channel_config.colors_name[k]) == 0 ) );
if( k >= Channel_Config.colors_count ) { 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, unsigned long, color_count );
CREATE( Channel_Config.colors_name, char *, 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); 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] = 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[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++) { for (k = 0; k < channel_config.colors_count; k++) {
if( strcmpi(Channel_Config.colors_name[k],map_color) == 0 ) if( strcmpi(channel_config.colors_name[k],map_color) == 0 )
break; break;
} }
if( k < Channel_Config.colors_count ) { if( k < channel_config.colors_count ) {
Channel_Config.map_chcolor = k; 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++) { for (k = 0; k < channel_config.colors_count; k++) {
if( strcmpi(Channel_Config.colors_name[k],ally_color) == 0 ) if( strcmpi(channel_config.colors_name[k],ally_color) == 0 )
break; break;
} }
if( k < Channel_Config.colors_count ) { if( k < channel_config.colors_count ) {
Channel_Config.ally_chcolor = k; 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++) { for (k = 0; k < channel_config.colors_count; k++) {
if( strcmpi(Channel_Config.colors_name[k],color) == 0 ) 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++) { for(i = 0; i < channel_config.colors_count; i++) {
aFree(Channel_Config.colors_name[i]); aFree(channel_config.colors_name[i]);
} }
aFree(Channel_Config.colors_name); aFree(channel_config.colors_name);
aFree(Channel_Config.colors); aFree(channel_config.colors);
} }
} }

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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();

View File

@ -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

View File

@ -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)

View File

@ -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&1 && nd->subtype == NPCTYPE_WARP) break;
if (skill_db[idx].unit_nonearnpc_type&2 && nd->subtype == SHOP) break; if (skill_db[idx].unit_nonearnpc_type&2 && nd->subtype == NPCTYPE_SHOP) break;
if (skill_db[idx].unit_nonearnpc_type&4 && nd->subtype == SCRIPT) break; if (skill_db[idx].unit_nonearnpc_type&4 && nd->subtype == NPCTYPE_SCRIPT) break;
if (skill_db[idx].unit_nonearnpc_type&8 && nd->subtype == TOMB) 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 NPCTYPE_SHOP:
case ITEMSHOP: case NPCTYPE_ITEMSHOP:
case POINTSHOP: 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 != NPCTYPE_SHOP) {
if (type == ITEMSHOP) nd->u.shop.itemshop_nameid = nameid; // Item shop currency if (type == NPCTYPE_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 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) || if( (type == NPCTYPE_ITEMSHOP && battle_config.discount_item_point_shop&1) ||
(type == POINTSHOP && battle_config.discount_item_point_shop&2) ) (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> if( type == NPCTYPE_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 == NPCTYPE_SCRIPT && sscanf(w4, "%*[^,],%d,%d", &xs, &ys) == 2);// <sprite id>,<triggerX>,<triggerY>
else if( type == WARP ) { 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 NPCTYPE_SHOP:
case CASHSHOP: case NPCTYPE_CASHSHOP:
case ITEMSHOP: case NPCTYPE_ITEMSHOP:
case POINTSHOP: 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;

View File

@ -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);
} }

View File

@ -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, dummy_sd;
TBL_PC* 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 ) if( bl == NULL ) {
{ ShowError("buildin_warpportal: NPC is needed\n");
ShowError("script:warpportal: npc is needed\n"); return SCRIPT_CMD_FAILURE;
return 1;
} }
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 ) if( mapindex == 0 ) {
return 0;// map not found 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;

View File

@ -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;

View File

@ -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];

View File

@ -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;