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

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

View File

@ -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&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;
}
// 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;

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

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

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