summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorai4rei <ai4rei@54d463be-8e91-2dee-dedb-b68131a5f0ec>2010-12-26 22:36:41 +0000
committerai4rei <ai4rei@54d463be-8e91-2dee-dedb-b68131a5f0ec>2010-12-26 22:36:41 +0000
commit6096ce0b42a3eee07dc70ae5ef489aa4c30bf515 (patch)
treee91f8afd3b7b8b80f0c55aae07f7a478f469c37a /src
parent23e1b7db5ba2277a406fc84c30e87c324a83097c (diff)
downloadhercules-6096ce0b42a3eee07dc70ae5ef489aa4c30bf515.tar.gz
hercules-6096ce0b42a3eee07dc70ae5ef489aa4c30bf515.tar.bz2
hercules-6096ce0b42a3eee07dc70ae5ef489aa4c30bf515.tar.xz
hercules-6096ce0b42a3eee07dc70ae5ef489aa4c30bf515.zip
* Merged changes from trunk [14496:14630/trunk].
git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/branches/renewal@14632 54d463be-8e91-2dee-dedb-b68131a5f0ec
Diffstat (limited to 'src')
-rw-r--r--src/char/char.c404
-rw-r--r--src/char/char.h1
-rw-r--r--src/char/int_guild.c8
-rw-r--r--src/char/int_party.c1
-rw-r--r--src/char/int_storage.c28
-rw-r--r--src/char/inter.c2
-rw-r--r--src/char_sql/char.c347
-rw-r--r--src/char_sql/int_guild.c8
-rw-r--r--src/char_sql/int_storage.c4
-rw-r--r--src/char_sql/inter.c2
-rw-r--r--src/common/lock.c9
-rw-r--r--src/common/mmo.h16
-rw-r--r--src/common/socket.c13
-rw-r--r--src/common/strlib.c20
-rw-r--r--src/common/utils.c9
-rw-r--r--src/common/utils.h1
-rw-r--r--src/ladmin/ladmin.c3
-rw-r--r--src/login/login.c2
-rw-r--r--src/map/atcommand.c203
-rw-r--r--src/map/battle.c6
-rw-r--r--src/map/battle.h9
-rw-r--r--src/map/battleground.c4
-rw-r--r--src/map/chrif.c38
-rw-r--r--src/map/clif.c692
-rw-r--r--src/map/clif.h121
-rw-r--r--src/map/guild.c4
-rw-r--r--src/map/homunculus.c50
-rw-r--r--src/map/instance.c6
-rw-r--r--src/map/intif.c11
-rw-r--r--src/map/itemdb.c43
-rw-r--r--src/map/itemdb.h7
-rw-r--r--src/map/log.c6
-rw-r--r--src/map/map.c31
-rw-r--r--src/map/map.h3
-rw-r--r--src/map/mapreg_sql.c4
-rw-r--r--src/map/mercenary.c6
-rw-r--r--src/map/mob.c430
-rw-r--r--src/map/mob.h7
-rw-r--r--src/map/npc.c237
-rw-r--r--src/map/party.c97
-rw-r--r--src/map/party.h8
-rw-r--r--src/map/path.c2
-rw-r--r--src/map/pc.c378
-rw-r--r--src/map/pc.h20
-rw-r--r--src/map/pet.c8
-rw-r--r--src/map/script.c1384
-rw-r--r--src/map/script.h7
-rw-r--r--src/map/skill.c69
-rw-r--r--src/map/skill.h3
-rw-r--r--src/map/status.c331
-rw-r--r--src/map/storage.c63
-rw-r--r--src/map/unit.c83
-rw-r--r--src/map/unit.h9
-rw-r--r--src/map/vending.c2
-rw-r--r--src/plugins/sig.c9
-rw-r--r--src/tool/adduser.c6
-rw-r--r--src/txt-converter/Makefile.in2
57 files changed, 2896 insertions, 2381 deletions
diff --git a/src/char/char.c b/src/char/char.c
index 91ad7d33d..6dd131976 100644
--- a/src/char/char.c
+++ b/src/char/char.c
@@ -2,19 +2,16 @@
// For more information, see LICENCE in the main folder
#include "../common/cbasetypes.h"
-#include "../common/mmo.h"
+#include "../common/core.h"
#include "../common/db.h"
#include "../common/lock.h"
#include "../common/malloc.h"
-#include "../common/core.h"
+#include "../common/mapindex.h"
+#include "../common/mmo.h"
+#include "../common/showmsg.h"
#include "../common/socket.h"
#include "../common/strlib.h"
-#include "../common/showmsg.h"
#include "../common/timer.h"
-#include "../common/lock.h"
-#include "../common/malloc.h"
-#include "../common/mapindex.h"
-#include "../common/showmsg.h"
#include "../common/utils.h"
#include "../common/version.h"
#include "inter.h"
@@ -27,16 +24,8 @@
#include "char.h"
#include <sys/types.h>
-#ifdef WIN32
-#include <winsock2.h>
-#else
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#endif
#include <time.h>
#include <signal.h>
-#include <fcntl.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
@@ -51,8 +40,13 @@ char friends_txt[1024] = "save/friends.txt";
char hotkeys_txt[1024] = "save/hotkeys.txt";
char char_log_filename[1024] = "log/char.log";
-int save_log = 1; // show loading/saving messages
+// show loading/saving messages
+#ifndef TXT_SQL_CONVERT
+int save_log = 1;
+#endif
+//If your code editor is having problems syntax highlighting this file, uncomment this and RECOMMENT IT BEFORE COMPILING
+//#undef TXT_SQL_CONVERT
#ifndef TXT_SQL_CONVERT
char db_path[1024] = "db";
@@ -85,9 +79,12 @@ int email_creation = 0; // disabled by default
bool name_ignoring_case = false; // Allow or not identical name for characters but with a different case by [Yor]
int char_name_option = 0; // Option to know which letters/symbols are authorised in the name of a character (0: all, 1: only those in char_name_letters, 2: all EXCEPT those in char_name_letters) by [Yor]
-char unknown_char_name[1024] = "Unknown"; // Name to use when the requested name cannot be determined
+char unknown_char_name[NAME_LENGTH] = "Unknown"; // Name to use when the requested name cannot be determined
#define TRIM_CHARS "\032\t\x0A\x0D " //The following characters are trimmed regardless because they cause confusion and problems on the servers. [Skotlex]
-char char_name_letters[1024] = ""; // list of letters/symbols authorised (or not) in a character name. by [Yor]
+char char_name_letters[1024] = ""; // list of letters/symbols allowed (or not) in a character name. by [Yor]
+
+int char_per_account = 0; //Maximum charas per account (default unlimited) [Sirius]
+int char_del_level = 0; //From which level u can delete character [Lupus]
int log_char = 1; // loggin char or not [devil]
int log_inter = 1; // loggin inter or not [devil]
@@ -118,7 +115,7 @@ int char_num, char_max;
int max_connect_user = 0;
int gm_allow_level = 99;
int autosave_interval = DEFAULT_AUTOSAVE_INTERVAL;
-int start_zeny = 500;
+int start_zeny = 0;
int start_weapon = 1201;
int start_armor = 2301;
int guild_exp_rate = 100;
@@ -173,7 +170,7 @@ struct online_char_data {
int char_id;
int fd;
int waiting_disconnect;
- short server;
+ short server; // -2: unknown server, -1: not connected, 0+: id of server
};
static DBMap* online_char_db; // int account_id -> struct online_char_data*
@@ -223,6 +220,7 @@ void set_char_online(int map_id, int char_id, int account_id)
{
struct online_char_data* character;
+ //Check to see for online conflicts
character = (struct online_char_data*)idb_ensure(online_char_db, account_id, create_online_char_data);
if( character->char_id != -1 && character->server > -1 && character->server != map_id )
{
@@ -238,11 +236,13 @@ void set_char_online(int map_id, int char_id, int account_id)
if( character->server > -1 )
server[character->server].users++;
+ //Get rid of disconnect timer
if(character->waiting_disconnect != -1) {
delete_timer(character->waiting_disconnect, chardb_waiting_disconnect);
character->waiting_disconnect = -1;
}
+ //Notify login server
if (login_fd > 0 && !session[login_fd]->flag.eof)
{
WFIFOHEAD(login_fd,6);
@@ -261,7 +261,7 @@ void set_char_offline(int char_id, int account_id)
if( character->server > -1 )
if( server[character->server].users > 0 ) // Prevent this value from going negative.
server[character->server].users--;
-
+
if(character->waiting_disconnect != -1){
delete_timer(character->waiting_disconnect, chardb_waiting_disconnect);
character->waiting_disconnect = -1;
@@ -678,7 +678,7 @@ int mmo_char_fromstr(char *str, struct mmo_charstatus *p, struct global_reg *reg
tmp_int[46] = mapindex_name2id(tmp_str[2]);
} // Char structure of version 1500 (homun + mapindex maps)
- memcpy(p->name, tmp_str[0], NAME_LENGTH); //Overflow protection [Skotlex]
+ safestrncpy(p->name, tmp_str[0], NAME_LENGTH); //Overflow protection [Skotlex]
p->char_id = tmp_int[0];
p->account_id = tmp_int[1];
p->slot = tmp_int[2];
@@ -1150,16 +1150,9 @@ int mmo_char_sync_timer(int tid, unsigned int tick, int id, intptr data)
return 0;
}
-//-----------------------------------
-// Function to create a new character
-//-----------------------------------
-int make_new_char(struct char_session_data* sd, char* name_, int str, int agi, int vit, int int_, int dex, int luk, int slot, int hair_color, int hair_style)
+int check_char_name(char * name)
{
- char name[NAME_LENGTH];
int i;
-
- safestrncpy(name, name_, NAME_LENGTH);
- normalize_name(name,TRIM_CHARS);
// check length of character name
if( name[0] == '\0' )
@@ -1174,33 +1167,64 @@ int make_new_char(struct char_session_data* sd, char* name_, int str, int agi, i
return -1; // nick reserved for internal server messages
// Check Authorised letters/symbols in the name of the character
- if( char_name_option == 1 ) { // only letters/symbols in char_name_letters are authorised
+ if( char_name_option == 1 )
+ { // only letters/symbols in char_name_letters are authorised
for( i = 0; i < NAME_LENGTH && name[i]; i++ )
if( strchr(char_name_letters, name[i]) == NULL )
return -2;
- } else
- if( char_name_option == 2 ) { // letters/symbols in char_name_letters are forbidden
+ }
+ else if( char_name_option == 2 )
+ { // letters/symbols in char_name_letters are forbidden
for( i = 0; i < NAME_LENGTH && name[i]; i++ )
if( strchr(char_name_letters, name[i]) != NULL )
return -2;
- } // else, all letters/symbols are authorised (except control char removed before)
+ }
// check name (already in use?)
- ARR_FIND( 0, char_num, i,
- (name_ignoring_case && strncmp(char_dat[i].status.name, name, NAME_LENGTH) == 0) ||
- (!name_ignoring_case && strncmpi(char_dat[i].status.name, name, NAME_LENGTH) == 0) );
+ if( name_ignoring_case )
+ {
+ ARR_FIND( 0, char_num, i, strncmp(char_dat[i].status.name, name, NAME_LENGTH) == 0 );
+ }
+ else
+ {
+ ARR_FIND( 0, char_num, i, strncmpi(char_dat[i].status.name, name, NAME_LENGTH) == 0 );
+ }
if( i < char_num )
return -1; // name already exists
+ return 0;
+}
+
+//-----------------------------------
+// Function to create a new character
+//-----------------------------------
+int make_new_char(struct char_session_data* sd, char* name_, int str, int agi, int vit, int int_, int dex, int luk, int slot, int hair_color, int hair_style)
+{
+ char name[NAME_LENGTH];
+ int i, flag;
+
+ safestrncpy(name, name_, NAME_LENGTH);
+ normalize_name(name,TRIM_CHARS);
+
+ flag = check_char_name(name);
+ if( flag < 0 )
+ return flag;
+
//check other inputs
if((slot >= MAX_CHARS) // slots
- || (hair_style >= 24) // hair style
- || (hair_color >= 9) // hair color
|| (str + agi + vit + int_ + dex + luk != 6*5 ) // stats
|| (str < 1 || str > 9 || agi < 1 || agi > 9 || vit < 1 || vit > 9 || int_ < 1 || int_ > 9 || dex < 1 || dex > 9 || luk < 1 || luk > 9) // individual stat values
|| (str + int_ != 10 || agi + luk != 10 || vit + dex != 10) ) // pairs
return -2; // invalid input
+ // check the number of already existing chars in this account
+ if( char_per_account != 0 ) {
+ ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == -1 );
+
+ if( i >= char_per_account )
+ return -2; // character account limit exceeded
+ }
+
// check char slot
ARR_FIND( 0, char_num, i, char_dat[i].status.account_id == sd->account_id && char_dat[i].status.slot == slot );
if( i < char_num )
@@ -1563,7 +1587,7 @@ void create_online_files(void)
j = id[i];
// displaying the character name
if ((online_display_option & 1) || (online_display_option & 64)) { // without/with 'GM' display
- strcpy(temp, char_dat[j].status.name);
+ safestrncpy(temp, char_dat[j].status.name, sizeof(temp));
//l = isGM(char_dat[j].status.account_id);
l = 0; //FIXME: how to get the gm level?
if (online_display_option & 64) {
@@ -1611,7 +1635,7 @@ void create_online_files(void)
// displaying of the map
if (online_display_option & 24) { // 8 or 16
// prepare map name
- memcpy(temp, mapindex_id2name(char_dat[j].status.last_point.map), MAP_NAME_LENGTH);
+ safestrncpy(temp, mapindex_id2name(char_dat[j].status.last_point.map), sizeof(temp));
// write map name
if (online_display_option & 16) { // map-name AND coordinates
fprintf(fp2, " <td>%s (%d, %d)</td>\n", temp, char_dat[j].status.last_point.x, char_dat[j].status.last_point.y);
@@ -1670,10 +1694,11 @@ int count_users(void)
int i, users;
users = 0;
- for(i = 0; i < MAX_MAP_SERVERS; i++)
- if (server[i].fd >= 0)
+ for(i = 0; i < MAX_MAP_SERVERS; i++) {
+ if (server[i].fd > 0) {
users += server[i].users;
-
+ }
+ }
return users;
}
@@ -1738,7 +1763,7 @@ int mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p)
#endif
#if (PACKETVER >= 20100720 && PACKETVER <= 20100727) || PACKETVER >= 20100803
mapindex_getmapname_ext(mapindex_id2name(p->last_point.map), (char*)WBUFP(buf,108));
- offset += 16;
+ offset += MAP_NAME_LENGTH_EXT;
#endif
return 106+offset;
}
@@ -1807,7 +1832,7 @@ int char_divorce(struct mmo_charstatus *cs)
return 0;
}
-int char_married(int pl1,int pl2)
+int char_married(int pl1, int pl2)
{
return (char_dat[pl1].status.char_id == char_dat[pl2].status.partner_id && char_dat[pl2].status.char_id == char_dat[pl1].status.partner_id);
}
@@ -1850,38 +1875,18 @@ int char_family(int cid1, int cid2, int cid3)
return 0;
}
-//Clears the given party id from all characters.
-//Since sometimes the party format changes and parties must be wiped, this
-//method is required to prevent stress during the "party not found!" stages.
-void char_clearparty(int party_id)
-{
- int i;
- for(i = 0; i < char_num; i++)
- {
- if (char_dat[i].status.party_id == party_id)
- char_dat[i].status.party_id = 0;
- }
-}
-
//----------------------------------------------------------------------
// Force disconnection of an online player (with account value) by [Yor]
//----------------------------------------------------------------------
-int disconnect_player(int account_id)
+void disconnect_player(int account_id)
{
int i;
- struct char_session_data *sd;
+ struct char_session_data* sd;
// disconnect player if online on char-server
- for(i = 0; i < fd_max; i++) {
- if (session[i] && (sd = (struct char_session_data*)session[i]->session_data)) {
- if (sd->account_id == account_id) {
- set_eof(i);
- return 1;
- }
- }
- }
-
- return 0;
+ ARR_FIND( 0, fd_max, i, session[i] && (sd = (struct char_session_data*)session[i]->session_data) && sd->account_id == account_id );
+ if( i < fd_max )
+ set_eof(i);
}
// キャラ削除に伴うデータ削除
@@ -2005,8 +2010,8 @@ int parse_fromlogin(int fd)
//printf("connect login server error : %d\n", RFIFOB(fd,2));
ShowError("Can not connect to login-server.\n");
ShowError("The server communication passwords (default s1/p1) are probably invalid.\n");
- ShowInfo("Also, please make sure your accounts file (default: accounts.txt) has those values present.\n");
- ShowInfo("The communication passwords can be changed in map_athena.conf and char_athena.conf\n");
+ ShowError("Also, please make sure your accounts file (default: accounts.txt) has the correct communication username/passwords and the gender of the account is S.\n");
+ ShowError("The communication passwords are set in map_athena.conf and char_athena.conf\n");
} else {
ShowStatus("Connected to login-server (connection #%d).\n", fd);
@@ -2099,7 +2104,7 @@ int parse_fromlogin(int fd)
if (RFIFOREST(fd) < 7)
return 0;
{
- int i, j;
+ int j;
unsigned char buf[7];
int acc = RFIFOL(fd,2);
@@ -2107,7 +2112,7 @@ int parse_fromlogin(int fd)
RFIFOSKIP(fd,7);
if( acc > 0 )
- {
+ {// TODO: Is this even possible?
struct auth_node* node = (struct auth_node*)idb_get(auth_db, acc);
if( node != NULL )
node->sex = sex;
@@ -2162,6 +2167,8 @@ int parse_fromlogin(int fd)
// disconnect player if online on char-server
disconnect_player(acc);
}
+
+ // notify all mapservers about this change
WBUFW(buf,0) = 0x2b0d;
WBUFL(buf,2) = acc;
WBUFB(buf,6) = sex;
@@ -2235,14 +2242,14 @@ int parse_fromlogin(int fd)
RFIFOSKIP(fd,8 + RFIFOL(fd,4));
break;
- // account_reg2変更通知
+ // reply to an account_reg2 registry request
case 0x2729:
if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
return 0;
+
{ //Receive account_reg2 registry, forward to map servers.
unsigned char buf[13+ACCOUNT_REG2_NUM*sizeof(struct global_reg)];
memcpy(buf,RFIFOP(fd,0), RFIFOW(fd,2));
-// WBUFW(buf,0) = 0x2b11;
WBUFW(buf,0) = 0x3804; //Map server can now receive all kinds of reg values with the same packet. [Skotlex]
mapif_sendall(buf, WBUFW(buf,2));
RFIFOSKIP(fd, RFIFOW(fd,2));
@@ -2297,12 +2304,12 @@ int parse_fromlogin(int fd)
RFIFOSKIP(fd,6);
break;
- // State change of account/ban notification (from login-server) by [Yor]
+ // State change of account/ban notification (from login-server)
case 0x2731:
if (RFIFOREST(fd) < 11)
return 0;
- // send to all map-servers to disconnect the player
- {
+
+ { // send to all map-servers to disconnect the player
unsigned char buf[11];
WBUFW(buf,0) = 0x2b14;
WBUFL(buf,2) = RFIFOL(fd,2);
@@ -2312,6 +2319,7 @@ int parse_fromlogin(int fd)
}
// disconnect player if online on char-server
disconnect_player(RFIFOL(fd,2));
+
RFIFOSKIP(fd,11);
break;
@@ -2351,7 +2359,8 @@ int parse_fromlogin(int fd)
idb_remove(auth_db, aid);// reject auth attempts from map-server
}
break;
-
+
+ // ip address update signal from login server
case 0x2735:
{
unsigned char buf[2];
@@ -2362,13 +2371,14 @@ int parse_fromlogin(int fd)
new_ip = host2ip(login_ip_str);
if (new_ip && new_ip != login_ip)
- login_ip = new_ip; //Update login up.
+ login_ip = new_ip; //Update login ip, too.
new_ip = host2ip(char_ip_str);
if (new_ip && new_ip != char_ip)
{ //Update ip.
char_ip = new_ip;
ShowInfo("Updating IP for [%s].\n", char_ip_str);
+ // notify login server about the change
WFIFOHEAD(fd,6);
WFIFOW(fd,0) = 0x2736;
WFIFOL(fd,2) = htonl(char_ip);
@@ -2380,7 +2390,7 @@ int parse_fromlogin(int fd)
break;
default:
- ShowError("Unknown packet 0x%04x received from login-server, disconnecting.\n", RFIFOW(fd,0));
+ ShowError("Unknown packet 0x%04x received from login-server, disconnecting.\n", command);
set_eof(fd);
return 0;
}
@@ -2498,7 +2508,7 @@ void char_read_fame_list(void)
{
fame_item.id = char_dat[id[i]].status.char_id;
fame_item.fame = char_dat[id[i]].status.fame;
- strncpy(fame_item.name, char_dat[id[i]].status.name, NAME_LENGTH);
+ safestrncpy(fame_item.name, char_dat[id[i]].status.name, NAME_LENGTH);
memcpy(&smith_fame_list[j],&fame_item,sizeof(struct fame_list));
j++;
@@ -2513,7 +2523,7 @@ void char_read_fame_list(void)
{
fame_item.id = char_dat[id[i]].status.char_id;
fame_item.fame = char_dat[id[i]].status.fame;
- strncpy(fame_item.name, char_dat[id[i]].status.name, NAME_LENGTH);
+ safestrncpy(fame_item.name, char_dat[id[i]].status.name, NAME_LENGTH);
memcpy(&chemist_fame_list[j],&fame_item,sizeof(struct fame_list));
@@ -2527,7 +2537,7 @@ void char_read_fame_list(void)
{
fame_item.id = char_dat[id[i]].status.char_id;
fame_item.fame = char_dat[id[i]].status.fame;
- strncpy(fame_item.name, char_dat[id[i]].status.name, NAME_LENGTH);
+ safestrncpy(fame_item.name, char_dat[id[i]].status.name, NAME_LENGTH);
memcpy(&taekwon_fame_list[j],&fame_item,sizeof(struct fame_list));
@@ -2536,6 +2546,7 @@ void char_read_fame_list(void)
}
DELETE_BUFFER(id);
}
+
// Send map-servers the fame ranking lists
int char_send_fame_list(int fd)
{
@@ -2565,7 +2576,7 @@ int char_send_fame_list(int fd)
// add total packet length
WBUFW(buf, 2) = len;
- if(fd!=-1)
+ if (fd != -1)
mapif_send(fd, buf, len);
else
mapif_sendall(buf, len);
@@ -2575,7 +2586,7 @@ int char_send_fame_list(int fd)
void char_update_fame_list(int type, int index, int fame)
{
- unsigned char buf[9];
+ unsigned char buf[8];
WBUFW(buf,0) = 0x2b22;
WBUFB(buf,2) = type;
WBUFB(buf,3) = index;
@@ -2588,14 +2599,18 @@ void char_update_fame_list(int type, int index, int fame)
int char_loadName(int char_id, char* name)
{
int j;
- for( j = 0; j < char_num && char_dat[j].status.char_id != char_id; ++j )
- ;// find char
+
+ ARR_FIND( 0, char_num, j, char_dat[j].status.char_id == char_id );
if( j < char_num )
- strncpy(name, char_dat[j].status.name, NAME_LENGTH);
+ {
+ safestrncpy(name, char_dat[j].status.name, NAME_LENGTH);
+ return 1;
+ }
else
- strncpy(name, unknown_char_name, NAME_LENGTH);
-
- return (j < char_num) ? 1 : 0;
+ {
+ safestrncpy(name, unknown_char_name, NAME_LENGTH);
+ }
+ return 0;
}
int search_mapserver(unsigned short map, uint32 ip, uint16 port);
@@ -2624,6 +2639,7 @@ int parse_frommap(int fd)
WBUFW(buf,2) = j * 4 + 10;
mapif_sendallwos(fd, buf, WBUFW(buf,2));
}
+ memset(&server[id], 0, sizeof(struct mmo_map_server));
server[id].fd = -1;
online_char_db->foreach(online_char_db,char_db_setoffline,id); //Tag relevant chars as 'in disconnected' server.
}
@@ -2634,8 +2650,6 @@ int parse_frommap(int fd)
while(RFIFOREST(fd) >= 2)
{
- //ShowDebug("Received packet 0x%4x (%d bytes) from map-server (connection %d)\n", RFIFOW(fd, 0), RFIFOREST(fd), fd);
-
switch(RFIFOW(fd,0))
{
@@ -2727,7 +2741,7 @@ int parse_frommap(int fd)
RFIFOSKIP(fd, 10);
}
break;
-
+
case 0x2afe: //set MAP user count
if (RFIFOREST(fd) < 4)
return 0;
@@ -2741,12 +2755,14 @@ int parse_frommap(int fd)
case 0x2aff: //set MAP users
if (RFIFOREST(fd) < 6 || RFIFOREST(fd) < RFIFOW(fd,2))
return 0;
+ {
//TODO: When data mismatches memory, update guild/party online/offline states.
+ int aid, cid;
+ struct online_char_data* character;
+
server[id].users = RFIFOW(fd,4);
online_char_db->foreach(online_char_db,char_db_setoffline,id); //Set all chars from this server as 'unknown'
for(i = 0; i < server[id].users; i++) {
- int aid, cid;
- struct online_char_data* character;
aid = RFIFOL(fd,6+i*8);
cid = RFIFOL(fd,6+i*8+4);
character = (struct online_char_data*)idb_ensure(online_char_db, aid, create_online_char_data);
@@ -2756,33 +2772,44 @@ int parse_frommap(int fd)
character->account_id, character->char_id, character->server, id, aid, cid);
mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2);
}
- character->char_id = cid;
character->server = id;
+ character->char_id = cid;
}
//If any chars remain in -2, they will be cleaned in the cleanup timer.
- RFIFOSKIP(fd,6+i*8);
+ RFIFOSKIP(fd,RFIFOW(fd,2));
+ }
break;
case 0x2b01: // Receive character data from map-server for saving
if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
return 0;
+ {
+ int aid = RFIFOL(fd,4), cid = RFIFOL(fd,8), size = RFIFOW(fd,2);
+ struct mmo_charstatus* cs;
- ARR_FIND( 0, char_num, i, char_dat[i].status.account_id == RFIFOL(fd,4) && char_dat[i].status.char_id == RFIFOL(fd,8) );
- if( i < char_num )
+ if (size - 13 != sizeof(struct mmo_charstatus))
+ {
+ ShowError("parse_from_map (save-char): Size mismatch! %d != %d\n", size-13, sizeof(struct mmo_charstatus));
+ RFIFOSKIP(fd,size);
+ break;
+ }
+ if( ( cs = search_character(aid, cid) ) != NULL )
{
- memcpy(&char_dat[i].status, RFIFOP(fd,13), sizeof(struct mmo_charstatus));
- storage_save(char_dat[i].status.account_id, &char_dat[i].status.storage);
+ memcpy(cs, RFIFOP(fd,13), sizeof(struct mmo_charstatus));
+ storage_save(cs->account_id, &cs->storage);
}
if (RFIFOB(fd,12))
- { //Flag, set character offline. [Skotlex]
- set_char_offline(RFIFOL(fd,8),RFIFOL(fd,4));
+ { //Flag, set character offline after saving. [Skotlex]
+ set_char_offline(cid, aid);
+ WFIFOHEAD(fd,10);
WFIFOW(fd,0) = 0x2b21; //Save ack only needed on final save.
- WFIFOL(fd,2) = RFIFOL(fd,4);
- WFIFOL(fd,6) = RFIFOL(fd,8);
+ WFIFOL(fd,2) = aid;
+ WFIFOL(fd,6) = cid;
WFIFOSET(fd,10);
}
- RFIFOSKIP(fd,RFIFOW(fd,2));
+ RFIFOSKIP(fd,size);
+ }
break;
case 0x2b02: // req char selection
@@ -2805,7 +2832,8 @@ int parse_frommap(int fd)
node->login_id2 = login_id2;
//node->sex = 0;
node->ip = ntohl(ip);
- node->expiration_time = 0; // unlimited/unknown time by default (not display in map-server)
+ //node->expiration_time = 0; // unlimited/unknown time by default (not display in map-server)
+ //node->gmlevel = 0;
idb_put(auth_db, account_id, node);
//Set char to "@ char select" in online db [Kevin]
@@ -2823,22 +2851,15 @@ int parse_frommap(int fd)
if (RFIFOREST(fd) < 35)
return 0;
{
- unsigned short name;
int map_id, map_fd = -1;
struct online_char_data* data;
struct mmo_charstatus* char_data;
- name = RFIFOW(fd,18);
- map_id = search_mapserver(name, ntohl(RFIFOL(fd,24)), ntohs(RFIFOW(fd,28))); //Locate mapserver by ip and port.
+ map_id = search_mapserver(RFIFOW(fd,18), ntohl(RFIFOL(fd,24)), ntohs(RFIFOW(fd,28))); //Locate mapserver by ip and port.
if (map_id >= 0)
map_fd = server[map_id].fd;
- for(i = 0; i < char_num; i++) {
- if (char_dat[i].status.account_id == RFIFOL(fd,2) &&
- char_dat[i].status.char_id == RFIFOL(fd,14))
- break;
- }
- char_data = i < char_num ? &char_dat[i].status : NULL;
+ char_data = search_character(RFIFOL(fd,2), RFIFOL(fd,14));
if (map_fd >= 0 && session[map_fd] && char_data)
{ //Send the map server the auth of this player.
@@ -2940,6 +2961,7 @@ int parse_frommap(int fd)
if( login_fd <= 0 )
result = 3; // 3-login-server offline
+ //FIXME: need to move this check to login server [ultramage]
// else
// if( acc != -1 && isGM(acc) < isGM(account_id) )
// result = 2; // 2-gm level too low
@@ -3053,10 +3075,10 @@ int parse_frommap(int fd)
break;
case 0x2b16: // Receive rates [Wizputer]
- if (RFIFOREST(fd) < 6 || RFIFOREST(fd) < RFIFOW(fd,8))
+ if( RFIFOREST(fd) < 14 )
return 0;
// Txt doesn't need this packet, so just skip it
- RFIFOSKIP(fd,RFIFOW(fd,8));
+ RFIFOSKIP(fd,14);
break;
case 0x2b17: // Character disconnected set online 0 [Wizputer]
@@ -3238,7 +3260,7 @@ int lan_subnetcheck(uint32 ip)
{
int i;
ARR_FIND( 0, subnet_count, i, (subnet[i].char_ip & subnet[i].mask) == (ip & subnet[i].mask) );
- if ( i < subnet_count ) {
+ if( i < subnet_count ) {
ShowInfo("Subnet check [%u.%u.%u.%u]: Matches "CL_CYAN"%u.%u.%u.%u/%u.%u.%u.%u"CL_RESET"\n", CONVIP(ip), CONVIP(subnet[i].char_ip & subnet[i].mask), CONVIP(subnet[i].mask));
return subnet[i].char_ip;
} else {
@@ -3255,7 +3277,7 @@ int parse_char(int fd)
int map_fd;
struct char_session_data* sd;
uint32 ipl = session[fd]->client_addr;
-
+
sd = (struct char_session_data*)session[fd]->session_data;
// disconnect any player if no login-server.
@@ -3265,7 +3287,7 @@ int parse_char(int fd)
if(session[fd]->flag.eof)
{
if( sd != NULL && sd->auth )
- {
+ { // already authed client
struct online_char_data* data = (struct online_char_data*)idb_get(online_char_db, sd->account_id);
if( data != NULL && data->fd == fd)
data->fd = -1;
@@ -3377,15 +3399,21 @@ int parse_char(int fd)
ARR_FIND( 0, MAX_CHARS, ch, sd->found_char[ch] >= 0 && char_dat[sd->found_char[ch]].status.slot == slot );
if (ch == MAX_CHARS)
{ //Not found?? May be forged packet.
+ WFIFOHEAD(fd,3);
+ WFIFOW(fd,0) = 0x6c;
+ WFIFOB(fd,2) = 0; // rejected from server
+ WFIFOSET(fd,3);
break;
}
cd = &char_dat[sd->found_char[ch]].status;
char_log("Character Selected, Account ID: %d, Character Slot: %d, Character Name: %s.\n", sd->account_id, slot, cd->name);
cd->sex = sd->sex;
-
+
+ ShowInfo("Selected char: (Account %d: %d - %s)\n", sd->account_id, slot, cd->name);
+
// searching map server
- i = search_mapserver(cd->last_point.map,-1,-1);
+ i = search_mapserver(cd->last_point.map, -1, -1);
// if map is not found, we check major cities
if (i < 0) {
@@ -3430,6 +3458,7 @@ int parse_char(int fd)
cd->last_point.map = j;
}
+ //Send NEW auth packet [Kevin]
//FIXME: is this case even possible? [ultramage]
if ((map_fd = server[i].fd) < 1 || session[map_fd] == NULL)
{
@@ -3454,8 +3483,6 @@ int parse_char(int fd)
WFIFOW(fd,26) = ntows(htons(server[i].port)); // [!] LE byte order here [!]
WFIFOSET(fd,28);
- ShowInfo("Character selection '%s' (account: %d, slot: %d).\n", cd->name, sd->account_id, ch);
-
// create temporary auth entry
CREATE(node, struct auth_node, 1);
node->account_id = sd->account_id;
@@ -3495,8 +3522,9 @@ int parse_char(int fd)
else
{
int len;
+
// send to player
- WFIFOHEAD(fd,MAX_CHAR_BUF+2);
+ WFIFOHEAD(fd,2+MAX_CHAR_BUF);
WFIFOW(fd,0) = 0x6d;
len = 2 + mmo_char_tobuf(WFIFOP(fd,2), &char_dat[i].status);
WFIFOSET(fd,len);
@@ -3504,7 +3532,7 @@ int parse_char(int fd)
// add new entry to the chars list
ARR_FIND( 0, MAX_CHARS, ch, sd->found_char[ch] == -1 );
if( ch < MAX_CHARS )
- sd->found_char[ch] = i; // position of the new char in the char_dat[] array
+ sd->found_char[ch] = i; // position of the new char in the char_dat[] array
}
RFIFOSKIP(fd,37);
@@ -3519,12 +3547,13 @@ int parse_char(int fd)
{
int cid = RFIFOL(fd,2);
struct mmo_charstatus* cs = NULL;
+
ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, cid);
memcpy(email, RFIFOP(fd,6), 40);
RFIFOSKIP(fd,RFIFOREST(fd)); // hack to make the other deletion packet work
if (e_mail_check(email) == 0)
- strncpy(email, "a@a.com", 40); // default e-mail
+ safestrncpy(email, "a@a.com", sizeof(email)); // default e-mail
// BEGIN HACK: "change email using the char deletion 'confirm email' menu"
// if we activated email creation and email is default email
@@ -3587,6 +3616,17 @@ int parse_char(int fd)
// deletion process
cs = &char_dat[sd->found_char[i]].status;
+
+ //check for config char del condition [Lupus]
+ if( ( char_del_level > 0 && cs->base_level >= (unsigned int)char_del_level ) || ( char_del_level < 0 && cs->base_level <= (unsigned int)(-char_del_level) ) )
+ {
+ WFIFOHEAD(fd,3);
+ WFIFOW(fd,0) = 0x70;
+ WFIFOB(fd,2) = 1; // This character cannot be deleted.
+ WFIFOSET(fd,3);
+ break;
+ }
+
char_delete(cs);
if (sd->found_char[i] != char_num - 1) {
int j, k;
@@ -3632,9 +3672,25 @@ int parse_char(int fd)
// R 028d <account ID>.l <char ID>.l <new name>.24B
case 0x28d:
FIFOSD_CHECK(34);
- //not implemented
- RFIFOSKIP(fd,34);
- break;
+ {
+ //not implemented
+ RFIFOSKIP(fd,34);
+ }
+ break;
+ //Confirm change name.
+ // 0x28f <char_id>.L
+ case 0x28f:
+ // 0: Sucessfull
+ // 1: This character's name has already been changed. You cannot change a character's name more than once.
+ // 2: User information is not correct.
+ // 3: You have failed to change this character's name.
+ // 4: Another user is using this character name, so please select another one.
+ FIFOSD_CHECK(6);
+ {
+ //not implemented
+ RFIFOSKIP(fd,6);
+ }
+ break;
// captcha code request (not implemented)
// R 07e5 <?>.w <aid>.l
@@ -3752,7 +3808,6 @@ int parse_console(char* buf)
return 0;
}
-// 全てのMAPサーバーにデータ送信(送信したmap鯖の数を返す)
int mapif_sendall(unsigned char *buf, unsigned int len)
{
int i, c;
@@ -3771,7 +3826,6 @@ int mapif_sendall(unsigned char *buf, unsigned int len)
return c;
}
-// 自分以外の全てのMAPサーバーにデータ送信(送信したmap鯖の数を返す)
int mapif_sendallwos(int sfd, unsigned char *buf, unsigned int len)
{
int i, c;
@@ -3789,19 +3843,19 @@ int mapif_sendallwos(int sfd, unsigned char *buf, unsigned int len)
return c;
}
-// MAPサーバーにデータ送信(map鯖生存確認有り)
+
int mapif_send(int fd, unsigned char *buf, unsigned int len)
{
int i;
if (fd >= 0) {
- for(i = 0; i < MAX_MAP_SERVERS; i++) {
- if (fd == server[i].fd) {
- WFIFOHEAD(fd,len);
- memcpy(WFIFOP(fd,0), buf, len);
- WFIFOSET(fd,len);
- return 1;
- }
+ ARR_FIND( 0, MAX_MAP_SERVERS, i, fd == server[i].fd );
+ if( i < MAX_MAP_SERVERS )
+ {
+ WFIFOHEAD(fd,len);
+ memcpy(WFIFOP(fd,0), buf, len);
+ WFIFOSET(fd,len);
+ return 1;
}
}
return 0;
@@ -4028,7 +4082,7 @@ int char_config_read(const char *cfgName)
remove_control_chars(w1);
remove_control_chars(w2);
if(strcmpi(w1,"timestamp_format") == 0) {
- strncpy(timestamp_format, w2, 20);
+ safestrncpy(timestamp_format, w2, sizeof(timestamp_format));
} else if(strcmpi(w1,"console_silent")==0){
ShowInfo("Console Silent Setting: %d\n", atoi(w2));
msg_silent = atoi(w2);
@@ -4036,23 +4090,21 @@ int char_config_read(const char *cfgName)
} else if(strcmpi(w1,"stdout_with_ansisequence")==0){
stdout_with_ansisequence = config_switch(w2);
} else if (strcmpi(w1, "userid") == 0) {
- strncpy(userid, w2, 24);
+ safestrncpy(userid, w2, sizeof(userid));
} else if (strcmpi(w1, "passwd") == 0) {
- strncpy(passwd, w2, 24);
+ safestrncpy(passwd, w2, sizeof(passwd));
} else if (strcmpi(w1, "server_name") == 0) {
- strncpy(server_name, w2, 20);
- server_name[sizeof(server_name) - 1] = '\0';
+ safestrncpy(server_name, w2, sizeof(server_name));
ShowStatus("%s server has been initialized\n", w2);
} else if (strcmpi(w1, "wisp_server_name") == 0) {
if (strlen(w2) >= 4) {
- memcpy(wisp_server_name, w2, sizeof(wisp_server_name));
- wisp_server_name[sizeof(wisp_server_name) - 1] = '\0';
+ safestrncpy(wisp_server_name, w2, sizeof(wisp_server_name));
}
} else if (strcmpi(w1, "login_ip") == 0) {
char ip_str[16];
login_ip = host2ip(w2);
if (login_ip) {
- strncpy(login_ip_str, w2, sizeof(login_ip_str));
+ safestrncpy(login_ip_str, w2, sizeof(login_ip_str));
ShowStatus("Login server IP address : %s -> %s\n", w2, ip2str(login_ip, ip_str));
}
} else if (strcmpi(w1, "login_port") == 0) {
@@ -4061,14 +4113,14 @@ int char_config_read(const char *cfgName)
char ip_str[16];
char_ip = host2ip(w2);
if (char_ip){
- strncpy(char_ip_str, w2, sizeof(char_ip_str));
+ safestrncpy(char_ip_str, w2, sizeof(char_ip_str));
ShowStatus("Character server IP address : %s -> %s\n", w2, ip2str(char_ip, ip_str));
}
} else if (strcmpi(w1, "bind_ip") == 0) {
char ip_str[16];
bind_ip = host2ip(w2);
if (bind_ip) {
- strncpy(bind_ip_str, w2, sizeof(bind_ip_str));
+ safestrncpy(bind_ip_str, w2, sizeof(bind_ip_str));
ShowStatus("Character server binding IP address : %s -> %s\n", w2, ip2str(bind_ip, ip_str));
}
} else if (strcmpi(w1, "char_port") == 0) {
@@ -4082,14 +4134,14 @@ int char_config_read(const char *cfgName)
} else if (strcmpi(w1, "email_creation") == 0) {
email_creation = config_switch(w2);
} else if (strcmpi(w1, "scdata_txt") == 0) { //By Skotlex
- strcpy(scdata_txt, w2);
+ safestrncpy(scdata_txt, w2, sizeof(scdata_txt));
#endif
} else if (strcmpi(w1, "char_txt") == 0) {
- strcpy(char_txt, w2);
+ safestrncpy(char_txt, w2, sizeof(char_txt));
} else if (strcmpi(w1, "friends_txt") == 0) { //By davidsiaw
- strcpy(friends_txt, w2);
+ safestrncpy(friends_txt, w2, sizeof(friends_txt));
} else if (strcmpi(w1, "hotkeys_txt") == 0) { //By davidsiaw
- strcpy(hotkeys_txt, w2);
+ safestrncpy(hotkeys_txt, w2, sizeof(hotkeys_txt));
#ifndef TXT_SQL_CONVERT
} else if (strcmpi(w1, "max_connect_user") == 0) {
max_connect_user = atoi(w2);
@@ -4111,10 +4163,8 @@ int char_config_read(const char *cfgName)
if (sscanf(w2, "%15[^,],%d,%d", map, &x, &y) < 3)
continue;
start_point.map = mapindex_name2id(map);
- if (!start_point.map) {
+ if (!start_point.map)
ShowError("Specified start_point %s not found in map-index cache.\n", map);
- start_point.map = 0;
- }
start_point.x = x;
start_point.y = y;
} else if (strcmpi(w1, "start_zeny") == 0) {
@@ -4132,21 +4182,25 @@ int char_config_read(const char *cfgName)
} else if(strcmpi(w1,"log_char")==0) { //log char or not [devil]
log_char = atoi(w2);
} else if (strcmpi(w1, "unknown_char_name") == 0) {
- strcpy(unknown_char_name, w2);
+ safestrncpy(unknown_char_name, w2, sizeof(unknown_char_name));
unknown_char_name[NAME_LENGTH-1] = '\0';
} else if (strcmpi(w1, "char_log_filename") == 0) {
- strcpy(char_log_filename, w2);
+ safestrncpy(char_log_filename, w2, sizeof(char_log_filename));
} else if (strcmpi(w1, "name_ignoring_case") == 0) {
name_ignoring_case = (bool)config_switch(w2);
} else if (strcmpi(w1, "char_name_option") == 0) {
char_name_option = atoi(w2);
} else if (strcmpi(w1, "char_name_letters") == 0) {
- strcpy(char_name_letters, w2);
+ safestrncpy(char_name_letters, w2, sizeof(char_name_letters));
+ } else if (strcmpi(w1, "chars_per_account") == 0) { //maxchars per account [Sirius]
+ char_per_account = atoi(w2);
+ } else if (strcmpi(w1, "char_del_level") == 0) { //disable/enable char deletion by its level condition [Lupus]
+ char_del_level = atoi(w2);
// online files options
} else if (strcmpi(w1, "online_txt_filename") == 0) {
- strcpy(online_txt_filename, w2);
+ safestrncpy(online_txt_filename, w2, sizeof(online_txt_filename));
} else if (strcmpi(w1, "online_html_filename") == 0) {
- strcpy(online_html_filename, w2);
+ safestrncpy(online_html_filename, w2, sizeof(online_html_filename));
} else if (strcmpi(w1, "online_sorting_option") == 0) {
online_sorting_option = atoi(w2);
} else if (strcmpi(w1, "online_display_option") == 0) {
@@ -4160,7 +4214,7 @@ int char_config_read(const char *cfgName)
if (online_refresh_html < 1)
online_refresh_html = 1;
} else if(strcmpi(w1,"db_path")==0) {
- strcpy(db_path,w2);
+ safestrncpy(db_path, w2, sizeof(db_path));
} else if (strcmpi(w1, "console") == 0) {
console = config_switch(w2);
} else if (strcmpi(w1, "fame_list_alchemist") == 0) {
@@ -4195,11 +4249,6 @@ int char_config_read(const char *cfgName)
}
#ifndef TXT_SQL_CONVERT
-int chardb_final(int key, void* data, va_list va)
-{
- aFree(data);
- return 0;
-}
void do_final(void)
{
ShowStatus("Terminating server.\n");
@@ -4209,9 +4258,10 @@ void do_final(void)
set_all_offline(-1);
flush_fifos();
// write online players files with no player
- online_char_db->clear(online_char_db, NULL); //clean the db...
+ online_char_db->clear(online_char_db, NULL);
create_online_files();
- online_char_db->destroy(online_char_db, NULL); //dispose the db...
+
+ online_char_db->destroy(online_char_db, NULL);
auth_db->destroy(auth_db, NULL);
if(char_dat) aFree(char_dat);
@@ -4294,11 +4344,11 @@ int do_init(int argc, char **argv)
else
ShowStatus("Defaulting to %s as our IP address\n", ip_str);
if (!login_ip) {
- strcpy(login_ip_str, ip_str);
+ safestrncpy(login_ip_str, ip_str, sizeof(login_ip_str));
login_ip = str2ip(login_ip_str);
}
if (!char_ip) {
- strcpy(char_ip_str, ip_str);
+ safestrncpy(char_ip_str, ip_str, sizeof(char_ip_str));
char_ip = str2ip(char_ip_str);
}
}
diff --git a/src/char/char.h b/src/char/char.h
index 8c8d7c554..18bb7b1b5 100644
--- a/src/char/char.h
+++ b/src/char/char.h
@@ -29,7 +29,6 @@ int mapif_send(int fd,unsigned char *buf, unsigned int len);
int char_married(int pl1,int pl2);
int char_child(int parent_id, int child_id);
int char_family(int cid1, int cid2, int cid3);
-void char_clearparty(int party_id);
int char_log(char *fmt, ...);
diff --git a/src/char/int_guild.c b/src/char/int_guild.c
index 9a815200f..31cceeff0 100644
--- a/src/char/int_guild.c
+++ b/src/char/int_guild.c
@@ -865,8 +865,8 @@ int mapif_guild_notice(struct guild *g)
WBUFW(buf,0) = 0x383e;
WBUFL(buf,2) = g->guild_id;
- memcpy(WBUFP(buf,6), g->mes1, 60);
- memcpy(WBUFP(buf,66), g->mes2, 120);
+ memcpy(WBUFP(buf,6), g->mes1, MAX_GUILDMES1);
+ memcpy(WBUFP(buf,66), g->mes2, MAX_GUILDMES2);
mapif_sendall(buf, 186);
return 0;
@@ -1404,8 +1404,8 @@ int mapif_parse_GuildNotice(int fd, int guild_id, const char *mes1, const char *
g = (struct guild*)idb_get(guild_db, guild_id);
if (g == NULL)
return 0;
- memcpy(g->mes1, mes1, 60);
- memcpy(g->mes2, mes2, 120);
+ memcpy(g->mes1, mes1, MAX_GUILDMES1);
+ memcpy(g->mes2, mes2, MAX_GUILDMES2);
return mapif_guild_notice(g);
}
diff --git a/src/char/int_party.c b/src/char/int_party.c
index 04d638049..b340aa9cf 100644
--- a/src/char/int_party.c
+++ b/src/char/int_party.c
@@ -488,7 +488,6 @@ int mapif_parse_PartyInfo(int fd, int party_id)
mapif_party_info(fd, &p->party);
else {
mapif_party_noinfo(fd, party_id);
- char_clearparty(party_id);
}
return 0;
diff --git a/src/char/int_storage.c b/src/char/int_storage.c
index bae72fcf4..2a041b286 100644
--- a/src/char/int_storage.c
+++ b/src/char/int_storage.c
@@ -101,12 +101,12 @@ int guild_storage_tostr(char *str,struct guild_storage *p)
str_p+=sprintf(str,"%d,%d\t",p->guild_id,p->storage_amount);
for(i=0;i<MAX_GUILD_STORAGE;i++)
- if( (p->storage_[i].nameid) && (p->storage_[i].amount) ){
+ if( (p->items[i].nameid) && (p->items[i].amount) ){
str_p += sprintf(str_p,"%d,%d,%d,%d,%d,%d,%d",
- p->storage_[i].id,p->storage_[i].nameid,p->storage_[i].amount,p->storage_[i].equip,
- p->storage_[i].identify,p->storage_[i].refine,p->storage_[i].attribute);
+ p->items[i].id,p->items[i].nameid,p->items[i].amount,p->items[i].equip,
+ p->items[i].identify,p->items[i].refine,p->items[i].attribute);
for(j=0; j<MAX_SLOTS; j++)
- str_p += sprintf(str_p,",%d",p->storage_[i].card[j]);
+ str_p += sprintf(str_p,",%d",p->items[i].card[j]);
str_p += sprintf(str_p," ");
f++;
}
@@ -138,15 +138,15 @@ int guild_storage_fromstr(char *str,struct guild_storage *p)
&tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3],
&tmp_int[4], &tmp_int[5], &tmp_int[6], tmp_str, &len) == 8)
{
- p->storage_[i].id = tmp_int[0];
- p->storage_[i].nameid = tmp_int[1];
- p->storage_[i].amount = tmp_int[2];
- p->storage_[i].equip = tmp_int[3];
- p->storage_[i].identify = tmp_int[4];
- p->storage_[i].refine = tmp_int[5];
- p->storage_[i].attribute = tmp_int[6];
+ p->items[i].id = tmp_int[0];
+ p->items[i].nameid = tmp_int[1];
+ p->items[i].amount = tmp_int[2];
+ p->items[i].equip = tmp_int[3];
+ p->items[i].identify = tmp_int[4];
+ p->items[i].refine = tmp_int[5];
+ p->items[i].attribute = tmp_int[6];
for(j = 0; j < MAX_SLOTS && tmp_str[0] && sscanf(tmp_str, ",%d%[0-9,-]",&tmp_int[0], tmp_str) > 0; j++)
- p->storage_[i].card[j] = tmp_int[0];
+ p->items[i].card[j] = tmp_int[0];
next += len;
if (str[next] == ' ')
next++;
@@ -371,8 +371,8 @@ int inter_guild_storage_delete(int guild_id)
if(gs) {
int i;
for(i=0;i<gs->storage_amount;i++){
- if(gs->storage_[i].card[0] == (short)0xff00)
- inter_pet_delete( MakeDWord(gs->storage_[i].card[1],gs->storage_[i].card[2]) );
+ if(gs->items[i].card[0] == (short)0xff00)
+ inter_pet_delete( MakeDWord(gs->items[i].card[1],gs->items[i].card[2]) );
}
idb_remove(guild_storage_db,guild_id);
}
diff --git a/src/char/inter.c b/src/char/inter.c
index 051d8117a..8d9cac99f 100644
--- a/src/char/inter.c
+++ b/src/char/inter.c
@@ -210,7 +210,7 @@ static int inter_config_read(const char *cfgName) {
} else if(strcmpi(w1,"log_inter")==0) {
log_inter = atoi(w2);
} else if(strcmpi(w1, "main_chat_nick")==0){ // Main chat nick [LuzZza]
- strcpy(main_chat_nick, w2);
+ safestrncpy(main_chat_nick, w2, sizeof(main_chat_nick));
#endif //TXT_SQL_CONVERT
} else if (strcmpi(w1, "import") == 0) {
inter_config_read(w2);
diff --git a/src/char_sql/char.c b/src/char_sql/char.c
index 36944cd35..46b645ce6 100644
--- a/src/char_sql/char.c
+++ b/src/char_sql/char.c
@@ -2,17 +2,17 @@
// For more information, see LICENCE in the main folder
#include "../common/cbasetypes.h"
-#include "../common/strlib.h"
#include "../common/core.h"
-#include "../common/timer.h"
-#include "../common/mmo.h"
#include "../common/db.h"
#include "../common/malloc.h"
#include "../common/mapindex.h"
+#include "../common/mmo.h"
#include "../common/showmsg.h"
#include "../common/socket.h"
-#include "../common/version.h"
+#include "../common/strlib.h"
+#include "../common/timer.h"
#include "../common/utils.h"
+#include "../common/version.h"
#include "inter.h"
#include "int_guild.h"
#include "int_homun.h"
@@ -60,6 +60,13 @@ char friend_db[256] = "friends";
char hotkey_db[256] = "hotkey";
char quest_db[256] = "quest";
+// show loading/saving messages
+#ifdef TXT_SQL_CONVERT
+int save_log = 0; //Have the logs be off by default when converting
+#else
+int save_log = 1;
+#endif
+
//If your code editor is having problems syntax highlighting this file, uncomment this and RECOMMENT IT BEFORE COMPILING
//#undef TXT_SQL_CONVERT
#ifndef TXT_SQL_CONVERT
@@ -94,11 +101,11 @@ int char_maintenance = 0;
bool char_new = true;
int char_new_display = 0;
-int name_ignoring_case = 0; // Allow or not identical name for characters but with a different case by [Yor]
+bool name_ignoring_case = false; // Allow or not identical name for characters but with a different case by [Yor]
int char_name_option = 0; // Option to know which letters/symbols are authorised in the name of a character (0: all, 1: only those in char_name_letters, 2: all EXCEPT those in char_name_letters) by [Yor]
char unknown_char_name[NAME_LENGTH] = "Unknown"; // Name to use when the requested name cannot be determined
#define TRIM_CHARS "\032\t\x0A\x0D " //The following characters are trimmed regardless because they cause confusion and problems on the servers. [Skotlex]
-char char_name_letters[1024] = ""; // list of letters/symbols used to authorise or not a name of a character. by [Yor]
+char char_name_letters[1024] = ""; // list of letters/symbols allowed (or not) in a character name. by [Yor]
int char_per_account = 0; //Maximum charas per account (default unlimited) [Sirius]
int char_del_level = 0; //From which level u can delete character [Lupus]
@@ -106,12 +113,6 @@ int char_del_level = 0; //From which level u can delete character [Lupus]
int log_char = 1; // loggin char or not [devil]
int log_inter = 1; // loggin inter or not [devil]
-#ifdef TXT_SQL_CONVERT
-int save_log = 0; //Have the logs be off by default when converting
-#else
-int save_log = 1;
-#endif
-
// Advanced subnet check [LuzZza]
struct s_subnet {
uint32 mask;
@@ -813,7 +814,6 @@ int memitemdata_to_sql(const struct item items[], int max, int id, int tableswit
return 0;
}
-#define MAX_CHAR_BUF 110 //Max size (for WFIFOHEAD calls)
int mmo_char_tobuf(uint8* buf, struct mmo_charstatus* p);
#ifndef TXT_SQL_CONVERT
@@ -1249,7 +1249,7 @@ int check_char_name(char * name, char * esc_name)
// check for reserved names
if( strcmpi(name, main_chat_nick) == 0 || strcmpi(name, wisp_server_name) == 0 )
return -1; // nick reserved for internal server messages
-
+
// Check Authorised letters/symbols in the name of the character
if( char_name_option == 1 )
{ // only letters/symbols in char_name_letters are authorised
@@ -1264,13 +1264,14 @@ int check_char_name(char * name, char * esc_name)
return -2;
}
+ // check name (already in use?)
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `name` = '%s'", char_db, esc_name) )
- { // check name (already in use?)
+ {
Sql_ShowDebug(sql_handle);
return -2;
}
if( Sql_NumRows(sql_handle) > 0 )
- return -1; // name already exists
+ return -1; // name already exists
return 0;
}
@@ -1294,8 +1295,6 @@ int make_new_char_sql(struct char_session_data* sd, char* name_, int str, int ag
//check other inputs
if((slot >= MAX_CHARS) // slots
- || (hair_style >= 24) // hair style
- || (hair_color >= 9) // hair color
|| (str + agi + vit + int_ + dex + luk != 6*5 ) // stats
|| (str < 1 || str > 9 || agi < 1 || agi > 9 || vit < 1 || vit > 9 || int_ < 1 || int_ > 9 || dex < 1 || dex > 9 || luk < 1 || luk > 9) // individual stat values
|| (str + int_ != 10 || agi + luk != 10 || vit + dex != 10) ) // pairs
@@ -1524,27 +1523,26 @@ int delete_char_sql(int char_id)
return 0;
}
-//==========================================================================================================
-
+//---------------------------------------------------------------------
+// This function return the number of online players in all map-servers
+//---------------------------------------------------------------------
int count_users(void)
{
int i, users;
- if (login_fd > 0 && session[login_fd]){
- users = 0;
- for(i = 0; i < MAX_MAP_SERVERS; i++) {
- if (server[i].fd > 0) {
- users += server[i].users;
- }
+ users = 0;
+ for(i = 0; i < MAX_MAP_SERVERS; i++) {
+ if (server[i].fd > 0) {
+ users += server[i].users;
}
- return users;
}
- return 0;
+ return users;
}
-/// Writes char data to the buffer in the format used by the client.
-/// Used in packets 0x6b (chars info) and 0x6d (new char info)
+// Writes char data to the buffer in the format used by the client.
+// Used in packets 0x6b (chars info) and 0x6d (new char info)
// Returns the size
+#define MAX_CHAR_BUF 110 //Max size (for WFIFOHEAD calls)
int mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p)
{
unsigned short offset = 0;
@@ -1598,15 +1596,18 @@ int mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p)
WBUFW(buf,104) = p->slot;
#if PACKETVER >= 20061023
WBUFW(buf,106) = ( p->rename > 0 ) ? 0 : 1;
- offset+=2;
+ offset += 2;
#endif
#if (PACKETVER >= 20100720 && PACKETVER <= 20100727) || PACKETVER >= 20100803
mapindex_getmapname_ext(mapindex_id2name(p->last_point.map), (char*)WBUFP(buf,108));
- offset += 16;
+ offset += MAP_NAME_LENGTH_EXT;
#endif
return 106+offset;
}
+//----------------------------------------
+// Function to send characters to a player
+//----------------------------------------
int mmo_char_send006b(int fd, struct char_session_data* sd)
{
int j, offset = 0;
@@ -1671,9 +1672,9 @@ int char_child(int parent_id, int child_id)
return 0;
}
-int char_family(int pl1, int pl2, int pl3)
+int char_family(int cid1, int cid2, int cid3)
{
- if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`partner_id`,`child` FROM `%s` WHERE `char_id` IN ('%d','%d','%d')", char_db, pl1, pl2, pl3) )
+ if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `char_id`,`partner_id`,`child` FROM `%s` WHERE `char_id` IN ('%d','%d','%d')", char_db, cid1, cid2, cid3) )
Sql_ShowDebug(sql_handle);
else while( SQL_SUCCESS == Sql_NextRow(sql_handle) )
{
@@ -1686,9 +1687,9 @@ int char_family(int pl1, int pl2, int pl3)
Sql_GetData(sql_handle, 1, &data, NULL); partnerid = atoi(data);
Sql_GetData(sql_handle, 2, &data, NULL); childid = atoi(data);
- if( (pl1 == charid && ((pl2 == partnerid && pl3 == childid ) || (pl2 == childid && pl3 == partnerid))) ||
- (pl1 == partnerid && ((pl2 == charid && pl3 == childid ) || (pl2 == childid && pl3 == charid ))) ||
- (pl1 == childid && ((pl2 == charid && pl3 == partnerid) || (pl2 == partnerid && pl3 == charid ))) )
+ if( (cid1 == charid && ((cid2 == partnerid && cid3 == childid ) || (cid2 == childid && cid3 == partnerid))) ||
+ (cid1 == partnerid && ((cid2 == charid && cid3 == childid ) || (cid2 == childid && cid3 == charid ))) ||
+ (cid1 == childid && ((cid2 == charid && cid3 == partnerid) || (cid2 == partnerid && cid3 == charid ))) )
{
Sql_FreeResult(sql_handle);
return childid;
@@ -1698,6 +1699,20 @@ int char_family(int pl1, int pl2, int pl3)
return 0;
}
+//----------------------------------------------------------------------
+// Force disconnection of an online player (with account value) by [Yor]
+//----------------------------------------------------------------------
+void disconnect_player(int account_id)
+{
+ int i;
+ struct char_session_data* sd;
+
+ // disconnect player if online on char-server
+ ARR_FIND( 0, fd_max, i, session[i] && (sd = (struct char_session_data*)session[i]->session_data) && sd->account_id == account_id );
+ if( i < fd_max )
+ set_eof(i);
+}
+
static void char_auth_ok(int fd, struct char_session_data *sd)
{
struct online_char_data* character;
@@ -1777,17 +1792,17 @@ int parse_fromlogin(int fd)
return 0;
if (RFIFOB(fd,2)) {
- //printf("connect login server error : %d\n", RFIFOB(fd, 2));
+ //printf("connect login server error : %d\n", RFIFOB(fd,2));
ShowError("Can not connect to login-server.\n");
ShowError("The server communication passwords (default s1/p1) are probably invalid.\n");
ShowError("Also, please make sure your login db has the correct communication username/passwords and the gender of the account is S.\n");
ShowError("The communication passwords are set in map_athena.conf and char_athena.conf\n");
- }else {
+ } else {
ShowStatus("Connected to login-server (connection #%d).\n", fd);
//Send online accounts to login server.
send_accounts_tologin(-1, gettick(), 0, 0);
-
+
// if no map-server already connected, display a message...
ARR_FIND( 0, MAX_MAP_SERVERS, i, server[i].fd > 0 && server[i].map[0] );
if( i == MAX_MAP_SERVERS )
@@ -1874,19 +1889,18 @@ int parse_fromlogin(int fd)
if (RFIFOREST(fd) < 7)
return 0;
{
- unsigned char buf[16];
+ unsigned char buf[7];
int acc = RFIFOL(fd,2);
int sex = RFIFOB(fd,6);
RFIFOSKIP(fd,7);
if( acc > 0 )
- {
+ {// TODO: Is this even possible?
int char_id[MAX_CHARS];
int class_[MAX_CHARS];
int guild_id[MAX_CHARS];
int num;
- int i;
char* data;
struct auth_node* node = (struct auth_node*)idb_get(auth_db, acc);
@@ -1935,12 +1949,10 @@ int parse_fromlogin(int fd)
inter_guild_sex_changed(guild_id[i], acc, char_id[i], sex);
}
Sql_FreeResult(sql_handle);
- }
- // disconnect player if online on char-server
- ARR_FIND( 0, fd_max, i, session[i] && (sd = (struct char_session_data*)session[i]->session_data) && sd->account_id == acc );
- if( i < fd_max )
- set_eof(i);
+ // disconnect player if online on char-server
+ disconnect_player(acc);
+ }
// notify all mapservers about this change
WBUFW(buf,0) = 0x2b0d;
@@ -1960,8 +1972,8 @@ int parse_fromlogin(int fd)
memcpy(buf,RFIFOP(fd,0), RFIFOW(fd,2));
WBUFW(buf,0) = 0x3804; //Map server can now receive all kinds of reg values with the same packet. [Skotlex]
mapif_sendall(buf, WBUFW(buf,2));
- }
RFIFOSKIP(fd, RFIFOW(fd,2));
+ }
break;
// State change of account/ban notification (from login-server)
@@ -1978,9 +1990,7 @@ int parse_fromlogin(int fd)
mapif_sendall(buf, 11);
}
// disconnect player if online on char-server
- ARR_FIND( 0, fd_max, i, session[i] && (sd = (struct char_session_data*)session[i]->session_data) && sd->account_id == RFIFOL(fd,2) );
- if( i < fd_max )
- set_eof(i);
+ disconnect_player(RFIFOL(fd,2));
RFIFOSKIP(fd,11);
break;
@@ -2032,8 +2042,8 @@ int parse_fromlogin(int fd)
mapif_sendall(buf, 2);
new_ip = host2ip(login_ip_str);
- if (new_ip && new_ip != login_ip) //Update login ip, too.
- login_ip = new_ip;
+ if (new_ip && new_ip != login_ip)
+ login_ip = new_ip; //Update login ip, too.
new_ip = host2ip(char_ip_str);
if (new_ip && new_ip != char_ip)
@@ -2046,13 +2056,13 @@ int parse_fromlogin(int fd)
WFIFOL(fd,2) = htonl(char_ip);
WFIFOSET(fd,6);
}
- }
RFIFOSKIP(fd,2);
+ }
break;
default:
- ShowError("Unknown packet 0x%04x received from login server, disconnecting.\n", command);
+ ShowError("Unknown packet 0x%04x received from login-server, disconnecting.\n", command);
set_eof(fd);
return 0;
}
@@ -2180,6 +2190,7 @@ int char_send_fame_list(int fd)
mapif_send(fd, buf, len);
else
mapif_sendall(buf, len);
+
return 0;
}
@@ -2205,13 +2216,12 @@ int char_loadName(int char_id, char* name)
else if( SQL_SUCCESS == Sql_NextRow(sql_handle) )
{
Sql_GetData(sql_handle, 0, &data, &len);
- memset(name, 0, NAME_LENGTH);
- memcpy(name, data, min(len, NAME_LENGTH));
+ safestrncpy(name, data, NAME_LENGTH);
return 1;
}
else
{
- memcpy(name, unknown_char_name, NAME_LENGTH);
+ safestrncpy(name, unknown_char_name, NAME_LENGTH);
}
return 0;
}
@@ -2220,15 +2230,9 @@ int search_mapserver(unsigned short map, uint32 ip, uint16 port);
int parse_frommap(int fd)
{
- int i = 0, j = 0;
+ int i, j;
int id;
- // Sometimes fd=0, and it will cause server crash. Don't know why. :(
- if (fd <= 0) {
- ShowError("parse_frommap error fd=%d\n", fd);
- return 0;
- }
-
ARR_FIND( 0, MAX_MAP_SERVERS, id, server[id].fd == fd );
if(id == MAX_MAP_SERVERS)
set_eof(fd);
@@ -2260,7 +2264,7 @@ int parse_frommap(int fd)
while(RFIFOREST(fd) >= 2)
{
- switch(RFIFOW(fd, 0))
+ switch(RFIFOW(fd,0))
{
case 0x2afa: // Receiving map names list from the map-server
@@ -2390,16 +2394,16 @@ int parse_frommap(int fd)
return 0;
{
//TODO: When data mismatches memory, update guild/party online/offline states.
- int i, aid, cid;
+ int aid, cid;
struct online_char_data* character;
- online_char_db->foreach(online_char_db,char_db_setoffline,id); //Set all chars from this server as 'unknown'
server[id].users = RFIFOW(fd,4);
+ online_char_db->foreach(online_char_db,char_db_setoffline,id); //Set all chars from this server as 'unknown'
for(i = 0; i < server[id].users; i++) {
aid = RFIFOL(fd,6+i*8);
cid = RFIFOL(fd,6+i*8+4);
character = (struct online_char_data*)idb_ensure(online_char_db, aid, create_online_char_data);
- if (character->server > -1 && character->server != id)
+ if( character->server > -1 && character->server != id )
{
ShowNotice("Set map user: Character (%d:%d) marked on map server %d, but map server %d claims to have (%d:%d) online!\n",
character->account_id, character->char_id, character->server, id, aid, cid);
@@ -2419,6 +2423,7 @@ int parse_frommap(int fd)
{
int aid = RFIFOL(fd,4), cid = RFIFOL(fd,8), size = RFIFOW(fd,2);
struct online_char_data* character;
+
if (size - 13 != sizeof(struct mmo_charstatus))
{
ShowError("parse_from_map (save-char): Size mismatch! %d != %d\n", size-13, sizeof(struct mmo_charstatus));
@@ -2439,7 +2444,7 @@ int parse_frommap(int fd)
}
if (RFIFOB(fd,12))
- { //Flag? Set character offline after saving [Skotlex]
+ { //Flag, set character offline after saving. [Skotlex]
set_char_offline(cid, aid);
WFIFOHEAD(fd,10);
WFIFOW(fd,0) = 0x2b21; //Save ack only needed on final save.
@@ -2530,7 +2535,7 @@ int parse_frommap(int fd)
data = (struct online_char_data*)idb_ensure(online_char_db, RFIFOL(fd,2), create_online_char_data);
data->char_id = char_data->char_id;
data->server = map_id; //Update server where char is.
-
+
//Reply with an ack.
WFIFOHEAD(fd,30);
WFIFOW(fd,0) = 0x2b06;
@@ -2738,22 +2743,17 @@ int parse_frommap(int fd)
break;
case 0x2b16: // Receive rates [Wizputer]
- if (RFIFOREST(fd) < 6 || RFIFOREST(fd) < RFIFOW(fd,8))
+ if( RFIFOREST(fd) < 14 )
return 0;
{
- char motd[256];
- char esc_motd[sizeof(motd)*2+1];
char esc_server_name[sizeof(server_name)*2+1];
- strncpy(motd, (char*)RFIFOP(fd,10), 255); //First copy it to make sure the motd fits.
- motd[255] = '\0';
- Sql_EscapeString(sql_handle, esc_motd, motd);
Sql_EscapeString(sql_handle, esc_server_name, server_name);
- if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `ragsrvinfo` SET `index`='%d',`name`='%s',`exp`='%d',`jexp`='%d',`drop`='%d',`motd`='%s'",
- fd, esc_server_name, RFIFOW(fd,2), RFIFOW(fd,4), RFIFOW(fd,6), esc_motd) )
+ if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `ragsrvinfo` SET `index`='%d',`name`='%s',`exp`='%d',`jexp`='%d',`drop`='%d'",
+ fd, esc_server_name, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)) )
Sql_ShowDebug(sql_handle);
- RFIFOSKIP(fd,RFIFOW(fd,8));
+ RFIFOSKIP(fd,14);
}
break;
@@ -2790,7 +2790,7 @@ int parse_frommap(int fd)
{
#ifdef ENABLE_SC_SAVING
int count, aid, cid;
-
+
aid = RFIFOL(fd, 4);
cid = RFIFOL(fd, 8);
count = RFIFOW(fd, 12);
@@ -2939,7 +2939,8 @@ int search_mapserver(unsigned short map, uint32 ip, uint16 port)
return -1;
}
-int char_mapif_init(int fd)
+// char_mapifの初期化処理(現在はinter_mapif初期化のみ)
+static int char_mapif_init(int fd)
{
return inter_mapif_init(fd);
}
@@ -2962,8 +2963,8 @@ int lan_subnetcheck(uint32 ip)
int parse_char(int fd)
{
- int i, ch = 0;
- char email[40];
+ int i, ch;
+ char email[40];
unsigned short cmd;
int map_fd;
struct char_session_data* sd;
@@ -3072,7 +3073,7 @@ int parse_char(int fd)
FIFOSD_CHECK(3);
{
struct mmo_charstatus char_dat;
- struct mmo_charstatus * cp;
+ struct mmo_charstatus *cd;
char* data;
int char_id;
uint32 subnet_map_ip;
@@ -3084,11 +3085,13 @@ int parse_char(int fd)
if ( SQL_SUCCESS != Sql_Query(sql_handle, "SELECT `char_id` FROM `%s` WHERE `account_id`='%d' AND `char_num`='%d'", char_db, sd->account_id, slot)
|| SQL_SUCCESS != Sql_NextRow(sql_handle)
|| SQL_SUCCESS != Sql_GetData(sql_handle, 0, &data, NULL) )
- {
- //Not found?? May be forged packet.
+ { //Not found?? May be forged packet.
Sql_ShowDebug(sql_handle);
Sql_FreeResult(sql_handle);
- //TODO: perhaps add some reply? (otherwise it hangs the client)
+ WFIFOHEAD(fd,3);
+ WFIFOW(fd,0) = 0x6c;
+ WFIFOB(fd,2) = 0; // rejected from server
+ WFIFOSET(fd,3);
break;
}
@@ -3097,8 +3100,8 @@ int parse_char(int fd)
mmo_char_fromsql(char_id, &char_dat, true);
//Have to switch over to the DB instance otherwise data won't propagate [Kevin]
- cp = (struct mmo_charstatus *)idb_get(char_db_, char_id);
- cp->sex = sd->sex;
+ cd = (struct mmo_charstatus *)idb_get(char_db_, char_id);
+ cd->sex = sd->sex;
if (log_char) {
char esc_name[NAME_LENGTH*2+1];
@@ -3111,7 +3114,7 @@ int parse_char(int fd)
ShowInfo("Selected char: (Account %d: %d - %s)\n", sd->account_id, slot, char_dat.name);
// searching map server
- i = search_mapserver(char_dat.last_point.map, -1, -1);
+ i = search_mapserver(cd->last_point.map, -1, -1);
// if map is not found, we check major cities
if (i < 0) {
@@ -3127,33 +3130,33 @@ int parse_char(int fd)
break;
}
if ((i = search_mapserver((j=mapindex_name2id(MAP_PRONTERA)),-1,-1)) >= 0) {
- cp->last_point.x = 273;
- cp->last_point.y = 354;
+ cd->last_point.x = 273;
+ cd->last_point.y = 354;
} else if ((i = search_mapserver((j=mapindex_name2id(MAP_GEFFEN)),-1,-1)) >= 0) {
- cp->last_point.x = 120;
- cp->last_point.y = 100;
+ cd->last_point.x = 120;
+ cd->last_point.y = 100;
} else if ((i = search_mapserver((j=mapindex_name2id(MAP_MORROC)),-1,-1)) >= 0) {
- cp->last_point.x = 160;
- cp->last_point.y = 94;
+ cd->last_point.x = 160;
+ cd->last_point.y = 94;
} else if ((i = search_mapserver((j=mapindex_name2id(MAP_ALBERTA)),-1,-1)) >= 0) {
- cp->last_point.x = 116;
- cp->last_point.y = 57;
+ cd->last_point.x = 116;
+ cd->last_point.y = 57;
} else if ((i = search_mapserver((j=mapindex_name2id(MAP_PAYON)),-1,-1)) >= 0) {
- cp->last_point.x = 87;
- cp->last_point.y = 117;
+ cd->last_point.x = 87;
+ cd->last_point.y = 117;
} else if ((i = search_mapserver((j=mapindex_name2id(MAP_IZLUDE)),-1,-1)) >= 0) {
- cp->last_point.x = 94;
- cp->last_point.y = 103;
+ cd->last_point.x = 94;
+ cd->last_point.y = 103;
} else {
- ShowInfo("Connection Closed. No map server available that has a major city, and unable to find map-server for '%s'.\n", mapindex_id2name(char_dat.last_point.map));
+ ShowInfo("Connection Closed. No map server available that has a major city, and unable to find map-server for '%s'.\n", mapindex_id2name(cd->last_point.map));
WFIFOHEAD(fd,3);
WFIFOW(fd,0) = 0x81;
WFIFOB(fd,2) = 1; // 01 = Server closed
WFIFOSET(fd,3);
break;
}
- ShowWarning("Unable to find map-server for '%s', sending to major city '%s'.\n", mapindex_id2name(char_dat.last_point.map), mapindex_id2name(j));
- cp->last_point.map = j;
+ ShowWarning("Unable to find map-server for '%s', sending to major city '%s'.\n", mapindex_id2name(cd->last_point.map), mapindex_id2name(j));
+ cd->last_point.map = j;
}
//Send NEW auth packet [Kevin]
@@ -3174,9 +3177,9 @@ int parse_char(int fd)
//Send player to map
WFIFOHEAD(fd,28);
WFIFOW(fd,0) = 0x71;
- WFIFOL(fd,2) = cp->char_id;
- mapindex_getmapname_ext(mapindex_id2name(cp->last_point.map), (char*)WFIFOP(fd,6));
- subnet_map_ip = lan_subnetcheck(ipl);
+ WFIFOL(fd,2) = cd->char_id;
+ mapindex_getmapname_ext(mapindex_id2name(cd->last_point.map), (char*)WFIFOP(fd,6));
+ subnet_map_ip = lan_subnetcheck(ipl); // Advanced subnet check [LuzZza]
WFIFOL(fd,22) = htonl((subnet_map_ip) ? subnet_map_ip : server[i].ip);
WFIFOW(fd,26) = ntows(htons(server[i].port)); // [!] LE byte order here [!]
WFIFOSET(fd,28);
@@ -3184,7 +3187,7 @@ int parse_char(int fd)
// create temporary auth entry
CREATE(node, struct auth_node, 1);
node->account_id = sd->account_id;
- node->char_id = cp->char_id;
+ node->char_id = cd->char_id;
node->login_id1 = sd->login_id1;
node->login_id2 = sd->login_id2;
node->sex = sd->sex;
@@ -3219,8 +3222,6 @@ int parse_char(int fd)
case -3: WFIFOB(fd,2) = 0x01; break;
}
WFIFOSET(fd,3);
- RFIFOSKIP(fd,37);
- break;
}
else
{
@@ -3253,7 +3254,6 @@ int parse_char(int fd)
{
int cid = RFIFOL(fd,2);
- WFIFOHEAD(fd,46);
ShowInfo(CL_RED"Request Char Deletion: "CL_GREEN"%d (%d)"CL_RESET"\n", sd->account_id, cid);
memcpy(email, RFIFOP(fd,6), 40);
RFIFOSKIP(fd,RFIFOREST(fd)); // hack to make the other deletion packet work
@@ -3270,7 +3270,7 @@ int parse_char(int fd)
WFIFOSET(fd,3);
break;
}
-
+
// check if this char exists
ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
if( i == MAX_CHARS )
@@ -3313,7 +3313,7 @@ int parse_char(int fd)
break;
// char rename request
- // R 028d <account ID>.l <char ID>.l <new name>.24B
+ // R 028d <account ID>.l <char ID>.l <new name>.24B
case 0x28d:
FIFOSD_CHECK(34);
{
@@ -3393,7 +3393,7 @@ int parse_char(int fd)
RFIFOSKIP(fd,32);
break;
- // log in as map-server
+ // login as map-server
case 0x2af8:
if (RFIFOREST(fd) < 60)
return 0;
@@ -3424,7 +3424,7 @@ int parse_char(int fd)
realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
char_mapif_init(fd);
}
-
+
RFIFOSKIP(fd,60);
}
return 0; // avoid processing of followup packets here
@@ -3487,7 +3487,6 @@ int parse_console(char* buf)
return 0;
}
-// MAP send all
int mapif_sendall(unsigned char *buf, unsigned int len)
{
int i, c;
@@ -3665,7 +3664,7 @@ static int online_data_cleanup_sub(DBKey key, void *data, va_list ap)
{
struct online_char_data *character= (struct online_char_data*)data;
if (character->fd != -1)
- return 0; //Still connected
+ return 0; //Character still connected
if (character->server == -2) //Unknown server.. set them offline
set_char_offline(character->char_id, character->account_id);
if (character->server < 0)
@@ -3758,59 +3757,55 @@ void sql_config_read(const char* cfgName)
continue;
if(!strcmpi(w1,"char_db"))
- strcpy(char_db,w2);
+ safestrncpy(char_db, w2, sizeof(char_db));
else if(!strcmpi(w1,"scdata_db"))
- strcpy(scdata_db,w2);
+ safestrncpy(scdata_db, w2, sizeof(scdata_db));
else if(!strcmpi(w1,"cart_db"))
- strcpy(cart_db,w2);
+ safestrncpy(cart_db, w2, sizeof(cart_db));
else if(!strcmpi(w1,"inventory_db"))
- strcpy(inventory_db, w2);
+ safestrncpy(inventory_db, w2, sizeof(inventory_db));
else if(!strcmpi(w1,"charlog_db"))
- strcpy(charlog_db,w2);
+ safestrncpy(charlog_db, w2, sizeof(charlog_db));
else if(!strcmpi(w1,"storage_db"))
- strcpy(storage_db,w2);
+ safestrncpy(storage_db, w2, sizeof(storage_db));
else if(!strcmpi(w1,"reg_db"))
- strcpy(reg_db,w2);
+ safestrncpy(reg_db, w2, sizeof(reg_db));
else if(!strcmpi(w1,"skill_db"))
- strcpy(skill_db,w2);
+ safestrncpy(skill_db, w2, sizeof(skill_db));
else if(!strcmpi(w1,"interlog_db"))
- strcpy(interlog_db,w2);
+ safestrncpy(interlog_db, w2, sizeof(interlog_db));
else if(!strcmpi(w1,"memo_db"))
- strcpy(memo_db,w2);
+ safestrncpy(memo_db, w2, sizeof(memo_db));
else if(!strcmpi(w1,"guild_db"))
- strcpy(guild_db,w2);
+ safestrncpy(guild_db, w2, sizeof(guild_db));
else if(!strcmpi(w1,"guild_alliance_db"))
- strcpy(guild_alliance_db,w2);
+ safestrncpy(guild_alliance_db, w2, sizeof(guild_alliance_db));
else if(!strcmpi(w1,"guild_castle_db"))
- strcpy(guild_castle_db,w2);
+ safestrncpy(guild_castle_db, w2, sizeof(guild_castle_db));
else if(!strcmpi(w1,"guild_expulsion_db"))
- strcpy(guild_expulsion_db,w2);
+ safestrncpy(guild_expulsion_db, w2, sizeof(guild_expulsion_db));
else if(!strcmpi(w1,"guild_member_db"))
- strcpy(guild_member_db,w2);
+ safestrncpy(guild_member_db, w2, sizeof(guild_member_db));
else if(!strcmpi(w1,"guild_skill_db"))
- strcpy(guild_skill_db,w2);
+ safestrncpy(guild_skill_db, w2, sizeof(guild_skill_db));
else if(!strcmpi(w1,"guild_position_db"))
- strcpy(guild_position_db,w2);
+ safestrncpy(guild_position_db, w2, sizeof(guild_position_db));
else if(!strcmpi(w1,"guild_storage_db"))
- strcpy(guild_storage_db,w2);
+ safestrncpy(guild_storage_db, w2, sizeof(guild_storage_db));
else if(!strcmpi(w1,"party_db"))
- strcpy(party_db,w2);
+ safestrncpy(party_db, w2, sizeof(party_db));
else if(!strcmpi(w1,"pet_db"))
- strcpy(pet_db,w2);
+ safestrncpy(pet_db, w2, sizeof(pet_db));
else if(!strcmpi(w1,"mail_db"))
- strcpy(mail_db,w2);
+ safestrncpy(mail_db, w2, sizeof(mail_db));
else if(!strcmpi(w1,"auction_db"))
- strcpy(auction_db,w2);
+ safestrncpy(auction_db, w2, sizeof(auction_db));
else if(!strcmpi(w1,"friend_db"))
- strcpy(friend_db,w2);
+ safestrncpy(friend_db, w2, sizeof(friend_db));
else if(!strcmpi(w1,"hotkey_db"))
- strcpy(hotkey_db,w2);
+ safestrncpy(hotkey_db, w2, sizeof(hotkey_db));
else if(!strcmpi(w1,"quest_db"))
- strcpy(quest_db,w2);
-#ifndef TXT_SQL_CONVERT
- else if(!strcmpi(w1,"db_path"))
- strcpy(db_path,w2);
-#endif
+ safestrncpy(quest_db,w2,sizeof(quest_db));
//support the import command, just like any other config
else if(!strcmpi(w1,"import"))
sql_config_read(w2);
@@ -3842,30 +3837,28 @@ int char_config_read(const char* cfgName)
remove_control_chars(w1);
remove_control_chars(w2);
if(strcmpi(w1,"timestamp_format") == 0) {
- strncpy(timestamp_format, w2, 20);
+ safestrncpy(timestamp_format, w2, sizeof(timestamp_format));
} else if(strcmpi(w1,"console_silent")==0){
ShowInfo("Console Silent Setting: %d\n", atoi(w2));
msg_silent = atoi(w2);
} else if(strcmpi(w1,"stdout_with_ansisequence")==0){
stdout_with_ansisequence = config_switch(w2);
} else if (strcmpi(w1, "userid") == 0) {
- strncpy(userid, w2, 24);
+ safestrncpy(userid, w2, sizeof(userid));
} else if (strcmpi(w1, "passwd") == 0) {
- strncpy(passwd, w2, 24);
+ safestrncpy(passwd, w2, sizeof(passwd));
} else if (strcmpi(w1, "server_name") == 0) {
- strncpy(server_name, w2, 20);
- server_name[sizeof(server_name) - 1] = '\0';
+ safestrncpy(server_name, w2, sizeof(server_name));
ShowStatus("%s server has been initialized\n", w2);
} else if (strcmpi(w1, "wisp_server_name") == 0) {
if (strlen(w2) >= 4) {
- memcpy(wisp_server_name, w2, sizeof(wisp_server_name));
- wisp_server_name[sizeof(wisp_server_name) - 1] = '\0';
+ safestrncpy(wisp_server_name, w2, sizeof(wisp_server_name));
}
} else if (strcmpi(w1, "login_ip") == 0) {
char ip_str[16];
login_ip = host2ip(w2);
if (login_ip) {
- strncpy(login_ip_str, w2, sizeof(login_ip_str));
+ safestrncpy(login_ip_str, w2, sizeof(login_ip_str));
ShowStatus("Login server IP address : %s -> %s\n", w2, ip2str(login_ip, ip_str));
}
} else if (strcmpi(w1, "login_port") == 0) {
@@ -3874,14 +3867,14 @@ int char_config_read(const char* cfgName)
char ip_str[16];
char_ip = host2ip(w2);
if (char_ip){
- strncpy(char_ip_str, w2, sizeof(char_ip_str));
+ safestrncpy(char_ip_str, w2, sizeof(char_ip_str));
ShowStatus("Character server IP address : %s -> %s\n", w2, ip2str(char_ip, ip_str));
}
} else if (strcmpi(w1, "bind_ip") == 0) {
char ip_str[16];
bind_ip = host2ip(w2);
if (bind_ip) {
- strncpy(bind_ip_str, w2, sizeof(bind_ip_str));
+ safestrncpy(bind_ip_str, w2, sizeof(bind_ip_str));
ShowStatus("Character server binding IP address : %s -> %s\n", w2, ip2str(bind_ip, ip_str));
}
} else if (strcmpi(w1, "char_port") == 0) {
@@ -3931,18 +3924,20 @@ int char_config_read(const char* cfgName)
} else if(strcmpi(w1,"log_char")==0) { //log char or not [devil]
log_char = atoi(w2);
} else if (strcmpi(w1, "unknown_char_name") == 0) {
- strcpy(unknown_char_name, w2);
+ safestrncpy(unknown_char_name, w2, sizeof(unknown_char_name));
unknown_char_name[NAME_LENGTH-1] = '\0';
} else if (strcmpi(w1, "name_ignoring_case") == 0) {
- name_ignoring_case = config_switch(w2);
+ name_ignoring_case = (bool)config_switch(w2);
} else if (strcmpi(w1, "char_name_option") == 0) {
char_name_option = atoi(w2);
} else if (strcmpi(w1, "char_name_letters") == 0) {
- strcpy(char_name_letters, w2);
+ safestrncpy(char_name_letters, w2, sizeof(char_name_letters));
} else if (strcmpi(w1, "chars_per_account") == 0) { //maxchars per account [Sirius]
char_per_account = atoi(w2);
} else if (strcmpi(w1, "char_del_level") == 0) { //disable/enable char deletion by its level condition [Lupus]
char_del_level = atoi(w2);
+ } else if(strcmpi(w1,"db_path")==0) {
+ safestrncpy(db_path, w2, sizeof(db_path));
} else if (strcmpi(w1, "console") == 0) {
console = config_switch(w2);
} else if (strcmpi(w1, "fame_list_alchemist") == 0) {
@@ -3970,16 +3965,14 @@ int char_config_read(const char* cfgName)
}
}
fclose(fp);
-
+
ShowInfo("Done reading %s.\n", cfgName);
return 0;
}
void do_final(void)
{
- ShowInfo("Doing final stage...\n");
- //check SQL save progress.
- //wait until save char complete
+ ShowStatus("Terminating server.\n");
set_all_offline(-1);
set_all_offline_sql();
@@ -3988,22 +3981,20 @@ void do_final(void)
flush_fifos();
- mapindex_final();
-
if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `ragsrvinfo`") )
Sql_ShowDebug(sql_handle);
+ char_db_->destroy(char_db_, NULL);
+ online_char_db->destroy(online_char_db, NULL);
+ auth_db->destroy(auth_db, NULL);
+
if (login_fd > 0)
do_close(login_fd);
if (char_fd > 0)
do_close(char_fd);
- char_db_->destroy(char_db_, NULL);
- online_char_db->destroy(online_char_db, NULL);
- auth_db->destroy(auth_db, NULL);
Sql_Free(sql_handle);
-
- ShowInfo("ok! all done...\n");
+ mapindex_final();
}
//------------------------------
@@ -4031,7 +4022,7 @@ int do_init(int argc, char **argv)
//Read map indexes
mapindex_init();
start_point.map = mapindex_name2id("new_zone01");
-
+
char_config_read((argc < 2) ? CHAR_CONF_NAME : argv[1]);
char_lan_config_read((argc > 3) ? argv[3] : LAN_CONF_NAME);
sql_config_read(SQL_CONF_NAME);
@@ -4041,7 +4032,7 @@ int do_init(int argc, char **argv)
ShowNotice("Please edit your 'login' table to create a proper inter-server user/password (gender 'S')\n");
ShowNotice("And then change the user/password to use in conf/char_athena.conf (or conf/import/char_conf.txt)\n");
}
-
+
ShowInfo("Finished reading the char-server configuration.\n");
inter_init_sql((argc > 2) ? argv[2] : inter_cfgName); // inter server テハア篳ュ
@@ -4066,11 +4057,11 @@ int do_init(int argc, char **argv)
else
ShowStatus("Defaulting to %s as our IP address\n", ip_str);
if (!login_ip) {
- strcpy(login_ip_str, ip_str);
+ safestrncpy(login_ip_str, ip_str, sizeof(login_ip_str));
login_ip = str2ip(login_ip_str);
}
if (!char_ip) {
- strcpy(char_ip_str, ip_str);
+ safestrncpy(char_ip_str, ip_str, sizeof(char_ip_str));
char_ip = str2ip(char_ip_str);
}
}
@@ -4089,7 +4080,7 @@ int do_init(int argc, char **argv)
// send a list of all online account IDs to login server
add_timer_func_list(send_accounts_tologin, "send_accounts_tologin");
- add_timer_interval(gettick() + 1000, send_accounts_tologin, 0, 0, 3600 * 1000); //Sync online accounts every hour.
+ add_timer_interval(gettick() + 1000, send_accounts_tologin, 0, 0, 3600 * 1000); //Sync online accounts every hour
// ???
add_timer_func_list(chardb_waiting_disconnect, "chardb_waiting_disconnect");
diff --git a/src/char_sql/int_guild.c b/src/char_sql/int_guild.c
index 00331e8e6..0b3d77f07 100644
--- a/src/char_sql/int_guild.c
+++ b/src/char_sql/int_guild.c
@@ -1131,8 +1131,8 @@ int mapif_guild_notice(struct guild *g)
unsigned char buf[256];
WBUFW(buf,0)=0x383e;
WBUFL(buf,2)=g->guild_id;
- memcpy(WBUFP(buf,6),g->mes1,60);
- memcpy(WBUFP(buf,66),g->mes2,120);
+ memcpy(WBUFP(buf,6),g->mes1,MAX_GUILDMES1);
+ memcpy(WBUFP(buf,66),g->mes2,MAX_GUILDMES2);
mapif_sendall(buf,186);
return 0;
}
@@ -1826,8 +1826,8 @@ int mapif_parse_GuildNotice(int fd,int guild_id,const char *mes1,const char *mes
if(g==NULL)
return 0;
- memcpy(g->mes1,mes1,60);
- memcpy(g->mes2,mes2,120);
+ memcpy(g->mes1,mes1,MAX_GUILDMES1);
+ memcpy(g->mes2,mes2,MAX_GUILDMES2);
g->save_flag |= GS_MES; //Change mes of guild
return mapif_guild_notice(g);
}
diff --git a/src/char_sql/int_storage.c b/src/char_sql/int_storage.c
index 7cab6d5d9..0719685ae 100644
--- a/src/char_sql/int_storage.c
+++ b/src/char_sql/int_storage.c
@@ -76,7 +76,7 @@ int storage_fromsql(int account_id, struct storage_data* p)
/// Save guild_storage data to sql
int guild_storage_tosql(int guild_id, struct guild_storage* p)
{
- memitemdata_to_sql(p->storage_, MAX_GUILD_STORAGE, guild_id, TABLE_GUILD_STORAGE);
+ memitemdata_to_sql(p->items, MAX_GUILD_STORAGE, guild_id, TABLE_GUILD_STORAGE);
ShowInfo ("guild storage save to DB - guild: %d\n", guild_id);
return 0;
}
@@ -109,7 +109,7 @@ int guild_storage_fromsql(int guild_id, struct guild_storage* p)
for( i = 0; i < MAX_GUILD_STORAGE && SQL_SUCCESS == Sql_NextRow(sql_handle); ++i )
{
- item = &p->storage_[i];
+ item = &p->items[i];
Sql_GetData(sql_handle, 0, &data, NULL); item->id = atoi(data);
Sql_GetData(sql_handle, 1, &data, NULL); item->nameid = atoi(data);
Sql_GetData(sql_handle, 2, &data, NULL); item->amount = atoi(data);
diff --git a/src/char_sql/inter.c b/src/char_sql/inter.c
index 2f5c2daff..97c48bdf1 100644
--- a/src/char_sql/inter.c
+++ b/src/char_sql/inter.c
@@ -235,7 +235,7 @@ static int inter_config_read(const char* cfgName)
else if(!strcmpi(w1,"log_inter"))
log_inter = atoi(w2);
else if(!strcmpi(w1,"main_chat_nick"))
- strcpy(main_chat_nick, w2);
+ safestrncpy(main_chat_nick, w2, sizeof(main_chat_nick));
#endif //TXT_SQL_CONVERT
else if(!strcmpi(w1,"import"))
inter_config_read(w2);
diff --git a/src/common/lock.c b/src/common/lock.c
index 5cb4c3a67..643b86e5c 100644
--- a/src/common/lock.c
+++ b/src/common/lock.c
@@ -1,8 +1,9 @@
// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
// For more information, see LICENCE in the main folder
-#include "../common/cbasetypes.h"
-#include "../common/showmsg.h"
+#include "cbasetypes.h"
+#include "showmsg.h"
+#include "utils.h"
#include "lock.h"
#include <stdio.h>
@@ -12,12 +13,8 @@
#include <unistd.h>
#else
#include <io.h>
-#define F_OK 0x0
-#define R_OK 0x4
#endif
-#define exists(filename) (!access(filename, F_OK))
-
// 書き込みファイルの保護処理
// (書き込みが終わるまで、旧ファイルを保管しておく)
diff --git a/src/common/mmo.h b/src/common/mmo.h
index 6a78d840c..92adf8af0 100644
--- a/src/common/mmo.h
+++ b/src/common/mmo.h
@@ -108,13 +108,6 @@
#define MAX_QUEST_DB 2000 //Max quests that the server will load
#define MAX_QUEST_OBJECTIVES 3 //Max quest objectives for a quest
-#define MIN_HAIR_STYLE battle_config.min_hair_style
-#define MAX_HAIR_STYLE battle_config.max_hair_style
-#define MIN_HAIR_COLOR battle_config.min_hair_color
-#define MAX_HAIR_COLOR battle_config.max_hair_color
-#define MIN_CLOTH_COLOR battle_config.min_cloth_color
-#define MAX_CLOTH_COLOR battle_config.max_cloth_color
-
// for produce
#define MIN_ATTRIBUTE 0
#define MAX_ATTRIBUTE 4
@@ -147,6 +140,10 @@
#define END_ACCOUNT_NUM 100000000
#define START_CHAR_NUM 150000
+//Guilds
+#define MAX_GUILDMES1 60
+#define MAX_GUILDMES2 120
+
//Base Homun skill.
#define HM_SKILLBASE 8001
#define MAX_HOMUNSKILL 16
@@ -177,6 +174,7 @@ enum item_types {
IT_UNKNOWN2,//9
IT_AMMO, //10
IT_DELAYCONSUME,//11
+ IT_CASH = 18,
IT_MAX
};
@@ -240,7 +238,7 @@ struct guild_storage {
int guild_id;
short storage_status;
short storage_amount;
- struct item storage_[MAX_GUILD_STORAGE];
+ struct item items[MAX_GUILD_STORAGE];
};
struct s_pet {
@@ -474,7 +472,7 @@ struct guild {
char name[NAME_LENGTH],master[NAME_LENGTH];
struct guild_member member[MAX_GUILD];
struct guild_position position[MAX_GUILDPOSITION];
- char mes1[60],mes2[120];
+ char mes1[MAX_GUILDMES1],mes2[MAX_GUILDMES2];
int emblem_len,emblem_id;
char emblem_data[2048];
struct guild_alliance alliance[MAX_GUILDALLIANCE];
diff --git a/src/common/socket.c b/src/common/socket.c
index deba0e97b..89c605c9d 100644
--- a/src/common/socket.c
+++ b/src/common/socket.c
@@ -199,6 +199,10 @@ time_t stall_time = 60;
uint32 addr_[16]; // ip addresses of local host (host byte order)
int naddr_ = 0; // # of ip addresses
+// Maximum packet size in bytes, which the client is able to handle.
+// Larger packets cause a buffer overflow and stack corruption.
+static size_t socket_max_client_packet = 20480;
+
// initial recv buffer size (this will also be the max. size)
// biggest known packet: S 0153 <len>.w <emblem data>.?B -> 24x24 256 color .bmp (0153 + len.w + 1618/1654/1756 bytes)
#define RFIFO_SIZE (2*1024)
@@ -643,8 +647,15 @@ int WFIFOSET(int fd, size_t len)
exit(EXIT_FAILURE);
}
+ if( !s->flag.server && len > socket_max_client_packet )
+ {// see declaration of socket_max_client_packet for details
+ ShowError("WFIFOSET: Dropped too large client packet 0x%04x (length=%u, max=%u).\n", WFIFOW(fd,0), len, socket_max_client_packet);
+ return 0;
+ }
+
if( !s->flag.server && s->wdata_size+len > WFIFO_MAX )
{// reached maximum write fifo size
+ ShowError("WFIFOSET: Maximum write buffer size for client connection %d exceeded, most likely caused by packet 0x%04x (len=%u, ip=%lu.%lu.%lu.%lu).\n", fd, WFIFOW(fd,0), len, CONVIP(s->client_addr));
set_eof(fd);
return 0;
}
@@ -1064,6 +1075,8 @@ int socket_config_read(const char* cfgName)
ddos_autoreset = atoi(w2);
else if (!strcmpi(w1,"debug"))
access_debug = config_switch(w2);
+ else if (!strcmpi(w1,"socket_max_client_packet"))
+ socket_max_client_packet = strtoul(w2, NULL, 0);
#endif
else if (!strcmpi(w1, "import"))
socket_config_read(w2);
diff --git a/src/common/strlib.c b/src/common/strlib.c
index 7a6c134e7..019e2d629 100644
--- a/src/common/strlib.c
+++ b/src/common/strlib.c
@@ -12,7 +12,6 @@
#include <errno.h>
-
#define J_MAX_MALLOC_SIZE 65535
// escapes a string in-place (' -> \' , \ -> \\ , % -> _)
@@ -657,7 +656,7 @@ int sv_split(char* str, int len, int startoff, char delim, char** out_fields, in
end[0] = end[1] = '\0';
*out_fields = end + 2;
}
- else if( (opt&SV_TERMINATE_LF) && end[0] == '\r' )
+ else if( (opt&SV_TERMINATE_CR) && end[0] == '\r' )
{
if( !(opt&SV_KEEP_TERMINATOR) )
end[0] = '\0';
@@ -923,18 +922,12 @@ bool sv_readdb(const char* directory, const char* filename, char delim, int minc
FILE* fp;
int lines = 0;
int entries = 0;
- char* fields[64]; // room for 63 fields ([0] is reserved)
- int columns;
+ char** fields; // buffer for fields ([0] is reserved)
+ int columns, fields_length;
char path[1024], line[1024];
snprintf(path, sizeof(path), "%s/%s", directory, filename);
- if( maxcols > ARRAYLENGTH(fields)-1 )
- {
- ShowError("sv_readdb: Insufficient column storage in parser for file \"%s\" (want %d, have only %d). Increase the capacity in the source code please.\n", path, maxcols, ARRAYLENGTH(fields)-1);
- return false;
- }
-
// open file
fp = fopen(path, "r");
if( fp == NULL )
@@ -943,6 +936,10 @@ bool sv_readdb(const char* directory, const char* filename, char delim, int minc
return false;
}
+ // allocate enough memory for the maximum requested amount of columns plus the reserved one
+ fields_length = maxcols+1;
+ fields = aMalloc(fields_length*sizeof(char*));
+
// process rows one by one
while( fgets(line, sizeof(line), fp) )
{
@@ -954,7 +951,7 @@ bool sv_readdb(const char* directory, const char* filename, char delim, int minc
if( line[0] == '\0' || line[0] == '\n' || line[0] == '\r')
continue;
- columns = sv_split(line, strlen(line), 0, delim, fields, ARRAYLENGTH(fields), (e_svopt)(SV_TERMINATE_LF|SV_TERMINATE_CRLF));
+ columns = sv_split(line, strlen(line), 0, delim, fields, fields_length, (e_svopt)(SV_TERMINATE_LF|SV_TERMINATE_CRLF));
if( columns < mincols )
{
@@ -983,6 +980,7 @@ bool sv_readdb(const char* directory, const char* filename, char delim, int minc
entries++;
}
+ aFree(fields);
fclose(fp);
ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", entries, path);
diff --git a/src/common/utils.c b/src/common/utils.c
index c1128edb4..12123784f 100644
--- a/src/common/utils.c
+++ b/src/common/utils.c
@@ -14,7 +14,11 @@
#include <math.h> // floor()
#ifdef WIN32
+ #include <io.h>
#include <windows.h>
+ #ifndef F_OK
+ #define F_OK 0x0
+ #endif /* F_OK */
#else
#include <unistd.h>
#include <dirent.h>
@@ -182,6 +186,11 @@ void findfile(const char *p, const char *pat, void (func)(const char*))
}
#endif
+bool exists(const char* filename)
+{
+ return !access(filename, F_OK);
+}
+
uint8 GetByte(uint32 val, int idx)
{
switch( idx )
diff --git a/src/common/utils.h b/src/common/utils.h
index 93563dc34..5cf3ff3cf 100644
--- a/src/common/utils.h
+++ b/src/common/utils.h
@@ -14,6 +14,7 @@
void dump(FILE* fp, const unsigned char* buffer, int length);
void findfile(const char *p, const char *pat, void (func)(const char*));
+bool exists(const char* filename);
//Caps values to min/max
#define cap_value(a, min, max) ((a >= max) ? max : (a <= min) ? min : a)
diff --git a/src/ladmin/ladmin.c b/src/ladmin/ladmin.c
index 3f02a240a..d7a78c119 100644
--- a/src/ladmin/ladmin.c
+++ b/src/ladmin/ladmin.c
@@ -261,7 +261,7 @@ int ladmin_log(char *fmt, ...)
}
//---------------------------------------------
-// Function to return ordonal text of a number.
+// Function to return ordinal text of a number.
//---------------------------------------------
char* makeordinal(int number)
{
@@ -275,7 +275,6 @@ char* makeordinal(int number)
} else {
return "th";
}
- return "";
}
//-----------------------------------------------------------------------------------------
diff --git a/src/login/login.c b/src/login/login.c
index e888d21f6..6b3a1bcaf 100644
--- a/src/login/login.c
+++ b/src/login/login.c
@@ -402,7 +402,7 @@ int parse_fromchar(int fd)
uint32 login_id1 = RFIFOL(fd,6);
uint32 login_id2 = RFIFOL(fd,10);
uint8 sex = RFIFOB(fd,14);
- uint32 ip_ = ntohl(RFIFOL(fd,15));
+ //uint32 ip_ = ntohl(RFIFOL(fd,15));
int request_id = RFIFOL(fd,19);
RFIFOSKIP(fd,23);
diff --git a/src/map/atcommand.c b/src/map/atcommand.c
index d48dda0db..95b3dc33e 100644
--- a/src/map/atcommand.c
+++ b/src/map/atcommand.c
@@ -452,7 +452,7 @@ ACMD_FUNC(mapmove)
clif_displaymessage(fd, msg_txt(248));
return -1;
}
- if (pc_setpos(sd, mapindex, x, y, 3) != 0) {
+ if (pc_setpos(sd, mapindex, x, y, CLR_TELEPORT) != 0) {
clif_displaymessage(fd, msg_txt(1)); // Map not found.
return -1;
}
@@ -535,7 +535,7 @@ ACMD_FUNC(jumpto)
return -1;
}
- pc_setpos(sd, pl_sd->mapindex, pl_sd->bl.x, pl_sd->bl.y, 3);
+ pc_setpos(sd, pl_sd->mapindex, pl_sd->bl.x, pl_sd->bl.y, CLR_TELEPORT);
sprintf(atcmd_output, msg_txt(4), pl_sd->status.name); // Jumped to %s
clif_displaymessage(fd, atcmd_output);
@@ -572,7 +572,7 @@ ACMD_FUNC(jump)
x = y = 0; //Invalid cell, use random spot.
}
- pc_setpos(sd, sd->mapindex, x, y, 3);
+ pc_setpos(sd, sd->mapindex, x, y, CLR_TELEPORT);
sprintf(atcmd_output, msg_txt(5), sd->bl.x, sd->bl.y); // Jumped to %d %d
clif_displaymessage(fd, atcmd_output);
return 0;
@@ -1114,7 +1114,7 @@ ACMD_FUNC(load)
return -1;
}
- pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, 0);
+ pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, CLR_OUTSIGHT);
clif_displaymessage(fd, msg_txt(7)); // Warping to save point..
return 0;
@@ -1663,15 +1663,15 @@ ACMD_FUNC(item2)
if (item_id > 500) {
loop = 1;
get_count = number;
- if (item_data->type == 4 || item_data->type == 5 ||
- item_data->type == 7 || item_data->type == 8) {
+ if (item_data->type == IT_WEAPON || item_data->type == IT_ARMOR ||
+ item_data->type == IT_PETEGG || item_data->type == IT_PETARMOR) {
loop = number;
get_count = 1;
- if (item_data->type == 7) {
+ if (item_data->type == IT_PETEGG) {
identify = 1;
refine = 0;
}
- if (item_data->type == 8)
+ if (item_data->type == IT_PETARMOR)
refine = 0;
if (refine > 10)
refine = 10;
@@ -1777,8 +1777,10 @@ ACMD_FUNC(baselevelup)
sd->status.base_level -= (unsigned int)level;
clif_displaymessage(fd, msg_txt(22)); // Base level lowered.
}
+ sd->status.base_exp = 0;
clif_updatestatus(sd, SP_STATUSPOINT);
clif_updatestatus(sd, SP_BASELEVEL);
+ clif_updatestatus(sd, SP_BASEEXP);
clif_updatestatus(sd, SP_NEXTBASEEXP);
status_calc_pc(sd, 0);
if(sd->status.party_id)
@@ -1808,11 +1810,7 @@ ACMD_FUNC(joblevelup)
if ((unsigned int)level > pc_maxjoblv(sd) || (unsigned int)level > pc_maxjoblv(sd) - sd->status.job_level) // fix positiv overflow
level = pc_maxjoblv(sd) - sd->status.job_level;
sd->status.job_level += (unsigned int)level;
- clif_updatestatus(sd, SP_JOBLEVEL);
- clif_updatestatus(sd, SP_NEXTJOBEXP);
sd->status.skill_point += level;
- clif_updatestatus(sd, SP_SKILLPOINT);
- status_calc_pc(sd, 0);
clif_misceffect(&sd->bl, 1);
clif_displaymessage(fd, msg_txt(24)); // Job level raised.
} else {
@@ -1824,18 +1822,20 @@ ACMD_FUNC(joblevelup)
if ((unsigned int)level >= sd->status.job_level) // fix negativ overflow
level = sd->status.job_level-1;
sd->status.job_level -= (unsigned int)level;
- clif_updatestatus(sd, SP_JOBLEVEL);
- clif_updatestatus(sd, SP_NEXTJOBEXP);
if (sd->status.skill_point < level)
pc_resetskill(sd,0); //Reset skills since we need to substract more points.
if (sd->status.skill_point < level)
sd->status.skill_point = 0;
else
sd->status.skill_point -= level;
- clif_updatestatus(sd, SP_SKILLPOINT);
- status_calc_pc(sd, 0);
clif_displaymessage(fd, msg_txt(25)); // Job level lowered.
}
+ sd->status.job_exp = 0;
+ clif_updatestatus(sd, SP_JOBLEVEL);
+ clif_updatestatus(sd, SP_JOBEXP);
+ clif_updatestatus(sd, SP_NEXTJOBEXP);
+ clif_updatestatus(sd, SP_SKILLPOINT);
+ status_calc_pc(sd, 0);
return 0;
}
@@ -2308,7 +2308,7 @@ ACMD_FUNC(go)
clif_displaymessage(fd, msg_txt(248));
return -1;
}
- if (pc_setpos(sd, mapindex_name2id(data[town].map), data[town].x, data[town].y, 3) == 0) {
+ if (pc_setpos(sd, mapindex_name2id(data[town].map), data[town].x, data[town].y, CLR_TELEPORT) == 0) {
clif_displaymessage(fd, msg_txt(0)); // Warped.
} else {
clif_displaymessage(fd, msg_txt(1)); // Map not found.
@@ -3329,7 +3329,7 @@ ACMD_FUNC(recall)
clif_displaymessage(fd, "You are not authorized to warp this player from its actual map.");
return -1;
}
- pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, 2);
+ pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_RESPAWN);
sprintf(atcmd_output, msg_txt(46), pl_sd->status.name); // %s recalled!
clif_displaymessage(fd, atcmd_output);
@@ -3988,7 +3988,7 @@ ACMD_FUNC(recallall)
pc_setstand(pl_sd);
pc_setrestartvalue(pl_sd,1);
}
- pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, 2);
+ pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_RESPAWN);
}
}
}
@@ -4047,7 +4047,7 @@ ACMD_FUNC(guildrecall)
if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd))
count++;
else
- pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, 2);
+ pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_RESPAWN);
}
}
mapit_free(iter);
@@ -4106,7 +4106,7 @@ ACMD_FUNC(partyrecall)
if (pl_sd->bl.m >= 0 && map[pl_sd->bl.m].flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd))
count++;
else
- pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, 2);
+ pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_RESPAWN);
}
}
mapit_free(iter);
@@ -4704,7 +4704,7 @@ ACMD_FUNC(tonpc)
}
if ((nd = npc_name2id(npcname)) != NULL) {
- if (pc_setpos(sd, map_id2index(nd->bl.m), nd->bl.x, nd->bl.y, 3) == 0)
+ if (pc_setpos(sd, map_id2index(nd->bl.m), nd->bl.x, nd->bl.y, CLR_TELEPORT) == 0)
clif_displaymessage(fd, msg_txt(0)); // Warped.
else
return -1;
@@ -5786,7 +5786,7 @@ ACMD_FUNC(skilltree)
ent = &skill_tree[c][j];
meets = 1;
- for(j=0;j<5;j++)
+ for(j=0;j<MAX_PC_SKILL_REQUIRE;j++)
{
if( ent->need[j].id && pc_checkskill(sd,ent->need[j].id) < ent->need[j].lv)
{
@@ -6352,7 +6352,7 @@ ACMD_FUNC(mobsearch)
clif_displaymessage(fd, atcmd_output);
it = mapit_geteachmob();
- while( true )
+ for(;;)
{
TBL_MOB* md = (TBL_MOB*)mapit_next(it);
if( md == NULL )
@@ -6502,7 +6502,7 @@ ACMD_FUNC(users)
// count users on each map
iter = mapit_getallusers();
- while( true )
+ for(;;)
{
struct map_session_data* sd2 = (struct map_session_data*)mapit_next(iter);
if( sd2 == NULL )
@@ -6585,7 +6585,7 @@ ACMD_FUNC(summon)
md->master_id=sd->bl.id;
md->special_state.ai=1;
md->deletetimer=add_timer(tick+(duration*60000),mob_timer_delete,md->bl.id,0);
- clif_misceffect2(&md->bl,344);
+ clif_specialeffect(&md->bl,344,AREA);
mob_spawn(md);
sc_start4(&md->bl, SC_MODECHANGE, 100, 1, 0, MD_AGGRESSIVE, 0, 60000);
clif_skill_poseffect(&sd->bl,AM_CALLHOMUN,1,md->bl.x,md->bl.y,tick);
@@ -6862,26 +6862,36 @@ ACMD_FUNC(identify)
*------------------------------------------*/
ACMD_FUNC(gmotd)
{
- char buf[CHAT_SIZE_MAX];
- FILE *fp;
- nullpo_retr(-1, sd);
- if((fp = fopen(motd_txt, "r"))!=NULL){
- while(fgets(buf, sizeof(buf), fp) != NULL)
+ char buf[CHAT_SIZE_MAX];
+ size_t len;
+ FILE* fp;
+
+ if( ( fp = fopen(motd_txt, "r") ) != NULL )
+ {
+ while( fgets(buf, sizeof(buf), fp) )
+ {
+ if( buf[0] == '/' && buf[1] == '/' )
{
- int i;
- if (buf[0] == '/' && buf[1] == '/')
- continue;
- for(i=0; buf[i]; i++){
- if(buf[i]=='\r' || buf[i]=='\n'){
- buf[i]=0;
- break;
- }
- }
- intif_broadcast(buf, strlen(buf)+1, 0);
+ continue;
+ }
+
+ len = strlen(buf);
+
+ while( len && ( buf[len-1] == '\r' || buf[len-1] == '\n' ) )
+ {// strip trailing EOL characters
+ len--;
+ }
+
+ if( len )
+ {
+ buf[len] = 0;
+
+ intif_broadcast(buf, len+1, 0);
}
- fclose(fp);
}
- return 0;
+ fclose(fp);
+ }
+ return 0;
}
ACMD_FUNC(misceffect)
@@ -7071,7 +7081,7 @@ ACMD_FUNC(showmobs)
clif_displaymessage(fd, atcmd_output);
it = mapit_geteachmob();
- while( true )
+ for(;;)
{
TBL_MOB* md = (TBL_MOB*)mapit_next(it);
if( md == NULL )
@@ -7124,7 +7134,7 @@ ACMD_FUNC(homlevel)
}
status_calc_homunculus(hd,0);
status_percent_heal(&hd->bl, 100, 100);
- clif_misceffect2(&hd->bl,568);
+ clif_specialeffect(&hd->bl,568,AREA);
return 0;
}
@@ -7390,9 +7400,6 @@ ACMD_FUNC(homshuffle)
*------------------------------------------*/
ACMD_FUNC(iteminfo)
{
- char *itype[12] = {"Potion/Food", "BUG!", "Usable", "Etc", "Weapon", "Protection", "Card", "Egg", "Pet Acessory", "BUG!", "Arrow"};
- //, "Lure/Scroll"}; No need, type 11 items are converted to type 2 upon loading [Skotlex]
-
struct item_data *item_data, *item_array[MAX_SEARCH];
int i, count = 1;
@@ -7417,20 +7424,20 @@ ACMD_FUNC(iteminfo)
item_data = item_array[i];
sprintf(atcmd_output, "Item: '%s'/'%s'[%d] (%d) Type: %s | Extra Effect: %s",
item_data->name,item_data->jname,item_data->slot,item_data->nameid,
- item_data->type < 12 ? itype[item_data->type] : "BUG!",
+ itemdb_typename(item_data->type),
(item_data->script==NULL)? "None" : "With script"
);
clif_displaymessage(fd, atcmd_output);
- sprintf(atcmd_output, "NPC Buy:%dz%s, Sell:%dz%s | Weight: %.1f ", item_data->value_buy, item_data->flag.value_notdc ? "(No Discount!)":"", item_data->value_sell, item_data->flag.value_notoc ? "(No Overcharge!)":"", item_data->weight/10. );
+ sprintf(atcmd_output, "NPC Buy:%dz, Sell:%dz | Weight: %.1f ", item_data->value_buy, item_data->value_sell, item_data->weight/10. );
clif_displaymessage(fd, atcmd_output);
- if (item_data->maxchance == 10000)
- strcpy(atcmd_output, " - Available in the shops only");
+ if (item_data->maxchance == -1)
+ strcpy(atcmd_output, " - Available in the shops only.");
else if (item_data->maxchance)
sprintf(atcmd_output, " - Maximal monsters drop chance: %02.02f%%", (float)item_data->maxchance / 100 );
else
- strcpy(atcmd_output, " - Monsters don't drop this item");
+ strcpy(atcmd_output, " - Monsters don't drop this item.");
clif_displaymessage(fd, atcmd_output);
}
@@ -7700,7 +7707,7 @@ ACMD_FUNC(size)
size = atoi(message);
if(sd->state.size) {
sd->state.size=0;
- pc_setpos(sd, sd->mapindex, sd->bl.x, sd->bl.y, 3);
+ pc_setpos(sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_TELEPORT);
}
if(size==1) {
@@ -8499,58 +8506,68 @@ ACMD_FUNC(stats)
ACMD_FUNC(delitem)
{
char item_name[100];
- int i, number = 0, item_id, item_position, count;
- struct item_data *item_data;
- char output[CHAT_SIZE_MAX];
+ int nameid, amount = 0, total, idx;
+ struct item_data* id;
nullpo_retr(-1, sd);
- memset(item_name, '\0', sizeof(item_name));
- memset(output, '\0', sizeof(output));
+ if( !message || !*message || ( sscanf(message, "\"%99[^\"]\" %d", item_name, &amount) < 2 && sscanf(message, "%99s %d", item_name, &amount) < 2 ) || amount < 1 )
+ {
+ clif_displaymessage(fd, "Please, enter an item name/id, a quantity and a player name (usage: #delitem <player> <item_name_or_ID> <quantity>).");
+ return -1;
+ }
- if (!message || !*message || (
- sscanf(message, "\"%99[^\"]\" %d", item_name, &number) < 2 &&
- sscanf(message, "%s %d", item_name, &number) < 2
- ) || number < 1) {
- clif_displaymessage(fd, "Please, enter an item name/id, a quantity and a player name (usage: #delitem <item_name_or_ID> <quantity> <player>).");
+ if( ( id = itemdb_searchname(item_name) ) != NULL || ( id = itemdb_exists(atoi(item_name)) ) != NULL )
+ {
+ nameid = id->nameid;
+ }
+ else
+ {
+ clif_displaymessage(fd, msg_txt(19)); // Invalid item ID or name.
return -1;
}
- item_id = 0;
- if ((item_data = itemdb_searchname(item_name)) != NULL ||
- (item_data = itemdb_exists(atoi(item_name))) != NULL)
- item_id = item_data->nameid;
-
- if (item_id > 500) {
- item_position = pc_search_inventory(sd, item_id);
- if (item_position >= 0) {
- count = 0;
- for(i = 0; i < number && item_position >= 0; i++) {
+ total = amount;
- //Logs (A)dmins items [Lupus]
- if(log_config.enable_logs&0x400)
- log_pick_pc(sd, "A", sd->status.inventory[item_position].nameid, -1, &sd->status.inventory[item_position]);
+ // delete items
+ while( amount && ( idx = pc_search_inventory(sd, nameid) ) != -1 )
+ {
+ int delamount = ( amount < sd->status.inventory[idx].amount ) ? amount : sd->status.inventory[idx].amount;
- pc_delitem(sd, item_position, 1, 0, 0);
- count++;
- item_position = pc_search_inventory(sd, item_id); // for next loop
- }
- sprintf(output, msg_txt(113), count); // %d item(s) removed by a GM.
- clif_displaymessage(sd->fd, output);
- if (number == count)
- sprintf(output, msg_txt(114), count); // %d item(s) removed from the player.
- else
- sprintf(output, msg_txt(115), count, count, number); // %d item(s) removed. Player had only %d on %d items.
- clif_displaymessage(fd, output);
- } else {
- clif_displaymessage(fd, msg_txt(116)); // Character does not have the item.
- return -1;
+ if( sd->inventory_data[idx]->type == IT_PETEGG && sd->status.inventory[idx].card[0] == CARD0_PET )
+ {// delete pet
+ intif_delete_petdata(MakeDWord(sd->status.inventory[idx].card[1], sd->status.inventory[idx].card[2]));
+ }
+
+ //Logs (A)dmins items [Lupus]
+ if( log_config.enable_logs&0x400 )
+ {
+ log_pick_pc(sd, "A", nameid, -delamount, &sd->status.inventory[idx]);
}
+
+ pc_delitem(sd, idx, delamount, 0, 0);
+
+ amount-= delamount;
+ }
+
+ // notify target
+ sprintf(atcmd_output, msg_txt(113), total-amount); // %d item(s) removed by a GM.
+ clif_displaymessage(sd->fd, atcmd_output);
+
+ // notify source
+ if( amount == total )
+ {
+ clif_displaymessage(fd, msg_txt(116)); // Character does not have the item.
+ }
+ else if( amount )
+ {
+ sprintf(atcmd_output, msg_txt(115), total-amount, total-amount, total); // %d item(s) removed. Player had only %d on %d items.
+ clif_displaymessage(fd, atcmd_output);
}
else
{
- clif_displaymessage(fd, msg_txt(19)); // Invalid item ID or name.
- return -1;
+ sprintf(atcmd_output, msg_txt(114), total); // %d item(s) removed from the player.
+ clif_displaymessage(fd, atcmd_output);
}
return 0;
diff --git a/src/map/battle.c b/src/map/battle.c
index 5c6da69e3..32def23f3 100644
--- a/src/map/battle.c
+++ b/src/map/battle.c
@@ -1942,8 +1942,8 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
if (sc && sc->data[SC_MIRACLE]) i = 2; //Star anger
else
- ARR_FIND(0, 3, i, t_class == sd->hate_mob[i]);
- if (i < 3 && (skill=pc_checkskill(sd,sg_info[i].anger_id)))
+ ARR_FIND(0, MAX_PC_FEELHATE, i, t_class == sd->hate_mob[i]);
+ if (i < MAX_PC_FEELHATE && (skill=pc_checkskill(sd,sg_info[i].anger_id)))
{
skillratio = sd->status.base_level + sstatus->dex + sstatus->luk;
if (i == 2) skillratio += sstatus->str; //Star Anger
@@ -4004,6 +4004,8 @@ static const struct _battle_data {
{ "invincible.nodamage", &battle_config.invincible_nodamage, 0, 0, 1, },
{ "mob_slave_keep_target", &battle_config.mob_slave_keep_target, 0, 0, 1, },
{ "autospell_check_range", &battle_config.autospell_check_range, 0, 0, 1, },
+ { "client_reshuffle_dice", &battle_config.client_reshuffle_dice, 0, 0, 1, },
+ { "client_sort_storage", &battle_config.client_sort_storage, 0, 0, 1, },
// BattleGround Settings
{ "bg_update_interval", &battle_config.bg_update_interval, 1000, 100, INT_MAX, },
{ "bg_short_attack_damage_rate", &battle_config.bg_short_damage_rate, 80, 0, INT_MAX, },
diff --git a/src/map/battle.h b/src/map/battle.h
index 230a86007..3abc6b0a4 100644
--- a/src/map/battle.h
+++ b/src/map/battle.h
@@ -96,6 +96,13 @@ bool battle_check_range(struct block_list *src,struct block_list *bl,int range);
void battle_consume_ammo(struct map_session_data* sd, int skill, int lv);
// 設定
+#define MIN_HAIR_STYLE battle_config.min_hair_style
+#define MAX_HAIR_STYLE battle_config.max_hair_style
+#define MIN_HAIR_COLOR battle_config.min_hair_color
+#define MAX_HAIR_COLOR battle_config.max_hair_color
+#define MIN_CLOTH_COLOR battle_config.min_cloth_color
+#define MAX_CLOTH_COLOR battle_config.max_cloth_color
+
extern struct Battle_Config
{
int warp_point_debug;
@@ -471,6 +478,8 @@ extern struct Battle_Config
int invincible_nodamage;
int mob_slave_keep_target;
int autospell_check_range; //Enable range check for autospell bonus. [L0ne_W0lf]
+ int client_reshuffle_dice; // Reshuffle /dice
+ int client_sort_storage;
// [BattleGround Settings]
int bg_update_interval;
diff --git a/src/map/battleground.c b/src/map/battleground.c
index fad22c38f..1c2a90d90 100644
--- a/src/map/battleground.c
+++ b/src/map/battleground.c
@@ -64,7 +64,7 @@ int bg_team_warp(int bg_id, unsigned short mapindex, short x, short y)
struct battleground_data *bg = bg_team_search(bg_id);
if( bg == NULL ) return 0;
for( i = 0; i < MAX_BG_MEMBERS; i++ )
- if( bg->members[i].sd != NULL ) pc_setpos(bg->members[i].sd, mapindex, x, y, 3);
+ if( bg->members[i].sd != NULL ) pc_setpos(bg->members[i].sd, mapindex, x, y, CLR_TELEPORT);
return 1;
}
@@ -145,7 +145,7 @@ int bg_member_respawn(struct map_session_data *sd)
return 0;
if( bg->mapindex == 0 )
return 0; // Respawn not handled by Core
- pc_setpos(sd, bg->mapindex, bg->x, bg->y, 0);
+ pc_setpos(sd, bg->mapindex, bg->x, bg->y, CLR_OUTSIGHT);
status_revive(&sd->bl, 1, 100);
return 1; // Warped
diff --git a/src/map/chrif.c b/src/map/chrif.c
index 40e7ca8d1..a9634d2c2 100644
--- a/src/map/chrif.c
+++ b/src/map/chrif.c
@@ -74,7 +74,7 @@ static const int packet_len_table[0x3d] = { // U - used, F - free
//2b13: Incoming, chrif_accountdeletion -> 'Delete acc XX, if the player is on, kick ....'
//2b14: Incoming, chrif_accountban -> 'not sure: kick the player with message XY'
//2b15: FREE
-//2b16: Outgoing, chrif_ragsrvinfo -> 'sends motd / rates ....'
+//2b16: Outgoing, chrif_ragsrvinfo -> 'sends base / job / drop rates ....'
//2b17: Outgoing, chrif_char_offline -> 'tell the charserver that the char is now offline'
//2b18: Outgoing, chrif_char_reset_offline -> 'set all players OFF!'
//2b19: Outgoing, chrif_char_online -> 'tell the charserver that the char .. is online'
@@ -1229,40 +1229,18 @@ int chrif_load_scdata(int fd)
/*==========================================
* Send rates and motd to char server [Wizputer]
- * S 2b16 <base rate>.w <job rate>.w <drop rate>.w <motd len>.w <motd>.256B
+ * S 2b16 <base rate>.L <job rate>.L <drop rate>.L
*------------------------------------------*/
- int chrif_ragsrvinfo(int base_rate, int job_rate, int drop_rate)
+int chrif_ragsrvinfo(int base_rate, int job_rate, int drop_rate)
{
- char buf[256];
- FILE *fp;
- int i;
-
chrif_check(-1);
- WFIFOHEAD(char_fd, sizeof(buf) + 10);
+ WFIFOHEAD(char_fd,14);
WFIFOW(char_fd,0) = 0x2b16;
- WFIFOW(char_fd,2) = base_rate;
- WFIFOW(char_fd,4) = job_rate;
- WFIFOW(char_fd,6) = drop_rate;
- WFIFOW(char_fd,8) = sizeof(buf) + 10;
-
- if ((fp = fopen(motd_txt, "r")) != NULL) {
- if (fgets(buf, sizeof(buf), fp) != NULL)
- {
- for(i = 0; buf[i]; i++) {
- if (buf[i] == '\r' || buf[i] == '\n') {
- buf[i] = 0;
- break;
- }
- }
- memcpy(WFIFOP(char_fd,10), buf, sizeof(buf));
- }
- fclose(fp);
- } else {
- memset(buf, 0, sizeof(buf)); //No data found, send empty packets?
- memcpy(WFIFOP(char_fd,10), buf, sizeof(buf));
- }
- WFIFOSET(char_fd,WFIFOW(char_fd,8));
+ WFIFOL(char_fd,2) = base_rate;
+ WFIFOL(char_fd,6) = job_rate;
+ WFIFOL(char_fd,10) = drop_rate;
+ WFIFOSET(char_fd,14);
return 0;
}
diff --git a/src/map/clif.c b/src/map/clif.c
index e55a27108..c5796555a 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -168,9 +168,9 @@ static inline unsigned char clif_bl_type(struct block_list *bl) {
case BL_ITEM: return 0x2; //ITEM_TYPE
case BL_SKILL: return 0x3; //SKILL_TYPE
case BL_CHAT: return 0x4; //UNKNOWN_TYPE
- case BL_MOB: return pcdb_checkid(((TBL_MOB*)bl)->vd->class_)?0x0:0x5; //NPC_MOB_TYPE
+ case BL_MOB: return pcdb_checkid(status_get_viewdata(bl)->class_)?0x0:0x5; //NPC_MOB_TYPE
case BL_NPC: return 0x6; //NPC_EVT_TYPE
- case BL_PET: return 0x7; //NPC_PET_TYPE
+ case BL_PET: return pcdb_checkid(status_get_viewdata(bl)->class_)?0x0:0x7; //NPC_PET_TYPE
case BL_HOM: return 0x8; //NPC_HOM_TYPE
case BL_MER: return 0x9; //NPC_MERSOL_TYPE
// case BL_ELEM: return 0xA; //NPC_ELEMENTAL_TYPE
@@ -658,7 +658,7 @@ int clif_clearflooritem(struct flooritem_data *fitem, int fd)
* 3 - teleported / logged out
* fd : the target client
*------------------------------------------*/
-int clif_clearunit_single(int id, uint8 type, int fd)
+int clif_clearunit_single(int id, clr_type type, int fd)
{
WFIFOHEAD(fd, packet_len(0x80));
WFIFOW(fd,0) = 0x80;
@@ -676,7 +676,7 @@ int clif_clearunit_single(int id, uint8 type, int fd)
* 2 - respawned
* 3 - teleported / logged out
*------------------------------------------*/
-int clif_clearunit_area(struct block_list* bl, uint8 type)
+int clif_clearunit_area(struct block_list* bl, clr_type type)
{
unsigned char buf[16];
@@ -686,7 +686,7 @@ int clif_clearunit_area(struct block_list* bl, uint8 type)
WBUFL(buf,2) = bl->id;
WBUFB(buf,6) = type;
- clif_send(buf, packet_len(0x80), bl, type == 1 ? AREA : AREA_WOS);
+ clif_send(buf, packet_len(0x80), bl, type == CLR_DEAD ? AREA : AREA_WOS);
if(disguised(bl)) {
WBUFL(buf,2) = -bl->id;
@@ -699,7 +699,7 @@ int clif_clearunit_area(struct block_list* bl, uint8 type)
static int clif_clearunit_delayed_sub(int tid, unsigned int tick, int id, intptr data)
{
struct block_list *bl = (struct block_list *)data;
- clif_clearunit_area(bl, 0);
+ clif_clearunit_area(bl, CLR_OUTSIGHT);
aFree(bl);
return 0;
}
@@ -1059,16 +1059,6 @@ static void clif_spiritball_single(int fd, struct map_session_data *sd)
WFIFOSET(fd, packet_len(0x1e1));
}
-// new and improved weather display [Valaris]
-static void clif_weather_sub(int fd, int id, int type)
-{
- WFIFOHEAD(fd,packet_len(0x1f3));
- WFIFOW(fd,0) = 0x1f3;
- WFIFOL(fd,2) = id;
- WFIFOL(fd,6) = type;
- WFIFOSET(fd,packet_len(0x1f3));
-}
-
/*==========================================
*
*------------------------------------------*/
@@ -1086,24 +1076,24 @@ static void clif_weather_check(struct map_session_data *sd)
|| map[m].flag.clouds2)
{
if (map[m].flag.snow)
- clif_weather_sub(fd, sd->bl.id, 162);
+ clif_specialeffect_single(&sd->bl, 162, fd);
if (map[m].flag.clouds)
- clif_weather_sub(fd, sd->bl.id, 233);
+ clif_specialeffect_single(&sd->bl, 233, fd);
if (map[m].flag.clouds2)
- clif_weather_sub(fd, sd->bl.id, 516);
+ clif_specialeffect_single(&sd->bl, 516, fd);
if (map[m].flag.fog)
- clif_weather_sub(fd, sd->bl.id, 515);
+ clif_specialeffect_single(&sd->bl, 515, fd);
if (map[m].flag.fireworks) {
- clif_weather_sub(fd, sd->bl.id, 297);
- clif_weather_sub(fd, sd->bl.id, 299);
- clif_weather_sub(fd, sd->bl.id, 301);
+ clif_specialeffect_single(&sd->bl, 297, fd);
+ clif_specialeffect_single(&sd->bl, 299, fd);
+ clif_specialeffect_single(&sd->bl, 301, fd);
}
if (map[m].flag.sakura)
- clif_weather_sub(fd, sd->bl.id, 163);
+ clif_specialeffect_single(&sd->bl, 163, fd);
if (map[m].flag.leaves)
- clif_weather_sub(fd, sd->bl.id, 333);
+ clif_specialeffect_single(&sd->bl, 333, fd);
if (map[m].flag.rain)
- clif_weather_sub(fd, sd->bl.id, 161);
+ clif_specialeffect_single(&sd->bl, 161, fd);
}
}
@@ -1280,13 +1270,14 @@ int clif_homskillinfoblock(struct map_session_data *sd)
void clif_homskillup(struct map_session_data *sd, int skill_num)
{ //[orn]
struct homun_data *hd;
- int fd=sd->fd, skillid;
- WFIFOHEAD(fd, packet_len(0x239));
+ int fd, skillid;
nullpo_retv(sd);
skillid = skill_num - HM_SKILLBASE;
+ fd=sd->fd;
hd=sd->hd;
+ WFIFOHEAD(fd, packet_len(0x239));
WFIFOW(fd,0) = 0x239;
WFIFOW(fd,2) = skill_num;
WFIFOW(fd,4) = hd->homunculus.hskill[skillid].lv;
@@ -1468,9 +1459,10 @@ void clif_blown(struct block_list *bl)
clif_slide(bl, bl->x, bl->y);
}
-/*==========================================
- *
- *------------------------------------------*/
+/// Visually moves(slides) a character to x,y. If the target cell
+/// isn't walkable, the char doesn't move at all. If the char is
+/// sitting it will stand up.
+/// S 0088 <gid>.L <x>.W <y>.W
void clif_fixpos(struct block_list *bl)
{
unsigned char buf[10];
@@ -1529,9 +1521,7 @@ int clif_buylist(struct map_session_data *sd, struct npc_data *nd)
if( id == NULL )
continue;
WFIFOL(fd, 4+c*11) = val;
- if (!id->flag.value_notdc)
- val = pc_modifybuyvalue(sd,val);
- WFIFOL(fd, 8+c*11) = val;
+ WFIFOL(fd, 8+c*11) = pc_modifybuyvalue(sd,val);
WFIFOB(fd,12+c*11) = itemtype(id->type);
WFIFOW(fd,13+c*11) = ( id->view_id > 0 ) ? id->view_id : id->nameid;
c++;
@@ -1570,9 +1560,7 @@ int clif_selllist(struct map_session_data *sd)
continue;
WFIFOW(fd,4+c*10)=i+2;
WFIFOL(fd,6+c*10)=val;
- if( !sd->inventory_data[i]->flag.value_notoc )
- val=pc_modifysellvalue(sd,val);
- WFIFOL(fd,10+c*10)=val;
+ WFIFOL(fd,10+c*10)=pc_modifysellvalue(sd,val);
c++;
}
}
@@ -2166,7 +2154,7 @@ void clif_equiplist(struct map_session_data *sd)
}
}
-void clif_storagelist(struct map_session_data* sd, struct storage_data* stor)
+void clif_storagelist(struct map_session_data* sd, struct item* items, int items_length)
{
struct item_data *id;
int i,n,ne;
@@ -2187,21 +2175,21 @@ void clif_storagelist(struct map_session_data* sd, struct storage_data* stor)
const int cmd = 28;
#endif
- buf = (unsigned char*)aMallocA(MAX_STORAGE * s + 4);
- bufe = (unsigned char*)aMallocA(MAX_STORAGE * cmd + 4);
+ buf = (unsigned char*)aMallocA(items_length * s + 4);
+ bufe = (unsigned char*)aMallocA(items_length * cmd + 4);
- for( i = 0, n = 0, ne = 0; i < MAX_STORAGE; i++ )
+ for( i = 0, n = 0, ne = 0; i < items_length; i++ )
{
- if( stor->items[i].nameid <= 0 )
+ if( items[i].nameid <= 0 )
continue;
- id = itemdb_search(stor->items[i].nameid);
+ id = itemdb_search(items[i].nameid);
if( !itemdb_isstackable2(id) )
{ //Equippable
WBUFW(bufe,ne*cmd+4)=i+1;
- clif_item_sub(bufe, ne*cmd+6, &stor->items[i], id, id->equip);
- clif_addcards(WBUFP(bufe, ne*cmd+16), &stor->items[i]);
+ clif_item_sub(bufe, ne*cmd+6, &items[i], id, id->equip);
+ clif_addcards(WBUFP(bufe, ne*cmd+16), &items[i]);
#if PACKETVER >= 20071002
- WBUFL(bufe,ne*cmd+24)=stor->items[i].expire_time;
+ WBUFL(bufe,ne*cmd+24)=items[i].expire_time;
WBUFW(bufe,ne*cmd+28)=0; //Unknown
#endif
ne++;
@@ -2209,93 +2197,12 @@ void clif_storagelist(struct map_session_data* sd, struct storage_data* stor)
else
{ //Stackable
WBUFW(buf,n*s+4)=i+1;
- clif_item_sub(buf, n*s+6, &stor->items[i], id,-1);
+ clif_item_sub(buf, n*s+6, &items[i], id,-1);
#if PACKETVER >= 5
- clif_addcards(WBUFP(buf,n*s+14), &stor->items[i]);
+ clif_addcards(WBUFP(buf,n*s+14), &items[i]);
#endif
#if PACKETVER >= 20080102
- WBUFL(buf,n*s+22)=stor->items[i].expire_time;
-#endif
- n++;
- }
- }
- if( n )
- {
-#if PACKETVER < 5
- WBUFW(buf,0)=0xa5;
-#elif PACKETVER < 20080102
- WBUFW(buf,0)=0x1f0;
-#else
- WBUFW(buf,0)=0x2ea;
-#endif
- WBUFW(buf,2)=4+n*s;
- clif_send(buf, WBUFW(buf,2), &sd->bl, SELF);
- }
- if( ne )
- {
-#if PACKETVER < 20071002
- WBUFW(bufe,0)=0xa6;
-#else
- WBUFW(bufe,0)=0x2d1;
-#endif
- WBUFW(bufe,2)=4+ne*cmd;
- clif_send(bufe, WBUFW(bufe,2), &sd->bl, SELF);
- }
-
- if( buf ) aFree(buf);
- if( bufe ) aFree(bufe);
-}
-
-//Unified storage function which sends all of the storage (requires two packets, one for equipable items and one for stackable ones. [Skotlex]
-void clif_guildstoragelist(struct map_session_data *sd,struct guild_storage *stor)
-{
- struct item_data *id;
- int i,n,ne;
- unsigned char *buf;
- unsigned char *bufe;
-#if PACKETVER < 5
- const int s = 10; //Entry size.
-#elif PACKETVER < 20080102
- const int s = 18;
-#else
- const int s = 22;
-#endif
-#if PACKETVER < 20071002
- const int cmd = 20;
-#elif PACKETVER < 20100629
- const int cmd = 26;
-#else
- const int cmd = 28;
-#endif
-
- buf = (unsigned char*)aMallocA(MAX_GUILD_STORAGE * s + 4);
- bufe = (unsigned char*)aMallocA(MAX_GUILD_STORAGE * cmd + 4);
-
- for( i = 0, n = 0, ne = 0; i < MAX_GUILD_STORAGE; i++ )
- {
- if( stor->storage_[i].nameid <= 0 )
- continue;
- id = itemdb_search(stor->storage_[i].nameid);
- if( !itemdb_isstackable2(id) )
- { //Equippable
- WBUFW(bufe,ne*cmd+4)=i+1;
- clif_item_sub(bufe, ne*cmd+6, &stor->storage_[i], id, id->equip);
- clif_addcards(WBUFP(bufe, ne*cmd+16), &stor->storage_[i]);
-#if PACKETVER >= 20071002
- WBUFL(bufe,ne*cmd+24)=stor->storage_[i].expire_time;
- WBUFW(bufe,ne*cmd+28)=0; //Unknown
-#endif
- ne++;
- }
- else
- { //Stackable
- WBUFW(buf,n*s+4)=i+1;
- clif_item_sub(buf, n*s+6, &stor->storage_[i], id,-1);
-#if PACKETVER >= 5
- clif_addcards(WBUFP(buf,n*s+14), &stor->storage_[i]);
-#endif
-#if PACKETVER >= 20080102
- WBUFL(buf,n*s+22)=stor->storage_[i].expire_time;
+ WBUFL(buf,n*s+22)=items[i].expire_time;
#endif
n++;
}
@@ -3089,23 +2996,7 @@ int clif_misceffect(struct block_list* bl,int type)
return 0;
}
-int clif_misceffect2(struct block_list *bl, int type)
-{
- unsigned char buf[24];
-
- nullpo_ret(bl);
-
- memset(buf, 0, packet_len(0x1f3));
-
- WBUFW(buf,0) = 0x1f3;
- WBUFL(buf,2) = bl->id;
- WBUFL(buf,6) = type;
-
- clif_send(buf, packet_len(0x1f3), bl, AREA);
-
- return 0;
-}
/*==========================================
* 表示オプション変更
*------------------------------------------*/
@@ -3226,11 +3117,13 @@ int clif_useitemack(struct map_session_data *sd,int index,int amount,int ok)
return 0;
}
-/*==========================================
- * Inform client whether chatroom creation was successful or not
- * R 00d6 <fail>.B
- *------------------------------------------*/
-void clif_createchat(struct map_session_data* sd, int fail)
+/// Inform client whether chatroom creation was successful or not
+/// R 00d6 <flag>.B
+/// flag:
+/// 0 = Room has been successfully created (opens chat room)
+/// 1 = Room limit exceeded
+/// 2 = Same room already exists
+void clif_createchat(struct map_session_data* sd, int flag)
{
int fd;
@@ -3239,7 +3132,7 @@ void clif_createchat(struct map_session_data* sd, int fail)
fd = sd->fd;
WFIFOHEAD(fd,packet_len(0xd6));
WFIFOW(fd,0) = 0xd6;
- WFIFOB(fd,2) = fail;
+ WFIFOB(fd,2) = flag;
WFIFOSET(fd,packet_len(0xd6));
}
@@ -3327,10 +3220,18 @@ int clif_clearchat(struct chat_data *cd,int fd)
return 0;
}
-/*==========================================
- *
- *------------------------------------------*/
-int clif_joinchatfail(struct map_session_data *sd,int fail)
+/// Displays message (mostly) regarding join chat
+/// failures
+/// R 0x00da <flag>.B
+/// flag:
+/// 0 = The room is already full.
+/// 1 = Incorrect password, please try again.
+/// 2 = You have been kicked out of the room.
+/// 4 = You don't have enough money.
+/// 5 = You are not the required level.
+/// 6 = Too high level for this job.
+/// 7 = Not the suitable job for this type of work.
+int clif_joinchatfail(struct map_session_data *sd,int flag)
{
int fd;
@@ -3340,7 +3241,7 @@ int clif_joinchatfail(struct map_session_data *sd,int fail)
WFIFOHEAD(fd,packet_len(0xda));
WFIFOW(fd,0) = 0xda;
- WFIFOB(fd,2) = fail;
+ WFIFOB(fd,2) = flag;
WFIFOSET(fd,packet_len(0xda));
return 0;
@@ -3393,7 +3294,7 @@ int clif_addchat(struct chat_data* cd,struct map_session_data *sd)
/*==========================================
* Announce the new owner
- * R 00e1 <index>.l <nick>.24B
+ * R 00e1 <owner flag>.l <nick>.24B
*------------------------------------------*/
void clif_changechatowner(struct chat_data* cd, struct map_session_data* sd)
{
@@ -3405,6 +3306,8 @@ void clif_changechatowner(struct chat_data* cd, struct map_session_data* sd)
//FIXME: this announces a swap between positions 0 and 1 (probably not what we want) [ultramage]
//FIXME: aegis sends obviously incorrect packets; need to figure out what to send to display it correctly :X
//TODO: is it just owner swap, or can it do general-purpose reordering?
+ // It's not position, but operator flag, everyone set to 1 gets chat
+ // operator menu (yes, that means a chat may host multiple operators) [Ai4rei]
WBUFW(buf, 0) = 0xe1;
WBUFL(buf, 2) = 1;
@@ -3690,41 +3593,6 @@ void clif_updateguildstorageamount(struct map_session_data* sd, int amount)
}
/*==========================================
- *
- *------------------------------------------*/
-void clif_guildstorageitemadded(struct map_session_data* sd, struct item* i, int index, int amount)
-{
- int view,fd;
- unsigned char *buf;
-#if PACKETVER < 20090603
- const int cmd = 0xf4;
-#else
- const int cmd = 0x1c4;
-#endif
-
- nullpo_retv(sd);
- nullpo_retv(i);
- fd=sd->fd;
- view = itemdb_viewid(i->nameid);
- buf = WFIFOP(fd,0);
-
- WFIFOHEAD(fd,packet_len(cmd));
- WBUFW(buf, 0) = cmd; // Storage item added
- WBUFW(buf, 2) = index+1; // index
- WBUFL(buf, 4) = amount; // amount
- WBUFW(buf, 8) = ( view > 0 ) ? view : i->nameid; // id
-#if PACKETVER >= 20090603
- WBUFB(buf,10) = itemdb_type(i->nameid); //type
- buf = WBUFP(buf,1); //Advance 1B
-#endif
- WBUFB(buf,10) = i->identify; //identify flag
- WBUFB(buf,11) = i->attribute; // attribute
- WBUFB(buf,12) = i->refine; //refine
- clif_addcards(WBUFP(buf,13), i);
- WFIFOSET(fd,packet_len(cmd));
-}
-
-/*==========================================
* カプラ倉庫からアイテムを取り去る
*------------------------------------------*/
void clif_storageitemremoved(struct map_session_data* sd, int index, int amount)
@@ -3885,7 +3753,8 @@ static int clif_calc_walkdelay(struct block_list *bl,int delay, int type, int da
/*==========================================
* Sends a 'damage' packet (src performs action on dst)
- * R 008a <src ID>.l <dst ID>.l <server tick>.l <src speed>.l <dst speed>.l <param1>.w <param2>.w <type>.B <param3>.w
+ * R 008a <src ID>.L <dst ID>.L <server tick>.L <src speed>.L <dst speed>.L <damage>.W <div>.W <type>.B <damage2>.W
+ * R 02e1 <src ID>.L <dst ID>.L <server tick>.L <src speed>.L <dst speed>.L <damage>.L <div>.W <type>.B <damage2>.L
*
* type=00 damage [param1: total damage, param2: div, param3: assassin dual-wield damage]
* type=01 pick up item
@@ -4131,12 +4000,11 @@ void clif_skill_delunit(struct skill_unit *unit)
}
/*==========================================
- * Unknown... trap related?
- * Sent when an object gets ankle-snared
+ * Sent when an object gets ankle-snared (ZC_SKILL_UPDATE)
* Only affects units with class [139,153] client-side
* R 01ac <object id>.l
*------------------------------------------*/
-void clif_01ac(struct block_list* bl)
+void clif_skillunit_update(struct block_list* bl)
{
unsigned char buf[6];
nullpo_retv(bl);
@@ -4195,7 +4063,7 @@ int clif_outsight(struct block_list *bl,va_list ap)
switch(bl->type){
case BL_PC:
if (sd->vd.class_ != INVISIBLE_CLASS)
- clif_clearunit_single(bl->id,0,tsd->fd);
+ clif_clearunit_single(bl->id,CLR_OUTSIGHT,tsd->fd);
if(sd->chatID){
struct chat_data *cd;
cd=(struct chat_data*)map_id2bl(sd->chatID);
@@ -4213,14 +4081,14 @@ int clif_outsight(struct block_list *bl,va_list ap)
break;
default:
if ((vd=status_get_viewdata(bl)) && vd->class_ != INVISIBLE_CLASS)
- clif_clearunit_single(bl->id,0,tsd->fd);
+ clif_clearunit_single(bl->id,CLR_OUTSIGHT,tsd->fd);
break;
}
}
if (sd && sd->fd)
{ //sd is watching tbl go out of view.
if ((vd=status_get_viewdata(tbl)) && vd->class_ != INVISIBLE_CLASS)
- clif_clearunit_single(tbl->id,0,sd->fd);
+ clif_clearunit_single(tbl->id,CLR_OUTSIGHT,sd->fd);
}
return 0;
}
@@ -4414,6 +4282,15 @@ int clif_skillup(struct map_session_data *sd,int skill_num)
/*==========================================
* スキル詠唱エフェクトを送信する
+ * pl:
+ * 0 = Yellow cast aura
+ * 1 = Water elemental cast aura
+ * 2 = Earth elemental cast aura
+ * 3 = Fire elemental cast aura
+ * 4 = Wind elemental cast aura
+ * 5 = Poison elemental cast aura
+ * 6 = White cast aura
+ * ? = like 0
*------------------------------------------*/
int clif_skillcasting(struct block_list* bl,
int src_id,int dst_id,int dst_x,int dst_y,int skill_num,int pl, int casttime)
@@ -7081,8 +6958,8 @@ int clif_guild_notice(struct map_session_data* sd, struct guild* g)
WFIFOHEAD(fd,packet_len(0x16f));
WFIFOW(fd,0) = 0x16f;
- memcpy(WFIFOP(fd,2), g->mes1, 60);
- memcpy(WFIFOP(fd,62), g->mes2, 120);
+ memcpy(WFIFOP(fd,2), g->mes1, MAX_GUILDMES1);
+ memcpy(WFIFOP(fd,62), g->mes2, MAX_GUILDMES2);
WFIFOSET(fd,packet_len(0x16f));
return 0;
}
@@ -7106,7 +6983,12 @@ int clif_guild_invite(struct map_session_data *sd,struct guild *g)
return 0;
}
/*==========================================
- * ギルドメンバ勧誘結果
+ * Reply to invite request
+ * Flag:
+ * 0 = Already in guild.
+ * 1 = Offer rejected.
+ * 2 = Offer accepted.
+ * 3 = Guild full.
*------------------------------------------*/
int clif_guild_inviteack(struct map_session_data *sd,int flag)
{
@@ -7285,7 +7167,11 @@ int clif_guild_delalliance(struct map_session_data *sd,int guild_id,int flag)
return 0;
}
/*==========================================
- * ギルド敵対結果
+ * Reply to opposition request
+ * Flag:
+ * 0 = Antagonist has been set.
+ * 1 = Guild has too many Antagonists.
+ * 2 = Already set as an Antagonist.
*------------------------------------------*/
int clif_guild_oppositionack(struct map_session_data *sd,int flag)
{
@@ -7579,20 +7465,17 @@ int clif_wisall(struct map_session_data *sd,int type,int flag)
/*==========================================
* Play a BGM! [Rikter/Yommy]
*------------------------------------------*/
-void clif_playBGM(struct map_session_data* sd, struct block_list* bl, const char* name)
+void clif_playBGM(struct map_session_data* sd, const char* name)
{
int fd;
nullpo_retv(sd);
- nullpo_retv(bl);
fd = sd->fd;
WFIFOHEAD(fd,packet_len(0x7fe));
WFIFOW(fd,0) = 0x7fe;
safestrncpy((char*)WFIFOP(fd,2), name, NAME_LENGTH);
WFIFOSET(fd,packet_len(0x7fe));
-
- return;
}
/*==========================================
@@ -7742,7 +7625,7 @@ int clif_refresh(struct map_session_data *sd)
if( pc_issit(sd) )
clif_sitting(&sd->bl); // FIXME: just send to self, not area
if( pc_isdead(sd) ) //When you refresh, resend the death packet.
- clif_clearunit_single(sd->bl.id,1,sd->fd);
+ clif_clearunit_single(sd->bl.id,CLR_DEAD,sd->fd);
else
clif_changed_dir(&sd->bl, SELF);
@@ -7928,6 +7811,9 @@ int clif_charnameupdate (struct map_session_data *ssd)
return 0;
}
+/// Visually moves(instant) a character to x,y. The char moves even
+/// when the target cell isn't walkable. If the char is sitting it
+/// stays that way.
void clif_slide(struct block_list *bl, int x, int y)
{
unsigned char buf[10];
@@ -8014,21 +7900,58 @@ void clif_gospel_info(struct map_session_data *sd, int type)
WFIFOSET(fd, packet_len(0x215));
}
+
+/// Multi purpose mission information packet (ZC_STARSKILL).
+/// 0x20e <mapname>.24B <monster_id>.L <star>.B <result>.B
+/// result:
+/// 0 = Star Gladiator %s has designed <mapname>'s as the %s.
+/// star:
+/// 0 = Place of the Sun
+/// 1 = Place of the Moon
+/// 2 = Place of the Stars
+/// 1 = Star Gladiator %s's %s: <mapname>
+/// star:
+/// 0 = Place of the Sun
+/// 1 = Place of the Moon
+/// 2 = Place of the Stars
+/// 10 = Star Gladiator %s has designed <mapname>'s as the %s.
+/// star:
+/// 0 = Target of the Sun
+/// 1 = Target of the Moon
+/// 2 = Target of the Stars
+/// 11 = Star Gladiator %s's %s: <mapname used as monster name>
+/// star:
+/// 0 = Monster of the Sun
+/// 1 = Monster of the Moon
+/// 2 = Monster of the Stars
+/// 20 = [TaeKwon Mission] Target Monster : <mapname used as monster name> (<star>%)
+/// 21 = [Taming Mission] Target Monster : <mapname used as monster name>
+/// 22 = [Collector Rank] Target Item : <monster_id used as item id>
+/// 30 = [Sun, Moon and Stars Angel] Designed places and monsters have been reset.
+/// 40 = Target HP : <monster_id used as HP>
+void clif_starskill(struct map_session_data* sd, const char* mapname, int monster_id, unsigned char star, unsigned char result)
+{
+ int fd = sd->fd;
+
+ WFIFOHEAD(fd,packet_len(0x20e));
+ WFIFOW(fd,0) = 0x20e;
+ safestrncpy((char*)WFIFOP(fd,2), mapname, NAME_LENGTH);
+ WFIFOL(fd,26) = monster_id;
+ WFIFOB(fd,30) = star;
+ WFIFOB(fd,31) = result;
+ WFIFOSET(fd,packet_len(0x20e));
+}
+
/*==========================================
* Info about Star Glaldiator save map [Komurka]
* type: 1: Information, 0: Map registered
*------------------------------------------*/
void clif_feel_info(struct map_session_data* sd, unsigned char feel_level, unsigned char type)
{
- int fd=sd->fd;
+ char mapname[MAP_NAME_LENGTH_EXT];
- WFIFOHEAD(fd,packet_len(0x20e));
- WFIFOW(fd,0) = 0x20e;
- mapindex_getmapname_ext(mapindex_id2name(sd->feel_map[feel_level].index), (char*)WFIFOP(fd,2));
- WFIFOL(fd,26) = sd->bl.id;
- WFIFOB(fd,30) = feel_level;
- WFIFOB(fd,31) = type?1:0;
- WFIFOSET(fd,packet_len(0x20e));
+ mapindex_getmapname_ext(mapindex_id2name(sd->feel_map[feel_level].index), mapname);
+ clif_starskill(sd, mapname, 0, feel_level, type ? 1 : 0);
}
/*==========================================
@@ -8037,19 +7960,18 @@ void clif_feel_info(struct map_session_data* sd, unsigned char feel_level, unsig
*------------------------------------------*/
void clif_hate_info(struct map_session_data *sd, unsigned char hate_level,int class_, unsigned char type)
{
- int fd=sd->fd;
- WFIFOHEAD(fd,packet_len(0x20e));
- WFIFOW(fd,0)=0x20e;
- if (pcdb_checkid(class_))
- strncpy((char*)WFIFOP(fd,2),job_name(class_), NAME_LENGTH);
- else if (mobdb_checkid(class_))
- strncpy((char*)WFIFOP(fd,2),mob_db(class_)->jname, NAME_LENGTH);
- else //Really shouldn't happen...
- memset(WFIFOP(fd,2), 0, NAME_LENGTH);
- WFIFOL(fd,26)=sd->bl.id;
- WFIFOB(fd,30)=hate_level;
- WFIFOB(fd,31)=type?10:11; //Register/Info
- WFIFOSET(fd, packet_len(0x20e));
+ if( pcdb_checkid(class_) )
+ {
+ clif_starskill(sd, job_name(class_), class_, hate_level, type ? 10 : 11);
+ }
+ else if( mobdb_checkid(class_) )
+ {
+ clif_starskill(sd, mob_db(class_)->jname, class_, hate_level, type ? 10 : 11);
+ }
+ else
+ {
+ ShowWarning("clif_hate_info: Received invalid class %d for this packet (char_id=%d, hate_level=%u, type=%u).\n", class_, sd->status.char_id, (unsigned int)hate_level, (unsigned int)type);
+ }
}
/*==========================================
@@ -8057,14 +7979,7 @@ void clif_hate_info(struct map_session_data *sd, unsigned char hate_level,int cl
*------------------------------------------*/
void clif_mission_info(struct map_session_data *sd, int mob_id, unsigned char progress)
{
- int fd=sd->fd;
- WFIFOHEAD(fd,packet_len(0x20e));
- WFIFOW(fd,0)=0x20e;
- strncpy((char*)WFIFOP(fd,2),mob_db(mob_id)->jname, NAME_LENGTH);
- WFIFOL(fd,26)=mob_id;
- WFIFOB(fd,30)=progress; //Message to display
- WFIFOB(fd,31)=20;
- WFIFOSET(fd, packet_len(0x20e));
+ clif_starskill(sd, mob_db(mob_id)->jname, mob_id, progress, 20);
}
/*==========================================
@@ -8072,14 +7987,7 @@ void clif_mission_info(struct map_session_data *sd, int mob_id, unsigned char pr
*------------------------------------------*/
void clif_feel_hate_reset(struct map_session_data *sd)
{
- int fd=sd->fd;
- WFIFOHEAD(fd,packet_len(0x20e));
- WFIFOW(fd,0)=0x20e;
- memset(WFIFOP(fd,2), 0, NAME_LENGTH); //Blank name as all was reset.
- WFIFOL(fd,26)=sd->bl.id;
- WFIFOB(fd,30)=0; //Feel/hate level: irrelevant
- WFIFOB(fd,31)=30;
- WFIFOSET(fd, packet_len(0x20e));
+ clif_starskill(sd, "", 0, 0, 30);
}
/*==========================================
@@ -8175,12 +8083,9 @@ void clif_viewequip_ack(struct map_session_data* sd, struct map_session_data* ts
WFIFOSET(fd, WFIFOW(fd, 2));
}
-/*==========================================
- * View player equip request denied
- * R 0291 <message>.W
- * TODO: this looks like a general-purpose packet to print msgstringtable entries.
- *------------------------------------------*/
-void clif_viewequip_fail(struct map_session_data* sd)
+/// Display msgstringtable.txt string (ZC_MSG)
+/// R 0291 <message>.W
+void clif_msg(struct map_session_data* sd, unsigned short id)
{
int fd;
nullpo_retv(sd);
@@ -8188,10 +8093,16 @@ void clif_viewequip_fail(struct map_session_data* sd)
WFIFOHEAD(fd, packet_len(0x291));
WFIFOW(fd, 0) = 0x291;
- WFIFOW(fd, 2) = 0x54d; // This controls which message is displayed. 0x54d is the correct one. Maybe it's used for something else too?
+ WFIFOW(fd, 2) = id; // zero-based msgstringtable.txt index
WFIFOSET(fd, packet_len(0x291));
}
+/// View player equip request denied
+void clif_viewequip_fail(struct map_session_data* sd)
+{
+ clif_msg(sd, 0x54d);
+}
+
/// Validates one global/guild/party/whisper message packet and tries to recognize its components.
/// Returns true if the packet was parsed successfully.
/// Formats: 0 - <packet id>.w <packet len>.w (<name> : <message>).?B 00
@@ -8329,6 +8240,10 @@ static int clif_guess_PacketVer(int fd, int get_previous, int *error)
err = n;\
//define SET_ERROR
+ // FIXME: If the packet is not received at once, this will FAIL.
+ // Figure out, when it happens, that only part of the packet is
+ // received, or fix the function to be able to deal with that
+ // case.
#define CHECK_PACKET_VER() \
if( cmd != clif_config.connect_cmd[packet_ver] || packet_len != packet_db[packet_ver][cmd].len )\
;/* not wanttoconnection or wrong length */\
@@ -8561,20 +8476,22 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd)
// must use foreachinarea (CIRCULAR_AREA interferes with foreachinrange)
map_foreachinarea(clif_getareachar, sd->bl.m, sd->bl.x-AREA_SIZE, sd->bl.y-AREA_SIZE, sd->bl.x+AREA_SIZE, sd->bl.y+AREA_SIZE, BL_ALL, sd);
- //TODO: merge it with the code below
- if (battle_config.pet_no_gvg && map_flag_gvg(sd->bl.m) && sd->pd)
- { //Return the pet to egg. [Skotlex]
- clif_displaymessage(sd->fd, "Pets are not allowed in Guild Wars.");
- pet_menu(sd, 3); //Option 3 is return to egg.
- }
-
// pet
- if(sd->pd) {
- map_addblock(&sd->pd->bl);
- clif_spawn(&sd->pd->bl);
- clif_send_petdata(sd,sd->pd,0,0);
- clif_send_petstatus(sd);
-// skill_unit_move(&sd->pd->bl,gettick(),1);
+ if( sd->pd )
+ {
+ if( battle_config.pet_no_gvg && map_flag_gvg(sd->bl.m) )
+ { //Return the pet to egg. [Skotlex]
+ clif_displaymessage(sd->fd, "Pets are not allowed in Guild Wars.");
+ pet_menu(sd, 3); //Option 3 is return to egg.
+ }
+ else
+ {
+ map_addblock(&sd->pd->bl);
+ clif_spawn(&sd->pd->bl);
+ clif_send_petdata(sd,sd->pd,0,0);
+ clif_send_petstatus(sd);
+// skill_unit_move(&sd->pd->bl,gettick(),1);
+ }
}
//homunculus [blackhole89]
@@ -8605,7 +8522,9 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd)
sd->state.connect_new = 0;
clif_skillinfoblock(sd);
clif_hotkeys_send(sd);
+ clif_updatestatus(sd,SP_BASEEXP);
clif_updatestatus(sd,SP_NEXTBASEEXP);
+ clif_updatestatus(sd,SP_JOBEXP);
clif_updatestatus(sd,SP_NEXTJOBEXP);
clif_updatestatus(sd,SP_SKILLPOINT);
clif_initialstatus(sd);
@@ -8720,7 +8639,7 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd)
// If player is dead, and is spawned (such as @refresh) send death packet. [Valaris]
if(pc_isdead(sd))
- clif_clearunit_area(&sd->bl, 1);
+ clif_clearunit_area(&sd->bl, CLR_DEAD);
// Uncomment if you want to make player face in the same direction he was facing right before warping. [Skotlex]
// else
// clif_changed_dir(&sd->bl, SELF);
@@ -8821,7 +8740,7 @@ void clif_parse_WalkToXY(int fd, struct map_session_data *sd)
int cmd;
if (pc_isdead(sd)) {
- clif_clearunit_area(&sd->bl, 1);
+ clif_clearunit_area(&sd->bl, CLR_DEAD);
return;
}
@@ -8940,6 +8859,7 @@ void clif_parse_GlobalMessage(int fd, struct map_session_data* sd)
WFIFOW(fd,2) = 8 + textlen;
WFIFOL(fd,4) = sd->bl.id;
safestrncpy((char*)WFIFOP(fd,8), text, textlen);
+ //FIXME: chat has range of 9 only
clif_send(WFIFOP(fd,0), WFIFOW(fd,2), &sd->bl, sd->chatID ? CHAT_WOS : AREA_CHAT_WOC);
// send back message to the speaker
@@ -9063,10 +8983,10 @@ void clif_parse_ChangeDir(int fd, struct map_session_data *sd)
*------------------------------------------*/
void clif_parse_Emotion(int fd, struct map_session_data *sd)
{
- unsigned char buf[64];
+ int emoticon = RFIFOB(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0]);
if (battle_config.basic_skill_check == 0 || pc_checkskill(sd, NV_BASIC) >= 2) {
- if (RFIFOB(fd,2) == 34) {// prevent use of the mute emote [Valaris]
+ if (emoticon == E_MUTE) {// prevent use of the mute emote [Valaris]
clif_skill_fail(sd, 1, 0, 1);
return;
}
@@ -9077,11 +8997,13 @@ void clif_parse_Emotion(int fd, struct map_session_data *sd)
return;
}
sd->emotionlasttime = time(NULL) + 1; // not more than 1 per second (using /commands the client can spam it)
-
- WBUFW(buf,0) = 0xc0;
- WBUFL(buf,2) = sd->bl.id;
- WBUFB(buf,6) = RFIFOB(fd,2);
- clif_send(buf, packet_len(0xc0), &sd->bl, AREA);
+
+ if(battle_config.client_reshuffle_dice && emoticon>=E_DICE1 && emoticon<=E_DICE6)
+ {// re-roll dice
+ emoticon = rand()%6+E_DICE1;
+ }
+
+ clif_emotion(&sd->bl, emoticon);
} else
clif_skill_fail(sd, 1, 0, 1);
}
@@ -9100,7 +9022,7 @@ void clif_parse_HowManyConnections(int fd, struct map_session_data *sd)
void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, int target_id, unsigned int tick)
{
if (pc_isdead(sd)) {
- clif_clearunit_area(&sd->bl, 1);
+ clif_clearunit_area(&sd->bl, CLR_DEAD);
return;
}
@@ -9198,7 +9120,7 @@ void clif_parse_Restart(int fd, struct map_session_data *sd)
{
switch(RFIFOB(fd,2)) {
case 0x00:
- pc_respawn(sd,2);
+ pc_respawn(sd,CLR_RESPAWN);
break;
case 0x01:
/* Rovert's Prevent logout option - Fixed [Valaris] */
@@ -9219,7 +9141,7 @@ void clif_parse_Restart(int fd, struct map_session_data *sd)
/*==========================================
* Validates and processes whispered messages
- * S 0096 <packet len>.w <nick>.23B 00 <message>.?B
+ * S 0096 <packet len>.w <nick>.24B <message>.?B
*------------------------------------------*/
void clif_parse_WisMessage(int fd, struct map_session_data* sd)
{
@@ -9416,7 +9338,7 @@ void clif_parse_TakeItem(int fd, struct map_session_data *sd)
do {
if (pc_isdead(sd)) {
- clif_clearunit_area(&sd->bl, 1);
+ clif_clearunit_area(&sd->bl, CLR_DEAD);
break;
}
@@ -9451,7 +9373,8 @@ void clif_parse_DropItem(int fd, struct map_session_data *sd)
{
int item_index = RFIFOW(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0])-2;
int item_amount = RFIFOW(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[1]);
- do {
+
+ for(;;) {
if (pc_isdead(sd))
break;
@@ -9469,7 +9392,7 @@ void clif_parse_DropItem(int fd, struct map_session_data *sd)
break;
return;
- } while (0);
+ }
//Because the client does not like being ignored.
clif_dropitem(sd, item_index,0);
@@ -9483,7 +9406,7 @@ void clif_parse_UseItem(int fd, struct map_session_data *sd)
int n;
if (pc_isdead(sd)) {
- clif_clearunit_area(&sd->bl, 1);
+ clif_clearunit_area(&sd->bl, CLR_DEAD);
return;
}
@@ -9516,7 +9439,7 @@ void clif_parse_EquipItem(int fd,struct map_session_data *sd)
int index;
if(pc_isdead(sd)) {
- clif_clearunit_area(&sd->bl,1);
+ clif_clearunit_area(&sd->bl,CLR_DEAD);
return;
}
index = RFIFOW(fd,2)-2;
@@ -9559,7 +9482,7 @@ void clif_parse_UnequipItem(int fd,struct map_session_data *sd)
int index;
if(pc_isdead(sd)) {
- clif_clearunit_area(&sd->bl,1);
+ clif_clearunit_area(&sd->bl,CLR_DEAD);
return;
}
@@ -9581,7 +9504,7 @@ void clif_parse_NpcClicked(int fd,struct map_session_data *sd)
struct block_list *bl;
if(pc_isdead(sd)) {
- clif_clearunit_area(&sd->bl,1);
+ clif_clearunit_area(&sd->bl,CLR_DEAD);
return;
}
@@ -9592,8 +9515,6 @@ void clif_parse_NpcClicked(int fd,struct map_session_data *sd)
if (!bl) return;
switch (bl->type) {
case BL_MOB:
- clif_parse_ActionRequest_sub(sd, 0x07, bl->id, gettick());
- break;
case BL_PC:
clif_parse_ActionRequest_sub(sd, 0x07, bl->id, gettick());
break;
@@ -10260,6 +10181,11 @@ void clif_parse_Cooking(int fd,struct map_session_data *sd)
//int type = RFIFOW(fd,2); // '1' for cooking, but what do other values mean?
int nameid = RFIFOW(fd,4);
+ if( sd->menuskill_id != AM_PHARMACY )
+ {
+ return;
+ }
+
if (pc_istrading(sd)) {
//Make it fail to avoid shop exploits where you sell something different than you see.
clif_skill_fail(sd,sd->ud.skillid,0,0);
@@ -10379,9 +10305,15 @@ void clif_parse_NpcCloseClicked(int fd,struct map_session_data *sd)
*------------------------------------------*/
void clif_parse_ItemIdentify(int fd,struct map_session_data *sd)
{
+ short idx = RFIFOW(fd,2);
+
if (sd->menuskill_id != MC_IDENTIFY)
return;
- skill_identify(sd,RFIFOW(fd,2)-2);
+ if( idx == -1 )
+ {// cancel pressed
+ return;
+ }
+ skill_identify(sd,idx-2);
sd->menuskill_val = sd->menuskill_id = 0;
}
/*==========================================
@@ -10585,7 +10517,7 @@ void clif_parse_StoragePassword(int fd, struct map_session_data *sd)
/*==========================================
* Party creation request
* S 00f9 <party name>.24S
- * S 01e8 <party name>.24S <item1>.B <item2>.B
+ * S 01e8 <party name>.24S <share flag>.B <share type>.B
*------------------------------------------*/
void clif_parse_CreateParty(int fd, struct map_session_data *sd)
{
@@ -10796,10 +10728,10 @@ void clif_parse_PartyBookingRegisterReq(int fd, struct map_session_data* sd)
{
short level = RFIFOW(fd,2);
short mapid = RFIFOW(fd,4);
- short job[6];
+ short job[PARTY_BOOKING_JOBS];
int i;
- for(i=0; i<6; i++)
+ for(i=0; i<PARTY_BOOKING_JOBS; i++)
job[i] = RFIFOB(fd,6+i*2);
party_booking_register(sd, level, mapid, job);
@@ -10832,7 +10764,7 @@ void clif_parse_PartyBookingSearchReq(int fd, struct map_session_data* sd)
/*==========================================
* more_result: 0 - no more, 1 - more
*------------------------------------------*/
-void clif_PartyBookingSearchAck(int fd, unsigned long *index, int count, bool more_result)
+void clif_PartyBookingSearchAck(int fd, struct party_booking_ad_info** results, int count, bool more_result)
{
int i, j;
int size = sizeof(struct party_booking_ad_info); // structure size (48)
@@ -10840,17 +10772,16 @@ void clif_PartyBookingSearchAck(int fd, unsigned long *index, int count, bool mo
WFIFOHEAD(fd,size*count + 5);
WFIFOW(fd,0) = 0x805;
WFIFOW(fd,2) = size*count + 5;
- WFIFOB(fd,4) = (bool)more_result;
+ WFIFOB(fd,4) = more_result;
for(i=0; i<count; i++)
{
- pb_ad = party_booking_getdata(index[i]);
- if(pb_ad == NULL) return;
+ pb_ad = results[i];
WFIFOL(fd,i*size+5) = pb_ad->index;
memcpy(WFIFOP(fd,i*size+9),pb_ad->charname,NAME_LENGTH);
WFIFOL(fd,i*size+33) = pb_ad->starttime;
WFIFOW(fd,i*size+37) = pb_ad->p_detail.level;
WFIFOW(fd,i*size+39) = pb_ad->p_detail.mapid;
- for(j=0; j<6; j++)
+ for(j=0; j<PARTY_BOOKING_JOBS; j++)
WFIFOW(fd,i*size+41+j*2) = pb_ad->p_detail.job[j];
}
WFIFOSET(fd,WFIFOW(fd,2));
@@ -10858,7 +10789,7 @@ void clif_PartyBookingSearchAck(int fd, unsigned long *index, int count, bool mo
void clif_parse_PartyBookingDeleteReq(int fd, struct map_session_data* sd)
{
- if(party_booking_delete(sd, false))
+ if(party_booking_delete(sd))
clif_PartyBookingDeleteAck(sd, 0);
}
@@ -10877,10 +10808,10 @@ void clif_PartyBookingDeleteAck(struct map_session_data* sd, int flag)
void clif_parse_PartyBookingUpdateReq(int fd, struct map_session_data* sd)
{
- short job[6];
+ short job[PARTY_BOOKING_JOBS];
int i;
- for(i=0; i<6; i++)
+ for(i=0; i<PARTY_BOOKING_JOBS; i++)
job[i] = RFIFOW(fd,2+i*2);
party_booking_update(sd, job);
@@ -10889,32 +10820,32 @@ void clif_parse_PartyBookingUpdateReq(int fd, struct map_session_data* sd)
void clif_PartyBookingInsertNotify(struct map_session_data* sd, struct party_booking_ad_info* pb_ad)
{
int i;
+ uint8 buf[38+PARTY_BOOKING_JOBS*2];
if(pb_ad == NULL) return;
- WFIFOHEAD(sd->fd,packet_len(0x809));
- WFIFOW(sd->fd,0) = 0x809;
- WFIFOL(sd->fd,2) = pb_ad->index;
- memcpy(WFIFOP(sd->fd,6),pb_ad->charname,NAME_LENGTH);
- WFIFOL(sd->fd,30) = pb_ad->starttime;
- WFIFOW(sd->fd,34) = pb_ad->p_detail.level;
- WFIFOW(sd->fd,36) = pb_ad->p_detail.mapid;
- for(i=0; i<6; i++)
- WFIFOW(sd->fd,38+i*2) = pb_ad->p_detail.job[i];
+ WBUFW(buf,0) = 0x809;
+ WBUFL(buf,2) = pb_ad->index;
+ memcpy(WBUFP(buf,6),pb_ad->charname,NAME_LENGTH);
+ WBUFL(buf,30) = pb_ad->starttime;
+ WBUFW(buf,34) = pb_ad->p_detail.level;
+ WBUFW(buf,36) = pb_ad->p_detail.mapid;
+ for(i=0; i<PARTY_BOOKING_JOBS; i++)
+ WBUFW(buf,38+i*2) = pb_ad->p_detail.job[i];
- WFIFOSET(sd->fd,packet_len(0x809));
+ clif_send(buf, packet_len(0x809), &sd->bl, ALL_CLIENT);
}
void clif_PartyBookingUpdateNotify(struct map_session_data* sd, struct party_booking_ad_info* pb_ad)
{
int i;
- uint8 buf[18];
+ uint8 buf[6+PARTY_BOOKING_JOBS*2];
if(pb_ad == NULL) return;
WBUFW(buf,0) = 0x80a;
WBUFL(buf,2) = pb_ad->index;
- for(i=0; i<6; i++)
+ for(i=0; i<PARTY_BOOKING_JOBS; i++)
WBUFW(buf,6+i*2) = pb_ad->p_detail.job[i];
clif_send(buf,packet_len(0x80a),&sd->bl,ALL_CLIENT); // Now UPDATE all client.
}
@@ -10941,10 +10872,11 @@ void clif_parse_CloseVending(int fd, struct map_session_data* sd)
*------------------------------------------*/
void clif_parse_VendingListReq(int fd, struct map_session_data* sd)
{
- vending_vendinglistreq(sd,RFIFOL(fd,2));
-
if( sd->npc_id )
- npc_event_dequeue(sd);
+ {// using an NPC
+ return;
+ }
+ vending_vendinglistreq(sd,RFIFOL(fd,2));
}
/*==========================================
@@ -11075,6 +11007,7 @@ void clif_parse_GuildChangePositionInfo(int fd, struct map_session_data *sd)
/*==========================================
* ギルドメンバ役職変更
+ * S 0155 <packet len>.W {<account id>.L <char id>.L <idx>.L}
*------------------------------------------*/
void clif_parse_GuildChangeMemberPosition(int fd, struct map_session_data *sd)
{
@@ -11103,6 +11036,7 @@ void clif_parse_GuildRequestEmblem(int fd,struct map_session_data *sd)
/*==========================================
* ギルドエンブレム変更
+ * S 0153 <packet len>.W <emblem data>.?B
*------------------------------------------*/
void clif_parse_GuildChangeEmblem(int fd,struct map_session_data *sd)
{
@@ -11128,7 +11062,7 @@ void clif_parse_GuildChangeNotice(int fd, struct map_session_data* sd)
// compensate for some client defects when using multilanguage mode
if (msg1[0] == '|' && msg1[3] == '|') msg1+= 3; // skip duplicate marker
if (msg2[0] == '|' && msg2[3] == '|') msg2+= 3; // skip duplicate marker
- if (msg2[0] == '|') msg2[strnlen(msg2, 120)-1] = '\0'; // delete extra space at the end of string
+ if (msg2[0] == '|') msg2[strnlen(msg2, MAX_GUILDMES2)-1] = '\0'; // delete extra space at the end of string
guild_change_notice(sd, guild_id, msg1, msg2);
}
@@ -11186,7 +11120,7 @@ void clif_parse_GuildLeave(int fd,struct map_session_data *sd)
/*==========================================
* Request to expel a member of a guild
- * S 015b <guild_id>.L <account_id>.L <char_id>.L <reason>.39B 00
+ * S 015b <guild_id>.L <account_id>.L <char_id>.L <reason>.40B
*------------------------------------------*/
void clif_parse_GuildExpulsion(int fd,struct map_session_data *sd)
{
@@ -11458,10 +11392,11 @@ void clif_parse_GMKickAll(int fd, struct map_session_data* sd)
}
/*==========================================
- * /shift <name>
+ * /remove <account name>
+ * /shift <char name>
*------------------------------------------*/
void clif_parse_GMShift(int fd, struct map_session_data *sd)
-{
+{// FIXME: remove is supposed to receive account name for clients prior 20100803RE
char *player_name;
int lv;
@@ -11480,11 +11415,47 @@ void clif_parse_GMShift(int fd, struct map_session_data *sd)
}
}
+
+/// Warps oneself to the location of the character given by account id ( /remove <account id> ).
+/// R 0843 <account id>.L
+void clif_parse_GMRemove2(int fd, struct map_session_data* sd)
+{
+ int account_id, lv;
+ struct map_session_data* pl_sd;
+
+ if( battle_config.atc_gmonly && !pc_isGM(sd) )
+ {
+ return;
+ }
+
+ if( pc_isGM(sd) < ( lv = get_atcommand_level(atcommand_jumpto) ) )
+ {
+ return;
+ }
+
+ account_id = RFIFOL(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0]);
+
+ if( ( pl_sd = map_id2sd(account_id) ) != NULL && pc_isGM(sd) >= pc_isGM(pl_sd) )
+ {
+ pc_warpto(sd, pl_sd);
+ }
+
+ if( log_config.gm && lv >= log_config.gm )
+ {
+ char message[32];
+
+ sprintf(message, "/remove %d", account_id);
+ log_atcommand(sd, message);
+ }
+}
+
+
/*==========================================
- * /recall <name>
+ * /recall <account name>
+ * /summon <char name>
*------------------------------------------*/
void clif_parse_GMRecall(int fd, struct map_session_data *sd)
-{
+{// FIXME: recall is supposed to receive account name for clients prior 20100803RE
char *player_name;
int lv;
@@ -11504,8 +11475,44 @@ void clif_parse_GMRecall(int fd, struct map_session_data *sd)
}
}
+
+/// Summons a character given by account id to one's own position ( /recall <account id> )
+/// R 0842 <account id>.L
+void clif_parse_GMRecall2(int fd, struct map_session_data* sd)
+{
+ int account_id, lv;
+ struct map_session_data* pl_sd;
+
+ if( battle_config.atc_gmonly && !pc_isGM(sd) )
+ {
+ return;
+ }
+
+ if( pc_isGM(sd) < ( lv = get_atcommand_level(atcommand_recall) ) )
+ {
+ return;
+ }
+
+ account_id = RFIFOL(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0]);
+
+ if( ( pl_sd = map_id2sd(account_id) ) != NULL && pc_isGM(sd) >= pc_isGM(pl_sd) )
+ {
+ pc_recall(sd, pl_sd);
+ }
+
+ if( log_config.gm && lv >= log_config.gm )
+ {
+ char message[32];
+
+ sprintf(message, "/recall %d", account_id);
+ log_atcommand(sd, message);
+ }
+}
+
+
/*==========================================
* /monster /item
+ * R 01F3 <name>.24B
*------------------------------------------*/
void clif_parse_GM_Monster_Item(int fd, struct map_session_data *sd)
{
@@ -11663,11 +11670,11 @@ void clif_parse_GMReqAccountName(int fd, struct map_session_data *sd)
/*==========================================
* GM single cell type change request
- * /changemaptype <x> <y> <type>
+ * /changemaptype <x> <y> <type:0-1>
* S 0198 <x>.W <y>.W <gat>.W
*------------------------------------------*/
void clif_parse_GMChangeMapType(int fd, struct map_session_data *sd)
-{
+{// FIXME: type sent by client is 0 or 1 (even if you enter 2+); that suggests, that it is walkable gat attribute
int x,y,type;
if( battle_config.atc_gmonly && !pc_isGM(sd) )
@@ -12107,6 +12114,7 @@ void clif_parse_PVPInfo(int fd,struct map_session_data *sd)
/*==========================================
* /blacksmith
+ * S 0217
*------------------------------------------*/
void clif_parse_Blacksmith(int fd,struct map_session_data *sd)
{
@@ -12150,6 +12158,7 @@ int clif_fame_blacksmith(struct map_session_data *sd, int points)
/*==========================================
* /alchemist
+ * S 0218
*------------------------------------------*/
void clif_parse_Alchemist(int fd,struct map_session_data *sd)
{
@@ -12193,6 +12202,7 @@ int clif_fame_alchemist(struct map_session_data *sd, int points)
/*==========================================
* /taekwon
+ * S 0225
*------------------------------------------*/
void clif_parse_Taekwon(int fd,struct map_session_data *sd)
{
@@ -12234,7 +12244,8 @@ int clif_fame_taekwon(struct map_session_data *sd, int points)
}
/*==========================================
- * PK Ranking table?
+ * /pk
+ * S 0237
*------------------------------------------*/
void clif_parse_RankingPk(int fd,struct map_session_data *sd)
{
@@ -12259,7 +12270,7 @@ void clif_parse_FeelSaveOk(int fd,struct map_session_data *sd)
if (sd->menuskill_id != SG_FEEL)
return;
i = sd->menuskill_val-1;
- if (i<0 || i > 2) return; //Bug?
+ if (i<0 || i >= MAX_PC_FEELHATE) return; //Bug?
sd->feel_map[i].index = map_id2index(sd->bl.m);
sd->feel_map[i].m = sd->bl.m;
@@ -12738,9 +12749,10 @@ void clif_parse_Mail_setattach(int fd, struct map_session_data *sd)
/*------------------------------------------
* Mail Window Operation
+ * S 0246 <flag>.W
* 0 : Switch to 'new mail' window, or Close mailbox
* 1 : ???
- * 2 : ???
+ * 2 : Zeny entering start
*------------------------------------------*/
void clif_parse_Mail_winopen(int fd, struct map_session_data *sd)
{
@@ -13592,12 +13604,9 @@ void clif_parse_mercenary_action(int fd, struct map_session_data* sd)
* 2 = Your mercenary soldier has been fired.
* 3 = Your mercenary soldier has ran away.
*------------------------------------------*/
-void clif_mercenary_message(int fd, int message)
+void clif_mercenary_message(struct map_session_data* sd, int message)
{
- WFIFOHEAD(fd,4);
- WFIFOW(fd,0) = 0x0291;
- WFIFOW(fd,2) = 1266 + message;
- WFIFOSET(fd,4);
+ clif_msg(sd, 1266 + message);
}
/*------------------------------------------
@@ -13959,6 +13968,23 @@ void clif_displayexp(struct map_session_data *sd, unsigned int exp, char type, b
return;
}
+/// Displays digital clock digits on top of the screen (ZC_SHOWDIGIT).
+/// type:
+/// 0: Displays 'value' for 5 seconds.
+/// 1: Incremental counter (1 tick/second), negated 'value' specifies start value (e.g. using -10 lets the counter start at 10).
+/// 2: Decremental counter (1 tick/second), negated 'value' specifies start value (does not stop when reaching 0, but overflows).
+/// 3: Decremental counter (2 ticks/second), 'value' specifies start value (stops when reaching 0, displays at most 2 digits).
+/// value:
+/// Except for type 3 it is interpreted as seconds for displaying as DD:HH:MM:SS, HH:MM:SS, MM:SS or SS (leftmost '00' is not displayed).
+void clif_showdigit(struct map_session_data* sd, unsigned char type, int value)
+{
+ WFIFOHEAD(sd->fd, packet_len(0x1b1));
+ WFIFOW(sd->fd,0) = 0x1b1;
+ WFIFOB(sd->fd,0) = type;
+ WFIFOL(sd->fd,0) = value;
+ WFIFOSET(sd->fd, packet_len(0x1b1));
+}
+
/*==========================================
* パケットデバッグ
*------------------------------------------*/
@@ -13987,10 +14013,10 @@ int clif_parse(int fd)
TBL_PC* sd;
int pnum;
- //TODO apply deplays or disconnect based on packet throughput [FlavioJS]
+ //TODO apply delays or disconnect based on packet throughput [FlavioJS]
// Note: "click masters" can do 80+ clicks in 10 seconds
- for( pnum = 0; pnum < 3; ++pnum )// Limit max packets per cycle to 3 (delay packet spammers) [FlavioJS]
+ for( pnum = 0; pnum < 3; ++pnum )// Limit max packets per cycle to 3 (delay packet spammers) [FlavioJS] -- This actually aids packet spammers, but stuff like /str+ gets slow without it [Ai4rei]
{ // begin main client packet processing loop
sd = (TBL_PC *)session[fd]->session_data;
@@ -14491,6 +14517,8 @@ static int packetdb_readdb(void)
{clif_parse_GMShift,"shift"},
{clif_parse_GMChangeMapType,"changemaptype"},
{clif_parse_GMRc,"rc"},
+ {clif_parse_GMRecall2,"recall2"},
+ {clif_parse_GMRemove2,"remove2"},
{clif_parse_NoviceDoriDori,"sndoridori"},
{clif_parse_NoviceExplosionSpirits,"snexplosionspirits"},
diff --git a/src/map/clif.h b/src/map/clif.h
index d3a3679f1..ded8ece30 100644
--- a/src/map/clif.h
+++ b/src/map/clif.h
@@ -78,6 +78,101 @@ typedef enum send_target {
BG_AREA_WOS,
} send_target;
+typedef enum emotion_type
+{
+ E_GASP = 0, // /!
+ E_WHAT, // /?
+ E_HO,
+ E_LV,
+ E_SWT,
+ E_IC,
+ E_AN,
+ E_AG,
+ E_CASH, // /$
+ E_DOTS, // /...
+ E_SCISSORS, // /gawi --- 10
+ E_ROCK, // /bawi
+ E_PAPER, // /bo
+ E_KOREA,
+ E_LV2,
+ E_THX,
+ E_WAH,
+ E_SRY,
+ E_HEH,
+ E_SWT2,
+ E_HMM, // --- 20
+ E_NO1,
+ E_NO, // /??
+ E_OMG,
+ E_OH,
+ E_X,
+ E_HLP,
+ E_GO,
+ E_SOB,
+ E_GG,
+ E_KIS, // --- 30
+ E_KIS2,
+ E_PIF,
+ E_OK,
+ E_MUTE, // red /... used for muted characters
+ E_INDONESIA,
+ E_BZZ, // /bzz, /stare
+ E_RICE,
+ E_AWSM, // /awsm, /cool
+ E_MEH,
+ E_SHY, // --- 40
+ E_PAT, // /pat, /goodboy
+ E_MP, // /mp, /sptime
+ E_SLUR,
+ E_COM, // /com, /comeon
+ E_YAWN, // /yawn, /sleepy
+ E_GRAT, // /grat, /congrats
+ E_HP, // /hp, /hptime
+ E_PHILIPPINES,
+ E_MALAYSIA,
+ E_SINGAPORE, // --- 50
+ E_BRAZIL,
+ E_FLASH, // /fsh
+ E_SPIN, // /spin
+ E_SIGH,
+ E_PROUD, // /dum
+ E_LOUD, // /crwd
+ E_OHNOES, // /desp, /otl
+ E_DICE1,
+ E_DICE2,
+ E_DICE3, // --- 60
+ E_DICE4,
+ E_DICE5,
+ E_DICE6,
+ E_INDIA,
+ E_LOOSER,
+ E_RUSSIA,
+ E_VIRGIN,
+ E_PHONE,
+ E_MAIL,
+ E_CHINESE, // --- 70
+ E_SIGNAL,
+ E_SIGNAL2,
+ E_SIGNAL3,
+ E_HUM,
+ E_ABS,
+ E_OOPS,
+ E_SPIT,
+ E_ENE,
+ E_PANIC,
+ E_WHISP, // --- 80
+ //
+ E_MAX
+} emotion_type;
+
+typedef enum clr_type
+{
+ CLR_OUTSIGHT = 0,
+ CLR_DEAD,
+ CLR_RESPAWN,
+ CLR_TELEPORT,
+} clr_type;
+
int clif_setip(const char* ip);
void clif_setbindip(const char* ip);
void clif_setport(uint16 port);
@@ -92,8 +187,8 @@ int clif_charselectok(int);
int clif_dropflooritem(struct flooritem_data *);
int clif_clearflooritem(struct flooritem_data *,int);
-int clif_clearunit_single(int id, uint8 type, int fd);
-int clif_clearunit_area(struct block_list* bl, uint8 type);
+int clif_clearunit_single(int id, clr_type type, int fd);
+int clif_clearunit_area(struct block_list* bl, clr_type type);
int clif_clearunit_delayed(struct block_list* bl, unsigned int tick);
int clif_spawn(struct block_list*); //area
int clif_walkok(struct map_session_data*); // self
@@ -133,14 +228,13 @@ int clif_statusupack(struct map_session_data *,int,int,int); // self
int clif_equipitemack(struct map_session_data *,int,int,int); // self
int clif_unequipitemack(struct map_session_data *,int,int,int); // self
int clif_misceffect(struct block_list*,int); // area
-int clif_misceffect2(struct block_list *bl,int type);
int clif_changeoption(struct block_list*); // area
int clif_changeoption2(struct block_list*); // area
int clif_useitemack(struct map_session_data*,int,int,int); // self
void clif_GlobalMessage(struct block_list* bl, const char* message);
-void clif_createchat(struct map_session_data* sd, int fail); // self
+void clif_createchat(struct map_session_data* sd, int flag); // self
int clif_dispchat(struct chat_data*,int); // area or fd
-int clif_joinchatfail(struct map_session_data*,int); // self
+int clif_joinchatfail(struct map_session_data* sd,int flag); // self
int clif_joinchatok(struct map_session_data*,struct chat_data*); // self
int clif_addchat(struct chat_data*,struct map_session_data*); // chat
void clif_changechatowner(struct chat_data* cd, struct map_session_data* sd); // chat
@@ -158,7 +252,7 @@ void clif_talkiebox(struct block_list* bl, const char* talkie);
void clif_wedding_effect(struct block_list *bl);
void clif_divorced(struct map_session_data* sd, const char* name);
void clif_callpartner(struct map_session_data *sd);
-void clif_playBGM(struct map_session_data* sd, struct block_list* bl, const char* name);
+void clif_playBGM(struct map_session_data* sd, const char* name);
void clif_soundeffect(struct map_session_data* sd, struct block_list* bl, const char* name, int type);
int clif_soundeffectall(struct block_list* bl, const char *name, int type, enum send_target coverage);
void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type, int target_id, unsigned int tick);
@@ -176,14 +270,12 @@ void clif_tradecompleted(struct map_session_data* sd, int fail);
// storage
#include "storage.h"
-void clif_storagelist(struct map_session_data* sd, struct storage_data* stor);
+void clif_storagelist(struct map_session_data* sd, struct item* items, int items_length);
void clif_updatestorageamount(struct map_session_data* sd, int amount);
void clif_storageitemadded(struct map_session_data* sd, struct item* i, int index, int amount);
void clif_storageitemremoved(struct map_session_data* sd, int index, int amount);
void clif_storageclose(struct map_session_data* sd);
-void clif_guildstoragelist(struct map_session_data* sd, struct guild_storage* stor);
void clif_updateguildstorageamount(struct map_session_data* sd, int amount);
-void clif_guildstorageitemadded(struct map_session_data* sd, struct item* i, int index, int amount);
int clif_insight(struct block_list *,va_list); // map_forallinmovearea callback
int clif_outsight(struct block_list *,va_list); // map_forallinmovearea callback
@@ -218,7 +310,7 @@ int clif_produceeffect(struct map_session_data* sd,int flag,int nameid);
void clif_skill_setunit(struct skill_unit *unit);
void clif_skill_delunit(struct skill_unit *unit);
-void clif_01ac(struct block_list* bl);
+void clif_skillunit_update(struct block_list* bl);
int clif_autospell(struct map_session_data *sd,int skilllv);
void clif_devotion(struct block_list *src, struct map_session_data *tsd);
@@ -390,6 +482,7 @@ void clif_get_weapon_view(struct map_session_data* sd, unsigned short *rhand, un
int clif_party_xy_remove(struct map_session_data *sd); //Fix for minimap [Kevin]
void clif_gospel_info(struct map_session_data *sd, int type);
void clif_parse_ReqFeel(int fd, struct map_session_data *sd, int skilllv);
+void clif_starskill(struct map_session_data* sd, const char* mapname, int monster_id, unsigned char star, unsigned char result);
void clif_feel_info(struct map_session_data *sd, unsigned char feel_level, unsigned char type);
void clif_hate_info(struct map_session_data *sd, unsigned char hate_level,int class_, unsigned char type);
void clif_mission_info(struct map_session_data *sd, int mob_id, unsigned char progress);
@@ -409,6 +502,8 @@ void clif_viewequip_ack(struct map_session_data* sd, struct map_session_data* ts
void clif_viewequip_fail(struct map_session_data* sd);
void clif_equipcheckbox(struct map_session_data* sd);
+void clif_msg(struct map_session_data* sd, unsigned short id);
+
//quest system [Kevin] [Inkfish]
void clif_quest_send_list(struct map_session_data * sd);
void clif_quest_send_mission(struct map_session_data * sd);
@@ -450,7 +545,7 @@ void clif_Adopt_reply(struct map_session_data *sd, int type);
// MERCENARIES
void clif_mercenary_info(struct map_session_data *sd);
void clif_mercenary_skillblock(struct map_session_data *sd);
-void clif_mercenary_message(int fd, int message);
+void clif_mercenary_message(struct map_session_data* sd, int message);
void clif_mercenary_updatestatus(struct map_session_data *sd, int type);
// RENTAL SYSTEM
@@ -469,9 +564,11 @@ void clif_progressbar_abort(struct map_session_data * sd);
void clif_PartyBookingRegisterAck(struct map_session_data *sd, int flag);
void clif_PartyBookingDeleteAck(struct map_session_data* sd, int flag);
-void clif_PartyBookingSearchAck(int fd, unsigned long *index, int count, bool more_result);
+void clif_PartyBookingSearchAck(int fd, struct party_booking_ad_info** results, int count, bool more_result);
void clif_PartyBookingUpdateNotify(struct map_session_data* sd, struct party_booking_ad_info* pb_ad);
void clif_PartyBookingDeleteNotify(struct map_session_data* sd, int index);
void clif_PartyBookingInsertNotify(struct map_session_data* sd, struct party_booking_ad_info* pb_ad);
+void clif_showdigit(struct map_session_data* sd, unsigned char type, int value);
+
#endif /* _CLIF_H_ */
diff --git a/src/map/guild.c b/src/map/guild.c
index cdc978929..f90fc8946 100644
--- a/src/map/guild.c
+++ b/src/map/guild.c
@@ -1068,8 +1068,8 @@ int guild_notice_changed(int guild_id,const char *mes1,const char *mes2)
if(g==NULL)
return 0;
- memcpy(g->mes1,mes1,60);
- memcpy(g->mes2,mes2,120);
+ memcpy(g->mes1,mes1,MAX_GUILDMES1);
+ memcpy(g->mes2,mes2,MAX_GUILDMES2);
for(i=0;i<g->max_member;i++){
if((sd=g->member[i].sd)!=NULL)
diff --git a/src/map/homunculus.c b/src/map/homunculus.c
index 97a3274fb..0fbd7cbff 100644
--- a/src/map/homunculus.c
+++ b/src/map/homunculus.c
@@ -68,7 +68,7 @@ int merc_hom_dead(struct homun_data *hd, struct block_list *src)
//There's no intimacy penalties on death (from Tharis)
struct map_session_data *sd = hd->master;
- clif_emotion(&hd->bl, 16) ; //wah
+ clif_emotion(&hd->bl, E_WAH);
//Delete timers when dead.
merc_hom_hungry_timer_delete(hd);
@@ -77,7 +77,7 @@ int merc_hom_dead(struct homun_data *hd, struct block_list *src)
if (!sd) //unit remove map will invoke unit free
return 3;
- clif_emotion(&sd->bl, 28) ; //sob
+ clif_emotion(&sd->bl, E_SOB);
//Remove from map (if it has no intimacy, it is auto-removed from memory)
return 3;
}
@@ -107,7 +107,7 @@ int merc_hom_vaporize(struct map_session_data *sd, int flag)
memset(hd->blockskill, 0, sizeof(hd->blockskill));
clif_hominfo(sd, sd->hd, 0);
merc_save(hd);
- return unit_remove_map(&hd->bl, 0);
+ return unit_remove_map(&hd->bl, CLR_OUTSIGHT);
}
//delete a homunculus, completely "killing it".
@@ -119,7 +119,7 @@ int merc_hom_delete(struct homun_data *hd, int emote)
sd = hd->master;
if (!sd)
- return unit_free(&hd->bl,1);
+ return unit_free(&hd->bl,CLR_DEAD);
if (emote >= 0)
clif_emotion(&sd->bl, emote);
@@ -129,7 +129,7 @@ int merc_hom_delete(struct homun_data *hd, int emote)
// Send homunculus_dead to client
hd->homunculus.hp = 0;
clif_hominfo(sd, hd, 0);
- return unit_remove_map(&hd->bl,0);
+ return unit_remove_map(&hd->bl,CLR_OUTSIGHT);
}
int merc_hom_calc_skilltree(struct homun_data *hd)
@@ -147,7 +147,7 @@ int merc_hom_calc_skilltree(struct homun_data *hd)
continue; //Skill already known.
if(!battle_config.skillfree)
{
- for(j=0;j<5;j++)
+ for(j=0;j<MAX_PC_SKILL_REQUIRE;j++)
{
if( hskill_tree[c][i].need[j].id &&
merc_hom_checkskill(hd,hskill_tree[c][i].need[j].id) < hskill_tree[c][i].need[j].lv)
@@ -291,7 +291,7 @@ int merc_hom_evolution(struct homun_data *hd)
if(!hd->homunculusDB->evo_class || hd->homunculus.class_ == hd->homunculusDB->evo_class)
{
- clif_emotion(&hd->bl, 4) ; //swt
+ clif_emotion(&hd->bl, E_SWT);
return 0 ;
}
sd = hd->master;
@@ -317,12 +317,12 @@ int merc_hom_evolution(struct homun_data *hd)
hom->luk += 10*rand(min->luk, max->luk);
hom->intimacy = 500;
- unit_remove_map(&hd->bl, 0);
+ unit_remove_map(&hd->bl, CLR_OUTSIGHT);
map_addblock(&hd->bl);
clif_spawn(&hd->bl);
- clif_emotion(&sd->bl, 21); //no1
- clif_misceffect2(&hd->bl,568);
+ clif_emotion(&sd->bl, E_NO1);
+ clif_specialeffect(&hd->bl,568,AREA);
//status_Calc flag&1 will make current HP/SP be reloaded from hom structure
hom->hp = hd->battle_status.hp;
@@ -362,7 +362,7 @@ int merc_hom_gainexp(struct homun_data *hd,int exp)
if( hd->exp_next == 0 )
hd->homunculus.exp = 0 ;
- clif_misceffect2(&hd->bl,568);
+ clif_specialeffect(&hd->bl,568,AREA);
status_calc_homunculus(hd,0);
status_percent_heal(&hd->bl, 100, 100);
return 0;
@@ -448,33 +448,33 @@ int merc_hom_food(struct map_session_data *sd, struct homun_data *hd)
if ( hd->homunculus.hunger >= 91 ) {
merc_hom_decrease_intimacy(hd, 50);
- emotion = 16;
+ emotion = E_WAH;
} else if ( hd->homunculus.hunger >= 76 ) {
merc_hom_decrease_intimacy(hd, 5);
- emotion = 19;
+ emotion = E_SWT2;
} else if ( hd->homunculus.hunger >= 26 ) {
merc_hom_increase_intimacy(hd, 75);
- emotion = 2;
+ emotion = E_HO;
} else if ( hd->homunculus.hunger >= 11 ) {
merc_hom_increase_intimacy(hd, 100);
- emotion = 2;
+ emotion = E_HO;
} else {
merc_hom_increase_intimacy(hd, 50);
- emotion = 2;
+ emotion = E_HO;
}
hd->homunculus.hunger += 10; //dunno increase value for each food
if(hd->homunculus.hunger > 100)
hd->homunculus.hunger = 100;
- clif_emotion(&hd->bl,emotion) ;
+ clif_emotion(&hd->bl,emotion);
clif_send_homdata(sd,SP_HUNGRY,hd->homunculus.hunger);
clif_send_homdata(sd,SP_INTIMATE,hd->homunculus.intimacy / 100);
clif_hom_food(sd,foodID,1);
// Too much food :/
if(hd->homunculus.intimacy == 0)
- return merc_hom_delete(sd->hd, 23); //omg
+ return merc_hom_delete(sd->hd, E_OMG);
return 0;
}
@@ -500,18 +500,18 @@ static int merc_hom_hungry(int tid, unsigned int tick, int id, intptr data)
hd->homunculus.hunger-- ;
if(hd->homunculus.hunger <= 10) {
- clif_emotion(&hd->bl, 6) ; //an
+ clif_emotion(&hd->bl, E_AN);
} else if(hd->homunculus.hunger == 25) {
- clif_emotion(&hd->bl, 20) ; //hmm
+ clif_emotion(&hd->bl, E_HMM);
} else if(hd->homunculus.hunger == 75) {
- clif_emotion(&hd->bl, 33) ; //ok
+ clif_emotion(&hd->bl, E_OK);
}
if(hd->homunculus.hunger < 0) {
hd->homunculus.hunger = 0;
// Delete the homunculus if intimacy <= 100
if ( !merc_hom_decrease_intimacy(hd, 100) )
- return merc_hom_delete(hd, 23); //omg
+ return merc_hom_delete(hd, E_OMG);
clif_send_homdata(sd,SP_INTIMATE,hd->homunculus.intimacy / 100);
}
@@ -676,7 +676,7 @@ int merc_call_homunculus(struct map_session_data *sd)
merc_save(hd);
} else
//Warp him to master.
- unit_warp(&hd->bl,sd->bl.m, sd->bl.x, sd->bl.y,0);
+ unit_warp(&hd->bl,sd->bl.m, sd->bl.x, sd->bl.y,CLR_OUTSIGHT);
return 1;
}
@@ -871,7 +871,7 @@ int merc_hom_shuffle(struct homun_data *hd)
clif_homskillinfoblock(sd);
status_calc_homunculus(hd,0);
status_percent_heal(&hd->bl, 100, 100);
- clif_misceffect2(&hd->bl,568);
+ clif_specialeffect(&hd->bl,568,AREA);
return 1;
}
@@ -1088,7 +1088,7 @@ int read_homunculus_skilldb(void)
if (minJobLevelPresent)
hskill_tree[classid][j].joblv=atoi(split[3]);
- for(k=0;k<5;k++){
+ for(k=0;k<MAX_PC_SKILL_REQUIRE;k++){
hskill_tree[classid][j].need[k].id=atoi(split[3+k*2+minJobLevelPresent]);
hskill_tree[classid][j].need[k].lv=atoi(split[3+k*2+minJobLevelPresent+1]);
}
diff --git a/src/map/instance.c b/src/map/instance.c
index c1d43c27b..6fa3a2c0a 100644
--- a/src/map/instance.c
+++ b/src/map/instance.c
@@ -235,7 +235,7 @@ int instance_del_load(struct map_session_data* sd, va_list args)
if( !sd || sd->bl.m != m )
return 0;
- pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, 0);
+ pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, CLR_OUTSIGHT);
return 1;
}
@@ -439,9 +439,9 @@ void instance_check_kick(struct map_session_data *sd)
if( map[m].instance_id )
{ // User was on the instance map
if( map[m].save.map )
- pc_setpos(sd, map[m].save.map, map[m].save.x, map[m].save.y, 3);
+ pc_setpos(sd, map[m].save.map, map[m].save.x, map[m].save.y, CLR_TELEPORT);
else
- pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, 3);
+ pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, CLR_TELEPORT);
}
}
diff --git a/src/map/intif.c b/src/map/intif.c
index ba5230bab..875baa036 100644
--- a/src/map/intif.c
+++ b/src/map/intif.c
@@ -698,8 +698,8 @@ int intif_guild_notice(int guild_id,const char *mes1,const char *mes2)
WFIFOHEAD(inter_fd,186);
WFIFOW(inter_fd,0)=0x303e;
WFIFOL(inter_fd,2)=guild_id;
- memcpy(WFIFOP(inter_fd,6),mes1,60);
- memcpy(WFIFOP(inter_fd,66),mes2,120);
+ memcpy(WFIFOP(inter_fd,6),mes1,MAX_GUILDMES1);
+ memcpy(WFIFOP(inter_fd,66),mes2,MAX_GUILDMES2);
WFIFOSET(inter_fd,186);
return 0;
}
@@ -984,10 +984,7 @@ int intif_parse_LoadGuildStorage(int fd)
if(battle_config.save_log)
ShowInfo("intif_open_guild_storage: %d\n",RFIFOL(fd,4) );
memcpy(gstor,RFIFOP(fd,12),sizeof(struct guild_storage));
- gstor->storage_status = 1;
- sd->state.storage_flag = 2;
- clif_guildstoragelist(sd,gstor);
- clif_updateguildstorageamount(sd,gstor->storage_amount);
+ storage_guild_storageopen(sd);
return 0;
}
int intif_parse_SaveGuildStorage(int fd)
@@ -1920,7 +1917,7 @@ int intif_parse_mercenary_received(int fd)
if( sizeof(struct s_mercenary) != len )
{
if( battle_config.etc_log )
- ShowError("intif: create mercenary data size error %d != %d\n", sizeof(struct s_homunculus), len);
+ ShowError("intif: create mercenary data size error %d != %d\n", sizeof(struct s_mercenary), len);
return 0;
}
diff --git a/src/map/itemdb.c b/src/map/itemdb.c
index 2096ddf9e..ce10f4f39 100644
--- a/src/map/itemdb.c
+++ b/src/map/itemdb.c
@@ -27,8 +27,6 @@ static struct item_group itemgroup_db[MAX_ITEMGROUP];
struct item_data dummy_item; //This is the default dummy item used for non-existant items. [Skotlex]
-int item_delays = 0;
-
/*==========================================
* 名前で検索用
*------------------------------------------*/
@@ -182,6 +180,27 @@ struct item_data* itemdb_exists(int nameid)
return item;
}
+/// Returns human readable name for given item type.
+/// @param type Type id to retrieve name for ( IT_* ).
+const char* itemdb_typename(int type)
+{
+ switch(type)
+ {
+ case IT_HEALING: return "Potion/Food";
+ case IT_USABLE: return "Usable";
+ case IT_ETC: return "Etc.";
+ case IT_WEAPON: return "Weapon";
+ case IT_ARMOR: return "Armor";
+ case IT_CARD: return "Card";
+ case IT_PETEGG: return "Pet Egg";
+ case IT_PETARMOR: return "Pet Accessory";
+ case IT_AMMO: return "Arrow/Ammunition";
+ case IT_DELAYCONSUME: return "Delay-Consume Usable";
+ case IT_CASH: return "Cash Usable";
+ }
+ return "Unknown Type";
+}
+
/*==========================================
* Converts the jobid from the format in itemdb
* to the format used by the map server. [Skotlex]
@@ -667,7 +686,7 @@ static int itemdb_read_itemtrade(void)
static int itemdb_read_itemdelay(void)
{
FILE *fp;
- int nameid, j;
+ int nameid, j, item_delays = 0;
char line[1024], *str[10], *p;
struct item_data *id;
@@ -679,12 +698,12 @@ static int itemdb_read_itemdelay(void)
while(fgets(line, sizeof(line), fp))
{
+ if (line[0] == '/' && line[1] == '/')
+ continue;
if (item_delays == MAX_ITEMDELAYS) {
- ShowError("itemdb_read_itemdelay: Too many entries specified in %s/item_delay.txt!\n", db_path);
+ ShowError("itemdb_read_itemdelay: Too many entries specified in %s/item_delay.txt! Increase MAX_ITEMDELAYS in itemdb.h!\n", db_path);
break;
}
- if (line[0] == '/' && line[1] == '/')
- continue;
memset(str, 0, sizeof(str));
for (j = 0, p = line; j < 2 && p; j++) {
str[j] = p;
@@ -750,6 +769,13 @@ static bool itemdb_parse_dbrow(char** str, const char* source, int line, int scr
safestrncpy(id->jname, str[2], sizeof(id->jname));
id->type = atoi(str[3]);
+
+ if( id->type < 0 || id->type == IT_UNKNOWN || id->type == IT_UNKNOWN2 || ( id->type > IT_DELAYCONSUME && id->type < IT_CASH ) || id->type >= IT_MAX )
+ {// catch invalid item types
+ ShowWarning("itemdb_parse_dbrow: Invalid item type %d for item %d. IT_ETC will be used.\n", id->type, nameid);
+ id->type = IT_ETC;
+ }
+
if (id->type == IT_DELAYCONSUME)
{ //Items that are consumed only after target confirmation
id->type = IT_USABLE;
@@ -809,8 +835,6 @@ static bool itemdb_parse_dbrow(char** str, const char* source, int line, int scr
id->look = atoi(str[18]);
id->flag.available = 1;
- id->flag.value_notdc = 0;
- id->flag.value_notoc = 0;
id->view_id = 0;
id->sex = itemdb_gendercheck(id); //Apply gender filtering.
@@ -1075,7 +1099,10 @@ void itemdb_reload(void)
// readjust itemdb pointer cache for each player
iter = mapit_geteachpc();
for( sd = (struct map_session_data*)mapit_first(iter); mapit_exists(iter); sd = (struct map_session_data*)mapit_next(iter) )
+ {
+ memset(sd->item_delay, 0, sizeof(sd->item_delay)); // reset item delays
pc_setinventorydata(sd);
+ }
mapit_free(iter);
}
diff --git a/src/map/itemdb.h b/src/map/itemdb.h
index 5b07b5c1b..3fb14b2d4 100644
--- a/src/map/itemdb.h
+++ b/src/map/itemdb.h
@@ -45,7 +45,7 @@ struct item_data {
int value_buy;
int value_sell;
int type;
- int maxchance; //For logs, for external game info, for scripts: Max drop chance of this item (e.g. 0.01% , etc.. if it = 0, then monsters don't drop it) [Lupus]
+ int maxchance; //For logs, for external game info, for scripts: Max drop chance of this item (e.g. 0.01% , etc.. if it = 0, then monsters don't drop it, -1 denotes items sold in shops only) [Lupus]
int sex;
int equip;
int weight;
@@ -71,8 +71,6 @@ struct item_data {
struct script_code *unequip_script;//Script executed once when unequipping.
struct {
unsigned available : 1;
- unsigned value_notdc : 1;
- unsigned value_notoc : 1;
short no_equip;
unsigned no_refine : 1; // [celest]
unsigned delay_consume : 1; // Signifies items that are not consumed immediately upon double-click [Skotlex]
@@ -108,14 +106,13 @@ struct item_data* itemdb_exists(int nameid);
#define itemdb_available(n) (itemdb_exists(n) && itemdb_search(n)->flag.available)
#define itemdb_viewid(n) (itemdb_search(n)->view_id)
#define itemdb_autoequip(n) (itemdb_search(n)->flag.autoequip)
+const char* itemdb_typename(int type);
int itemdb_group_bonus(struct map_session_data* sd, int itemid);
int itemdb_searchrandomid(int flags);
#define itemdb_value_buy(n) itemdb_search(n)->value_buy
#define itemdb_value_sell(n) itemdb_search(n)->value_sell
-#define itemdb_value_notdc(n) itemdb_search(n)->flag.value_notdc
-#define itemdb_value_notoc(n) itemdb_search(n)->flag.value_notoc
#define itemdb_canrefine(n) itemdb_search(n)->flag.no_refine
//Item trade restrictions [Skotlex]
int itemdb_isdropable_sub(struct item_data *, int, int);
diff --git a/src/map/log.c b/src/map/log.c
index 474a6bb96..bf6133684 100644
--- a/src/map/log.c
+++ b/src/map/log.c
@@ -27,7 +27,7 @@ time_t curtime;
//Bits: ||
//2 - Healing items (0)
//3 - Etc Items(3) + Arrows (10)
-//4 - Usable Items(2) + Scrolls,Lures(11)
+//4 - Usable Items(2) + Scrolls,Lures(11) + Usable Cash Items(18)
//5 - Weapon(4)
//6 - Shields,Armor,Headgears,Accessories,etc(5)
//7 - Cards(6)
@@ -45,14 +45,14 @@ int should_log_item(int filter, int nameid, int amount)
if ((filter&1) || // Filter = 1, we log any item
(filter&2 && item_data->type == IT_HEALING ) ||
(filter&4 && (item_data->type == IT_ETC || item_data->type == IT_AMMO) ) ||
- (filter&8 && item_data->type == IT_USABLE ) ||
+ (filter&8 && (item_data->type == IT_USABLE || item_data->type == IT_CASH) ) ||
(filter&16 && item_data->type == IT_WEAPON ) ||
(filter&32 && item_data->type == IT_ARMOR ) ||
(filter&64 && item_data->type == IT_CARD ) ||
(filter&128 && (item_data->type == IT_PETEGG || item_data->type == IT_PETARMOR) ) ||
(filter&256 && item_data->value_buy >= log_config.price_items_log ) || //expensive items
(filter&512 && abs(amount) >= log_config.amount_items_log ) || //big amount of items
- (filter&2048 && ((item_data->maxchance <= log_config.rare_items_log) || item_data->nameid == 714) ) //Rare items or Emperium
+ (filter&2048 && ((item_data->maxchance != -1 && item_data->maxchance <= log_config.rare_items_log) || item_data->nameid == 714) ) //Rare items or Emperium
) return item_data->nameid;
return 0;
diff --git a/src/map/map.c b/src/map/map.c
index 309095ff0..b052cd7bc 100644
--- a/src/map/map.c
+++ b/src/map/map.c
@@ -1645,7 +1645,7 @@ int map_quit(struct map_session_data *sd)
if( sd->pd ) pet_lootitem_drop(sd->pd, sd);
if( sd->state.storage_flag == 1 ) sd->state.storage_flag = 0; // No need to Double Save Storage on Quit.
- unit_remove_map_pc(sd,3);
+ unit_remove_map_pc(sd,CLR_TELEPORT);
if( map[sd->bl.m].instance_id )
{ // Avoid map conflicts and warnings on next login
@@ -1665,7 +1665,7 @@ int map_quit(struct map_session_data *sd)
}
}
- party_booking_delete(sd, true); // Party Booking [Spiria]
+ party_booking_delete(sd); // Party Booking [Spiria]
pc_makesavestatus(sd);
pc_clean_skilltree(sd);
chrif_save(sd,1);
@@ -2150,7 +2150,7 @@ int map_removemobs_sub(struct block_list *bl, va_list ap)
if( md->db->mexp > 0 )
return 0;
- unit_free(&md->bl,0);
+ unit_free(&md->bl,CLR_OUTSIGHT);
return 1;
}
@@ -2797,6 +2797,20 @@ int map_delmap(char* mapname)
return 0;
}
+/// Initializes map flags and adjusts them depending on configuration.
+void map_flags_init(void)
+{
+ int i;
+
+ for( i = 0; i < map_num; i++ )
+ {
+ memset(&map[i].flag, 0, sizeof(map[i].flag));
+
+ if( battle_config.pk_mode )
+ map[i].flag.pvp = 1; // make all maps pvp for pk_mode [Valaris]
+ }
+}
+
#define NO_WATER 1000000
/*
@@ -2892,7 +2906,7 @@ int map_readallmaps (void)
int i;
FILE* fp=NULL;
int maps_removed = 0;
- unsigned char *map_cache_buffer; // Has the uncompressed gat data of all maps, so just one allocation has to be made
+ unsigned char *map_cache_buffer = NULL; // Has the uncompressed gat data of all maps, so just one allocation has to be made
unsigned char map_cache_decode_buffer[MAX_MAP_SIZE];
if( enable_grf )
@@ -2958,8 +2972,6 @@ int map_readallmaps (void)
map[i].m = i;
memset(map[i].moblist, 0, sizeof(map[i].moblist)); //Initialize moblist [Skotlex]
map[i].mob_delete_timer = INVALID_TIMER; //Initialize timer [Skotlex]
- if(battle_config.pk_mode)
- map[i].flag.pvp = 1; // make all maps pvp for pk_mode [Valaris]
map[i].bxs = (map[i].xs + BLOCK_SIZE - 1) / BLOCK_SIZE;
map[i].bys = (map[i].ys + BLOCK_SIZE - 1) / BLOCK_SIZE;
@@ -2973,6 +2985,9 @@ int map_readallmaps (void)
map[i].block_mob = (struct block_list**)aCalloc(size, 1);
}
+ // intialization and configuration-dependent adjustments of mapflags
+ map_flags_init();
+
if( !enable_grf ) {
fclose(fp);
@@ -3205,7 +3220,7 @@ int inter_config_read(char *cfgName)
continue;
if(strcmpi(w1, "main_chat_nick")==0)
- strcpy(main_chat_nick, w2);
+ safestrncpy(main_chat_nick, w2, sizeof(main_chat_nick));
#ifndef TXT_ONLY
else
@@ -3365,7 +3380,7 @@ int cleanup_sub(struct block_list *bl, va_list ap)
npc_unload((struct npc_data *)bl);
break;
case BL_MOB:
- unit_free(bl,0);
+ unit_free(bl,CLR_OUTSIGHT);
break;
case BL_PET:
//There is no need for this, the pet is removed together with the player. [Skotlex]
diff --git a/src/map/map.h b/src/map/map.h
index 9f25249e2..3b1775e46 100644
--- a/src/map/map.h
+++ b/src/map/map.h
@@ -296,6 +296,8 @@ enum _sp {
SP_BASEJOB=119, // 100+19 - celest
SP_BASECLASS=120, //Hmm.. why 100+19? I just use the next one... [Skotlex]
+ SP_KILLERRID=121,
+ SP_KILLEDRID=122,
// Mercenaries
SP_MERCFLEE=165, SP_MERCKILLS=189, SP_MERCFAITH=190,
@@ -628,6 +630,7 @@ int cleanup_sub(struct block_list *bl, va_list ap);
void map_helpscreen(int flag); // [Valaris]
int map_delmap(char* mapname);
+void map_flags_init(void);
bool map_iwall_set(int m, int x, int y, int size, int dir, bool shootable, const char* wall_name);
void map_iwall_get(struct map_session_data *sd);
diff --git a/src/map/mapreg_sql.c b/src/map/mapreg_sql.c
index 287aae4f9..f80be56a2 100644
--- a/src/map/mapreg_sql.c
+++ b/src/map/mapreg_sql.c
@@ -122,9 +122,9 @@ static void script_load_mapreg(void)
return;
}
- SqlStmt_BindColumn(stmt, 0, SQLDT_STRING, &varname[0], 32, &length, NULL);
+ SqlStmt_BindColumn(stmt, 0, SQLDT_STRING, &varname[0], sizeof(varname), &length, NULL);
SqlStmt_BindColumn(stmt, 1, SQLDT_INT, &index, 0, NULL, NULL);
- SqlStmt_BindColumn(stmt, 2, SQLDT_STRING, &value[0], 255, NULL, NULL);
+ SqlStmt_BindColumn(stmt, 2, SQLDT_STRING, &value[0], sizeof(value), NULL, NULL);
while ( SQL_SUCCESS == SqlStmt_NextRow(stmt) )
{
diff --git a/src/map/mercenary.c b/src/map/mercenary.c
index 84974e906..79bec2da6 100644
--- a/src/map/mercenary.c
+++ b/src/map/mercenary.c
@@ -244,7 +244,7 @@ int merc_delete(struct mercenary_data *md, int reply)
merc_contract_stop(md);
if( !sd )
- return unit_free(&md->bl, 0);
+ return unit_free(&md->bl, CLR_OUTSIGHT);
if( md->devotion_flag )
{
@@ -258,8 +258,8 @@ int merc_delete(struct mercenary_data *md, int reply)
case 1: mercenary_set_faith(md, -1); break; // -1 Loyalty on Mercenary killed
}
- clif_mercenary_message(sd->fd, reply);
- return unit_remove_map(&md->bl, 0);
+ clif_mercenary_message(sd, reply);
+ return unit_remove_map(&md->bl, CLR_OUTSIGHT);
}
void merc_contract_stop(struct mercenary_data *md)
diff --git a/src/map/mob.c b/src/map/mob.c
index 413d88f26..d67b470af 100644
--- a/src/map/mob.c
+++ b/src/map/mob.c
@@ -82,7 +82,6 @@ const int mob_splendide[5] = { 1991, 1992, 1993, 1994, 1995 };
*------------------------------------------*/
static int mob_makedummymobdb(int);
static int mob_spawn_guardian_sub(int tid, unsigned int tick, int id, intptr data);
-int mobskill_use(struct mob_data *md,unsigned int tick,int event);
int mob_skillid2skillidx(int class_,int skillid);
/*==========================================
@@ -276,7 +275,7 @@ int mob_get_random_id(int type, int flag, int lv)
(flag&8 && mob->spawn[0].qty < 1)
) && (i++) < MAX_MOB_DB);
- if(i >= MAX_MOB_DB)
+ if(i >= MAX_MOB_DB) // no suitable monster found, use fallback for given list
class_ = mob_db_data[0]->summonper[type];
return class_;
}
@@ -449,7 +448,7 @@ int mob_once_spawn(struct map_session_data* sd, int m, short x, short y, const c
if (class_ < 0 && battle_config.dead_branch_active)
//Behold Aegis's masterful decisions yet again...
//"I understand the "Aggressive" part, but the "Can Move" and "Can Attack" is just stupid" - Poki#3
- sc_start4(&md->bl, SC_MODECHANGE, 100, 1, 0, MD_AGGRESSIVE|MD_CANATTACK|MD_CANMOVE, 0, 60000);
+ sc_start4(&md->bl, SC_MODECHANGE, 100, 1, 0, MD_AGGRESSIVE|MD_CANATTACK|MD_CANMOVE|MD_ANGRY, 0, 60000);
}
return (md)?md->bl.id : 0; // id of last spawned mob
@@ -547,7 +546,7 @@ static int mob_spawn_guardian_sub(int tid, unsigned int tick, int id, intptr dat
md->guardian_data->castle->guardian[md->guardian_data->number].visible = 0;
guild_castledatasave(md->guardian_data->castle->castle_id, 10+md->guardian_data->number,0);
}
- unit_free(&md->bl,0); //Remove guardian.
+ unit_free(&md->bl,CLR_OUTSIGHT); //Remove guardian.
}
return 0;
}
@@ -795,7 +794,7 @@ int mob_setdelayspawn(struct mob_data *md)
unsigned int spawntime;
if (!md->spawn) //Doesn't has respawn data!
- return unit_free(&md->bl,1);
+ return unit_free(&md->bl,CLR_DEAD);
spawntime = md->spawn->delay1; //Base respawn time
if (md->spawn->delay2) //random variance
@@ -826,7 +825,7 @@ int mob_spawn (struct mob_data *md)
md->last_thinktime = tick;
if (md->bl.prev != NULL)
- unit_remove_map(&md->bl,2);
+ unit_remove_map(&md->bl,CLR_RESPAWN);
else
if (md->spawn && md->class_ != md->spawn->class_)
{
@@ -1121,7 +1120,7 @@ static int mob_ai_sub_hard_slavemob(struct mob_data *md,unsigned int tick)
md->master_dist > MAX_MINCHASE
){
md->master_dist = 0;
- unit_warp(&md->bl,bl->m,bl->x,bl->y,3);
+ unit_warp(&md->bl,bl->m,bl->x,bl->y,CLR_TELEPORT);
return 1;
}
@@ -1761,7 +1760,7 @@ int mob_timer_delete(int tid, unsigned int tick, int id, intptr data)
}
//for Alchemist CANNIBALIZE [Lupus]
md->deletetimer = INVALID_TIMER;
- unit_free(bl, 3);
+ unit_free(bl, CLR_TELEPORT);
}
return 0;
}
@@ -1805,7 +1804,7 @@ int mob_respawn(int tid, unsigned int tick, int id, intptr data)
void mob_log_damage(struct mob_data *md, struct block_list *src, int damage)
{
- int char_id = 0, flag = 0;
+ int char_id = 0, flag = MDLF_NORMAL;
if( damage < 0 )
return; //Do nothing for absorbed damage.
@@ -1827,7 +1826,7 @@ void mob_log_damage(struct mob_data *md, struct block_list *src, int damage)
case BL_HOM:
{
struct homun_data *hd = (TBL_HOM*)src;
- flag = 1;
+ flag = MDLF_HOMUN;
if( hd->master )
char_id = hd->master->status.char_id;
if( damage )
@@ -1846,7 +1845,7 @@ void mob_log_damage(struct mob_data *md, struct block_list *src, int damage)
case BL_PET:
{
struct pet_data *pd = (TBL_PET*)src;
- flag = 2;
+ flag = MDLF_PET;
if( pd->msd )
{
char_id = pd->msd->status.char_id;
@@ -1960,9 +1959,9 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
unsigned int base_exp,job_exp;
} pt[DAMAGELOG_SIZE];
int i,temp,count,pnum=0,m=md->bl.m;
+ int dmgbltypes = 0; // bitfield of all bl types, that caused damage to the mob and are elligible for exp distribution
unsigned int mvp_damage, tick = gettick();
- unsigned short flaghom = 1; // [Zephyrus] Does the mob only received damage from homunculus?
- bool rebirth;
+ bool rebirth, homkillonly;
status = &md->status;
@@ -2022,9 +2021,9 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
count++; //Only logged into same map chars are counted for the total.
if (pc_isdead(tsd))
continue; // skip dead players
- if(md->dmglog[i].flag == 1 && !merc_is_hom_active(tsd->hd))
+ if(md->dmglog[i].flag == MDLF_HOMUN && !merc_is_hom_active(tsd->hd))
continue; // skip homunc's share if inactive
- if( md->dmglog[i].flag == 2 && (!tsd->status.pet_id || !tsd->pd) )
+ if( md->dmglog[i].flag == MDLF_PET && (!tsd->status.pet_id || !tsd->pd) )
continue; // skip pet's share if inactive
if(md->dmglog[i].dmg > mvp_damage)
@@ -2037,10 +2036,17 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
tmpsd[i] = tsd; // record as valid damage-log entry
- if(!md->dmglog[i].flag == 1 && flaghom)
- flaghom = 0; // Damage received from other Types != Homunculus
+ switch( md->dmglog[i].flag )
+ {
+ case MDLF_NORMAL: dmgbltypes|= BL_PC; break;
+ case MDLF_HOMUN: dmgbltypes|= BL_HOM; break;
+ case MDLF_PET: dmgbltypes|= BL_PET; break;
+ }
}
+ // determines, if the monster was killed by homunculus' damage only
+ homkillonly = (bool)( ( dmgbltypes&BL_HOM ) && !( dmgbltypes&~BL_HOM ) );
+
if(!battle_config.exp_calc_type && count > 1)
{ //Apply first-attacker 200% exp share bonus
//TODO: Determine if this should go before calculating the MVP player instead of after.
@@ -2065,9 +2071,9 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
temp = status_get_class(&md->bl);
if(sd->sc.data[SC_MIRACLE]) i = 2; //All mobs are Star Targets
else
- ARR_FIND(0, 3, i, temp == sd->hate_mob[i] &&
+ ARR_FIND(0, MAX_PC_FEELHATE, i, temp == sd->hate_mob[i] &&
(battle_config.allow_skill_without_day || sg_info[i].day_func()));
- if(i<3 && (temp=pc_checkskill(sd,sg_info[i].bless_id)))
+ if(i<MAX_PC_FEELHATE && (temp=pc_checkskill(sd,sg_info[i].bless_id)))
bonus += (i==2?20:10)*temp;
}
if(battle_config.mobs_level_up && md->level > md->db->lv) // [Valaris]
@@ -2103,7 +2109,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
else if(md->special_state.size==2)
per *=2.;
- if( md->dmglog[i].flag == 2 )
+ if( md->dmglog[i].flag == MDLF_PET )
per *= battle_config.pet_attack_exp_rate/100.;
if(battle_config.zeny_from_mobs && md->level) {
@@ -2118,12 +2124,12 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
else
base_exp = (unsigned int)cap_value(md->db->base_exp * per * bonus/100. * map[m].bexp/100., 1, UINT_MAX);
- if (map[m].flag.nojobexp || !md->db->job_exp || md->dmglog[i].flag == 1) //Homun earned job-exp is always lost.
+ if (map[m].flag.nojobexp || !md->db->job_exp || md->dmglog[i].flag == MDLF_HOMUN) //Homun earned job-exp is always lost.
job_exp = 0;
else
job_exp = (unsigned int)cap_value(md->db->job_exp * per * bonus/100. * map[m].jexp/100., 1, UINT_MAX);
- if((temp = tmpsd[i]->status.party_id )>0 && !md->dmglog[i].flag == 1) //Homun-done damage (flag 1) is not given to party
+ if((temp = tmpsd[i]->status.party_id )>0 && !md->dmglog[i].flag == MDLF_HOMUN) //Homun-done damage (flag 1) is not given to party
{
int j;
for(j=0;j<pnum && pt[j].id!=temp;j++); //Locate party.
@@ -2155,11 +2161,11 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
}
}
if(flag) {
- if(base_exp && md->dmglog[i].flag == 1) //tmpsd[i] is null if it has no homunc.
+ if(base_exp && md->dmglog[i].flag == MDLF_HOMUN) //tmpsd[i] is null if it has no homunc.
merc_hom_gainexp(tmpsd[i]->hd, base_exp);
if(base_exp || job_exp)
{
- if( md->dmglog[i].flag != 2 || battle_config.pet_attack_exp_to_master )
+ if( md->dmglog[i].flag != MDLF_PET || battle_config.pet_attack_exp_to_master )
pc_gainexp(tmpsd[i], &md->bl, base_exp, job_exp, false);
}
if(zeny) // zeny from mobs [Valaris]
@@ -2241,13 +2247,13 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
}
// Announce first, or else ditem will be freed. [Lance]
// By popular demand, use base drop rate for autoloot code. [Skotlex]
- mob_item_drop(md, dlist, ditem, 0, md->db->dropitem[i].p, flaghom);
+ mob_item_drop(md, dlist, ditem, 0, md->db->dropitem[i].p, homkillonly);
}
// Ore Discovery [Celest]
if (sd == mvp_sd && pc_checkskill(sd,BS_FINDINGORE)>0 && battle_config.finding_ore_rate/10 >= rand()%10000) {
ditem = mob_setdropitem(itemdb_searchrandomid(IG_FINDINGORE), 1);
- mob_item_drop(md, dlist, ditem, 0, battle_config.finding_ore_rate/10, 0);
+ mob_item_drop(md, dlist, ditem, 0, battle_config.finding_ore_rate/10, homkillonly);
}
if(sd) {
@@ -2273,7 +2279,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
if (rand()%10000 >= drop_rate)
continue;
itemid = (sd->add_drop[i].id > 0) ? sd->add_drop[i].id : itemdb_searchrandomid(sd->add_drop[i].group);
- mob_item_drop(md, dlist, mob_setdropitem(itemid,1), 0, drop_rate, 0);
+ mob_item_drop(md, dlist, mob_setdropitem(itemid,1), 0, drop_rate, homkillonly);
}
}
@@ -2289,7 +2295,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
// process items looted by the mob
if(md->lootitem) {
for(i = 0; i < md->lootitem_count; i++)
- mob_item_drop(md, dlist, mob_setlootitem(&md->lootitem[i]), 1, 10000, 0);
+ mob_item_drop(md, dlist, mob_setlootitem(&md->lootitem[i]), 1, 10000, homkillonly);
}
if (dlist->item) //There are drop items.
add_timer(tick + (!battle_config.delay_battle_damage?500:0), mob_delay_item_drop, 0, (intptr)dlist);
@@ -2305,7 +2311,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
dlist->third_charid = (third_sd ? third_sd->status.char_id : 0);
dlist->item = NULL;
for(i = 0; i < md->lootitem_count; i++)
- mob_item_drop(md, dlist, mob_setlootitem(&md->lootitem[i]), 1, 10000, 0);
+ mob_item_drop(md, dlist, mob_setlootitem(&md->lootitem[i]), 1, 10000, homkillonly);
add_timer(tick + (!battle_config.delay_battle_damage?500:0), mob_delay_item_drop, 0, (intptr)dlist);
}
@@ -2406,12 +2412,12 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
{
if( sd && battle_config.mob_npc_event_type )
{
- pc_setglobalreg(sd,"killerrid",sd->bl.id);
+ pc_setparam(sd, SP_KILLERRID, sd->bl.id);
npc_event(sd,md->npc_event,0);
}
else if( mvp_sd )
{
- pc_setglobalreg(mvp_sd,"killerrid",sd?sd->bl.id:0);
+ pc_setparam(mvp_sd, SP_KILLERRID, sd?sd->bl.id:0);
npc_event(mvp_sd,md->npc_event,0);
}
else
@@ -2419,7 +2425,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
}
else if( mvp_sd && !md->state.npc_killmonster )
{
- pc_setglobalreg(mvp_sd,"killedrid",md->class_);
+ pc_setparam(mvp_sd, SP_KILLEDRID, md->class_);
npc_script_event(mvp_sd, NPCE_KILLNPC); // PCKillNPC [Lance]
}
@@ -2491,7 +2497,7 @@ int mob_guardian_guildchange(struct block_list *bl,va_list ap)
md->guardian_data->castle->guardian[md->guardian_data->number].visible = 0;
guild_castledatasave(md->guardian_data->castle->castle_id, 10+md->guardian_data->number,0);
}
- unit_free(&md->bl,0); //Remove guardian.
+ unit_free(&md->bl,CLR_OUTSIGHT); //Remove guardian.
}
return 0;
}
@@ -2505,7 +2511,7 @@ int mob_guardian_guildchange(struct block_list *bl,va_list ap)
md->guardian_data->castle->guardian[md->guardian_data->number].visible = 0;
guild_castledatasave(md->guardian_data->castle->castle_id, 10+md->guardian_data->number,0);
}
- unit_free(&md->bl,0);
+ unit_free(&md->bl,CLR_OUTSIGHT);
return 0;
}
@@ -2631,7 +2637,7 @@ int mob_warpslave_sub(struct block_list *bl,va_list ap)
return 0;
map_search_freecell(master, 0, &x, &y, range, range, 0);
- unit_warp(&md->bl, master->m, x, y,2);
+ unit_warp(&md->bl, master->m, x, y,CLR_RESPAWN);
return 1;
}
@@ -3409,9 +3415,7 @@ static bool mob_parse_dbrow(char** str)
double exp, maxhp;
struct mob_data data;
- class_ = str[0] ? atoi(str[0]) : 0;
- if (class_ == 0)
- return false; //Leave blank lines alone... [Skotlex]
+ class_ = atoi(str[0]);
if (class_ <= 1000 || class_ > MAX_MOB_DB) {
ShowWarning("Mob with ID: %d not loaded. ID must be in range [%d-%d]\n", class_, 1000, MAX_MOB_DB);
@@ -3552,7 +3556,7 @@ static bool mob_parse_dbrow(char** str)
//calculate and store Max available drop chance of the MVP item
if (db->mvpitem[i].p) {
id = itemdb_search(db->mvpitem[i].nameid);
- if (id->maxchance == 10000 || (id->maxchance < db->mvpitem[i].p/10 + 1) ) {
+ if (id->maxchance == -1 || (id->maxchance < db->mvpitem[i].p/10 + 1) ) {
//item has bigger drop chance or sold in shops
id->maxchance = db->mvpitem[i].p/10 + 1; //reduce MVP drop info to not spoil common drop rate
}
@@ -3585,6 +3589,7 @@ static bool mob_parse_dbrow(char** str)
ratemax = battle_config.item_drop_heal_max;
break;
case IT_USABLE:
+ case IT_CASH:
rate_adjust = (status->mode&MD_BOSS) ? battle_config.item_rate_use_boss : battle_config.item_rate_use;
ratemin = battle_config.item_drop_use_min;
ratemax = battle_config.item_drop_use_max;
@@ -3613,7 +3618,7 @@ static bool mob_parse_dbrow(char** str)
if( db->dropitem[i].p && (class_ < 1324 || class_ > 1363) && (class_ < 1938 || class_ > 1946) )
{ //Skip treasure chests.
id = itemdb_search(db->dropitem[i].nameid);
- if (id->maxchance == 10000 || (id->maxchance < db->dropitem[i].p) ) {
+ if (id->maxchance == -1 || (id->maxchance < db->dropitem[i].p) ) {
id->maxchance = db->dropitem[i].p; //item has bigger drop chance or sold in shops
}
for (k = 0; k< MAX_SEARCH; k++) {
@@ -3636,61 +3641,31 @@ static bool mob_parse_dbrow(char** str)
/*==========================================
* mob_db.txt reading
*------------------------------------------*/
-static int mob_readdb(void)
+static bool mob_readdb_sub(char* fields[], int columns, int current)
+{
+ return mob_parse_dbrow(fields);
+}
+
+static void mob_readdb(void)
{
const char* filename[] = { "mob_db.txt", "mob_db2.txt" };
int fi;
for( fi = 0; fi < ARRAYLENGTH(filename); ++fi )
{
- uint32 lines = 0, count = 0;
- char line[1024];
char path[256];
- FILE* fp;
-
- sprintf(path, "%s/%s", db_path, filename[fi]);
- fp = fopen(path, "r");
- if(fp == NULL) {
- if(fi > 0)
- continue;
- return -1;
- }
-
- // process rows one by one
- while(fgets(line, sizeof(line), fp))
+
+ if(fi > 0)
{
- char *str[38+2*MAX_MOB_DROP], *p, *np;
- int i;
-
- lines++;
- if(line[0] == '/' && line[1] == '/')
- continue;
-
- for(i = 0, p = line; i < 38 + 2*MAX_MOB_DROP; i++)
+ sprintf(path, "%s/%s", db_path, filename[fi]);
+ if(!exists(path))
{
- str[i] = p;
- if((np = strchr(p, ',')) != NULL) {
- *np = '\0'; p = np + 1;
- }
- }
-
- if(i < 38 + 2*MAX_MOB_DROP) {
- ShowWarning("mob_readdb: Insufficient columns for mob with id: %d, skipping.\n", atoi(str[0]));
continue;
}
-
- if (!mob_parse_dbrow(str))
- continue;
-
- count++;
}
- fclose(fp);
-
- ShowStatus("Done reading '"CL_WHITE"%lu"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, filename[fi]);
+ sv_readdb(db_path, filename[fi], ',', 38+2*MAX_MOB_DROP, 38+2*MAX_MOB_DROP, -1, &mob_readdb_sub);
}
-
- return 0;
}
#ifndef TXT_ONLY
@@ -3753,73 +3728,42 @@ static int mob_read_sqldb(void)
/*==========================================
* MOB display graphic change data reading
*------------------------------------------*/
-static int mob_readdb_mobavail(void)
+static bool mob_readdb_mobavail(char* str[], int columns, int current)
{
- FILE *fp;
- char line[1024];
- int ln=0;
- int class_,j,k;
- char *str[20],*p,*np;
+ int class_, k;
- sprintf(line, "%s/mob_avail.txt", db_path);
- if( (fp=fopen(line,"r"))==NULL ){
- ShowError("can't read %s\n", line);
- return -1;
- }
+ class_=atoi(str[0]);
- while(fgets(line, sizeof(line), fp))
+ if(mob_db(class_) == mob_dummy) // 値が異常なら処理しない。
{
- if(line[0]=='/' && line[1]=='/')
- continue;
- memset(str,0,sizeof(str));
-
- for(j=0,p=line;j<12;j++){
- if((np=strchr(p,','))!=NULL){
- str[j]=p;
- *np=0;
- p=np+1;
- } else
- str[j]=p;
- }
-
- if(str[0]==NULL)
- continue;
-
- class_=atoi(str[0]);
- if (class_ == 0)
- continue; //Leave blank lines alone... [Skotlex]
-
- if(mob_db(class_) == mob_dummy) // 値が異常なら処理しない。
- continue;
-
- k=atoi(str[1]);
- if(k < 0)
- continue;
-
- memset(&mob_db_data[class_]->vd, 0, sizeof(struct view_data));
- mob_db_data[class_]->vd.class_=k;
-
- //Player sprites
- if(pcdb_checkid(k) && j>=12) {
- mob_db_data[class_]->vd.sex=atoi(str[2]);
- mob_db_data[class_]->vd.hair_style=atoi(str[3]);
- mob_db_data[class_]->vd.hair_color=atoi(str[4]);
- mob_db_data[class_]->vd.weapon=atoi(str[5]);
- mob_db_data[class_]->vd.shield=atoi(str[6]);
- mob_db_data[class_]->vd.head_top=atoi(str[7]);
- mob_db_data[class_]->vd.head_mid=atoi(str[8]);
- mob_db_data[class_]->vd.head_bottom=atoi(str[9]);
- mob_db_data[class_]->option=atoi(str[10])&~(OPTION_HIDE|OPTION_CLOAK|OPTION_INVISIBLE);
- mob_db_data[class_]->vd.cloth_color=atoi(str[11]); // Monster player dye option - Valaris
- }
- else if(str[2] && atoi(str[2]) > 0)
- mob_db_data[class_]->vd.head_bottom=atoi(str[2]); // mob equipment [Valaris]
+ ShowWarning("mob_readdb_mobavail: Unknown mob id %d.\n", class_);
+ return false;
+ }
- ln++;
+ k=atoi(str[1]);
+
+ memset(&mob_db_data[class_]->vd, 0, sizeof(struct view_data));
+ mob_db_data[class_]->vd.class_=k;
+
+ //Player sprites
+ if(pcdb_checkid(k) && columns==12) {
+ mob_db_data[class_]->vd.sex=atoi(str[2]);
+ mob_db_data[class_]->vd.hair_style=atoi(str[3]);
+ mob_db_data[class_]->vd.hair_color=atoi(str[4]);
+ mob_db_data[class_]->vd.weapon=atoi(str[5]);
+ mob_db_data[class_]->vd.shield=atoi(str[6]);
+ mob_db_data[class_]->vd.head_top=atoi(str[7]);
+ mob_db_data[class_]->vd.head_mid=atoi(str[8]);
+ mob_db_data[class_]->vd.head_bottom=atoi(str[9]);
+ mob_db_data[class_]->option=atoi(str[10])&~(OPTION_HIDE|OPTION_CLOAK|OPTION_INVISIBLE);
+ mob_db_data[class_]->vd.cloth_color=atoi(str[11]); // Monster player dye option - Valaris
}
- fclose(fp);
- ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n",ln,"mob_avail.txt");
- return 0;
+ else if(columns==3)
+ mob_db_data[class_]->vd.head_bottom=atoi(str[2]); // mob equipment [Valaris]
+ else if( columns != 2 )
+ return false;
+
+ return true;
}
/*==========================================
@@ -3842,7 +3786,7 @@ static int mob_read_randommonster(void)
for( i = 0; i < ARRAYLENGTH(mobfile) && i < MAX_RANDOMMONSTER; i++ )
{
- mob_db_data[0]->summonper[i] = 1002; // 設定し忘れた場合はポリンが出るようにしておく
+ mob_db_data[0]->summonper[i] = 1002; // Default fallback value, in case the database does not provide one
sprintf(line, "%s/%s", db_path, mobfile[i]);
fp=fopen(line,"r");
if(fp==NULL){
@@ -3894,8 +3838,10 @@ static int mob_read_randommonster(void)
*------------------------------------------*/
static bool mob_parse_row_chatdb(char** str, const char* source, int line, int* last_msg_id)
{
+ char* msg;
struct mob_chat *ms;
int msg_id;
+ size_t len;
msg_id = atoi(str[0]);
@@ -3917,13 +3863,29 @@ static bool mob_parse_row_chatdb(char** str, const char* source, int line, int*
//Color
ms->color=strtoul(str[1],NULL,0);
//Message
- if(strlen(str[2])>(CHAT_SIZE_MAX-1)){
+ msg = str[2];
+ len = strlen(msg);
+
+ while( len && ( msg[len-1]=='\r' || msg[len-1]=='\n' ) )
+ {// find EOL to strip
+ len--;
+ }
+
+ if(len>(CHAT_SIZE_MAX-1))
+ {
if (msg_id != *last_msg_id) {
ShowError("mob_chat: readdb: Message too long! Line %d, id: %d\n", line, msg_id);
*last_msg_id = msg_id;
}
return false;
}
+ else if( !len )
+ {
+ ShowWarning("mob_parse_row_chatdb: Empty message for id %d.\n", msg_id);
+ return false;
+ }
+
+ msg[len] = 0; // strip previously found EOL
strncpy(ms->msg, str[2], CHAT_SIZE_MAX);
return true;
@@ -3987,9 +3949,8 @@ static void mob_readchatdb(void)
/*==========================================
* processes one mob_skill_db entry
- * @param last_mob_id ensures that only one error message per mob id is printed
*------------------------------------------*/
-static bool mob_parse_row_mobskilldb(char** str, const char* source, int line, int* last_mob_id)
+static bool mob_parse_row_mobskilldb(char** str, int columns, int current)
{
static const struct {
char str[32];
@@ -4058,6 +4019,7 @@ static bool mob_parse_row_mobskilldb(char** str, const char* source, int line, i
{ "around4", MST_AROUND4 },
{ "around", MST_AROUND },
};
+ static int last_mob_id = 0; // ensures that only one error message per mob id is printed
struct mob_skill *ms, gms;
int mob_id;
@@ -4067,9 +4029,9 @@ static bool mob_parse_row_mobskilldb(char** str, const char* source, int line, i
if (mob_id > 0 && mob_db(mob_id) == mob_dummy)
{
- if (mob_id != *last_mob_id) {
- ShowError("mob_skill: Non existant Mob id %d at %s, line %d\n", mob_id, source, line);
- *last_mob_id = mob_id;
+ if (mob_id != last_mob_id) {
+ ShowError("mob_parse_row_mobskilldb: Non existant Mob id %d\n", mob_id);
+ last_mob_id = mob_id;
}
return false;
}
@@ -4089,9 +4051,9 @@ static bool mob_parse_row_mobskilldb(char** str, const char* source, int line, i
ARR_FIND( 0, MAX_MOBSKILL, i, (ms = &mob_db_data[mob_id]->skill[i])->skill_id == 0 );
if( i == MAX_MOBSKILL )
{
- if (mob_id != *last_mob_id) {
- ShowError("mob_skill: readdb: too many skills! Line %d in %d[%s]\n", line, mob_id, mob_db_data[mob_id]->sprite);
- *last_mob_id = mob_id;
+ if (mob_id != last_mob_id) {
+ ShowError("mob_parse_row_mobskilldb: Too many skills for monster %d[%s]\n", mob_id, mob_db_data[mob_id]->sprite);
+ last_mob_id = mob_id;
}
return false;
}
@@ -4102,7 +4064,7 @@ static bool mob_parse_row_mobskilldb(char** str, const char* source, int line, i
if( j < ARRAYLENGTH(state) )
ms->state = state[j].id;
else {
- ShowWarning("mob_skill: Unrecognized state %s at %s, line %d\n", str[2], source, line);
+ ShowWarning("mob_parse_row_mobskilldb: Unrecognized state %s\n", str[2]);
ms->state = MSS_ANY;
}
@@ -4111,9 +4073,9 @@ static bool mob_parse_row_mobskilldb(char** str, const char* source, int line, i
if (j<=0 || j>MAX_SKILL_DB) //fixed Lupus
{
if (mob_id < 0)
- ShowError("Invalid Skill ID (%d) for all mobs\n", j);
+ ShowError("mob_parse_row_mobskilldb: Invalid Skill ID (%d) for all mobs\n", j);
else
- ShowError("Invalid Skill ID (%d) for mob %d (%s)\n", j, mob_id, mob_db_data[mob_id]->sprite);
+ ShowError("mob_parse_row_mobskilldb: Invalid Skill ID (%d) for mob %d (%s)\n", j, mob_id, mob_db_data[mob_id]->sprite);
return false;
}
ms->skill_id=j;
@@ -4146,7 +4108,7 @@ static bool mob_parse_row_mobskilldb(char** str, const char* source, int line, i
if( j < ARRAYLENGTH(target) )
ms->target = target[j].id;
else {
- ShowWarning("mob_skill: Unrecognized target %s at %s, line %d\n", str[9], source, line);
+ ShowWarning("mob_parse_row_mobskilldb: Unrecognized target %s for %d\n", str[9], mob_id);
ms->target = MST_TARGET;
}
@@ -4155,13 +4117,13 @@ static bool mob_parse_row_mobskilldb(char** str, const char* source, int line, i
{ //Ground skill.
if (ms->target > MST_AROUND)
{
- ShowWarning("Wrong mob skill target for ground skill %d (%s) for %s.\n",
+ ShowWarning("mob_parse_row_mobskilldb: Wrong mob skill target for ground skill %d (%s) for %s.\n",
ms->skill_id, skill_get_name(ms->skill_id),
mob_id < 0?"all mobs":mob_db_data[mob_id]->sprite);
ms->target = MST_TARGET;
}
} else if (ms->target > MST_MASTER) {
- ShowWarning("Wrong mob skill target 'around' for non-ground skill %d (%s) for %s\n.",
+ ShowWarning("mob_parse_row_mobskilldb: Wrong mob skill target 'around' for non-ground skill %d (%s) for %s\n.",
ms->skill_id, skill_get_name(ms->skill_id),
mob_id < 0?"all mobs":mob_db_data[mob_id]->sprite);
ms->target = MST_TARGET;
@@ -4172,7 +4134,7 @@ static bool mob_parse_row_mobskilldb(char** str, const char* source, int line, i
if( j < ARRAYLENGTH(cond1) )
ms->cond1 = cond1[j].id;
else {
- ShowWarning("mob_skill: Unrecognized condition 1 %s at %s, line %d\n", str[10], source, line);
+ ShowWarning("mob_parse_row_mobskilldb: Unrecognized condition 1 %s for %d\n", str[10], mob_id);
ms->cond1 = -1;
}
@@ -4246,7 +4208,7 @@ static bool mob_parse_row_mobskilldb(char** str, const char* source, int line, i
/*==========================================
* mob_skill_db.txt reading
*------------------------------------------*/
-static int mob_readskilldb(void)
+static void mob_readskilldb(void)
{
const char* filename[] = { "mob_skill_db.txt", "mob_skill_db2.txt" };
int fi;
@@ -4254,130 +4216,72 @@ static int mob_readskilldb(void)
if( battle_config.mob_skill_rate == 0 )
{
ShowStatus("Mob skill use disabled. Not reading mob skills.\n");
- return 0;
+ return;
}
for( fi = 0; fi < ARRAYLENGTH(filename); ++fi )
{
- uint32 lines = 0, count = 0;
- char line[1024];
- int i;
- int tmp = 0;
-
char path[256];
- FILE *fp;
-
- sprintf(path, "%s/%s", db_path, filename[fi]);
- fp = fopen(path, "r");
- if( fp == NULL )
- {
- ShowWarning("mob_readskilldb: File not found \"%s\", skipping.\n", path);
- continue;
- }
- // process rows one by one
- while(fgets(line, sizeof(line), fp))
+ if(fi > 0)
{
- char *str[20], *p, *np;
- int j=0;
-
- lines++;
- if(line[0] == '/' && line[1] == '/')
- continue;
- memset(str, 0, sizeof(str));
-
- p = line;
- while( ISSPACE(*p) )
- ++p;
- if( *p == '\0' )
- continue;// empty line
- for(i = 0; i < 19; i++)
+ sprintf(path, "%s/%s", db_path, filename[fi]);
+ if(!exists(path))
{
- str[i] = p;
- if((np = strchr(p, ',')) != NULL) {
- *np = '\0'; p = np + 1; j++;
- }
- }
-
- if ( j < 18 || str[18]==NULL )
- {
- ShowError("mob_readskilldb: Insufficient number of fields for skill at %s, line %d\n", filename[fi], lines);
continue;
}
-
- if( !mob_parse_row_mobskilldb(str, path, lines, &tmp) )
- continue;
-
- count++;
}
- fclose(fp);
- ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n", filename[fi]);
+
+ sv_readdb(db_path, filename[fi], ',', 19, 19, -1, &mob_parse_row_mobskilldb);
}
- return 0;
}
/*==========================================
- * mob_race_db.txt reading
+ * mob_race2_db.txt reading
*------------------------------------------*/
-static int mob_readdb_race(void)
+static bool mob_readdb_race2(char* fields[], int columns, int current)
{
- FILE *fp;
- char line[1024];
- int race,j,k;
- char *str[20],*p,*np;
+ int race, mobid, i;
- sprintf(line, "%s/mob_race2_db.txt", db_path);
- if( (fp=fopen(line,"r"))==NULL ){
- ShowError("can't read %s\n", line);
- return -1;
- }
-
- while(fgets(line, sizeof(line), fp))
- {
- if(line[0]=='/' && line[1]=='/')
- continue;
- memset(str,0,sizeof(str));
+ race = atoi(fields[0]);
- for(j=0,p=line;j<12;j++){
- if((np=strchr(p,','))!=NULL){
- str[j]=p;
- *np=0;
- p=np+1;
- } else
- str[j]=p;
- }
- if(str[0]==NULL)
- continue;
+ if (race < RC2_NONE || race >= RC2_MAX)
+ {
+ ShowWarning("mob_readdb_race2: Unknown race2 %d.\n", race);
+ return false;
+ }
- race=atoi(str[0]);
- if (race < RC2_NONE || race >= RC2_MAX)
+ for(i = 1; i<columns; i++)
+ {
+ mobid = atoi(fields[i]);
+ if (mob_db(mobid) == mob_dummy)
+ {
+ ShowWarning("mob_readdb_race2: Unknown mob id %d for race2 %d.\n", mobid, race);
continue;
-
- for (j=1; j<20; j++) {
- if (!str[j])
- break;
- k=atoi(str[j]);
- if (mob_db(k) == mob_dummy)
- continue;
- mob_db_data[k]->race2 = race;
}
+ mob_db_data[mobid]->race2 = race;
}
- fclose(fp);
- ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n","mob_race2_db.txt");
- return 0;
+ return true;
}
-void mob_reload(void)
+static void mob_load(void)
{
- int i;
#ifndef TXT_ONLY
- if(db_use_sqldbs)
- mob_read_sqldb();
- else
+ if(db_use_sqldbs)
+ mob_read_sqldb();
+ else
#endif /* TXT_ONLY */
mob_readdb();
- mob_readdb_mobavail();
+ sv_readdb(db_path, "mob_avail.txt", ',', 2, 12, -1, &mob_readdb_mobavail);
mob_read_randommonster();
+ mob_readchatdb();
+ mob_readskilldb();
+ sv_readdb(db_path, "mob_race2_db.txt", ',', 2, 20, -1, &mob_readdb_race2);
+}
+
+void mob_reload(void)
+{
+ int i;
//Mob skills need to be cleared before re-reading them. [Skotlex]
for (i = 0; i < MAX_MOB_DB; i++)
@@ -4386,9 +4290,8 @@ void mob_reload(void)
memset(&mob_db_data[i]->skill,0,sizeof(mob_db_data[i]->skill));
mob_db_data[i]->maxskill=0;
}
- mob_readchatdb();
- mob_readskilldb();
- mob_readdb_race();
+
+ mob_load();
}
void mob_clear_spawninfo()
@@ -4410,18 +4313,7 @@ int do_init_mob(void)
item_drop_ers = ers_new(sizeof(struct item_drop));
item_drop_list_ers = ers_new(sizeof(struct item_drop_list));
-#ifndef TXT_ONLY
- if(db_use_sqldbs)
- mob_read_sqldb();
- else
-#endif /* TXT_ONLY */
- mob_readdb();
-
- mob_readdb_mobavail();
- mob_read_randommonster();
- mob_readchatdb();
- mob_readskilldb();
- mob_readdb_race();
+ mob_load();
add_timer_func_list(mob_delayspawn,"mob_delayspawn");
add_timer_func_list(mob_delay_item_drop,"mob_delay_item_drop");
diff --git a/src/map/mob.h b/src/map/mob.h
index e8bd0a837..ce896646c 100644
--- a/src/map/mob.h
+++ b/src/map/mob.h
@@ -55,6 +55,13 @@ enum MobSkillState {
MSS_ANYTARGET,
};
+enum MobDamageLogFlag
+{
+ MDLF_NORMAL = 0,
+ MDLF_HOMUN,
+ MDLF_PET,
+};
+
struct mob_skill {
enum MobSkillState state;
short skill_id,skill_lv;
diff --git a/src/map/npc.c b/src/map/npc.c
index dcfa52193..4b188c177 100644
--- a/src/map/npc.c
+++ b/src/map/npc.c
@@ -176,7 +176,7 @@ int npc_enable(const char* name, int flag)
if (nd->class_ == WARP_CLASS || nd->class_ == FLAG_CLASS)
{ //Client won't display option changes for these classes [Toms]
if (nd->sc.option&(OPTION_HIDE|OPTION_INVISIBLE))
- clif_clearunit_area(&nd->bl, 0);
+ clif_clearunit_area(&nd->bl, CLR_OUTSIGHT);
else
clif_spawn(&nd->bl);
} else
@@ -206,7 +206,7 @@ int npc_event_dequeue(struct map_session_data* sd)
if(sd->npc_id)
{ //Current script is aborted.
if(sd->state.using_fake_npc){
- clif_clearunit_single(sd->npc_id, 0, sd->fd);
+ clif_clearunit_single(sd->npc_id, CLR_OUTSIGHT, sd->fd);
sd->state.using_fake_npc = 0;
}
if (sd->st) {
@@ -866,7 +866,7 @@ int npc_touch_areanpc(struct map_session_data* sd, int m, int x, int y)
case WARP:
if( pc_ishiding(sd) )
break; // hidden 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,0);
+ 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:
if( npc_ontouch_event(sd,map[m].npc[i]) > 0 && npc_ontouch2_event(sd,map[m].npc[i]) > 0 )
@@ -923,7 +923,7 @@ int npc_touch_areanpc2(struct mob_data *md)
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, 0) == 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
break;
case SCRIPT:
@@ -1142,14 +1142,24 @@ static int npc_buylist_sub(struct map_session_data* sd, int n, unsigned short* i
{
char npc_ev[NAME_LENGTH*2+3];
int i;
- int regkey = add_str("@bought_nameid");
- int regkey2 = add_str("@bought_quantity");
- snprintf(npc_ev, ARRAYLENGTH(npc_ev), "%s::OnBuyItem", nd->exname);
- for(i=0;i<n;i++){
- pc_setreg(sd,regkey+(i<<24),(int)item_list[i*2+1]);
- pc_setreg(sd,regkey2+(i<<24),(int)item_list[i*2]);
+ int key_nameid = 0;
+ int key_amount = 0;
+
+ // discard old contents
+ script_cleararray_pc(sd, "@bought_nameid", (void*)0);
+ script_cleararray_pc(sd, "@bought_quantity", (void*)0);
+
+ // save list of bought items
+ for( i = 0; i < n; i++ )
+ {
+ script_setarray_pc(sd, "@bought_nameid", i, (void*)(intptr)item_list[i*2+1], &key_nameid);
+ script_setarray_pc(sd, "@bought_quantity", i, (void*)(intptr)item_list[i*2], &key_amount);
}
+
+ // invoke event
+ snprintf(npc_ev, ARRAYLENGTH(npc_ev), "%s::OnBuyItem", nd->exname);
npc_event(sd, npc_ev, 0);
+
return 0;
}
/*==========================================
@@ -1251,8 +1261,6 @@ 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->master_nd != NULL ) //Script-based shops.
- return npc_buylist_sub(sd,n,item_list,nd->master_nd);
if( nd->subtype != SHOP )
return 3;
@@ -1287,6 +1295,11 @@ int npc_buylist(struct map_session_data* sd, int n, unsigned short* item_list)
amount = item_list[i*2+0] = 1;
}
+ if( nd->master_nd )
+ {// Script-controlled shops decide by themselves, what can be bought and for what price.
+ continue;
+ }
+
switch( pc_checkadditem(sd,nameid,amount) )
{
case ADDITEM_EXIST:
@@ -1300,13 +1313,15 @@ int npc_buylist(struct map_session_data* sd, int n, unsigned short* item_list)
return 2;
}
- if( !itemdb_value_notdc(nameid) )
- value = pc_modifybuyvalue(sd,value);
+ value = pc_modifybuyvalue(sd,value);
z += (double)value * amount;
w += itemdb_weight(nameid) * amount;
}
+ if( nd->master_nd != NULL ) //Script-based shops.
+ return npc_buylist_sub(sd,n,item_list,nd->master_nd);
+
if( z > (double)sd->status.zeny )
return 1; // Not enough Zeny
if( w + sd->weight > sd->max_weight )
@@ -1356,90 +1371,139 @@ int npc_buylist(struct map_session_data* sd, int n, unsigned short* item_list)
return 0;
}
-/*==========================================
- *
- *------------------------------------------*/
+
+/// npc_selllist for script-controlled shops
+static int npc_selllist_sub(struct map_session_data* sd, int n, unsigned short* item_list, struct npc_data* nd)
+{
+ char npc_ev[NAME_LENGTH*2+3];
+ int i, idx;
+ int key_nameid = 0;
+ int key_amount = 0;
+
+ // discard old contents
+ script_cleararray_pc(sd, "@sold_nameid", (void*)0);
+ script_cleararray_pc(sd, "@sold_quantity", (void*)0);
+
+ // save list of to be sold items
+ for( i = 0; i < n; i++ )
+ {
+ idx = item_list[i*2]-2;
+
+ script_setarray_pc(sd, "@sold_nameid", i, (void*)(intptr)sd->status.inventory[idx].nameid, &key_nameid);
+ script_setarray_pc(sd, "@sold_quantity", i, (void*)(intptr)item_list[i*2+1], &key_amount);
+ }
+
+ // invoke event
+ snprintf(npc_ev, ARRAYLENGTH(npc_ev), "%s::OnSellItem", nd->exname);
+ npc_event(sd, npc_ev, 0);
+ return 0;
+}
+
+
+/// Player item selling to npc shop.
+///
+/// @param item_list 'n' pairs <index,amount>
+/// @return result code for clif_parse_NpcSellListSend
int npc_selllist(struct map_session_data* sd, int n, unsigned short* item_list)
{
double z;
int i,skill;
struct npc_data *nd;
-
+
nullpo_retr(1, sd);
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 )
+ {
return 1;
- nd = nd->master_nd; //For OnSell triggers.
+ }
- for(i=0,z=0;i<n;i++) {
- int nameid, idx;
- short qty;
- idx = item_list[i*2]-2;
- qty = (short)item_list[i*2+1];
-
- if (idx <0 || idx >=MAX_INVENTORY || qty < 0)
- break;
-
- nameid=sd->status.inventory[idx].nameid;
- if (nameid == 0 || !sd->inventory_data[idx] ||
- sd->status.inventory[idx].amount < qty)
- break;
-
- if (sd->inventory_data[idx]->flag.value_notoc)
- z+=(double)qty*sd->inventory_data[idx]->value_sell;
- else
- z+=(double)qty*pc_modifysellvalue(sd,sd->inventory_data[idx]->value_sell);
+ z = 0;
+
+ // verify the sell list
+ for( i = 0; i < n; i++ )
+ {
+ int nameid, amount, idx, value;
+
+ idx = item_list[i*2]-2;
+ amount = item_list[i*2+1];
- if(sd->inventory_data[idx]->type == IT_PETEGG &&
- sd->status.inventory[idx].card[0] == CARD0_PET)
+ if( idx >= MAX_INVENTORY || idx < 0 || amount < 0 )
{
- if(search_petDB_index(sd->status.inventory[idx].nameid, PET_EGG) >= 0)
- intif_delete_petdata(MakeDWord(sd->status.inventory[idx].card[1],sd->status.inventory[idx].card[2]));
+ return 1;
+ }
+
+ nameid = sd->status.inventory[idx].nameid;
+
+ if( !nameid || !sd->inventory_data[idx] || sd->status.inventory[idx].amount < amount )
+ {
+ return 1;
}
- if(log_config.enable_logs&0x20) //Logs items, Sold to NPC (S)hop [Lupus]
- log_pick_pc(sd, "S", nameid, -qty, &sd->status.inventory[idx]);
+ if( nd->master_nd )
+ {// Script-controlled shops decide by themselves, what can be sold and at what price.
+ continue;
+ }
+
+ value = pc_modifysellvalue(sd, sd->inventory_data[idx]->value_sell);
+
+ z+= (double)value*amount;
+ }
+
+ if( nd->master_nd )
+ {// Script-controlled shops
+ return npc_selllist_sub(sd, n, item_list, nd->master_nd);
+ }
+
+ // delete items
+ for( i = 0; i < n; i++ )
+ {
+ int nameid, amount, idx;
+
+ idx = item_list[i*2]-2;
+ amount = item_list[i*2+1];
+ nameid = sd->status.inventory[idx].nameid;
+
+ //Logs items, Sold to NPC (S)hop [Lupus]
+ if( log_config.enable_logs&0x20 )
+ log_pick_pc(sd, "S", nameid, -amount, &sd->status.inventory[idx]);
+ //Logs
- if(nd) {
- pc_setreg(sd,add_str("@sold_nameid")+(i<<24),(int)sd->status.inventory[idx].nameid);
- pc_setreg(sd,add_str("@sold_quantity")+(i<<24),qty);
+ if( sd->inventory_data[idx]->type == IT_PETEGG && sd->status.inventory[idx].card[0] == CARD0_PET )
+ {
+ if( search_petDB_index(sd->status.inventory[idx].nameid, PET_EGG) >= 0 )
+ {
+ intif_delete_petdata(MakeDWord(sd->status.inventory[idx].card[1], sd->status.inventory[idx].card[2]));
+ }
}
- pc_delitem(sd,idx,qty,0,6);
+
+ pc_delitem(sd, idx, amount, 0, 6);
}
- if (z > MAX_ZENY) z = MAX_ZENY;
+ if( z > MAX_ZENY )
+ z = MAX_ZENY;
- if(log_config.zeny) //Logs (S)hopping Zeny [Lupus]
+ //Logs (S)hopping Zeny [Lupus]
+ if( log_config.zeny )
log_zeny(sd, "S", sd, (int)z);
+ //Logs
- pc_getzeny(sd,(int)z);
-
- if (battle_config.shop_exp > 0 && z > 0 && (skill = pc_checkskill(sd,MC_OVERCHARGE)) > 0) {
- if (sd->status.skill[MC_OVERCHARGE].flag != 0)
+ pc_getzeny(sd, (int)z);
+
+ // custom merchant shop exp bonus
+ if( battle_config.shop_exp > 0 && z > 0 && ( skill = pc_checkskill(sd,MC_OVERCHARGE) ) > 0)
+ {
+ if( sd->status.skill[MC_OVERCHARGE].flag != 0 )
skill = sd->status.skill[MC_OVERCHARGE].flag - 2;
- if (skill > 0) {
+ if( skill > 0 )
+ {
z = z * (double)skill * (double)battle_config.shop_exp/10000.;
- if (z < 1)
+ if( z < 1 )
z = 1;
- pc_gainexp(sd,NULL,0,(int)z, false);
+ pc_gainexp(sd, NULL, 0, (int)z, false);
}
}
-
- if(nd) {
- char npc_ev[NAME_LENGTH*2+3];
- snprintf(npc_ev, ARRAYLENGTH(npc_ev), "%s::OnSellItem", nd->exname);
- npc_event(sd, npc_ev, 0);
- }
-
- if (i<n) {
- //Error/Exploit... of some sort. If we return 1, the client will not mark
- //any item as deleted even though a few were sold. In such a case, we
- //have no recourse but to kick them out so their inventory will refresh
- //correctly on relog. [Skotlex]
- if (i) set_eof(sd->fd);
- return 1;
- }
+
return 0;
}
@@ -1451,7 +1515,7 @@ 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;
- clif_clearunit_area(&nd->bl,2);
+ clif_clearunit_area(&nd->bl,CLR_RESPAWN);
npc_unsetcells(nd);
map_delblock(&nd->bl);
//Remove npc from map[].npc list. [Skotlex]
@@ -1875,8 +1939,8 @@ static const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const
id->name, nameid, value, (int)(value*0.75), id->value_sell, (int)(id->value_sell*1.24), filepath, strline(buffer,start-buffer));
}
//for logs filters, atcommands and iteminfo script command
- if( id->maxchance <= 0 )
- id->maxchance = 10000; //10000 (100% drop chance)would show that the item's sold in NPC Shop
+ if( id->maxchance == 0 )
+ id->maxchance = -1; // -1 would show that the item's sold in NPC Shop
items[i].nameid = nameid;
items[i].value = value;
@@ -2550,7 +2614,7 @@ void npc_setclass(struct npc_data* nd, short class_)
if( nd->class_ == class_ )
return;
- clif_clearunit_area(&nd->bl, 0);// fade out
+ clif_clearunit_area(&nd->bl, CLR_OUTSIGHT);// fade out
nd->class_ = class_;
status_set_viewdata(&nd->bl, class_);
clif_spawn(&nd->bl);// fade in
@@ -3129,7 +3193,12 @@ void npc_parsesrcfile(const char* filepath)
{// Incorrect map, we must skip the script info...
ShowError("npc_parsesrcfile: Unknown map '%s' in file '%s', line '%d'. Skipping line...\n", mapname, filepath, strline(buffer,p-buffer));
if( strcasecmp(w2,"script") == 0 && count > 3 )
- p = npc_skip_script(p,buffer,filepath);
+ {
+ if((p = npc_skip_script(p,buffer,filepath)) == NULL)
+ {
+ break;
+ }
+ }
p = strchr(p,'\n');// next line
continue;
}
@@ -3137,7 +3206,12 @@ void npc_parsesrcfile(const char* filepath)
if( m < 0 )
{// "mapname" is not assigned to this server, we must skip the script info...
if( strcasecmp(w2,"script") == 0 && count > 3 )
- p = npc_skip_script(p,buffer,filepath);
+ {
+ if((p = npc_skip_script(p,buffer,filepath)) == NULL)
+ {
+ break;
+ }
+ }
p = strchr(p,'\n');// next line
continue;
}
@@ -3270,7 +3344,7 @@ int npc_reload(void)
npc_unload((struct npc_data *)bl);
break;
case BL_MOB:
- unit_free(bl,0);
+ unit_free(bl,CLR_OUTSIGHT);
break;
}
}
@@ -3304,6 +3378,9 @@ int npc_reload(void)
npc_warp = npc_shop = npc_script = 0;
npc_mob = npc_cache_mob = npc_delay_mob = 0;
+ // reset mapflags
+ map_flags_init();
+
//TODO: the following code is copy-pasted from do_init_npc(); clean it up
// Reloading npcs now
for (nsl = npc_src_files; nsl; nsl = nsl->next)
@@ -3350,7 +3427,7 @@ int do_final_npc(void)
if (bl->type == BL_NPC)
npc_unload((struct npc_data *)bl);
else if (bl->type&(BL_MOB|BL_PET|BL_HOM|BL_MER))
- unit_free(bl, 0);
+ unit_free(bl, CLR_OUTSIGHT);
}
}
diff --git a/src/map/party.c b/src/map/party.c
index e6a7ffd8b..407221cde 100644
--- a/src/map/party.c
+++ b/src/map/party.c
@@ -30,8 +30,9 @@
static DBMap* party_db; // int party_id -> struct party_data*
static DBMap* party_booking_db; // Party Booking [Spiria]
+static unsigned long party_booking_nextid = 1;
+
int party_send_xy_timer(int tid, unsigned int tick, int id, intptr data);
-bool check_party_leader(struct map_session_data *sd, struct party_data *p); // Party Booking [Spiria]
/*==========================================
* Fills the given party_member structure according to the sd provided.
@@ -515,11 +516,6 @@ int party_leave(struct map_session_data *sd)
if( i == MAX_PARTY )
return 0;
- if( check_party_leader(sd, p) ){ // when party leader leaves party, cancel booking.
- party_booking_delete(sd,true);
- clif_PartyBookingDeleteAck(sd,0);
- }
-
intif_party_leave(p->party.party_id,sd->status.account_id,sd->status.char_id);
return 1;
}
@@ -665,8 +661,6 @@ bool party_changeleader(struct map_session_data *sd, struct map_session_data *ts
//Update info.
intif_party_leaderchange(p->party.party_id,p->party.member[tmi].account_id,p->party.member[tmi].char_id);
clif_party_info(p,NULL);
- party_booking_delete(sd, true); // Party Booking [Spiria]
- clif_PartyBookingDeleteAck(sd, 0); // Close small window
return true;
}
@@ -1070,52 +1064,25 @@ int party_foreachsamemap(int (*func)(struct block_list*,va_list),struct map_sess
* Party Booking in KRO [Spiria]
*------------------------------------------*/
-static struct party_booking_ad_info* create_party_booking_data(int party_id)
+static struct party_booking_ad_info* create_party_booking_data(void)
{
struct party_booking_ad_info *pb_ad;
CREATE(pb_ad, struct party_booking_ad_info, 1);
- pb_ad->index = party_id;
+ pb_ad->index = party_booking_nextid++;
return pb_ad;
}
-struct party_booking_ad_info* party_booking_getdata(unsigned long index)
-{
- struct party_booking_ad_info *pb_ad;
- pb_ad = (struct party_booking_ad_info*)idb_get(party_booking_db, index);
- return pb_ad;
-}
-
-bool check_party_leader(struct map_session_data *sd, struct party_data *p)
-{
- int i;
-
- if (!sd || !sd->status.party_id) return false;
-
- if( p == NULL ) return false;
-
- ARR_FIND(0, MAX_PARTY, i, p->party.member[i].leader && p->party.member[i].online && p->data[i].sd == sd);
- if(i == MAX_PARTY) return false;
-
- return true;
-}
-
void party_booking_register(struct map_session_data *sd, short level, short mapid, short* job)
{
struct party_booking_ad_info *pb_ad;
- struct party_data *p=party_search(sd->status.party_id);
int i;
- if (!check_party_leader(sd, p)) {
- clif_PartyBookingRegisterAck(sd, 1);
- return;
- }
-
- pb_ad = (struct party_booking_ad_info*)idb_get(party_booking_db, p->party.party_id);
+ pb_ad = (struct party_booking_ad_info*)idb_get(party_booking_db, sd->status.char_id);
if( pb_ad == NULL )
{
- pb_ad = create_party_booking_data(p->party.party_id);
- idb_put(party_booking_db, pb_ad->index, pb_ad);
+ pb_ad = create_party_booking_data();
+ idb_put(party_booking_db, sd->status.char_id, pb_ad);
}
memcpy(pb_ad->charname,sd->status.name,NAME_LENGTH);
@@ -1123,84 +1090,80 @@ void party_booking_register(struct map_session_data *sd, short level, short mapi
pb_ad->p_detail.level = level;
pb_ad->p_detail.mapid = mapid;
- for(i=0;i<6;i++)
+ for(i=0;i<PARTY_BOOKING_JOBS;i++)
if(job[i] != 0xFF)
pb_ad->p_detail.job[i] = job[i];
else pb_ad->p_detail.job[i] = -1;
clif_PartyBookingRegisterAck(sd, 0);
clif_PartyBookingInsertNotify(sd, pb_ad); // Notice
- clif_PartyBookingSearchAck(sd->fd, &pb_ad->index, 1, false); // Update Client!
- return;
}
void party_booking_update(struct map_session_data *sd, short* job)
{
int i;
- struct party_data *p=party_search(sd->status.party_id);
struct party_booking_ad_info *pb_ad;
- if (!check_party_leader(sd, p)) {
- return;
- }
-
- pb_ad = (struct party_booking_ad_info*)idb_get(party_booking_db, p->party.party_id);
+ pb_ad = (struct party_booking_ad_info*)idb_get(party_booking_db, sd->status.char_id);
if( pb_ad == NULL )
return;
pb_ad->starttime = (int)time(NULL);// Update time.
- for(i=0;i<6;i++)
+ for(i=0;i<PARTY_BOOKING_JOBS;i++)
if(job[i] != 0xFF)
pb_ad->p_detail.job[i] = job[i];
else pb_ad->p_detail.job[i] = -1;
clif_PartyBookingUpdateNotify(sd, pb_ad);
- return;
}
void party_booking_search(struct map_session_data *sd, short level, short mapid, short job, unsigned long lastindex, short resultcount)
{
struct party_booking_ad_info *pb_ad;
int i, count=0;
- unsigned long index_list[10];
+ struct party_booking_ad_info* result_list[PARTY_BOOKING_RESULTS];
bool more_result = false;
DBIterator* iter = party_booking_db->iterator(party_booking_db);
- memset(index_list, 0, sizeof(index_list));
+ memset(result_list, 0, sizeof(result_list));
for( pb_ad = (struct party_booking_ad_info*)iter->first(iter,NULL); iter->exists(iter); pb_ad = (struct party_booking_ad_info*)iter->next(iter,NULL) )
{
- if (pb_ad->index < lastindex || (pb_ad->p_detail.level < level || pb_ad->p_detail.level-15 > level))
+ if (pb_ad->index < lastindex || (level && (pb_ad->p_detail.level < level-15 || pb_ad->p_detail.level > level)))
continue;
- if (count >= 10){
+ if (count >= PARTY_BOOKING_RESULTS){
more_result = true;
break;
}
if (mapid == 0 && job == -1)
- index_list[count] = pb_ad->index;
+ result_list[count] = pb_ad;
else if (mapid == 0) {
- for(i=0; i<6; i++)
+ for(i=0; i<PARTY_BOOKING_JOBS; i++)
if (pb_ad->p_detail.job[i] == job && job != -1)
- index_list[count] = pb_ad->index;
+ result_list[count] = pb_ad;
} else if (job == -1){
if (pb_ad->p_detail.mapid == mapid)
- index_list[count] = pb_ad->index;
+ result_list[count] = pb_ad;
+ }
+ if( result_list[count] )
+ {
+ count++;
}
- count++;
}
iter->destroy(iter);
- clif_PartyBookingSearchAck(sd->fd, index_list, count, more_result);
+ clif_PartyBookingSearchAck(sd->fd, result_list, count, more_result);
}
-bool party_booking_delete(struct map_session_data *sd, bool force_delete)
+bool party_booking_delete(struct map_session_data *sd)
{
- struct party_data *p=party_search(sd->status.party_id);
- if (!check_party_leader(sd, p) && !force_delete) {
- return false;
+ struct party_booking_ad_info* pb_ad;
+
+ if((pb_ad = (struct party_booking_ad_info*)idb_get(party_booking_db, sd->status.char_id))!=NULL)
+ {
+ clif_PartyBookingDeleteNotify(sd, pb_ad->index);
+ idb_remove(party_booking_db,sd->status.char_id);
}
- clif_PartyBookingDeleteNotify(sd, sd->status.party_id);
- idb_remove(party_booking_db,sd->status.party_id);
return true;
}
diff --git a/src/map/party.h b/src/map/party.h
index d396d0fe6..31e46f5ec 100644
--- a/src/map/party.h
+++ b/src/map/party.h
@@ -12,6 +12,9 @@ struct item;
#include <stdarg.h>
+#define PARTY_BOOKING_JOBS 6
+#define PARTY_BOOKING_RESULTS 10
+
struct party_member_data {
struct map_session_data *sd;
unsigned int hp; //For HP,x,y refreshing.
@@ -34,7 +37,7 @@ struct party_data {
struct party_booking_detail {
short level;
short mapid;
- short job[6];
+ short job[PARTY_BOOKING_JOBS];
};
struct party_booking_ad_info {
@@ -83,10 +86,9 @@ int party_foreachsamemap(int (*func)(struct block_list *,va_list),struct map_ses
/*==========================================
* Party Booking in KRO [Spiria]
*------------------------------------------*/
-struct party_booking_ad_info* party_booking_getdata(unsigned long index);
void party_booking_register(struct map_session_data *sd, short level, short mapid, short* job);
void party_booking_update(struct map_session_data *sd, short* job);
void party_booking_search(struct map_session_data *sd, short level, short mapid, short job, unsigned long lastindex, short resultcount);
-bool party_booking_delete(struct map_session_data *sd, bool force_delete);
+bool party_booking_delete(struct map_session_data *sd);
#endif /* _PARTY_H_ */
diff --git a/src/map/path.c b/src/map/path.c
index e2e3ae44b..bbbb99a08 100644
--- a/src/map/path.c
+++ b/src/map/path.c
@@ -345,7 +345,7 @@ bool path_search(struct walkpath_data *wpd,int m,int x0,int y0,int x1,int y1,int
xs = md->xs-1; // あらかじめ1減算しておく
ys = md->ys-1;
- while(1)
+ for(;;)
{
int e=0,f=0,dist,cost,dc[4]={0,0,0,0};
diff --git a/src/map/pc.c b/src/map/pc.c
index 7ad0ecfe4..94121eba9 100644
--- a/src/map/pc.c
+++ b/src/map/pc.c
@@ -61,15 +61,13 @@ struct fame_list taekwon_fame_list[MAX_FAME_LIST];
static unsigned short equip_pos[EQI_MAX]={EQP_ACC_L,EQP_ACC_R,EQP_SHOES,EQP_GARMENT,EQP_HEAD_LOW,EQP_HEAD_MID,EQP_HEAD_TOP,EQP_ARMOR,EQP_HAND_L,EQP_HAND_R,EQP_AMMO};
#define MOTD_LINE_SIZE 128
-char motd_text[MOTD_LINE_SIZE][256]; // Message of the day buffer [Valaris]
+static char motd_text[MOTD_LINE_SIZE][CHAT_SIZE_MAX]; // Message of the day buffer [Valaris]
struct duel duel_list[MAX_DUEL];
int duel_count = 0;
-extern int item_delays; // [Paradox924X]
-
//Links related info to the sd->hate_mob[]/sd->feel_map[] entries
-const struct sg_data sg_info[3] = {
+const struct sg_data sg_info[MAX_PC_FEELHATE] = {
{ SG_SUN_ANGER, SG_SUN_BLESS, SG_SUN_COMFORT, "PC_FEEL_SUN", "PC_HATE_MOB_SUN", is_day_of_sun },
{ SG_MOON_ANGER, SG_MOON_BLESS, SG_MOON_COMFORT, "PC_FEEL_MOON", "PC_HATE_MOB_MOON", is_day_of_moon },
{ SG_STAR_ANGER, SG_STAR_BLESS, SG_STAR_COMFORT, "PC_FEEL_STAR", "PC_HATE_MOB_STAR", is_day_of_star }
@@ -532,11 +530,6 @@ int pc_setinventorydata(struct map_session_data *sd)
for(i=0;i<MAX_INVENTORY;i++) {
id = sd->status.inventory[i].nameid;
sd->inventory_data[i] = id?itemdb_search(id):NULL;
- if(sd->inventory_data[i] && sd->inventory_data[i]->delay > 0) { // Load delays
- sd->item_delay[item_delays].nameid = sd->inventory_data[i]->nameid;
- sd->item_delay[item_delays].tick = 0;
- ++item_delays;
- }
}
return 0;
}
@@ -612,7 +605,7 @@ int pc_setequipindex(struct map_session_data *sd)
if( sd->status.inventory[i].equip & EQP_HAND_L )
{
- if( sd->inventory_data[i] && sd->inventory_data[i]->type == 4 )
+ if( sd->inventory_data[i] && sd->inventory_data[i]->type == IT_WEAPON )
sd->weapontype2 = sd->inventory_data[i]->look;
else
sd->weapontype2 = 0;
@@ -847,6 +840,23 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim
sd->class_ = MAPID_NOVICE;
} else
sd->class_ = i;
+
+ // Checks and fixes to character status data, that are required
+ // in case of configuration change or stuff, which cannot be
+ // checked on char-server.
+ if( sd->status.hair < MIN_HAIR_STYLE || sd->status.hair > MAX_HAIR_STYLE )
+ {
+ sd->status.hair = MIN_HAIR_STYLE;
+ }
+ if( sd->status.hair_color < MIN_HAIR_COLOR || sd->status.hair_color > MAX_HAIR_COLOR )
+ {
+ sd->status.hair_color = MIN_HAIR_COLOR;
+ }
+ if( sd->status.clothes_color < MIN_CLOTH_COLOR || sd->status.clothes_color > MAX_CLOTH_COLOR )
+ {
+ sd->status.clothes_color = MIN_CLOTH_COLOR;
+ }
+
//Initializations to null/0 unneeded since map_session_data was filled with 0 upon allocation.
if(!sd->status.hp) pc_setdead(sd);
sd->state.connect_new = 1;
@@ -910,11 +920,11 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim
sd->hate_mob[i] = -1;
// 位置の設定
- if ((i=pc_setpos(sd,sd->status.last_point.map, sd->status.last_point.x, sd->status.last_point.y, 0)) != 0) {
+ if ((i=pc_setpos(sd,sd->status.last_point.map, sd->status.last_point.x, sd->status.last_point.y, CLR_OUTSIGHT)) != 0) {
ShowError ("Last_point_map %s - id %d not found (error code %d)\n", mapindex_id2name(sd->status.last_point.map), sd->status.last_point.map, i);
// try warping to a default map instead (church graveyard)
- if (pc_setpos(sd, mapindex_name2id(MAP_PRONTERA), 273, 354, 0) != 0) {
+ if (pc_setpos(sd, mapindex_name2id(MAP_PRONTERA), 273, 354, CLR_OUTSIGHT) != 0) {
// if we fail again
clif_authfail_fd(sd->fd, 0);
return false;
@@ -1037,7 +1047,7 @@ int pc_reg_received(struct map_session_data *sd)
}
//SG map and mob read [Komurka]
- for(i=0;i<3;i++) //for now - someone need to make reading from txt/sql
+ for(i=0;i<MAX_PC_FEELHATE;i++) //for now - someone need to make reading from txt/sql
{
if ((j = pc_readglobalreg(sd,sg_info[i].feel_var))!=0) {
sd->feel_map[i].index = j;
@@ -1206,7 +1216,7 @@ int pc_calc_skilltree(struct map_session_data *sd)
f = 1;
if(!battle_config.skillfree) {
- for(j = 0; j < 5; j++) {
+ for(j = 0; j < MAX_PC_SKILL_REQUIRE; j++) {
if((k=skill_tree[c][i].need[j].id))
{
if (!sd->status.skill[k].id || sd->status.skill[k].flag == 13)
@@ -1303,7 +1313,7 @@ static void pc_check_skilltree(struct map_session_data *sd, int skill)
if( sd->status.skill[id].id ) //Already learned
continue;
- for( j = 0; j < 5; j++ )
+ for( j = 0; j < MAX_PC_SKILL_REQUIRE; j++ )
{
if( (k = skill_tree[c][i].need[j].id) )
{
@@ -1439,7 +1449,7 @@ int pc_disguise(struct map_session_data *sd, int class_)
if (sd->bl.prev != NULL) {
pc_stop_walking(sd, 0);
- clif_clearunit_area(&sd->bl, 0);
+ clif_clearunit_area(&sd->bl, CLR_OUTSIGHT);
}
if (!class_) {
@@ -1507,13 +1517,7 @@ static int pc_bonus_autospell_onskill(struct s_autospell *spell, int max, short
for( i = 0; i < max && spell[i].id; i++ )
{
- if( spell[i].flag == src_skill && spell[i].id == id && spell[i].lv == lv && (spell[i].card_id == card_id || spell[i].rate <= 0 || rate < 0) )
- {
- if( !battle_config.autospell_stacking && spell[i].rate > 0 && rate > 0 )
- return 0;
- rate += spell[i].rate;
- break;
- }
+ ; // each autospell works independently
}
if( i == max )
@@ -2358,6 +2362,10 @@ int pc_bonus(struct map_session_data *sd,int type,int val)
if(sd->state.lr_flag != 2)
sd->add_heal2_rate += val;
break;
+ case SP_ADD_ITEM_HEAL_RATE:
+ if(sd->state.lr_flag != 2)
+ sd->itemhealrate2 += val;
+ break;
default:
ShowWarning("pc_bonus: unknown type %d %d !\n",type,val);
break;
@@ -3195,6 +3203,9 @@ int pc_checkadditem(struct map_session_data *sd,int nameid,int amount)
nullpo_ret(sd);
+ if(amount > MAX_AMOUNT)
+ return ADDITEM_OVERAMOUNT;
+
if(!itemdb_isstackable(nameid))
return ADDITEM_NEW;
@@ -3206,8 +3217,6 @@ int pc_checkadditem(struct map_session_data *sd,int nameid,int amount)
}
}
- if(amount > MAX_AMOUNT)
- return ADDITEM_OVERAMOUNT;
return ADDITEM_NEW;
}
@@ -3536,7 +3545,7 @@ int pc_isUseitem(struct map_session_data *sd,int n)
if( item == NULL )
return 0;
//Not consumable item
- if( item->type != IT_HEALING && item->type != IT_USABLE )
+ if( item->type != IT_HEALING && item->type != IT_USABLE && item->type != IT_CASH )
return 0;
if( !item->script ) //if it has no script, you can't really consume it!
return 0;
@@ -3662,7 +3671,7 @@ int pc_isUseitem(struct map_session_data *sd,int n)
*------------------------------------------*/
int pc_useitem(struct map_session_data *sd,int n)
{
- unsigned int delay, tick = gettick();
+ unsigned int tick = gettick();
int amount, i, nameid;
struct script_code *script;
@@ -3691,13 +3700,6 @@ int pc_useitem(struct map_session_data *sd,int n)
// Store information for later use before it is lost (via pc_delitem) [Paradox924X]
nameid = sd->inventory_data[n]->nameid;
- delay = sd->inventory_data[n]->delay;
-
- if( sd->inventory_data[n]->delay > 0 ) { // Check if there is a delay on this item [Paradox924X]
- ARR_FIND(0, item_delays, i, sd->item_delay[i].nameid == nameid);
- if( i < item_delays && DIFF_TICK(sd->item_delay[i].tick, tick) > 0 )
- return 0; // Delay has not expired yet
- }
//Since most delay-consume items involve using a "skill-type" target cursor,
//perform a skill-use check before going through. [Skotlex]
@@ -3706,6 +3708,27 @@ int pc_useitem(struct map_session_data *sd,int n)
if( sd->inventory_data[n]->flag.delay_consume && ( sd->ud.skilltimer != -1 /*|| !status_check_skilluse(&sd->bl, &sd->bl, ALL_RESURRECTION, 0)*/ ) )
return 0;
+ if( sd->inventory_data[n]->delay > 0 ) { // Check if there is a delay on this item [Paradox924X]
+ ARR_FIND(0, MAX_ITEMDELAYS, i, sd->item_delay[i].nameid == nameid || !sd->item_delay[i].nameid);
+ if( i < MAX_ITEMDELAYS )
+ {
+ if( sd->item_delay[i].nameid )
+ {// found
+ if( DIFF_TICK(sd->item_delay[i].tick, tick) > 0 )
+ return 0; // Delay has not expired yet
+ }
+ else
+ {// not yet used item (all slots are initially empty)
+ sd->item_delay[i].nameid = nameid;
+ }
+ sd->item_delay[i].tick = tick + sd->inventory_data[n]->delay;
+ }
+ else
+ {// should not happen
+ ShowError("pc_useitem: Exceeded item delay array capacity! (nameid=%d, char_id=%d)\n", nameid, sd->status.char_id);
+ }
+ }
+
sd->itemid = sd->status.inventory[n].nameid;
sd->itemindex = n;
if(sd->catch_target_class != -1) //Abort pet catching.
@@ -3741,10 +3764,8 @@ int pc_useitem(struct map_session_data *sd,int n)
//Update item use time.
sd->canuseitem_tick = tick + battle_config.item_use_interval;
- if( itemdb_iscashfood(sd->status.inventory[n].nameid) )
+ if( itemdb_iscashfood(nameid) )
sd->canusecashfood_tick = tick + battle_config.cashfood_use_interval;
- if( delay > 0 && i < item_delays )
- sd->item_delay[i].tick = tick + delay;
run_script(script,0,sd->bl.id,fake_nd->bl.id);
potion_flag = 0;
@@ -4038,7 +4059,7 @@ int pc_steal_coin(struct map_session_data *sd,struct block_list *target)
* 1 - Invalid map index.
* 2 - Map not in this map-server, and failed to locate alternate map-server.
*------------------------------------------*/
-int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y, uint8 clrtype)
+int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y, clr_type clrtype)
{
struct party_data *p;
int m;
@@ -4196,7 +4217,7 @@ int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y
/*==========================================
* PCのランダムワ?プ
*------------------------------------------*/
-int pc_randomwarp(struct map_session_data *sd, int type)
+int pc_randomwarp(struct map_session_data *sd, clr_type type)
{
int x,y,i=0;
int m;
@@ -4219,6 +4240,45 @@ int pc_randomwarp(struct map_session_data *sd, int type)
return 0;
}
+
+/// Warps one player to another.
+/// @param sd player to warp.
+/// @param pl_sd player to warp to.
+int pc_warpto(struct map_session_data* sd, struct map_session_data* pl_sd)
+{
+ if( map[sd->bl.m].flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd) )
+ {
+ return -2;
+ }
+
+ if( map[pl_sd->bl.m].flag.nowarpto && battle_config.any_warp_GM_min_level > pc_isGM(sd) )
+ {
+ return -3;
+ }
+
+ return pc_setpos(sd, pl_sd->mapindex, pl_sd->bl.x, pl_sd->bl.y, CLR_TELEPORT);
+}
+
+
+/// Recalls one player to another.
+/// @param sd player to warp to.
+/// @param pl_sd player to warp.
+int pc_recall(struct map_session_data* sd, struct map_session_data* pl_sd)
+{
+ if( map[pl_sd->bl.m].flag.nowarp && battle_config.any_warp_GM_min_level > pc_isGM(sd) )
+ {
+ return -2;
+ }
+
+ if( map[sd->bl.m].flag.nowarpto && battle_config.any_warp_GM_min_level > pc_isGM(sd) )
+ {
+ return -3;
+ }
+
+ return pc_setpos(pl_sd, sd->mapindex, sd->bl.x, sd->bl.y, CLR_RESPAWN);
+}
+
+
/*==========================================
* Records a memo point at sd's current position
* pos - entry to replace, (-1: shift oldest entry out)
@@ -4704,7 +4764,7 @@ int pc_follow_timer(int tid, unsigned int tick, int id, intptr data)
if (!check_distance_bl(&sd->bl, tbl, 5))
unit_walktobl(&sd->bl, tbl, 5, 0);
} else
- pc_setpos(sd, map_id2index(tbl->m), tbl->x, tbl->y, 3);
+ pc_setpos(sd, map_id2index(tbl->m), tbl->x, tbl->y, CLR_TELEPORT);
}
sd->followtimer = add_timer(
tick + 1000, // increase time a bit to loosen up map's load
@@ -4767,6 +4827,7 @@ int pc_checkbaselevelup(struct map_session_data *sd)
clif_updatestatus(sd,SP_STATUSPOINT);
clif_updatestatus(sd,SP_BASELEVEL);
+ clif_updatestatus(sd,SP_BASEEXP);
clif_updatestatus(sd,SP_NEXTBASEEXP);
status_calc_pc(sd,0);
status_percent_heal(&sd->bl,100,100);
@@ -4781,7 +4842,7 @@ int pc_checkbaselevelup(struct map_session_data *sd)
if (sd->state.snovice_dead_flag)
sd->state.snovice_dead_flag = 0; //Reenable steelbody resurrection on dead.
} else
- if((sd->class_&MAPID_UPPERMASK) == MAPID_TAEKWON || (sd->class_&MAPID_UPPERMASK) == MAPID_STAR_GLADIATOR)
+ if( (sd->class_&MAPID_BASEMASK) == MAPID_TAEKWON )
{
sc_start(&sd->bl,status_skill2sc(AL_INCAGI),100,10,600000);
sc_start(&sd->bl,status_skill2sc(AL_BLESSING),100,10,600000);
@@ -4814,6 +4875,7 @@ int pc_checkjoblevelup(struct map_session_data *sd)
} while ((next=pc_nextjobexp(sd)) > 0 && sd->status.job_exp >= next);
clif_updatestatus(sd,SP_JOBLEVEL);
+ clif_updatestatus(sd,SP_JOBEXP);
clif_updatestatus(sd,SP_NEXTJOBEXP);
clif_updatestatus(sd,SP_SKILLPOINT);
status_calc_pc(sd,0);
@@ -5272,8 +5334,8 @@ int pc_resetlvl(struct map_session_data* sd,int type)
sd->status.skill_point=0;
sd->status.base_level=1;
sd->status.job_level=1;
- sd->status.base_exp=sd->status.base_exp=0;
- sd->status.job_exp=sd->status.job_exp=0;
+ sd->status.base_exp=0;
+ sd->status.job_exp=0;
if(sd->sc.option !=0)
sd->sc.option = 0;
@@ -5317,6 +5379,8 @@ int pc_resetlvl(struct map_session_data* sd,int type)
clif_updatestatus(sd,SP_BASELEVEL);
clif_updatestatus(sd,SP_JOBLEVEL);
clif_updatestatus(sd,SP_STATUSPOINT);
+ clif_updatestatus(sd,SP_BASEEXP);
+ clif_updatestatus(sd,SP_JOBEXP);
clif_updatestatus(sd,SP_NEXTBASEEXP);
clif_updatestatus(sd,SP_NEXTJOBEXP);
clif_updatestatus(sd,SP_SKILLPOINT);
@@ -5498,7 +5562,7 @@ int pc_resetfeel(struct map_session_data* sd)
int i;
nullpo_ret(sd);
- for (i=0; i<3; i++)
+ for (i=0; i<MAX_PC_FEELHATE; i++)
{
sd->feel_map[i].m = -1;
sd->feel_map[i].index = 0;
@@ -5563,7 +5627,7 @@ int pc_skillheal2_bonus(struct map_session_data *sd, int skill_num)
return bonus;
}
-void pc_respawn(struct map_session_data* sd, uint8 clrtype)
+void pc_respawn(struct map_session_data* sd, clr_type clrtype)
{
if( !pc_isdead(sd) )
return; // not applicable
@@ -5582,7 +5646,7 @@ static int pc_respawn_timer(int tid, unsigned int tick, int id, intptr data)
if( sd != NULL )
{
sd->pvp_point=0;
- pc_respawn(sd,0);
+ pc_respawn(sd,CLR_OUTSIGHT);
}
return 0;
@@ -5656,7 +5720,7 @@ int pc_dead(struct map_session_data *sd,struct block_list *src)
}
pc_setglobalreg(sd,"PC_DIE_COUNTER",sd->die_counter+1);
- pc_setglobalreg(sd,"killerrid",src?src->id:0);
+ pc_setparam(sd, SP_KILLERRID, src?src->id:0);
if( sd->state.bg_id )
{
struct battleground_data *bg;
@@ -5710,7 +5774,7 @@ int pc_dead(struct map_session_data *sd,struct block_list *src)
if (src && src->type == BL_PC)
{
struct map_session_data *ssd = (struct map_session_data *)src;
- pc_setglobalreg(ssd, "killedrid", sd->bl.id);
+ pc_setparam(ssd, SP_KILLEDRID, sd->bl.id);
npc_script_event(ssd, NPCE_KILLPC);
if (battle_config.pk_mode&2) {
@@ -5966,6 +6030,8 @@ int pc_readparam(struct map_session_data* sd,int type)
case SP_KARMA: val = sd->status.karma; break;
case SP_MANNER: val = sd->status.manner; break;
case SP_FAME: val = sd->status.fame; break;
+ case SP_KILLERRID: val = sd->killerrid; break;
+ case SP_KILLEDRID: val = sd->killedrid; break;
}
return val;
@@ -5992,11 +6058,15 @@ int pc_setparam(struct map_session_data *sd,int type,int val)
}
sd->status.base_level = (unsigned int)val;
sd->status.base_exp = 0;
- clif_updatestatus(sd, SP_BASELEVEL);
+ // clif_updatestatus(sd, SP_BASELEVEL); // Gets updated at the bottom
clif_updatestatus(sd, SP_NEXTBASEEXP);
clif_updatestatus(sd, SP_STATUSPOINT);
clif_updatestatus(sd, SP_BASEEXP);
status_calc_pc(sd, 0);
+ if(sd->status.party_id)
+ {
+ party_send_levelup(sd);
+ }
break;
case SP_JOBLEVEL:
if ((unsigned int)val >= sd->status.job_level) {
@@ -6006,11 +6076,10 @@ int pc_setparam(struct map_session_data *sd,int type,int val)
}
sd->status.job_level = (unsigned int)val;
sd->status.job_exp = 0;
- clif_updatestatus(sd, SP_JOBLEVEL);
+ // clif_updatestatus(sd, SP_JOBLEVEL); // Gets updated at the bottom
clif_updatestatus(sd, SP_NEXTJOBEXP);
clif_updatestatus(sd, SP_JOBEXP);
status_calc_pc(sd, 0);
- clif_updatestatus(sd,type);
break;
case SP_SKILLPOINT:
sd->status.skill_point = val;
@@ -6083,6 +6152,15 @@ int pc_setparam(struct map_session_data *sd,int type,int val)
case SP_FAME:
sd->status.fame = val;
break;
+ case SP_KILLERRID:
+ sd->killerrid = val;
+ return 1;
+ case SP_KILLEDRID:
+ sd->killedrid = val;
+ return 1;
+ default:
+ ShowError("pc_setparam: Attempted to set unknown parameter '%d'.\n", type);
+ return 0;
}
clif_updatestatus(sd,type);
@@ -6122,6 +6200,8 @@ int pc_itemheal(struct map_session_data *sd,int itemid, int hp,int sp)
// A potion produced by an Alchemist in the Fame Top 10 gets +50% effect [DracoRPG]
if (potion_flag > 1)
bonus += bonus*(potion_flag-1)*50/100;
+ //All item bonuses.
+ bonus += sd->itemhealrate2;
//Item Group bonuses
bonus += bonus*itemdb_group_bonus(sd, itemid)/100;
//Individual item bonuses.
@@ -6358,10 +6438,8 @@ int pc_changelook(struct map_session_data *sd,int type,int val)
switch(type){
case LOOK_HAIR: //Use the battle_config limits! [Skotlex]
- if (val < battle_config.min_hair_style)
- val = battle_config.min_hair_style;
- else if (val > battle_config.max_hair_style)
- val = battle_config.max_hair_style;
+ val = cap_value(val, MIN_HAIR_STYLE, MAX_HAIR_STYLE);
+
if (sd->status.hair != val)
{
sd->status.hair=val;
@@ -6383,10 +6461,8 @@ int pc_changelook(struct map_session_data *sd,int type,int val)
sd->status.head_mid=val;
break;
case LOOK_HAIR_COLOR: //Use the battle_config limits! [Skotlex]
- if (val < battle_config.min_hair_color)
- val = battle_config.min_hair_color;
- else if (val > battle_config.max_hair_color)
- val = battle_config.max_hair_color;
+ val = cap_value(val, MIN_HAIR_COLOR, MAX_HAIR_COLOR);
+
if (sd->status.hair_color != val)
{
sd->status.hair_color=val;
@@ -6396,10 +6472,8 @@ int pc_changelook(struct map_session_data *sd,int type,int val)
}
break;
case LOOK_CLOTHES_COLOR: //Use the battle_config limits! [Skotlex]
- if (val < battle_config.min_cloth_color)
- val = battle_config.min_cloth_color;
- else if (val > battle_config.max_cloth_color)
- val = battle_config.max_cloth_color;
+ val = cap_value(val, MIN_CLOTH_COLOR, MAX_CLOTH_COLOR);
+
sd->status.clothes_color=val;
break;
case LOOK_SHIELD:
@@ -7099,10 +7173,7 @@ int pc_equipitem(struct map_session_data *sd,int n,int req_pos)
if(id) {
if(id->type == IT_WEAPON) {
sd->status.shield = 0;
- if(sd->status.inventory[n].equip == EQP_HAND_L)
- sd->weapontype2 = id->look;
- else
- sd->weapontype2 = 0;
+ sd->weapontype2 = id->look;
}
else
if(id->type == IT_ARMOR) {
@@ -7934,17 +8005,61 @@ int pc_split_atoui(char* str, unsigned int* val, char sep, int max)
/*==========================================
* DB reading.
* exp.txt - required experience values
- * job_db1.txt - weight, hp, sp, aspd
- * job_db2.txt - job level stat bonuses
* skill_tree.txt - skill tree for every class
* attr_fix.txt - elemental adjustment table
- * size_fix.txt - size adjustment table for weapons
- * refine_db.txt - refining data table
+ * statpoint.txt - status points per base level
*------------------------------------------*/
+static bool pc_readdb_skilltree(char* fields[], int columns, int current)
+{
+ unsigned char joblv = 0, skilllv;
+ unsigned short skillid;
+ int idx, class_;
+ unsigned int i, offset = 3, skillidx;
+
+ class_ = atoi(fields[0]);
+ skillid = (unsigned short)atoi(fields[1]);
+ skilllv = (unsigned char)atoi(fields[2]);
+
+ if(columns==4+MAX_PC_SKILL_REQUIRE*2)
+ {// job level requirement extra column
+ joblv = (unsigned char)atoi(fields[3]);
+ offset++;
+ }
+
+ if(!pcdb_checkid(class_))
+ {
+ ShowWarning("pc_readdb_skilltree: Invalid job class %d specified.\n", class_);
+ return false;
+ }
+ idx = pc_class2idx(class_);
+
+ //This is to avoid adding two lines for the same skill. [Skotlex]
+ ARR_FIND( 0, MAX_SKILL_TREE, skillidx, skill_tree[idx][skillidx].id == 0 || skill_tree[idx][skillidx].id == skillid );
+ if( skillidx == MAX_SKILL_TREE )
+ {
+ ShowWarning("pc_readdb_skilltree: Unable to load skill %hu into job %d's tree. Maximum number of skills per class has been reached.\n", skillid, class_);
+ return false;
+ }
+ else if(skill_tree[idx][skillidx].id)
+ {
+ ShowNotice("pc_readdb_skilltree: Overwriting skill %hu for job class %d.\n", skillid, class_);
+ }
+
+ skill_tree[idx][skillidx].id = skillid;
+ skill_tree[idx][skillidx].max = skilllv;
+ skill_tree[idx][skillidx].joblv = joblv;
+
+ for(i = 0; i < MAX_PC_SKILL_REQUIRE; i++)
+ {
+ skill_tree[idx][skillidx].need[i].id = atoi(fields[i*2+offset]);
+ skill_tree[idx][skillidx].need[i].lv = atoi(fields[i*2+offset+1]);
+ }
+ return true;
+}
+
int pc_readdb(void)
{
int i,j,k;
- unsigned int stat;
FILE *fp;
char line[24000],*p;
@@ -8033,53 +8148,7 @@ int pc_readdb(void)
// スキルツリ?
memset(skill_tree,0,sizeof(skill_tree));
- sprintf(line, "%s/skill_tree.txt", db_path);
- fp=fopen(line,"r");
- if(fp==NULL){
- ShowError("can't read %s\n", line);
- return 1;
- }
-
- while(fgets(line, sizeof(line), fp))
- {
- char *split[50];
- int f=0, m=3, idx;
- if(line[0]=='/' && line[1]=='/')
- continue;
- for(j=0,p=line;j<14 && p;j++){
- split[j]=p;
- p=strchr(p,',');
- if(p) *p++=0;
- }
- if(j<13)
- continue;
- if (j == 14) {
- f=1; // MinJobLvl has been added
- m++;
- }
- // check for bounds [celest]
- idx = atoi(split[0]);
- if(!pcdb_checkid(idx))
- continue;
- idx = pc_class2idx(idx);
- k = atoi(split[1]); //This is to avoid adding two lines for the same skill. [Skotlex]
- ARR_FIND( 0, MAX_SKILL_TREE, j, skill_tree[idx][j].id == 0 || skill_tree[idx][j].id == k );
- if( j == MAX_SKILL_TREE )
- {
- ShowWarning("Unable to load skill %d into job %d's tree. Maximum number of skills per class has been reached.\n", k, atoi(split[0]));
- continue;
- }
- skill_tree[idx][j].id=k;
- skill_tree[idx][j].max=atoi(split[2]);
- if (f) skill_tree[idx][j].joblv=atoi(split[3]);
-
- for(k=0;k<5;k++){
- skill_tree[idx][j].need[k].id=atoi(split[k*2+m]);
- skill_tree[idx][j].need[k].lv=atoi(split[k*2+m+1]);
- }
- }
- fclose(fp);
- ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n","skill_tree.txt");
+ sv_readdb(db_path, "skill_tree.txt", ',', 3+MAX_PC_SKILL_REQUIRE*2, 4+MAX_PC_SKILL_REQUIRE*2, -1, &pc_readdb_skilltree);
// ?性修正テ?ブル
for(i=0;i<4;i++)
@@ -8135,7 +8204,6 @@ int pc_readdb(void)
// スキルツリ?
memset(statp,0,sizeof(statp));
i=1;
- stat = 45; // base points
sprintf(line, "%s/statpoint.txt", db_path);
fp=fopen(line,"r");
if(fp == NULL){
@@ -8144,6 +8212,7 @@ int pc_readdb(void)
} else {
while(fgets(line, sizeof(line), fp))
{
+ int stat;
if(line[0]=='/' && line[1]=='/')
continue;
if ((stat=strtoul(line,NULL,10))<0)
@@ -8157,10 +8226,9 @@ int pc_readdb(void)
ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n","statpoint.txt");
}
// generate the remaining parts of the db if necessary
- for (; i <= MAX_LEVEL; i++) {
- stat += (i+15)/5;
- statp[i] = stat;
- }
+ statp[0] = 45; // seed value
+ for (; i <= MAX_LEVEL; i++)
+ statp[i] = statp[i-1] + (i-1+15)/5;
return 0;
}
@@ -8168,30 +8236,60 @@ int pc_readdb(void)
// Read MOTD on startup. [Valaris]
int pc_read_motd(void)
{
- FILE *fp;
- int ln=0,i=0;
+ char* buf, * ptr;
+ unsigned int lines = 0, entries = 0;
+ size_t len;
+ FILE* fp;
+
+ // clear old MOTD
+ memset(motd_text, 0, sizeof(motd_text));
+
+ // read current MOTD
+ if( ( fp = fopen(motd_txt, "r") ) != NULL )
+ {
+ while( entries < MOTD_LINE_SIZE && fgets(motd_text[entries], sizeof(motd_text[entries]), fp) )
+ {
+ lines++;
+
+ buf = motd_text[entries];
- memset(motd_text,0,sizeof(motd_text));
- if ((fp = fopen(motd_txt, "r")) != NULL) {
- while ((ln < MOTD_LINE_SIZE) && fgets(motd_text[ln], sizeof(motd_text[ln])-1, fp) != NULL) {
- if(motd_text[ln][0] == '/' && motd_text[ln][1] == '/')
+ if( buf[0] == '/' && buf[1] == '/' )
+ {
continue;
- for(i=0; motd_text[ln][i]; i++) {
- if (motd_text[ln][i] == '\r' || motd_text[ln][i]== '\n') {
- if(i)
- motd_text[ln][i]=0;
- else
- motd_text[ln][0]=' ';
- ln++;
- break;
+ }
+
+ len = strlen(buf);
+
+ while( len && ( buf[len-1] == '\r' || buf[len-1] == '\n' ) )
+ {// strip trailing EOL characters
+ len--;
+ }
+
+ if( len )
+ {
+ buf[len] = 0;
+
+ if( ( ptr = strstr(buf, " :") ) != NULL && ptr-buf >= NAME_LENGTH )
+ {// crashes newer clients
+ ShowWarning("Found sequence '"CL_WHITE" :"CL_RESET"' on line '"CL_WHITE"%u"CL_RESET"' in '"CL_WHITE"%s"CL_RESET"'. This can cause newer clients to crash.\n", lines, motd_txt);
}
}
+ else
+ {// empty line
+ buf[0] = ' ';
+ buf[1] = 0;
+ }
+ entries++;
}
fclose(fp);
+
+ ShowStatus("Done reading '"CL_WHITE"%u"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", entries, motd_txt);
}
else
- ShowWarning("In function pc_read_motd() -> File '"CL_WHITE"%s"CL_RESET"' not found.\n", motd_txt);
-
+ {
+ ShowWarning("File '"CL_WHITE"%s"CL_RESET"' not found.\n", motd_txt);
+ }
+
return 0;
}
diff --git a/src/map/pc.h b/src/map/pc.h
index 7bf3a050f..2921b4527 100644
--- a/src/map/pc.h
+++ b/src/map/pc.h
@@ -17,6 +17,8 @@
#include "mob.h"
#define MAX_PC_BONUS 10
+#define MAX_PC_SKILL_REQUIRE 5
+#define MAX_PC_FEELHATE 3
struct weapon_data {
int atkmods[3];
@@ -53,6 +55,7 @@ struct weapon_data {
struct s_autospell {
short id, lv, rate, card_id, flag;
+ bool lock; // bAutoSpellOnSkill: blocks autospell from triggering again, while being executed
};
struct s_addeffect {
@@ -132,7 +135,6 @@ struct map_session_data {
short pmap; // Previous map on Map Change
struct guild *gmaster_flag;
unsigned int bg_id;
- unsigned skillonskill : 1;
unsigned short user_font;
unsigned short autobonus; //flag to indicate if an autobonus is activated. [Inkfish]
} state;
@@ -290,6 +292,7 @@ struct map_session_data {
int crit_atk_rate;
int classchange; // [Valaris]
int speed_rate, speed_add_rate, aspd_add;
+ int itemhealrate2; // [Epoque] Increase heal rate of all healing items.
unsigned int setitem_hash, setitem_hash2; //Split in 2 because shift operations only work on int ranges. [Skotlex]
short splash_range, splash_add_range;
@@ -378,6 +381,8 @@ struct map_session_data {
int duel_group; // duel vars [LuzZza]
int duel_invite;
+ int killerrid, killedrid;
+
char away_message[128]; // [LuzZza]
int cashPoints, kafraPoints;
@@ -543,7 +548,7 @@ bool pc_can_give_items(int level);
int pc_setrestartvalue(struct map_session_data *sd,int type);
int pc_makesavestatus(struct map_session_data *);
-void pc_respawn(struct map_session_data* sd, uint8 clrtype);
+void pc_respawn(struct map_session_data* sd, clr_type clrtype);
int pc_setnewpc(struct map_session_data*,int,int,int,unsigned int,int,int);
bool pc_authok(struct map_session_data* sd, int, time_t, int gmlevel, struct mmo_charstatus* status);
void pc_authfail(struct map_session_data *);
@@ -564,11 +569,12 @@ int pc_clean_skilltree(struct map_session_data *sd);
#define pc_checkoverhp(sd) (sd->battle_status.hp == sd->battle_status.max_hp)
#define pc_checkoversp(sd) (sd->battle_status.sp == sd->battle_status.max_sp)
-int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y, uint8 clrtype);
+int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y, clr_type clrtype);
int pc_setsavepoint(struct map_session_data*,short,int,int);
-int pc_randomwarp(struct map_session_data *sd,int type);
+int pc_randomwarp(struct map_session_data *sd,clr_type type);
+int pc_warpto(struct map_session_data* sd, struct map_session_data* pl_sd);
+int pc_recall(struct map_session_data* sd, struct map_session_data* pl_sd);
int pc_memo(struct map_session_data* sd, int pos);
-int pc_remove_map(struct map_session_data *sd,int clrtype);
int pc_checkadditem(struct map_session_data*,int,int);
int pc_inventoryblank(struct map_session_data*);
@@ -720,7 +726,7 @@ struct skill_tree_entry {
struct {
short id;
unsigned char lv;
- } need[5];
+ } need[MAX_PC_SKILL_REQUIRE];
}; // Celest
extern struct skill_tree_entry skill_tree[CLASS_COUNT][MAX_SKILL_TREE];
@@ -732,7 +738,7 @@ struct sg_data {
char hate_var[NAME_LENGTH];
int (*day_func)(void);
};
-extern const struct sg_data sg_info[3];
+extern const struct sg_data sg_info[MAX_PC_FEELHATE];
void pc_setinvincibletimer(struct map_session_data* sd, int val);
void pc_delinvincibletimer(struct map_session_data* sd);
diff --git a/src/map/pet.c b/src/map/pet.c
index d02f93446..843f1cc11 100644
--- a/src/map/pet.c
+++ b/src/map/pet.c
@@ -306,7 +306,7 @@ static int pet_return_egg(struct map_session_data *sd, struct pet_data *pd)
map_addflooritem(&tmp_item,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0);
}
pd->pet.incuvate = 1;
- unit_free(&pd->bl,0);
+ unit_free(&pd->bl,CLR_OUTSIGHT);
status_calc_pc(sd,0);
sd->status.pet_id = 0;
@@ -509,7 +509,7 @@ int pet_catch_process2(struct map_session_data* sd, int target_id)
if (sd->catch_target_class == 0 && !(md->status.mode&MD_BOSS))
sd->catch_target_class = md->class_;
if(i < 0 || sd->catch_target_class != md->class_) {
- clif_emotion(&md->bl, 7); //mob will do /ag if wrong lure is used on them.
+ clif_emotion(&md->bl, E_AG); //mob will do /ag if wrong lure is used on them.
clif_pet_roulette(sd,0);
sd->catch_target_class = -1;
return 1;
@@ -523,7 +523,7 @@ int pet_catch_process2(struct map_session_data* sd, int target_id)
if(rand()%10000 < pet_catch_rate)
{
- unit_remove_map(&md->bl,0);
+ unit_remove_map(&md->bl,CLR_OUTSIGHT);
status_kill(&md->bl);
clif_pet_roulette(sd,1);
intif_create_pet(sd->status.account_id,sd->status.char_id,pet_db[i].class_,mob_db(pet_db[i].class_)->lv,
@@ -1100,7 +1100,7 @@ int pet_recovery_timer(int tid, unsigned int tick, int id, intptr data)
//Detoxify is chosen for now.
clif_skill_nodamage(&pd->bl,&sd->bl,TF_DETOXIFY,1,1);
status_change_end(&sd->bl,pd->recovery->type,-1);
- clif_emotion(&pd->bl, 33);
+ clif_emotion(&pd->bl, E_OK);
}
pd->recovery->timer = INVALID_TIMER;
diff --git a/src/map/script.c b/src/map/script.c
index c71debc0d..773f8d6c4 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -67,7 +67,6 @@
// - 'function FuncName;' function declarations reverting to global functions
// if local label isn't found
// - join callfunc and callsub's functionality
-// - use script_op2name in the DEBUG_DISASM block
// - remove dynamic allocation in add_word()
// - remove GETVALUE / SETVALUE
// - clean up the set_reg / set_val / setd_sub mess
@@ -160,6 +159,9 @@
if( script_hasdata(st,n) ) \
(t)=script_getnum(st,n);
+/// Maximum amount of elements in script arrays
+#define SCRIPT_MAX_ARRAYSIZE 128
+
#define SCRIPT_BLOCK_SIZE 512
enum { LABEL_NEXTLINE=1,LABEL_START };
@@ -210,6 +212,7 @@ DBMap* script_get_userfunc_db(){ return userfunc_db; }
static DBMap* autobonus_db=NULL; // char* script -> char* bytecode
struct Script_Config script_config = {
+ 1, // warn_func_mismatch_argtypes
1, 65535, 2048, //warn_func_mismatch_paramnum/check_cmdcount/check_gotocount
0, INT_MAX, // input_min_value/input_max_value
"OnPCDieEvent", //die_event_name
@@ -281,13 +284,11 @@ typedef struct script_function {
extern script_function buildin_func[];
static struct linkdb_node* sleep_db;// int oid -> struct script_state*
-uint32 crctab[256];
/*==========================================
* ローカルプロトタイプ宣言 (必要な物のみ)
*------------------------------------------*/
const char* parse_subexpr(const char* p,int limit);
-void push_val(struct script_stack *stack,int type,int val);
int run_func(struct script_state *st);
enum {
@@ -515,6 +516,44 @@ static void script_reportdata(struct script_data* data)
}
}
+
+/// Reports on the console information about the current built-in function.
+static void script_reportfunc(struct script_state* st)
+{
+ int i, params, id;
+ struct script_data* data;
+
+ if( !script_hasdata(st,0) )
+ {// no stack
+ return;
+ }
+
+ data = script_getdata(st,0);
+
+ if( !data_isreference(data) || str_data[reference_getid(data)].type != C_FUNC )
+ {// script currently not executing a built-in function or corrupt stack
+ return;
+ }
+
+ id = reference_getid(data);
+ params = script_lastdata(st)-1;
+
+ if( params > 0 )
+ {
+ ShowDebug("Function: %s (%d parameter%s):\n", get_str(id), params, ( params == 1 ) ? "" : "s");
+
+ for( i = 2; i <= script_lastdata(st); i++ )
+ {
+ script_reportdata(script_getdata(st,i));
+ }
+ }
+ else
+ {
+ ShowDebug("Function: %s (no parameters)\n", get_str(id));
+ }
+}
+
+
/*==========================================
* エラーメッセージ出力
*------------------------------------------*/
@@ -741,8 +780,8 @@ void set_label(int l,int pos, const char* script_pos)
{
int i,next;
- if(str_data[l].type==C_INT || str_data[l].type==C_PARAM)
- { //Prevent overwriting constants values and parameters [Skotlex]
+ if(str_data[l].type==C_INT || str_data[l].type==C_PARAM || str_data[l].type==C_FUNC)
+ { //Prevent overwriting constants values, parameters and built-in functions [Skotlex]
disp_error_message("set_label: invalid label name",script_pos);
return;
}
@@ -842,7 +881,7 @@ int add_word(const char* p)
disp_error_message("script:add_word: invalid word. A word consists of undercores and/or alfanumeric characters, and valid variable prefixes/postfixes.", p);
// Duplicate the word
- CREATE(word, char, len+1);
+ word = aMalloc(len+1);
memcpy(word, p, len);
word[len] = 0;
@@ -1502,7 +1541,7 @@ const char* parse_syntax(const char* p)
// function declaration - just register the name
int l;
l = add_word(func_name);
- if( str_data[l].type == C_NOP )//## ??? [FlavioJS]
+ if( str_data[l].type == C_NOP )// set type only if the name did not exist before
str_data[l].type = C_USERFUNC;
// if, for , while の閉じ判定
@@ -1528,7 +1567,7 @@ const char* parse_syntax(const char* p)
// Set the position of the function (label)
l=add_word(func_name);
- if( str_data[l].type == C_NOP )//## ??? [FlavioJS]
+ if( str_data[l].type == C_NOP )// set type only if the name did not exist before
str_data[l].type = C_USERFUNC;
set_label(l, script_pos, p);
if( parse_options&SCRIPT_USE_LABEL_DB )
@@ -2078,54 +2117,30 @@ struct script_code* parse_script(const char *src,const char *file,int line,int o
{
int i = 0,j;
while(i < script_pos) {
- ShowMessage("%06x ",i);
+ c_op op = get_com(script_buf,&i);
+
+ ShowMessage("%06x %s", i, script_op2name(op));
j = i;
- switch(get_com(script_buf,&i)) {
- case C_EOL: printf("C_EOL"); break;
- case C_INT: printf("C_INT %d",get_num(script_buf,&i)); break;
+ switch(op) {
+ case C_INT:
+ ShowMessage(" %d", get_num(script_buf,&i));
+ break;
case C_POS:
- ShowMessage("C_POS 0x%06x",*(int*)(script_buf+i)&0xffffff);
+ ShowMessage(" 0x%06x", *(int*)(script_buf+i)&0xffffff);
i += 3;
break;
case C_NAME:
j = (*(int*)(script_buf+i)&0xffffff);
- ShowMessage("C_NAME %s",j == 0xffffff ? "?? unknown ??" : get_str(j));
+ ShowMessage(" %s", ( j == 0xffffff ) ? "?? unknown ??" : get_str(j));
i += 3;
break;
- case C_ARG: ShowMessage("C_ARG"); break;
- case C_FUNC: ShowMessage("C_FUNC"); break;
- case C_ADD: ShowMessage("C_ADD"); break;
- case C_SUB: ShowMessage("C_SUB"); break;
- case C_MUL: ShowMessage("C_MUL"); break;
- case C_DIV: ShowMessage("C_DIV"); break;
- case C_MOD: ShowMessage("C_MOD"); break;
- case C_EQ: ShowMessage("C_EQ"); break;
- case C_NE: ShowMessage("C_NE"); break;
- case C_GT: ShowMessage("C_GT"); break;
- case C_GE: ShowMessage("C_GE"); break;
- case C_LT: ShowMessage("C_LT"); break;
- case C_LE: ShowMessage("C_LE"); break;
- case C_AND: ShowMessage("C_AND"); break;
- case C_OR: ShowMessage("C_OR"); break;
- case C_XOR: ShowMessage("C_XOR"); break;
- case C_LAND: ShowMessage("C_LAND"); break;
- case C_LOR: ShowMessage("C_LOR"); break;
- case C_R_SHIFT: ShowMessage("C_R_SHIFT"); break;
- case C_L_SHIFT: ShowMessage("C_L_SHIFT"); break;
- case C_NEG: ShowMessage("C_NEG"); break;
- case C_NOT: ShowMessage("C_NOT"); break;
- case C_LNOT: ShowMessage("C_LNOT"); break;
- case C_NOP: ShowMessage("C_NOP"); break;
- case C_OP3: ShowMessage("C_OP3"); break;
case C_STR:
j = strlen(script_buf + i);
- ShowMessage("C_STR %s",script_buf + i);
- i+= j+1;
+ ShowMessage(" %s", script_buf + i);
+ i += j+1;
break;
- default:
- ShowMessage("unknown");
}
- ShowMessage(CL_CLL "\n");
+ ShowMessage(CL_CLL"\n");
}
}
#endif
@@ -2144,6 +2159,7 @@ TBL_PC *script_rid2sd(struct script_state *st)
TBL_PC *sd=map_id2sd(st->rid);
if(!sd){
ShowError("script_rid2sd: fatal error ! player not attached!\n");
+ script_reportfunc(st);
script_reportsrc(st);
st->state = END;
}
@@ -2694,6 +2710,10 @@ struct script_state* script_alloc_state(struct script_code* script, int pos, int
/// @param st Script state
void script_free_state(struct script_state* st)
{
+ if(st->bk_st)
+ {// backup was not restored
+ ShowDebug("script_free_state: Previous script state lost (rid=%d, oid=%d, state=%d, bk_npcid=%d).\n", st->bk_st->rid, st->bk_st->oid, st->bk_st->state, st->bk_npcid);
+ }
if( st->sleep.timer != INVALID_TIMER )
delete_timer(st->sleep.timer, run_script_timer);
script_free_vars(st->stack->var_function);
@@ -2977,6 +2997,94 @@ void op_1(struct script_state* st, int op)
}
+/// Checks the type of all arguments passed to a built-in function.
+///
+/// @param st Script state whose stack arguments should be inspected.
+/// @param func Built-in function for which the arguments are intended.
+static void script_check_buildin_argtype(struct script_state* st, int func)
+{
+ char type;
+ int idx, invalid = 0;
+ script_function* sf = &buildin_func[str_data[func].val];
+
+ for( idx = 2; script_hasdata(st, idx); idx++ )
+ {
+ struct script_data* data = script_getdata(st, idx);
+
+ type = sf->arg[idx-2];
+
+ if( type == '?' || type == '*' )
+ {// optional argument or unknown number of optional parameters ( no types are after this )
+ break;
+ }
+ else if( type == 0 )
+ {// more arguments than necessary ( should not happen, as it is checked before )
+ ShowWarning("Found more arguments than necessary.\n");
+ invalid++;
+ break;
+ }
+ else
+ {
+ const char* name = NULL;
+
+ if( data_isreference(data) )
+ {// get name for variables to determine the type they refer to
+ name = reference_getname(data);
+ }
+
+ switch( type )
+ {
+ case 'v':
+ if( !data_isstring(data) && !data_isint(data) && !data_isreference(data) )
+ {// variant
+ ShowWarning("Unexpected type for argument %d. Expected string, number or variable.\n", idx-1);
+ script_reportdata(data);
+ invalid++;
+ }
+ break;
+ case 's':
+ if( !data_isstring(data) && !( data_isreference(data) && is_string_variable(name) ) )
+ {// string
+ ShowWarning("Unexpected type for argument %d. Expected string.\n", idx-1);
+ script_reportdata(data);
+ invalid++;
+ }
+ break;
+ case 'i':
+ if( !data_isint(data) && !( data_isreference(data) && ( reference_toparam(data) || reference_toconstant(data) || !is_string_variable(name) ) ) )
+ {// int ( params and constants are always int )
+ ShowWarning("Unexpected type for argument %d. Expected number.\n", idx-1);
+ script_reportdata(data);
+ invalid++;
+ }
+ break;
+ case 'r':
+ if( !data_isreference(data) )
+ {// variables
+ ShowWarning("Unexpected type for argument %d. Expected variable.\n", idx-1);
+ script_reportdata(data);
+ invalid++;
+ }
+ break;
+ case 'l':
+ if( !data_islabel(data) && !data_isfunclabel(data) )
+ {// label
+ ShowWarning("Unexpected type for argument %d. Expected label.\n", idx-1);
+ script_reportdata(data);
+ invalid++;
+ }
+ break;
+ }
+ }
+ }
+
+ if(invalid)
+ {
+ ShowDebug("Function: %s\n", get_str(func));
+ script_reportsrc(st);
+ }
+}
+
/// Executes a buildin command.
/// Stack: C_NAME(<command>) C_ARG <arg0> <arg1> ... <argN>
@@ -3012,6 +3120,11 @@ int run_func(struct script_state *st)
return 1;
}
+ if( script_config.warn_func_mismatch_argtypes )
+ {
+ script_check_buildin_argtype(st, func);
+ }
+
if(str_data[func].func){
if (str_data[func].func(st)) //Report error
script_reportsrc(st);
@@ -3062,8 +3175,6 @@ int run_func(struct script_state *st)
/*==========================================
* script execution
*------------------------------------------*/
-void run_script_main(struct script_state *st);
-
void run_script(struct script_code *rootscript,int pos,int rid,int oid)
{
struct script_state *st;
@@ -3138,6 +3249,63 @@ int run_script_timer(int tid, unsigned int tick, int id, intptr data)
return 0;
}
+/// Detaches script state from possibly attached character and restores it's previous script if any.
+///
+/// @param st Script state to detach.
+/// @param dequeue_event Whether to schedule any queued events, when there was no previous script.
+static void script_detach_state(struct script_state* st, bool dequeue_event)
+{
+ struct map_session_data* sd;
+
+ if(st->rid && (sd = map_id2sd(st->rid))!=NULL)
+ {
+ sd->st = st->bk_st;
+ sd->npc_id = st->bk_npcid;
+
+ if(st->bk_st)
+ {
+ //Remove tag for removal.
+ st->bk_st = NULL;
+ st->bk_npcid = 0;
+ }
+ else if(dequeue_event)
+ {
+ npc_event_dequeue(sd);
+ }
+ }
+ else if(st->bk_st)
+ {// rid was set to 0, before detaching the script state
+ ShowError("script_detach_state: Found previous script state without attached player (rid=%d, oid=%d, state=%d, bk_npcid=%d)\n", st->bk_st->rid, st->bk_st->oid, st->bk_st->state, st->bk_npcid);
+ script_reportsrc(st->bk_st);
+
+ script_free_state(st->bk_st);
+ st->bk_st = NULL;
+ }
+}
+
+/// Attaches script state to possibly attached character and backups it's previous script, if any.
+///
+/// @param st Script state to attach.
+static void script_attach_state(struct script_state* st)
+{
+ struct map_session_data* sd;
+
+ if(st->rid && (sd = map_id2sd(st->rid))!=NULL)
+ {
+ if(st!=sd->st)
+ {
+ if(st->bk_st)
+ {// there is already a backup
+ ShowDebug("script_free_state: Previous script state lost (rid=%d, oid=%d, state=%d, bk_npcid=%d).\n", st->bk_st->rid, st->bk_st->oid, st->bk_st->state, st->bk_npcid);
+ }
+ st->bk_st = sd->st;
+ st->bk_npcid = sd->npc_id;
+ }
+ sd->st = st;
+ sd->npc_id = st->oid;
+ }
+}
+
/*==========================================
* スクリプトの実行メイン部分
*------------------------------------------*/
@@ -3146,22 +3314,10 @@ void run_script_main(struct script_state *st)
int cmdcount=script_config.check_cmdcount;
int gotocount=script_config.check_gotocount;
TBL_PC *sd;
- //For backing up purposes
- struct script_state *bk_st = NULL;
- int bk_npcid = 0;
struct script_stack *stack=st->stack;
struct npc_data *nd;
- sd = map_id2sd(st->rid);
-
- if(sd){
- if(sd->st != st){
- bk_st = sd->st;
- bk_npcid = sd->npc_id;
- }
- sd->st = st;
- sd->npc_id = st->oid;
- }
+ script_attach_state(st);
nd = map_id2nd(st->oid);
if( nd && map[nd->bl.m].instance_id > 0 )
@@ -3260,43 +3416,37 @@ void run_script_main(struct script_state *st)
if(st->sleep.tick > 0) {
//Restore previous script
- if (sd) {
- sd->st = bk_st;
- sd->npc_id = bk_npcid;
- bk_st = NULL; //Remove tag for removal.
- }
+ script_detach_state(st, false);
//Delay execution
- sd = map_id2sd(st->rid); // Refresh sd since script might have attached someone while running. [Inkfish]
+ sd = map_id2sd(st->rid); // Get sd since script might have attached someone while running. [Inkfish]
st->sleep.charid = sd?sd->status.char_id:0;
st->sleep.timer = add_timer(gettick()+st->sleep.tick,
run_script_timer, st->sleep.charid, (intptr)st);
linkdb_insert(&sleep_db, (void*)st->oid, st);
}
- else if(st->state != END && sd){
+ else if(st->state != END && st->rid){
//Resume later (st is already attached to player).
- if(bk_st) {
+ if(st->bk_st) {
ShowWarning("Unable to restore stack! Double continuation!\n");
//Report BOTH scripts to see if that can help somehow.
ShowDebug("Previous script (lost):\n");
- script_reportsrc(bk_st);
+ script_reportsrc(st->bk_st);
ShowDebug("Current script:\n");
script_reportsrc(st);
+
+ script_free_state(st->bk_st);
+ st->bk_st = NULL;
}
} else {
//Dispose of script.
- if (sd)
+ if ((sd = map_id2sd(st->rid))!=NULL)
{ //Restore previous stack and save char.
if(sd->state.using_fake_npc){
- clif_clearunit_single(sd->npc_id, 0, sd->fd);
+ clif_clearunit_single(sd->npc_id, CLR_OUTSIGHT, sd->fd);
sd->state.using_fake_npc = 0;
}
//Restore previous script if any.
- sd->st = bk_st;
- sd->npc_id = bk_npcid;
- if (!bk_st)
- npc_event_dequeue(sd);
- else
- bk_st = NULL; //Remove tag for removal.
+ script_detach_state(st, true);
if (sd->state.reg_dirty&2)
intif_saveregistry(sd,2);
if (sd->state.reg_dirty&1)
@@ -3305,13 +3455,6 @@ void run_script_main(struct script_state *st)
script_free_state(st);
st = NULL;
}
-
- if (bk_st)
- { //Remove previous script
- script_free_state(bk_st);
- bk_st = NULL;
- }
-
}
int script_config_read(char *cfgName)
@@ -3349,6 +3492,9 @@ int script_config_read(char *cfgName)
else if(strcmpi(w1,"input_max_value")==0) {
script_config.input_max_value = config_switch(w2);
}
+ else if(strcmpi(w1,"warn_func_mismatch_argtypes")==0) {
+ script_config.warn_func_mismatch_argtypes = config_switch(w2);
+ }
else if(strcmpi(w1,"import")==0){
script_config_read(w2);
}
@@ -3401,6 +3547,74 @@ void script_add_autobonus(const char *autobonus)
}
}
+
+/// resets a temporary character array variable to given value
+void script_cleararray_pc(struct map_session_data* sd, const char* varname, void* value)
+{
+ int key;
+ uint8 idx;
+
+ if( not_array_variable(varname[0]) || !not_server_variable(varname[0]) )
+ {
+ ShowError("script_cleararray_pc: Variable '%s' has invalid scope (char_id=%d).\n", varname, sd->status.char_id);
+ return;
+ }
+
+ key = add_str(varname);
+
+ if( is_string_variable(varname) )
+ {
+ for( idx = 0; idx < SCRIPT_MAX_ARRAYSIZE; idx++ )
+ {
+ pc_setregstr(sd, reference_uid(key, idx), (const char*)value);
+ }
+ }
+ else
+ {
+ for( idx = 0; idx < SCRIPT_MAX_ARRAYSIZE; idx++ )
+ {
+ pc_setreg(sd, reference_uid(key, idx), (int)value);
+ }
+ }
+}
+
+
+/// sets a temporary character array variable element idx to given value
+/// @param refcache Pointer to an int variable, which keeps a copy of the reference to varname and must be initialized to 0. Can be NULL if only one element is set.
+void script_setarray_pc(struct map_session_data* sd, const char* varname, uint8 idx, void* value, int* refcache)
+{
+ int key;
+
+ if( not_array_variable(varname[0]) || !not_server_variable(varname[0]) )
+ {
+ ShowError("script_setarray_pc: Variable '%s' has invalid scope (char_id=%d).\n", varname, sd->status.char_id);
+ return;
+ }
+
+ if( idx >= SCRIPT_MAX_ARRAYSIZE )
+ {
+ ShowError("script_setarray_pc: Variable '%s' has invalid index '%d' (char_id=%d).\n", varname, (int)idx, sd->status.char_id);
+ return;
+ }
+
+ key = ( refcache && refcache[0] ) ? refcache[0] : add_str(varname);
+
+ if( is_string_variable(varname) )
+ {
+ pc_setregstr(sd, reference_uid(key, idx), (const char*)value);
+ }
+ else
+ {
+ pc_setreg(sd, reference_uid(key, idx), (int)value);
+ }
+
+ if( refcache )
+ {// save to avoid repeated add_str calls
+ refcache[0] = key;
+ }
+}
+
+
/*==========================================
* 終了
*------------------------------------------*/
@@ -3698,7 +3912,12 @@ BUILDIN_FUNC(menu)
sd->state.menu_or_input = 1;
clif_scriptmenu(sd, st->oid, StringBuf_Value(&buf));
StringBuf_Destroy(&buf);
- //TODO what's the maximum number of options that can be displayed and/or received? -> give warning
+
+ if( sd->npc_menu >= 0xff )
+ {// client supports only up to 254 entries; 0 is not used and 255 is reserved for cancel; excess entries are displayed but cause 'uint8' overflow
+ ShowWarning("buildin_menu: Too many options specified (current=%d, max=254).\n", sd->npc_menu);
+ script_reportsrc(st);
+ }
}
else if( sd->npc_menu == 0xff )
{// Cancel was pressed
@@ -3780,6 +3999,12 @@ BUILDIN_FUNC(select)
sd->state.menu_or_input = 1;
clif_scriptmenu(sd, st->oid, StringBuf_Value(&buf));
StringBuf_Destroy(&buf);
+
+ if( sd->npc_menu >= 0xff )
+ {
+ ShowWarning("buildin_select: Too many options specified (current=%d, max=254).\n", sd->npc_menu);
+ script_reportsrc(st);
+ }
}
else if( sd->npc_menu == 0xff )
{// Cancel was pressed
@@ -3842,6 +4067,12 @@ BUILDIN_FUNC(prompt)
sd->state.menu_or_input = 1;
clif_scriptmenu(sd, st->oid, StringBuf_Value(&buf));
StringBuf_Destroy(&buf);
+
+ if( sd->npc_menu >= 0xff )
+ {
+ ShowWarning("buildin_prompt: Too many options specified (current=%d, max=254).\n", sd->npc_menu);
+ script_reportsrc(st);
+ }
}
else if( sd->npc_menu == 0xff )
{// Cancel was pressed
@@ -4100,11 +4331,11 @@ BUILDIN_FUNC(warp)
y = script_getnum(st,4);
if(strcmp(str,"Random")==0)
- ret = pc_randomwarp(sd,3);
+ ret = pc_randomwarp(sd,CLR_TELEPORT);
else if(strcmp(str,"SavePoint")==0 || strcmp(str,"Save")==0)
- ret = pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,3);
+ ret = pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT);
else
- ret = pc_setpos(sd,mapindex_name2id(str),x,y,0);
+ ret = pc_setpos(sd,mapindex_name2id(str),x,y,CLR_OUTSIGHT);
if( ret ) {
ShowError("buildin_warp: moving player '%s' to \"%s\",%d,%d failed.\n", sd->status.name, str, x, y);
@@ -4124,9 +4355,9 @@ static int buildin_areawarp_sub(struct block_list *bl,va_list ap)
x=va_arg(ap,int);
y=va_arg(ap,int);
if(map == 0)
- pc_randomwarp((TBL_PC *)bl,3);
+ pc_randomwarp((TBL_PC *)bl,CLR_TELEPORT);
else
- pc_setpos((TBL_PC *)bl,map,x,y,0);
+ pc_setpos((TBL_PC *)bl,map,x,y,CLR_OUTSIGHT);
return 0;
}
BUILDIN_FUNC(areawarp)
@@ -4212,12 +4443,12 @@ BUILDIN_FUNC(warpchar)
return 0;
if(strcmp(str, "Random") == 0)
- pc_randomwarp(sd, 3);
+ pc_randomwarp(sd, CLR_TELEPORT);
else
if(strcmp(str, "SavePoint") == 0)
- pc_setpos(sd, sd->status.save_point.map,sd->status.save_point.x, sd->status.save_point.y, 3);
+ pc_setpos(sd, sd->status.save_point.map,sd->status.save_point.x, sd->status.save_point.y, CLR_TELEPORT);
else
- pc_setpos(sd, mapindex_name2id(str), x, y, 3);
+ pc_setpos(sd, mapindex_name2id(str), x, y, CLR_TELEPORT);
return 0;
}
@@ -4274,15 +4505,15 @@ BUILDIN_FUNC(warpparty)
{
case 0: // Random
if(!map[pl_sd->bl.m].flag.nowarp)
- pc_randomwarp(pl_sd,3);
+ pc_randomwarp(pl_sd,CLR_TELEPORT);
break;
case 1: // SavePointAll
if(!map[pl_sd->bl.m].flag.noreturn)
- pc_setpos(pl_sd,pl_sd->status.save_point.map,pl_sd->status.save_point.x,pl_sd->status.save_point.y,3);
+ pc_setpos(pl_sd,pl_sd->status.save_point.map,pl_sd->status.save_point.x,pl_sd->status.save_point.y,CLR_TELEPORT);
break;
case 2: // SavePoint
if(!map[pl_sd->bl.m].flag.noreturn)
- pc_setpos(pl_sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,3);
+ pc_setpos(pl_sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT);
break;
case 3: // Leader
for(j = 0; j < MAX_PARTY && !p->party.member[j].leader; j++);
@@ -4298,12 +4529,12 @@ BUILDIN_FUNC(warpparty)
continue;
if(map[pl_sd->bl.m].flag.noreturn || map[pl_sd->bl.m].flag.nowarp)
continue;
- pc_setpos(pl_sd,mapindex,x,y,3);
+ pc_setpos(pl_sd,mapindex,x,y,CLR_TELEPORT);
}
break;
case 4: // m,x,y
if(!map[pl_sd->bl.m].flag.noreturn && !map[pl_sd->bl.m].flag.nowarp)
- pc_setpos(pl_sd,mapindex_name2id(str),x,y,3);
+ pc_setpos(pl_sd,mapindex_name2id(str),x,y,CLR_TELEPORT);
break;
}
}
@@ -4352,19 +4583,19 @@ BUILDIN_FUNC(warpguild)
{
case 0: // Random
if(!map[pl_sd->bl.m].flag.nowarp)
- pc_randomwarp(pl_sd,3);
+ pc_randomwarp(pl_sd,CLR_TELEPORT);
break;
case 1: // SavePointAll
if(!map[pl_sd->bl.m].flag.noreturn)
- pc_setpos(pl_sd,pl_sd->status.save_point.map,pl_sd->status.save_point.x,pl_sd->status.save_point.y,3);
+ pc_setpos(pl_sd,pl_sd->status.save_point.map,pl_sd->status.save_point.x,pl_sd->status.save_point.y,CLR_TELEPORT);
break;
case 2: // SavePoint
if(!map[pl_sd->bl.m].flag.noreturn)
- pc_setpos(pl_sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,3);
+ pc_setpos(pl_sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT);
break;
case 3: // m,x,y
if(!map[pl_sd->bl.m].flag.noreturn && !map[pl_sd->bl.m].flag.nowarp)
- pc_setpos(pl_sd,mapindex_name2id(str),x,y,3);
+ pc_setpos(pl_sd,mapindex_name2id(str),x,y,CLR_TELEPORT);
break;
}
}
@@ -4588,7 +4819,7 @@ static int32 getarraysize(struct script_state* st, int32 id, int32 idx, int isst
if( isstring )
{
- for( ; idx < 128; ++idx )
+ for( ; idx < SCRIPT_MAX_ARRAYSIZE; ++idx )
{
char* str = (char*)get_val2(st, reference_uid(id, idx), ref);
if( str && *str )
@@ -4598,7 +4829,7 @@ static int32 getarraysize(struct script_state* st, int32 id, int32 idx, int isst
}
else
{
- for( ; idx < 128; ++idx )
+ for( ; idx < SCRIPT_MAX_ARRAYSIZE; ++idx )
{
int32 num = (int32)get_val2(st, reference_uid(id, idx), ref);
if( num )
@@ -4651,8 +4882,8 @@ BUILDIN_FUNC(setarray)
}
end = start + script_lastdata(st) - 2;
- if( end > 127 )
- end = 127;
+ if( end >= SCRIPT_MAX_ARRAYSIZE )
+ end = SCRIPT_MAX_ARRAYSIZE-1;
if( is_string_variable(name) )
{// string array
@@ -4714,8 +4945,8 @@ BUILDIN_FUNC(cleararray)
v = (void*)script_getnum(st, 3);
end = start + script_getnum(st, 4);
- if( end > 127 )
- end = 127;
+ if( end >= SCRIPT_MAX_ARRAYSIZE )
+ end = SCRIPT_MAX_ARRAYSIZE-1;
for( ; start <= end; ++start )
set_reg(st, sd, reference_uid(id, start), name, v, script_getref(st,2));
@@ -4784,8 +5015,8 @@ BUILDIN_FUNC(copyarray)
}
count = script_getnum(st, 4);
- if( count > 128 - idx1 )
- count = 128 - idx1;
+ if( count >= SCRIPT_MAX_ARRAYSIZE - idx1 )
+ count = (SCRIPT_MAX_ARRAYSIZE-1) - idx1;
if( count <= 0 || (id1 == id2 && idx1 == idx2) )
return 0;// nothing to copy
@@ -4802,7 +5033,7 @@ BUILDIN_FUNC(copyarray)
{// normal copy
for( i = 0; i < count; ++i )
{
- if( idx2 + i < 128 )
+ if( idx2 + i < SCRIPT_MAX_ARRAYSIZE )
{
v = get_val2(st, reference_uid(id2, idx2 + i), reference_getref(data2));
set_reg(st, sd, reference_uid(id1, idx1 + i), name1, v, reference_getref(data1));
@@ -4958,7 +5189,7 @@ BUILDIN_FUNC(getelementofarray)
}
i = script_getnum(st, 3);
- if( i < 0 || i >= 128 )
+ if( i < 0 || i >= SCRIPT_MAX_ARRAYSIZE )
{
ShowWarning("script:getelementofarray: index out of range (%d)\n", i);
script_reportdata(data);
@@ -5154,48 +5385,80 @@ BUILDIN_FUNC(countitem2)
*------------------------------------------*/
BUILDIN_FUNC(checkweight)
{
- int nameid=0,amount,i;
- unsigned long weight;
- TBL_PC *sd;
- struct script_data *data;
+ int nameid, amount, slots;
+ unsigned int weight;
+ struct item_data* id = NULL;
+ struct map_session_data* sd;
+ struct script_data* data;
- sd = script_rid2sd(st);
- if( sd == NULL )
+ if( ( sd = script_rid2sd(st) ) == NULL )
+ {
return 0;
+ }
- data=script_getdata(st,2);
- get_val(st,data);
- if( data_isstring(data) ){
- const char *name=conv_str(st,data);
- struct item_data *item_data = itemdb_searchname(name);
- if( item_data )
- nameid=item_data->nameid;
- }else
- nameid=conv_num(st,data);
+ data = script_getdata(st,2);
+ get_val(st, data); // convert into value in case of a variable
- amount=script_getnum(st,3);
- if ( amount<=0 || nameid<500 ) { //if get wrong item ID or amount<=0, don't count weight of non existing items
- script_pushint(st,0);
- ShowError("buildin_checkweight: Wrong item ID or amount.\n");
+ if( data_isstring(data) )
+ {// item name
+ id = itemdb_searchname(conv_str(st, data));
+ }
+ else
+ {// item id
+ id = itemdb_exists(conv_num(st, data));
+ }
+
+ if( id == NULL )
+ {
+ ShowError("buildin_checkweight: Invalid item '%s'.\n", script_getstr(st,2)); // returns string, regardless of what it was
+ return 1;
+ }
+
+ nameid = id->nameid;
+ amount = script_getnum(st,3);
+
+ if( amount < 1 )
+ {
+ ShowError("buildin_checkweight: Invalid amount '%d'.\n", amount);
return 1;
}
weight = itemdb_weight(nameid)*amount;
- if( amount > MAX_AMOUNT || weight + sd->weight > sd->max_weight )
+
+ if( weight + sd->weight > sd->max_weight )
+ {// too heavy
script_pushint(st,0);
- else if( itemdb_isstackable(nameid) )
- {
- if( (i = pc_search_inventory(sd,nameid)) >= 0 )
- script_pushint(st,amount + sd->status.inventory[i].amount > MAX_AMOUNT ? 0 : 1);
- else
- script_pushint(st,pc_search_inventory(sd,0) >= 0 ? 1 : 0);
+ return 0;
}
- else
+
+ switch( pc_checkadditem(sd, nameid, amount) )
{
- for( i = 0; i < MAX_INVENTORY && amount; ++i )
- if( sd->status.inventory[i].nameid == 0 )
- amount--;
- script_pushint(st,amount ? 0 : 1);
+ case ADDITEM_EXIST:
+ // item is already in inventory, but there is still space for the requested amount
+ break;
+ case ADDITEM_NEW:
+ slots = pc_inventoryblank(sd);
+
+ if( itemdb_isstackable(nameid) )
+ {// stackable
+ if( slots < 1 )
+ {
+ script_pushint(st,0);
+ return 0;
+ }
+ }
+ else
+ {// non-stackable
+ if( slots < amount )
+ {
+ script_pushint(st,0);
+ return 0;
+ }
+ }
+ break;
+ case ADDITEM_OVERAMOUNT:
+ script_pushint(st,0);
+ return 0;
}
return 0;
@@ -5390,8 +5653,8 @@ BUILDIN_FUNC(getitem2)
}
/*==========================================
- * rentitem <item id>
- * rentitem "<item name>"
+ * rentitem <item id>,<seconds>
+ * rentitem "<item name>",<seconds>
*------------------------------------------*/
BUILDIN_FUNC(rentitem)
{
@@ -5596,6 +5859,156 @@ BUILDIN_FUNC(makeitem)
return 0;
}
+
+/// Counts / deletes the current item given by idx.
+/// Used by buildin_delitem_search
+/// Relies on all input data being already fully valid.
+static void buildin_delitem_delete(struct map_session_data* sd, int idx, int* amount, bool delete_items)
+{
+ int delamount;
+ struct item* inv = &sd->status.inventory[idx];
+
+ delamount = ( amount[0] < inv->amount ) ? amount[0] : inv->amount;
+
+ if( delete_items )
+ {
+ if( sd->inventory_data[idx]->type == IT_PETEGG && inv->card[0] == CARD0_PET )
+ {// delete associated pet
+ intif_delete_petdata(MakeDWord(inv->card[1], inv->card[2]));
+ }
+
+ //Logs items, got from (N)PC scripts [Lupus]
+ if( log_config.enable_logs&0x40 )
+ {
+ log_pick_pc(sd, "N", inv->nameid, -delamount, inv);
+ }
+ //Logs
+
+ pc_delitem(sd, idx, delamount, 0, 0);
+ }
+
+ amount[0]-= delamount;
+}
+
+
+/// Searches for item(s) and checks, if there is enough of them.
+/// Used by delitem and delitem2
+/// Relies on all input data being already fully valid.
+/// @param exact_match will also match item attributes and cards, not just name id
+/// @return true when all items could be deleted, false when there were not enough items to delete
+static bool buildin_delitem_search(struct map_session_data* sd, struct item* it, bool exact_match)
+{
+ bool delete_items = false;
+ int i, amount, important;
+ struct item* inv;
+
+ // prefer always non-equipped items
+ it->equip = 0;
+
+ // when searching for nameid only, prefer additionally
+ if( !exact_match )
+ {
+ // non-refined items
+ it->refine = 0;
+ // card-less items
+ memset(it->card, 0, sizeof(it->card));
+ }
+
+ for(;;)
+ {
+ amount = it->amount;
+ important = 0;
+
+ // 1st pass -- less important items / exact match
+ for( i = 0; amount && i < ARRAYLENGTH(sd->status.inventory); i++ )
+ {
+ inv = &sd->status.inventory[i];
+
+ if( !inv->nameid || !sd->inventory_data[i] || inv->nameid != it->nameid )
+ {// wrong/invalid item
+ continue;
+ }
+
+ if( inv->equip != it->equip || inv->refine != it->refine )
+ {// not matching attributes
+ important++;
+ continue;
+ }
+
+ if( exact_match )
+ {
+ if( inv->identify != it->identify || inv->attribute != it->attribute || memcmp(inv->card, it->card, sizeof(inv->card)) )
+ {// not matching exact attributes
+ continue;
+ }
+ }
+ else
+ {
+ if( sd->inventory_data[i]->type == IT_PETEGG )
+ {
+ if( inv->card[0] == CARD0_PET && CheckForCharServer() )
+ {// pet which cannot be deleted
+ continue;
+ }
+ }
+ else if( memcmp(inv->card, it->card, sizeof(inv->card)) )
+ {// named/carded item
+ important++;
+ continue;
+ }
+ }
+
+ // count / delete item
+ buildin_delitem_delete(sd, i, &amount, delete_items);
+ }
+
+ // 2nd pass -- any matching item
+ if( amount == 0 || important == 0 )
+ {// either everything was already consumed or no items were skipped
+ ;
+ }
+ else for( i = 0; amount && i < ARRAYLENGTH(sd->status.inventory); i++ )
+ {
+ inv = &sd->status.inventory[i];
+
+ if( !inv->nameid || !sd->inventory_data[i] || inv->nameid != it->nameid )
+ {// wrong/invalid item
+ continue;
+ }
+
+ if( sd->inventory_data[i]->type == IT_PETEGG && inv->card[0] == CARD0_PET && CheckForCharServer() )
+ {// pet which cannot be deleted
+ continue;
+ }
+
+ if( exact_match )
+ {
+ if( inv->refine != it->refine || inv->identify != it->identify || inv->attribute != it->attribute || memcmp(inv->card, it->card, sizeof(inv->card)) )
+ {// not matching attributes
+ continue;
+ }
+ }
+
+ // count / delete item
+ buildin_delitem_delete(sd, i, &amount, delete_items);
+ }
+
+ if( amount )
+ {// not enough items
+ return false;
+ }
+ else if( delete_items )
+ {// we are done with the work
+ return true;
+ }
+ else
+ {// get rid of the items now
+ delete_items = true;
+ }
+ }
+}
+
+
/// Deletes items from the target/attached player.
/// Prioritizes ordinary items.
///
@@ -5603,8 +6016,8 @@ BUILDIN_FUNC(makeitem)
/// delitem "<item name>",<amount>{,<account id>}
BUILDIN_FUNC(delitem)
{
- int nameid=0,amount,i,important_item=0;
TBL_PC *sd;
+ struct item it;
struct script_data *data;
if( script_hasdata(st,4) )
@@ -5637,89 +6050,30 @@ BUILDIN_FUNC(delitem)
st->state = END;
return 1;
}
- nameid = id->nameid;// "<item name>"
+ it.nameid = id->nameid;// "<item name>"
}
else
- nameid = conv_num(st,data);// <item id>
-
- amount=script_getnum(st,3);
-
- if( amount <= 0 )
- return 0;// nothing to do
-
- //1st pass
- //here we won't delete items with CARDS, named items but we count them
- for(i=0;i<MAX_INVENTORY;i++){
- //we don't delete wrong item or equipped item
- if(sd->status.inventory[i].nameid<=0 || sd->inventory_data[i] == NULL ||
- sd->status.inventory[i].amount<=0 || sd->status.inventory[i].nameid!=nameid)
- continue;
- //1 egg uses 1 cell in the inventory. so it's ok to delete 1 pet / per cycle
- if(sd->inventory_data[i]->type==IT_PETEGG &&
- sd->status.inventory[i].card[0] == CARD0_PET)
+ {
+ it.nameid = conv_num(st,data);// <item id>
+ if( !itemdb_exists( it.nameid ) )
{
- if (!intif_delete_petdata(MakeDWord(sd->status.inventory[i].card[1], sd->status.inventory[i].card[2])))
- continue; //pet couldn't be sent for deletion.
- } else
- //is this item important? does it have cards? or Player's name? or Refined/Upgraded
- if(itemdb_isspecial(sd->status.inventory[i].card[0]) ||
- sd->status.inventory[i].card[0] ||
- sd->status.inventory[i].refine) {
- //this is important item, count it (except for pet eggs)
- if(sd->status.inventory[i].card[0] != CARD0_PET)
- important_item++;
- continue;
- }
-
- if(sd->status.inventory[i].amount>=amount){
-
- //Logs items, got from (N)PC scripts [Lupus]
- if(log_config.enable_logs&0x40)
- log_pick_pc(sd, "N", sd->status.inventory[i].nameid, -amount, &sd->status.inventory[i]);
-
- pc_delitem(sd,i,amount,0,0);
- return 0; //we deleted exact amount of items. now exit
- } else {
- amount-=sd->status.inventory[i].amount;
-
- //Logs items, got from (N)PC scripts [Lupus]
- if(log_config.enable_logs&0x40) {
- log_pick_pc(sd, "N", sd->status.inventory[i].nameid, -sd->status.inventory[i].amount, &sd->status.inventory[i]);
- }
- //Logs
-
- pc_delitem(sd,i,sd->status.inventory[i].amount,0,0);
+ ShowError("script:delitem: unknown item \"%d\".\n", it.nameid);
+ st->state = END;
+ return 1;
}
}
- //2nd pass
- //now if there WERE items with CARDs/REFINED/NAMED... and if we still have to delete some items. we'll delete them finally
- if (important_item>0 && amount>0)
- for(i=0;i<MAX_INVENTORY;i++){
- //we don't delete wrong item
- if(sd->status.inventory[i].nameid<=0 || sd->inventory_data[i] == NULL ||
- sd->status.inventory[i].amount<=0 || sd->status.inventory[i].nameid!=nameid )
- continue;
- if(sd->status.inventory[i].amount>=amount){
+ it.amount=script_getnum(st,3);
- //Logs items, got from (N)PC scripts [Lupus]
- if(log_config.enable_logs&0x40)
- log_pick_pc(sd, "N", sd->status.inventory[i].nameid, -amount, &sd->status.inventory[i]);
-
- pc_delitem(sd,i,amount,0,0);
- return 0; //we deleted exact amount of items. now exit
- } else {
- amount-=sd->status.inventory[i].amount;
-
- //Logs items, got from (N)PC scripts [Lupus]
- if(log_config.enable_logs&0x40)
- log_pick_pc(sd, "N", sd->status.inventory[i].nameid, -sd->status.inventory[i].amount, &sd->status.inventory[i]);
+ if( it.amount <= 0 )
+ return 0;// nothing to do
- pc_delitem(sd,i,sd->status.inventory[i].amount,0,0);
- }
- }
+ if( buildin_delitem_search(sd, &it, false) )
+ {// success
+ return 0;
+ }
- ShowError("script:delitem: failed to delete %d items (AID=%d item_id=%d).\n", amount, sd->status.account_id, nameid);
+ ShowError("script:delitem: failed to delete %d items (AID=%d item_id=%d).\n", it.amount, sd->status.account_id, it.nameid);
st->state = END;
clif_scriptclose(sd, st->oid);
return 1;
@@ -5731,9 +6085,8 @@ BUILDIN_FUNC(delitem)
/// delitem2 "<Item name>",<amount>,<identify>,<refine>,<attribute>,<card1>,<card2>,<card3>,<card4>{,<account ID>}
BUILDIN_FUNC(delitem2)
{
- int nameid=0,amount,i=0;
- int iden,ref,attr,c1,c2,c3,c4;
TBL_PC *sd;
+ struct item it;
struct script_data *data;
if( script_hasdata(st,11) )
@@ -5766,59 +6119,37 @@ BUILDIN_FUNC(delitem2)
st->state = END;
return 1;
}
- nameid = id->nameid;// "<item name>"
+ it.nameid = id->nameid;// "<item name>"
}
else
- nameid = conv_num(st,data);// <item id>
-
- amount=script_getnum(st,3);
- iden=script_getnum(st,4);
- ref=script_getnum(st,5);
- attr=script_getnum(st,6);
- c1=(short)script_getnum(st,7);
- c2=(short)script_getnum(st,8);
- c3=(short)script_getnum(st,9);
- c4=(short)script_getnum(st,10);
-
- if( amount <= 0 )
- return 0;// nothing to do
-
- for(i=0;i<MAX_INVENTORY;i++){
- //we don't delete wrong item or equipped item
- if(sd->status.inventory[i].nameid<=0 || sd->inventory_data[i] == NULL ||
- sd->status.inventory[i].amount<=0 || sd->status.inventory[i].nameid!=nameid ||
- sd->status.inventory[i].identify!=iden || sd->status.inventory[i].refine!=ref ||
- sd->status.inventory[i].attribute!=attr || sd->status.inventory[i].card[0]!=c1 ||
- sd->status.inventory[i].card[1]!=c2 || sd->status.inventory[i].card[2]!=c3 ||
- sd->status.inventory[i].card[3]!=c4)
- continue;
- //1 egg uses 1 cell in the inventory. so it's ok to delete 1 pet / per cycle
- if(sd->inventory_data[i]->type==IT_PETEGG && sd->status.inventory[i].card[0] == CARD0_PET)
+ {
+ it.nameid = conv_num(st,data);// <item id>
+ if( !itemdb_exists( it.nameid ) )
{
- if (!intif_delete_petdata( MakeDWord(sd->status.inventory[i].card[1], sd->status.inventory[i].card[2])))
- continue; //Failed to send delete the pet.
+ ShowError("script:delitem: unknown item \"%d\".\n", it.nameid);
+ st->state = END;
+ return 1;
}
+ }
- if(sd->status.inventory[i].amount>=amount){
-
- //Logs items, got from (N)PC scripts [Lupus]
- if(log_config.enable_logs&0x40)
- log_pick_pc(sd, "N", sd->status.inventory[i].nameid, -amount, &sd->status.inventory[i]);
-
- pc_delitem(sd,i,amount,0,0);
- return 0; //we deleted exact amount of items. now exit
- } else {
- amount-=sd->status.inventory[i].amount;
+ it.amount=script_getnum(st,3);
+ it.identify=script_getnum(st,4);
+ it.refine=script_getnum(st,5);
+ it.attribute=script_getnum(st,6);
+ it.card[0]=(short)script_getnum(st,7);
+ it.card[1]=(short)script_getnum(st,8);
+ it.card[2]=(short)script_getnum(st,9);
+ it.card[3]=(short)script_getnum(st,10);
- //Logs items, got from (N)PC scripts [Lupus]
- if(log_config.enable_logs&0x40)
- log_pick_pc(sd, "N", sd->status.inventory[i].nameid, -sd->status.inventory[i].amount, &sd->status.inventory[i]);
+ if( it.amount <= 0 )
+ return 0;// nothing to do
- pc_delitem(sd,i,sd->status.inventory[i].amount,0,0);
- }
+ if( buildin_delitem_search(sd, &it, true) )
+ {// success
+ return 0;
}
- ShowError("script:delitem2: failed to delete %d items (AID=%d item_id=%d).\n", amount, sd->status.account_id, nameid);
+ ShowError("script:delitem2: failed to delete %d items (AID=%d item_id=%d).\n", it.amount, sd->status.account_id, it.nameid);
st->state = END;
clif_scriptclose(sd, st->oid);
return 1;
@@ -5904,34 +6235,21 @@ BUILDIN_FUNC(getcharid)
/*==========================================
*指定IDのPT名取得
*------------------------------------------*/
-char *buildin_getpartyname_sub(int party_id)
-{
- struct party_data *p;
-
- p=party_search(party_id);
-
- if(p!=NULL){
- char *buf;
- buf=(char *)aMallocA(NAME_LENGTH*sizeof(char));
- memcpy(buf, p->party.name, NAME_LENGTH);
- buf[NAME_LENGTH-1] = '\0';
- return buf;
- }
-
- return 0;
-}
BUILDIN_FUNC(getpartyname)
{
- char *name;
int party_id;
+ struct party_data* p;
- party_id=script_getnum(st,2);
- name=buildin_getpartyname_sub(party_id);
- if(name != NULL)
- script_pushstr(st,name);
+ party_id = script_getnum(st,2);
+
+ if( ( p = party_search(party_id) ) != NULL )
+ {
+ script_pushstrcopy(st,p->party.name);
+ }
else
+ {
script_pushconststr(st,"null");
-
+ }
return 0;
}
/*==========================================
@@ -5952,13 +6270,13 @@ BUILDIN_FUNC(getpartymember)
if(p->party.member[i].account_id){
switch (type) {
case 2:
- mapreg_setreg(add_str("$@partymemberaid")+(j<<24),p->party.member[i].account_id);
+ mapreg_setreg(reference_uid(add_str("$@partymemberaid"), j),p->party.member[i].account_id);
break;
case 1:
- mapreg_setreg(add_str("$@partymembercid")+(j<<24),p->party.member[i].char_id);
+ mapreg_setreg(reference_uid(add_str("$@partymembercid"), j),p->party.member[i].char_id);
break;
default:
- mapreg_setregstr(add_str("$@partymembername$")+(j<<24),p->party.member[i].name);
+ mapreg_setregstr(reference_uid(add_str("$@partymembername$"), j),p->party.member[i].name);
}
j++;
}
@@ -6009,75 +6327,58 @@ BUILDIN_FUNC(getpartyleader)
/*==========================================
*指定IDのギルド名取得
*------------------------------------------*/
-char *buildin_getguildname_sub(int guild_id)
+BUILDIN_FUNC(getguildname)
{
- struct guild *g=NULL;
- g=guild_search(guild_id);
+ int guild_id;
+ struct guild* g;
- if(g!=NULL){
- char *buf;
- buf=(char *)aMallocA(NAME_LENGTH*sizeof(char));
- memcpy(buf, g->name, NAME_LENGTH);
- buf[NAME_LENGTH-1] = '\0';
- return buf;
+ guild_id = script_getnum(st,2);
+
+ if( ( g = guild_search(guild_id) ) != NULL )
+ {
+ script_pushstrcopy(st,g->name);
}
- return NULL;
-}
-BUILDIN_FUNC(getguildname)
-{
- char *name;
- int guild_id=script_getnum(st,2);
- name=buildin_getguildname_sub(guild_id);
- if(name != NULL)
- script_pushstr(st,name);
else
+ {
script_pushconststr(st,"null");
+ }
return 0;
}
/*==========================================
*指定IDのGuildMaster名取得
*------------------------------------------*/
-char *buildin_getguildmaster_sub(int guild_id)
+BUILDIN_FUNC(getguildmaster)
{
- struct guild *g=NULL;
- g=guild_search(guild_id);
+ int guild_id;
+ struct guild* g;
- if(g!=NULL){
- char *buf;
- buf=(char *)aMallocA(NAME_LENGTH*sizeof(char));
- memcpy(buf, g->master, NAME_LENGTH);
- buf[NAME_LENGTH-1] = '\0';
- return buf;
- }
+ guild_id = script_getnum(st,2);
- return 0;
-}
-BUILDIN_FUNC(getguildmaster)
-{
- char *master;
- int guild_id=script_getnum(st,2);
- master=buildin_getguildmaster_sub(guild_id);
- if(master!=0)
- script_pushstr(st,master);
+ if( ( g = guild_search(guild_id) ) != NULL )
+ {
+ script_pushstrcopy(st,g->member[0].name);
+ }
else
+ {
script_pushconststr(st,"null");
+ }
return 0;
}
BUILDIN_FUNC(getguildmasterid)
{
- char *master;
- TBL_PC *sd=NULL;
- int guild_id=script_getnum(st,2);
- master=buildin_getguildmaster_sub(guild_id);
- if(master!=0){
- if((sd=map_nick2sd(master)) == NULL){
- script_pushint(st,0);
- return 0;
- }
- script_pushint(st,sd->status.char_id);
- }else{
+ int guild_id;
+ struct guild* g;
+
+ guild_id = script_getnum(st,2);
+
+ if( ( g = guild_search(guild_id) ) != NULL )
+ {
+ script_pushint(st,g->member[0].char_id);
+ }
+ else
+ {
script_pushint(st,0);
}
return 0;
@@ -6090,7 +6391,8 @@ BUILDIN_FUNC(strcharinfo)
{
TBL_PC *sd;
int num;
- char *buf;
+ struct guild* g;
+ struct party_data* p;
sd=script_rid2sd(st);
if (!sd) { //Avoid crashing....
@@ -6103,18 +6405,24 @@ BUILDIN_FUNC(strcharinfo)
script_pushstrcopy(st,sd->status.name);
break;
case 1:
- buf=buildin_getpartyname_sub(sd->status.party_id);
- if(buf!=0)
- script_pushstr(st,buf);
+ if( ( p = party_search(sd->status.party_id) ) != NULL )
+ {
+ script_pushstrcopy(st,p->party.name);
+ }
else
+ {
script_pushconststr(st,"");
+ }
break;
case 2:
- buf=buildin_getguildname_sub(sd->status.guild_id);
- if(buf != NULL)
- script_pushstr(st,buf);
+ if( ( g = guild_search(sd->status.guild_id) ) != NULL )
+ {
+ script_pushstrcopy(st,g->name);
+ }
else
+ {
script_pushconststr(st,"");
+ }
break;
case 3:
script_pushconststr(st,map[sd->bl.m].name);
@@ -7534,8 +7842,8 @@ BUILDIN_FUNC(getmobdrops)
if( itemdb_exists(mob->dropitem[i].nameid) == NULL )
continue;
- mapreg_setreg(add_str("$@MobDrop_item") + (j<<24), mob->dropitem[i].nameid);
- mapreg_setreg(add_str("$@MobDrop_rate") + (j<<24), mob->dropitem[i].p);
+ mapreg_setreg(reference_uid(add_str("$@MobDrop_item"), j), mob->dropitem[i].nameid);
+ mapreg_setreg(reference_uid(add_str("$@MobDrop_rate"), j), mob->dropitem[i].p);
j++;
}
@@ -7750,8 +8058,15 @@ BUILDIN_FUNC(clone)
BUILDIN_FUNC(doevent)
{
const char* event = script_getstr(st,2);
+ struct map_session_data* sd;
+
+ if( ( sd = script_rid2sd(st) ) == NULL )
+ {
+ return 0;
+ }
+
check_event(st, event);
- npc_event(map_id2sd(st->rid),event,0);
+ npc_event(sd, event, 0);
return 0;
}
/*==========================================
@@ -8226,18 +8541,18 @@ BUILDIN_FUNC(getusers)
flag = script_getnum(st,2);
- if(flag&0x8)
- {// npc
- bl = map_id2bl(st->oid);
- }
- else if((sd = script_rid2sd(st))!=NULL)
- {// pc
- bl = &sd->bl;
- }
-
switch(flag&0x07)
{
case 0:
+ if(flag&0x8)
+ {// npc
+ bl = map_id2bl(st->oid);
+ }
+ else if((sd = script_rid2sd(st))!=NULL)
+ {// pc
+ bl = &sd->bl;
+ }
+
if(bl)
{
val = map[bl->m].users;
@@ -8657,7 +8972,7 @@ BUILDIN_FUNC(homunculus_evolution)
if (sd->hd->homunculus.intimacy > 91000)
merc_hom_evolution(sd->hd);
else
- clif_emotion(&sd->hd->bl, 4) ; //swt
+ clif_emotion(&sd->hd->bl, E_SWT);
}
return 0;
}
@@ -9061,23 +9376,23 @@ BUILDIN_FUNC(warpwaitingpc)
if( sd == NULL )
{
ShowDebug("script:warpwaitingpc: no user in chat room position 0 (cd->users=%d,%d/%d)\n", cd->users, i, n);
- mapreg_setreg(add_str("$@warpwaitingpc")+(i<<24), 0);
+ mapreg_setreg(reference_uid(add_str("$@warpwaitingpc"), i), 0);
continue;// Broken npc chat room?
}
- mapreg_setreg(add_str("$@warpwaitingpc")+(i<<24), sd->bl.id);
+ mapreg_setreg(reference_uid(add_str("$@warpwaitingpc"), i), sd->bl.id);
if( strcmp(map_name,"Random") == 0 )
- pc_randomwarp(sd,3);
+ pc_randomwarp(sd,CLR_TELEPORT);
else if( strcmp(map_name,"SavePoint") == 0 )
{
if( map[sd->bl.m].flag.noteleport )
return 0;// can't teleport on this map
- pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, 3);
+ pc_setpos(sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, CLR_TELEPORT);
}
else
- pc_setpos(sd, mapindex_name2id(map_name), x, y, 0);
+ pc_setpos(sd, mapindex_name2id(map_name), x, y, CLR_OUTSIGHT);
}
mapreg_setreg(add_str("$@warpwaitingpcnum"), i);
return 0;
@@ -9087,15 +9402,31 @@ BUILDIN_FUNC(warpwaitingpc)
// ...
//
+/// Detaches a character from a script.
+///
+/// @param st Script state to detach the character from.
+static void script_detach_rid(struct script_state* st)
+{
+ if(st->rid)
+ {
+ script_detach_state(st, false);
+ st->rid = 0;
+ }
+}
+
/*==========================================
* RIDのアタッチ
*------------------------------------------*/
BUILDIN_FUNC(attachrid)
{
int rid = script_getnum(st,2);
-
- if (map_id2sd(rid)) {
+ struct map_session_data* sd;
+
+ if ((sd = map_id2sd(rid))!=NULL) {
+ script_detach_rid(st);
+
st->rid = rid;
+ script_attach_state(st);
script_pushint(st,1);
} else
script_pushint(st,0);
@@ -9106,7 +9437,7 @@ BUILDIN_FUNC(attachrid)
*------------------------------------------*/
BUILDIN_FUNC(detachrid)
{
- st->rid=0;
+ script_detach_rid(st);
return 0;
}
/*==========================================
@@ -9495,7 +9826,7 @@ static int buildin_maprespawnguildid_sub_pc(struct map_session_data* sd, va_list
(sd->status.guild_id != g_id && flag&2) || //Warp out outsiders
(sd->status.guild_id == 0) // Warp out players not in guild [Valaris]
)
- pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,3);
+ pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT);
return 1;
}
@@ -9969,7 +10300,7 @@ BUILDIN_FUNC(mapwarp) // Added by RoVeRT
for( i=0; i < g->max_member; i++)
{
if(g->member[i].sd && g->member[i].sd->bl.m==m){
- pc_setpos(g->member[i].sd,index,x,y,3);
+ pc_setpos(g->member[i].sd,index,x,y,CLR_TELEPORT);
}
}
}
@@ -9979,7 +10310,7 @@ BUILDIN_FUNC(mapwarp) // Added by RoVeRT
if(p){
for(i=0;i<MAX_PARTY; i++){
if(p->data[i].sd && p->data[i].sd->bl.m == m){
- pc_setpos(p->data[i].sd,index,x,y,3);
+ pc_setpos(p->data[i].sd,index,x,y,CLR_TELEPORT);
}
}
}
@@ -10142,7 +10473,7 @@ BUILDIN_FUNC(warppartner)
mapindex = mapindex_name2id(str);
if (mapindex) {
- pc_setpos(p_sd,mapindex,x,y,0);
+ pc_setpos(p_sd,mapindex,x,y,CLR_OUTSIGHT);
script_pushint(st,1);
} else
script_pushint(st,0);
@@ -10356,7 +10687,7 @@ BUILDIN_FUNC(getitemslots)
2 type;
3 maxchance = Max drop chance of this item e.g. 1 = 0.01% , etc..
if = 0, then monsters don't drop it at all (rare or a quest item)
- if = 10000, then this item is sold in NPC shops only
+ if = -1, then this item is sold in NPC shops only
4 sex;
5 equip;
6 weight;
@@ -10396,7 +10727,7 @@ BUILDIN_FUNC(getiteminfo)
2 type;
3 maxchance = Max drop chance of this item e.g. 1 = 0.01% , etc..
if = 0, then monsters don't drop it at all (rare or a quest item)
- if = 10000, then this item is sold in NPC shops only
+ if = -1, then this item is sold in NPC shops only
4 sex;
5 equip;
6 weight;
@@ -10545,18 +10876,18 @@ BUILDIN_FUNC(getinventorylist)
if(!sd) return 0;
for(i=0;i<MAX_INVENTORY;i++){
if(sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].amount > 0){
- pc_setreg(sd,add_str("@inventorylist_id")+(j<<24),sd->status.inventory[i].nameid);
- pc_setreg(sd,add_str("@inventorylist_amount")+(j<<24),sd->status.inventory[i].amount);
- pc_setreg(sd,add_str("@inventorylist_equip")+(j<<24),sd->status.inventory[i].equip);
- pc_setreg(sd,add_str("@inventorylist_refine")+(j<<24),sd->status.inventory[i].refine);
- pc_setreg(sd,add_str("@inventorylist_identify")+(j<<24),sd->status.inventory[i].identify);
- pc_setreg(sd,add_str("@inventorylist_attribute")+(j<<24),sd->status.inventory[i].attribute);
+ pc_setreg(sd,reference_uid(add_str("@inventorylist_id"), j),sd->status.inventory[i].nameid);
+ pc_setreg(sd,reference_uid(add_str("@inventorylist_amount"), j),sd->status.inventory[i].amount);
+ pc_setreg(sd,reference_uid(add_str("@inventorylist_equip"), j),sd->status.inventory[i].equip);
+ pc_setreg(sd,reference_uid(add_str("@inventorylist_refine"), j),sd->status.inventory[i].refine);
+ pc_setreg(sd,reference_uid(add_str("@inventorylist_identify"), j),sd->status.inventory[i].identify);
+ pc_setreg(sd,reference_uid(add_str("@inventorylist_attribute"), j),sd->status.inventory[i].attribute);
for (k = 0; k < MAX_SLOTS; k++)
{
sprintf(card_var, "@inventorylist_card%d",k+1);
- pc_setreg(sd,add_str(card_var)+(j<<24),sd->status.inventory[i].card[k]);
+ pc_setreg(sd,reference_uid(add_str(card_var), j),sd->status.inventory[i].card[k]);
}
- pc_setreg(sd,add_str("@inventorylist_expire")+(j<<24),sd->status.inventory[i].expire_time);
+ pc_setreg(sd,reference_uid(add_str("@inventorylist_expire"), j),sd->status.inventory[i].expire_time);
j++;
}
}
@@ -10571,9 +10902,9 @@ BUILDIN_FUNC(getskilllist)
if(!sd) return 0;
for(i=0;i<MAX_SKILL;i++){
if(sd->status.skill[i].id > 0 && sd->status.skill[i].lv > 0){
- pc_setreg(sd,add_str("@skilllist_id")+(j<<24),sd->status.skill[i].id);
- pc_setreg(sd,add_str("@skilllist_lv")+(j<<24),sd->status.skill[i].lv);
- pc_setreg(sd,add_str("@skilllist_flag")+(j<<24),sd->status.skill[i].flag);
+ pc_setreg(sd,reference_uid(add_str("@skilllist_id"), j),sd->status.skill[i].id);
+ pc_setreg(sd,reference_uid(add_str("@skilllist_lv"), j),sd->status.skill[i].lv);
+ pc_setreg(sd,reference_uid(add_str("@skilllist_flag"), j),sd->status.skill[i].flag);
j++;
}
}
@@ -10665,11 +10996,11 @@ BUILDIN_FUNC(misceffect)
if(st->oid && st->oid != fake_nd->bl.id) {
struct block_list *bl = map_id2bl(st->oid);
if (bl)
- clif_misceffect2(bl,type);
+ clif_specialeffect(bl,type,AREA);
} else{
TBL_PC *sd=script_rid2sd(st);
if(sd)
- clif_misceffect2(&sd->bl,type);
+ clif_specialeffect(&sd->bl,type,AREA);
}
return 0;
}
@@ -10678,27 +11009,34 @@ BUILDIN_FUNC(misceffect)
*------------------------------------------*/
BUILDIN_FUNC(playBGM)
{
- TBL_PC* sd = script_rid2sd(st);
- const char* name = script_getstr(st,2);
+ const char* name;
+ struct map_session_data* sd;
- if(sd)
+ if( ( sd = script_rid2sd(st) ) != NULL )
{
- if(!st->rid)
- clif_playBGM(sd,map_id2bl(st->oid),name);
- else
- clif_playBGM(sd,&sd->bl,name);
+ name = script_getstr(st,2);
+
+ clif_playBGM(sd, name);
}
return 0;
}
-int playBGM_sub(struct block_list* bl,va_list ap)
+static int playBGM_sub(struct block_list* bl,va_list ap)
{
- char* name = va_arg(ap,char*);
+ const char* name = va_arg(ap,const char*);
- clif_playBGM((TBL_PC *)bl, bl, name);
+ clif_playBGM(BL_CAST(BL_PC, bl), name);
- return 0;
+ return 0;
+}
+
+static int playBGM_foreachpc_sub(struct map_session_data* sd, va_list args)
+{
+ const char* name = va_arg(args, const char*);
+
+ clif_playBGM(sd, name);
+ return 0;
}
/*==========================================
@@ -10706,33 +11044,29 @@ int playBGM_sub(struct block_list* bl,va_list ap)
*------------------------------------------*/
BUILDIN_FUNC(playBGMall)
{
- struct block_list* bl;
const char* name;
- bl = (st->rid) ? &(script_rid2sd(st)->bl) : map_id2bl(st->oid);
- if (!bl)
- return 0;
-
name = script_getstr(st,2);
- if(script_hasdata(st,7))
- { // specified part of map
+ if( script_hasdata(st,7) )
+ {// specified part of map
const char* map = script_getstr(st,3);
int x0 = script_getnum(st,4);
int y0 = script_getnum(st,5);
int x1 = script_getnum(st,6);
int y1 = script_getnum(st,7);
+
map_foreachinarea(playBGM_sub, map_mapname2mapid(map), x0, y0, x1, y1, BL_PC, name);
}
- else
- if(!script_hasdata(st,7))
- { // entire map
+ else if( script_hasdata(st,3) )
+ {// entire map
const char* map = script_getstr(st,3);
+
map_foreachinmap(playBGM_sub, map_mapname2mapid(map), BL_PC, name);
}
else
- {
- ShowError("buildin_playBGMall: insufficient arguments for specific area broadcast.\n");
+ {// entire server
+ map_foreachpc(&playBGM_foreachpc_sub, name);
}
return 0;
@@ -10749,10 +11083,7 @@ BUILDIN_FUNC(soundeffect)
if(sd)
{
- if(!st->rid)
- clif_soundeffect(sd,map_id2bl(st->oid),name,type);
- else
- clif_soundeffect(sd,&sd->bl,name,type);
+ clif_soundeffect(sd,&sd->bl,name,type);
}
return 0;
}
@@ -11702,7 +12033,7 @@ BUILDIN_FUNC(summon)
delete_timer(md->deletetimer, mob_timer_delete);
md->deletetimer = add_timer(tick+(timeout>0?timeout*1000:60000),mob_timer_delete,md->bl.id,0);
mob_spawn (md); //Now it is ready for spawning.
- clif_misceffect2(&md->bl,344);
+ clif_specialeffect(&md->bl,344,AREA);
sc_start4(&md->bl, SC_MODECHANGE, 100, 1, 0, MD_AGGRESSIVE, 0, 60000);
}
return 0;
@@ -11724,68 +12055,6 @@ BUILDIN_FUNC(isday)
}
/*================================================
- * Check whether another item/card has been
- * equipped - used for 2/15's cards patch [celest]
- *------------------------------------------------*/
-// leave this here, just in case
-#if 0
-BUILDIN_FUNC(isequipped)
-{
- TBL_PC *sd;
- int i, j, k, id = 1;
- int ret = -1;
-
- sd = script_rid2sd(st);
-
- for (i=0; id!=0; i++) {
- int flag = 0;
-
- FETCH (i+2, id) else id = 0;
- if (id <= 0)
- continue;
-
- for (j=0; j<EQI_MAX; j++) {
- int index;
- index = sd->equip_index[j];
- if(index < 0) continue;
- if(j == EQI_HAND_R && sd->equip_index[EQI_HAND_L] == index) continue;
- if(j == EQI_HEAD_MID && sd->equip_index[EQI_HEAD_LOW] == index) continue;
- if(j == EQI_HEAD_TOP && (sd->equip_index[EQI_HEAD_MID] == index || sd->equip_index[EQI_HEAD_LOW] == index)) continue;
-
- if(!sd->inventory_data[index])
- continue;
-
- if(itemdb_type(id) != IT_CARD) { //Non card
- if (sd->inventory_data[index]->nameid != id)
- continue;
- flag = 1;
- break;
- } else { //Card
- if (itemdb_isspecial(sd->status.inventory[index].card[0]))
- continue;
- for(k=0; k<sd->inventory_data[index]->slot; k++) {
- if (sd->status.inventory[index].card[k] == id)
- {
- flag = 1;
- break;
- }
- }
- }
- if (flag) break;
- }
- if (ret == -1)
- ret = flag;
- else
- ret &= flag;
- if (!ret) break;
- }
-
- script_pushint(st,ret);
- return 0;
-}
-#endif
-
-/*================================================
* Check how many items/cards in the list are
* equipped - used for 2/15's cards patch [celest]
*------------------------------------------------*/
@@ -12051,7 +12320,7 @@ BUILDIN_FUNC(setbattleflag)
const char *flag, *value;
flag = script_getstr(st,2);
- value = script_getstr(st,3);
+ value = script_getstr(st,3); // HACK: Retrieve number as string (auto-converted) for battle_set_value
if (battle_set_value(flag, value) == 0)
ShowWarning("buildin_setbattleflag: unknown battle_config flag '%s'\n",flag);
@@ -12142,7 +12411,7 @@ BUILDIN_FUNC(setnpcdisplay)
if( newname )
npc_setdisplayname(nd, newname);
- if( size != -1 && size != nd->size )
+ if( size != -1 && size != (int)nd->size )
nd->size = size;
else
size = -1;
@@ -12151,7 +12420,7 @@ BUILDIN_FUNC(setnpcdisplay)
npc_setclass(nd, class_);
else if( size != -1 )
{ // Required to update the visual size
- clif_clearunit_area(&nd->bl, 0);
+ clif_clearunit_area(&nd->bl, CLR_OUTSIGHT);
clif_spawn(&nd->bl);
}
@@ -12231,10 +12500,9 @@ BUILDIN_FUNC(setd)
{
TBL_PC *sd=NULL;
char varname[100];
- const char *value, *buffer;
+ const char *buffer;
int elem;
buffer = script_getstr(st, 2);
- value = script_getstr(st, 3);
if(sscanf(buffer, "%99[^[][%d]", varname, &elem) < 2)
elem = 0;
@@ -12249,10 +12517,10 @@ BUILDIN_FUNC(setd)
}
}
- if(varname[strlen(varname)-1] != '$') {
- setd_sub(st,sd, varname, elem, (void *)atoi(value),NULL);
+ if( is_string_variable(varname) ) {
+ setd_sub(st, sd, varname, elem, (void *)script_getstr(st, 3), NULL);
} else {
- setd_sub(st,sd, varname, elem, (void *)value,NULL);
+ setd_sub(st, sd, varname, elem, (void *)script_getnum(st, 3), NULL);
}
return 0;
@@ -12266,7 +12534,7 @@ int buildin_query_sql_sub(struct script_state* st, Sql* handle)
const char* query;
struct script_data* data;
const char* name;
- int max_rows = 128;// maximum number of rows
+ int max_rows = SCRIPT_MAX_ARRAYSIZE;// maximum number of rows
int num_vars;
int num_cols;
@@ -12413,7 +12681,7 @@ BUILDIN_FUNC(getd)
elem = 0;
// Push the 'pointer' so it's more flexible [Lance]
- push_val(st->stack, C_NAME, (elem<<24) | add_str(varname));
+ push_val(st->stack, C_NAME, reference_uid(add_str(varname), elem));
return 0;
}
@@ -12548,6 +12816,7 @@ BUILDIN_FUNC(npcshopdelitem)
{
const char* npcname = script_getstr(st,2);
struct npc_data* nd = npc_name2id(npcname);
+ unsigned int nameid;
int n, i;
int amount;
int size;
@@ -12564,7 +12833,9 @@ BUILDIN_FUNC(npcshopdelitem)
// remove specified items from the shop item list
for( i = 3; i < 3 + amount; i++ )
{
- ARR_FIND( 0, size, n, nd->u.shop.shop_item[n].nameid == script_getnum(st,i) );
+ nameid = script_getnum(st,i);
+
+ ARR_FIND( 0, size, n, nd->u.shop.shop_item[n].nameid == nameid );
if( n < size )
{
memmove(&nd->u.shop.shop_item[n], &nd->u.shop.shop_item[n+1], sizeof(nd->u.shop.shop_item[0])*(size-n));
@@ -13016,7 +13287,7 @@ BUILDIN_FUNC(unitwarp)
bl = map_id2bl(unit_id);
if( map >= 0 && bl != NULL )
- script_pushint(st, unit_warp(bl,map,x,y,0));
+ script_pushint(st, unit_warp(bl,map,x,y,CLR_OUTSIGHT));
else
script_pushint(st, 0);
@@ -13212,17 +13483,11 @@ BUILDIN_FUNC(unitskillusepos)
BUILDIN_FUNC(sleep)
{
int ticks;
- TBL_PC* sd;
ticks = script_getnum(st,2);
- sd = map_id2sd(st->rid);
// detach the player
- if( sd && sd->npc_id == st->oid )
- {
- sd->npc_id = 0;
- }
- st->rid = 0;
+ script_detach_rid(st);
if( ticks <= 0 )
{// do nothing
@@ -13779,9 +14044,9 @@ BUILDIN_FUNC(waitingroom2bg)
for( i = 0; i < n && i < MAX_BG_MEMBERS; i++ )
{
if( (sd = cd->usersd[i]) != NULL && bg_team_join(bg_id, sd) )
- mapreg_setreg(add_str("$@arenamembers") + (i<<24), sd->bl.id);
+ mapreg_setreg(reference_uid(add_str("$@arenamembers"), i), sd->bl.id);
else
- mapreg_setreg(add_str("$@arenamembers") + (i<<24), 0);
+ mapreg_setreg(reference_uid(add_str("$@arenamembers"), i), 0);
}
mapreg_setreg(add_str("$@arenamembersnum"), i);
@@ -13814,7 +14079,7 @@ BUILDIN_FUNC(waitingroom2bg_single)
if( bg_team_join(bg_id, sd) )
{
- pc_setpos(sd, mapindex, x, y, 3);
+ pc_setpos(sd, mapindex, x, y, CLR_TELEPORT);
script_pushint(st,1);
}
else
@@ -14283,7 +14548,7 @@ BUILDIN_FUNC(instance_warpall)
mapindex = map_id2index(m);
for( i = 0; i < MAX_PARTY; i++ )
- if( (pl_sd = p->data[i].sd) && map[pl_sd->bl.m].instance_id == st->instance_id ) pc_setpos(pl_sd,mapindex,x,y,3);
+ if( (pl_sd = p->data[i].sd) && map[pl_sd->bl.m].instance_id == st->instance_id ) pc_setpos(pl_sd,mapindex,x,y,CLR_TELEPORT);
return 0;
}
@@ -14451,7 +14716,8 @@ BUILDIN_FUNC(deactivatepset);
BUILDIN_FUNC(deletepset);
#endif
-
+/// script command definitions
+/// for an explanation on args, see add_buildin_func
struct script_function buildin_func[] = {
// NPC interaction
BUILDIN_DEF(mes,"s"),
@@ -14463,21 +14729,21 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(prompt,"s*"),
//
BUILDIN_DEF(goto,"l"),
- BUILDIN_DEF(callsub,"i*"),
+ BUILDIN_DEF(callsub,"l*"),
BUILDIN_DEF(callfunc,"s*"),
BUILDIN_DEF(return,"?"),
BUILDIN_DEF(getarg,"i?"),
- BUILDIN_DEF(jobchange,"i*"),
+ BUILDIN_DEF(jobchange,"i?"),
BUILDIN_DEF(jobname,"i"),
- BUILDIN_DEF(input,"v??"),
+ BUILDIN_DEF(input,"r??"),
BUILDIN_DEF(warp,"sii"),
BUILDIN_DEF(areawarp,"siiiisii"),
BUILDIN_DEF(warpchar,"siii"), // [LuzZza]
- BUILDIN_DEF(warpparty,"siii*"), // [Fredzilla] [Paradox924X]
+ BUILDIN_DEF(warpparty,"siii?"), // [Fredzilla] [Paradox924X]
BUILDIN_DEF(warpguild,"siii"), // [Fredzilla]
BUILDIN_DEF(setlook,"ii"),
BUILDIN_DEF(changelook,"ii"), // Simulates but don't Store it
- BUILDIN_DEF(set,"ii"),
+ BUILDIN_DEF(set,"rv"),
BUILDIN_DEF(setarray,"rv*"),
BUILDIN_DEF(cleararray,"rvi"),
BUILDIN_DEF(copyarray,"rri"),
@@ -14486,12 +14752,12 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(getelementofarray,"ri"),
BUILDIN_DEF(getitem,"vi?"),
BUILDIN_DEF(rentitem,"vi"),
- BUILDIN_DEF(getitem2,"iiiiiiiii*"),
- BUILDIN_DEF(getnameditem,"is"),
+ BUILDIN_DEF(getitem2,"viiiiiiii?"),
+ BUILDIN_DEF(getnameditem,"vv"),
BUILDIN_DEF2(grouprandomitem,"groupranditem","i"),
- BUILDIN_DEF(makeitem,"iisii"),
- BUILDIN_DEF(delitem,"ii?"),
- BUILDIN_DEF(delitem2,"iiiiiiiii?"),
+ BUILDIN_DEF(makeitem,"visii"),
+ BUILDIN_DEF(delitem,"vi?"),
+ BUILDIN_DEF(delitem2,"viiiiiiii?"),
BUILDIN_DEF2(enableitemuse,"enable_items",""),
BUILDIN_DEF2(disableitemuse,"disable_items",""),
BUILDIN_DEF(cutin,"si"),
@@ -14500,13 +14766,13 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(itemheal,"ii"),
BUILDIN_DEF(percentheal,"ii"),
BUILDIN_DEF(rand,"i?"),
- BUILDIN_DEF(countitem,"i"),
- BUILDIN_DEF(countitem2,"iiiiiiii"),
- BUILDIN_DEF(checkweight,"ii"),
- BUILDIN_DEF(readparam,"i*"),
- BUILDIN_DEF(getcharid,"i*"),
+ BUILDIN_DEF(countitem,"v"),
+ BUILDIN_DEF(countitem2,"viiiiiii"),
+ BUILDIN_DEF(checkweight,"vi"),
+ BUILDIN_DEF(readparam,"i?"),
+ BUILDIN_DEF(getcharid,"i?"),
BUILDIN_DEF(getpartyname,"i"),
- BUILDIN_DEF(getpartymember,"i*"),
+ BUILDIN_DEF(getpartymember,"i?"),
BUILDIN_DEF(getpartyleader,"i?"),
BUILDIN_DEF(getguildname,"i"),
BUILDIN_DEF(getguildmaster,"i"),
@@ -14557,16 +14823,16 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(gettime,"i"),
BUILDIN_DEF(gettimestr,"si"),
BUILDIN_DEF(openstorage,""),
- BUILDIN_DEF(guildopenstorage,"*"),
+ BUILDIN_DEF(guildopenstorage,""),
BUILDIN_DEF(itemskill,"vi"),
BUILDIN_DEF(produce,"i"),
BUILDIN_DEF(cooking,"i"),
- BUILDIN_DEF(monster,"siisii*"),
+ BUILDIN_DEF(monster,"siisii?"),
BUILDIN_DEF(getmobdrops,"i"),
- BUILDIN_DEF(areamonster,"siiiisii*"),
+ BUILDIN_DEF(areamonster,"siiiisii?"),
BUILDIN_DEF(killmonster,"ss?"),
BUILDIN_DEF(killmonsterall,"s?"),
- BUILDIN_DEF(clone,"siisi*"),
+ BUILDIN_DEF(clone,"siisi????"),
BUILDIN_DEF(doevent,"s"),
BUILDIN_DEF(donpcevent,"s"),
BUILDIN_DEF(cmdothernpc,"ss"),
@@ -14581,14 +14847,14 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(attachnpctimer,"?"), // attached the player id to the npc timer [Celest]
BUILDIN_DEF(detachnpctimer,"?"), // detached the player id from the npc timer [Celest]
BUILDIN_DEF(playerattached,""), // returns id of the current attached player. [Skotlex]
- BUILDIN_DEF(announce,"si*"),
- BUILDIN_DEF(mapannounce,"ssi*"),
- BUILDIN_DEF(areaannounce,"siiiisi*"),
+ BUILDIN_DEF(announce,"si?????"),
+ BUILDIN_DEF(mapannounce,"ssi?????"),
+ BUILDIN_DEF(areaannounce,"siiiisi?????"),
BUILDIN_DEF(getusers,"i"),
BUILDIN_DEF(getmapguildusers,"si"),
BUILDIN_DEF(getmapusers,"s"),
BUILDIN_DEF(getareausers,"siiii"),
- BUILDIN_DEF(getareadropitem,"siiiii"),
+ BUILDIN_DEF(getareadropitem,"siiiiv"),
BUILDIN_DEF(enablenpc,"s"),
BUILDIN_DEF(disablenpc,"s"),
BUILDIN_DEF(hideoffnpc,"s"),
@@ -14597,7 +14863,7 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(sc_start2,"iiii?"),
BUILDIN_DEF(sc_start4,"iiiiii?"),
BUILDIN_DEF(sc_end,"i?"),
- BUILDIN_DEF(getscrate,"ii*"),
+ BUILDIN_DEF(getscrate,"ii?"),
BUILDIN_DEF(debugmes,"s"),
BUILDIN_DEF2(catchpet,"pet","i"),
BUILDIN_DEF2(birthpet,"bpet",""),
@@ -14605,7 +14871,7 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(resetstatus,""),
BUILDIN_DEF(resetskill,""),
BUILDIN_DEF(skillpointcount,""),
- BUILDIN_DEF(changebase,"i"),
+ BUILDIN_DEF(changebase,"i?"),
BUILDIN_DEF(changesex,""),
BUILDIN_DEF(waitingroom,"si??"),
BUILDIN_DEF(delwaitingroom,"?"),
@@ -14621,22 +14887,22 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(isloggedin,"i?"),
BUILDIN_DEF(setmapflagnosave,"ssii"),
BUILDIN_DEF(getmapflag,"si"),
- BUILDIN_DEF(setmapflag,"si*"),
+ BUILDIN_DEF(setmapflag,"si?"),
BUILDIN_DEF(removemapflag,"si"),
BUILDIN_DEF(pvpon,"s"),
BUILDIN_DEF(pvpoff,"s"),
BUILDIN_DEF(gvgon,"s"),
BUILDIN_DEF(gvgoff,"s"),
- BUILDIN_DEF(emotion,"i*"),
+ BUILDIN_DEF(emotion,"i??"),
BUILDIN_DEF(maprespawnguildid,"sii"),
BUILDIN_DEF(agitstart,""), // <Agit>
BUILDIN_DEF(agitend,""),
BUILDIN_DEF(agitcheck,""), // <Agitcheck>
BUILDIN_DEF(flagemblem,"i"), // Flag Emblem
BUILDIN_DEF(getcastlename,"s"),
- BUILDIN_DEF(getcastledata,"si*"),
+ BUILDIN_DEF(getcastledata,"si?"),
BUILDIN_DEF(setcastledata,"sii"),
- BUILDIN_DEF(requestguildinfo,"i*"),
+ BUILDIN_DEF(requestguildinfo,"i?"),
BUILDIN_DEF(getequipcardcnt,"i"),
BUILDIN_DEF(successremovecards,"i"),
BUILDIN_DEF(failedremovecards,"ii"),
@@ -14649,7 +14915,7 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(getmotherid,""),
BUILDIN_DEF(getfatherid,""),
BUILDIN_DEF(warppartner,"sii"),
- BUILDIN_DEF(getitemname,"i"),
+ BUILDIN_DEF(getitemname,"v"),
BUILDIN_DEF(getitemslots,"i"),
BUILDIN_DEF(makepet,"i"),
BUILDIN_DEF(getexp,"ii"),
@@ -14659,9 +14925,9 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(classchange,"ii"),
BUILDIN_DEF(misceffect,"i"),
BUILDIN_DEF(playBGM,"s"),
- BUILDIN_DEF(playBGMall,"s*"),
+ BUILDIN_DEF(playBGMall,"s?????"),
BUILDIN_DEF(soundeffect,"si"),
- BUILDIN_DEF(soundeffectall,"si*"), // SoundEffectAll [Codemaster]
+ BUILDIN_DEF(soundeffectall,"si?????"), // SoundEffectAll [Codemaster]
BUILDIN_DEF(strmobinfo,"ii"), // display mob data [Valaris]
BUILDIN_DEF(guardian,"siisi??"), // summon guardians
BUILDIN_DEF(guardianinfo,"sii"), // display guardian data [Valaris]
@@ -14674,34 +14940,34 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(petskillsupport,"viiii"), // [Skotlex]
BUILDIN_DEF(skilleffect,"vi"), // skill effect [Celest]
BUILDIN_DEF(npcskilleffect,"viii"), // npc skill effect [Valaris]
- BUILDIN_DEF(specialeffect,"i*"), // npc skill effect [Valaris]
- BUILDIN_DEF(specialeffect2,"i*"), // skill effect on players[Valaris]
+ BUILDIN_DEF(specialeffect,"i??"), // npc skill effect [Valaris]
+ BUILDIN_DEF(specialeffect2,"i??"), // skill effect on players[Valaris]
BUILDIN_DEF(nude,""), // nude command [Valaris]
- BUILDIN_DEF(mapwarp,"ssii*"), // Added by RoVeRT
- BUILDIN_DEF(atcommand,"*"), // [MouseJstr]
- BUILDIN_DEF(charcommand,"*"), // [MouseJstr]
+ BUILDIN_DEF(mapwarp,"ssii??"), // Added by RoVeRT
+ BUILDIN_DEF(atcommand,"s"), // [MouseJstr]
+ BUILDIN_DEF(charcommand,"s"), // [MouseJstr]
BUILDIN_DEF(movenpc,"sii"), // [MouseJstr]
- BUILDIN_DEF(message,"s*"), // [MouseJstr]
- BUILDIN_DEF(npctalk,"*"), // [Valaris]
+ BUILDIN_DEF(message,"ss"), // [MouseJstr]
+ BUILDIN_DEF(npctalk,"s"), // [Valaris]
BUILDIN_DEF(mobcount,"ss"),
BUILDIN_DEF(getlook,"i"),
BUILDIN_DEF(getsavepoint,"i"),
BUILDIN_DEF(npcspeed,"i"), // [Valaris]
BUILDIN_DEF(npcwalkto,"ii"), // [Valaris]
BUILDIN_DEF(npcstop,""), // [Valaris]
- BUILDIN_DEF(getmapxy,"siii*"), //by Lorky [Lupus]
+ BUILDIN_DEF(getmapxy,"rrri?"), //by Lorky [Lupus]
BUILDIN_DEF(checkoption1,"i"),
BUILDIN_DEF(checkoption2,"i"),
BUILDIN_DEF(guildgetexp,"i"),
BUILDIN_DEF(guildchangegm,"is"),
BUILDIN_DEF(logmes,"s"), //this command actls as MES but rints info into LOG file either SQL/TXT [Lupus]
- BUILDIN_DEF(summon,"si*"), // summons a slave monster [Celest]
+ BUILDIN_DEF(summon,"si??"), // summons a slave monster [Celest]
BUILDIN_DEF(isnight,""), // check whether it is night time [Celest]
BUILDIN_DEF(isday,""), // check whether it is day time [Celest]
BUILDIN_DEF(isequipped,"i*"), // check whether another item/card has been equipped [Celest]
BUILDIN_DEF(isequippedcnt,"i*"), // check how many items/cards are being equipped [Celest]
BUILDIN_DEF(cardscnt,"i*"), // check how many items/cards are being equipped in the same arm [Lupus]
- BUILDIN_DEF(getrefine,"*"), // returns the refined number of the current item, or an item with index specified [celest]
+ BUILDIN_DEF(getrefine,""), // returns the refined number of the current item, or an item with index specified [celest]
BUILDIN_DEF(night,""), // sets the server to night time
BUILDIN_DEF(day,""), // sets the server to day time
#ifdef PCRE_SUPPORT
@@ -14711,13 +14977,13 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(deletepset,"i"), // Delete a pattern set [MouseJstr]
#endif
BUILDIN_DEF(dispbottom,"s"), //added from jA [Lupus]
- BUILDIN_DEF(getusersname,"*"),
+ BUILDIN_DEF(getusersname,""),
BUILDIN_DEF(recovery,""),
BUILDIN_DEF(getpetinfo,"i"),
BUILDIN_DEF(gethominfo,"i"),
BUILDIN_DEF(checkequipedcard,"i"),
- BUILDIN_DEF(jump_zero,"ii"), //for future jA script compatibility
- BUILDIN_DEF(globalmes,"s*"),
+ BUILDIN_DEF(jump_zero,"il"), //for future jA script compatibility
+ BUILDIN_DEF(globalmes,"s?"),
BUILDIN_DEF(getmapmobs,"s"), //end jA addition
BUILDIN_DEF(unequip,"i"), // unequip command [Spectre]
BUILDIN_DEF(getstrlen,"s"), //strlen [Valaris]
@@ -14734,22 +15000,22 @@ struct script_function buildin_func[] = {
// <--- [zBuffer] List of mathematics commands
BUILDIN_DEF(md5,"s"),
// [zBuffer] List of dynamic var commands --->
- BUILDIN_DEF(getd,"*"),
- BUILDIN_DEF(setd,"*"),
+ BUILDIN_DEF(getd,"s"),
+ BUILDIN_DEF(setd,"sv"),
// <--- [zBuffer] List of dynamic var commands
BUILDIN_DEF(petstat,"i"),
- BUILDIN_DEF(callshop,"si"), // [Skotlex]
+ BUILDIN_DEF(callshop,"s?"), // [Skotlex]
BUILDIN_DEF(npcshopitem,"sii*"), // [Lance]
BUILDIN_DEF(npcshopadditem,"sii*"),
BUILDIN_DEF(npcshopdelitem,"si*"),
BUILDIN_DEF(npcshopattach,"s?"),
BUILDIN_DEF(equip,"i"),
BUILDIN_DEF(autoequip,"ii"),
- BUILDIN_DEF(setbattleflag,"ss"),
+ BUILDIN_DEF(setbattleflag,"si"),
BUILDIN_DEF(getbattleflag,"s"),
- BUILDIN_DEF(setitemscript,"is*"), //Set NEW item bonus script. Lupus
+ BUILDIN_DEF(setitemscript,"is?"), //Set NEW item bonus script. Lupus
BUILDIN_DEF(disguise,"i"), //disguise player. Lupus
- BUILDIN_DEF(undisguise,"*"), //undisguise player. Lupus
+ BUILDIN_DEF(undisguise,""), //undisguise player. Lupus
BUILDIN_DEF(getmonsterinfo,"ii"), //Lupus
BUILDIN_DEF(axtoi,"s"),
BUILDIN_DEF(query_sql,"s*"),
@@ -14780,10 +15046,10 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(warpportal,"iisii"),
BUILDIN_DEF2(homunculus_evolution,"homevolution",""), //[orn]
BUILDIN_DEF2(homunculus_shuffle,"homshuffle",""), //[Zephyrus]
- BUILDIN_DEF(eaclass,"*"), //[Skotlex]
- BUILDIN_DEF(roclass,"i*"), //[Skotlex]
- BUILDIN_DEF(checkvending,"*"),
- BUILDIN_DEF(checkchatting,"*"),
+ BUILDIN_DEF(eaclass,"?"), //[Skotlex]
+ BUILDIN_DEF(roclass,"i?"), //[Skotlex]
+ BUILDIN_DEF(checkvending,"?"),
+ BUILDIN_DEF(checkchatting,"?"),
BUILDIN_DEF(openmail,""),
BUILDIN_DEF(openauction,""),
BUILDIN_DEF(checkcell,"siii"),
@@ -14801,7 +15067,7 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(readbook,"ii"),
BUILDIN_DEF(setfont,"i"),
BUILDIN_DEF(areamobuseskill,"siiiiviiiii"),
- BUILDIN_DEF(progressbar, "si"),
+ BUILDIN_DEF(progressbar,"si"),
BUILDIN_DEF(pushpc,"ii"),
// WoE SE
BUILDIN_DEF(agitstart2,""),
@@ -14812,7 +15078,7 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(waitingroom2bg_single,"isiis"),
BUILDIN_DEF(bg_team_setxy,"iii"),
BUILDIN_DEF(bg_warp,"isii"),
- BUILDIN_DEF(bg_monster,"isiisi*"),
+ BUILDIN_DEF(bg_monster,"isiisi?"),
BUILDIN_DEF(bg_monster_set_team,"ii"),
BUILDIN_DEF(bg_leave,""),
BUILDIN_DEF(bg_destroy,"i"),
@@ -14830,7 +15096,7 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(instance_id,"?"),
BUILDIN_DEF(instance_set_timeout,"ii?"),
BUILDIN_DEF(instance_init,"i"),
- BUILDIN_DEF(instance_announce,"isi*"),
+ BUILDIN_DEF(instance_announce,"isi?????"),
BUILDIN_DEF(instance_npcname,"s?"),
BUILDIN_DEF(has_instance,"s?"),
BUILDIN_DEF(instance_warpall,"sii?"),
@@ -14839,7 +15105,7 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(setquest, "i"),
BUILDIN_DEF(erasequest, "i"),
BUILDIN_DEF(completequest, "i"),
- BUILDIN_DEF(checkquest, "i*"),
+ BUILDIN_DEF(checkquest, "i?"),
BUILDIN_DEF(changequest, "ii"),
BUILDIN_DEF(showevent, "ii"),
{NULL,NULL,NULL},
diff --git a/src/map/script.h b/src/map/script.h
index aa6b85140..d6ede0e8b 100644
--- a/src/map/script.h
+++ b/src/map/script.h
@@ -11,6 +11,7 @@ extern int potion_hp, potion_per_hp, potion_sp, potion_per_sp;
extern int potion_target;
extern struct Script_Config {
+ unsigned warn_func_mismatch_argtypes : 1;
unsigned warn_func_mismatch_paramnum : 1;
int check_cmdcount;
int check_gotocount;
@@ -121,6 +122,9 @@ struct script_state {
int tick,timer,charid;
} sleep;
int instance_id;
+ //For backing up purposes
+ struct script_state *bk_st;
+ int bk_npcid;
};
struct script_reg {
@@ -163,6 +167,9 @@ struct DBMap* script_get_label_db(void);
struct DBMap* script_get_userfunc_db(void);
void script_run_autobonus(const char *autobonus,int id, int pos);
+void script_cleararray_pc(struct map_session_data* sd, const char* varname, void* value);
+void script_setarray_pc(struct map_session_data* sd, const char* varname, uint8 idx, void* value, int* refcache);
+
int script_config_read(char *cfgName);
int do_init_script(void);
int do_final_script(void);
diff --git a/src/map/skill.c b/src/map/skill.c
index ccc3d96f9..3c4cbcd21 100644
--- a/src/map/skill.c
+++ b/src/map/skill.c
@@ -180,9 +180,7 @@ int skill_tree_get_max(int id, int b_class)
return skill_get_max(id);
}
-int skill_castend_damage_id( struct block_list* src, struct block_list *bl,int skillid,int skilllv,unsigned int tick,int flag );
int skill_frostjoke_scream(struct block_list *bl,va_list ap);
-int status_change_timer_sub(struct block_list *bl, va_list ap);
int skill_attack_area(struct block_list *bl,va_list ap);
struct skill_unit_group *skill_locate_element_field(struct block_list *bl); // [Skotlex]
int skill_graffitiremover(struct block_list *bl, va_list ap); // [Valaris]
@@ -734,7 +732,7 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, int
case AM_ACIDTERROR:
sc_start(bl,SC_BLEEDING,(skilllv*3),skilllv,skill_get_time2(skillid,skilllv));
if (skill_break_equip(bl, EQP_ARMOR, 100*skill_get_time(skillid,skilllv), BCT_ENEMY))
- clif_emotion(bl,23);
+ clif_emotion(bl,E_OMG);
break;
case AM_DEMONSTRATION:
@@ -1093,11 +1091,14 @@ int skill_onskillusage(struct map_session_data *sd, struct block_list *bl, int s
if( sd == NULL || skillid <= 0 )
return 0;
- sd->state.skillonskill = 1;
for( i = 0; i < ARRAYLENGTH(sd->autospell3) && sd->autospell3[i].flag; i++ )
{
if( sd->autospell3[i].flag != skillid )
continue;
+
+ if( sd->autospell3[i].lock )
+ continue; // autospell already being executed
+
skill = (sd->autospell3[i].id > 0) ? sd->autospell3[i].id : -sd->autospell3[i].id;
if( skillnotok(skill, sd) )
continue;
@@ -1115,6 +1116,7 @@ int skill_onskillusage(struct map_session_data *sd, struct block_list *bl, int s
continue;
sd->state.autocast = 1;
+ sd->autospell3[i].lock = true;
skill_consume_requirement(sd,skill,skilllv,1);
switch( skill_get_casttype(skill) )
{
@@ -1122,6 +1124,7 @@ int skill_onskillusage(struct map_session_data *sd, struct block_list *bl, int s
case CAST_NODAMAGE: skill_castend_nodamage_id(&sd->bl, tbl, skill, skilllv, tick, 0); break;
case CAST_DAMAGE: skill_castend_damage_id(&sd->bl, tbl, skill, skilllv, tick, 0); break;
}
+ sd->autospell3[i].lock = false;
sd->state.autocast = 0;
}
@@ -1139,7 +1142,6 @@ int skill_onskillusage(struct map_session_data *sd, struct block_list *bl, int s
}
}
- sd->state.skillonskill = 0;
return 1;
}
@@ -2307,11 +2309,11 @@ static int skill_timerskill(int tid, unsigned int tick, int id, intptr data)
switch(skl->skill_id) {
case RG_INTIMIDATE:
- if (unit_warp(src,-1,-1,-1,3) == 0) {
+ if (unit_warp(src,-1,-1,-1,CLR_TELEPORT) == 0) {
short x,y;
map_search_freecell(src, 0, &x, &y, 1, 1, 0);
if (target != src && !status_isdead(target))
- unit_warp(target, -1, x, y, 3);
+ unit_warp(target, -1, x, y, CLR_TELEPORT);
}
break;
case BA_FROSTJOKER:
@@ -3002,7 +3004,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int
break;
case NPC_DARKBREATH:
- clif_emotion(src,7);
+ clif_emotion(src,E_AG);
case SN_FALCONASSAULT:
case PA_PRESSURE:
case CR_ACIDDEMONSTRATION:
@@ -3098,8 +3100,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int
{
if( sd->state.arrow_atk ) //Consume arrow on last invocation to this skill.
battle_consume_ammo(sd, skillid, skilllv);
- if( !sd->state.skillonskill )
- skill_onskillusage(sd, bl, skillid, tick);
+ skill_onskillusage(sd, bl, skillid, tick);
skill_consume_requirement(sd,skillid,skilllv,2);
}
@@ -4418,9 +4419,9 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
if( sd->state.autocast || ( (sd->skillitem == AL_TELEPORT || battle_config.skip_teleport_lv1_menu) && skilllv == 1 ) || skilllv == 3 )
{
if( skilllv == 1 )
- pc_randomwarp(sd,3);
+ pc_randomwarp(sd,CLR_TELEPORT);
else
- pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,3);
+ pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT);
break;
}
@@ -4430,12 +4431,12 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
else
clif_skill_warppoint(sd,skillid,skilllv, (unsigned short)-1,sd->status.save_point.map,0,0);
} else
- unit_warp(bl,-1,-1,-1,3);
+ unit_warp(bl,-1,-1,-1,CLR_TELEPORT);
break;
case NPC_EXPULSION:
clif_skill_nodamage(src,bl,skillid,skilllv,1);
- unit_warp(bl,-1,-1,-1,3);
+ unit_warp(bl,-1,-1,-1,CLR_TELEPORT);
break;
case AL_HOLYWATER:
@@ -5360,7 +5361,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
case 5: // 2000HP heal, random teleported
status_heal(src, 2000, 0, 0);
if( !map_flag_vs(bl->m) )
- unit_warp(bl, -1,-1,-1, 3);
+ unit_warp(bl, -1,-1,-1, CLR_TELEPORT);
break;
case 6: // random 2 other effects
if (count == -1)
@@ -5435,7 +5436,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
{ //Erase death count 1% of the casts
dstsd->die_counter = 0;
pc_setglobalreg(dstsd,"PC_DIE_COUNTER", 0);
- clif_misceffect2(bl, 0x152);
+ clif_specialeffect(bl, 0x152, AREA);
//SC_SPIRIT invokes status_calc_pc for us.
}
clif_skill_nodamage(src,bl,skillid,skilllv,
@@ -5530,7 +5531,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
continue;
if(map_getcell(src->m,src->x+dx[j],src->y+dy[j],CELL_CHKNOREACH))
dx[j] = dy[j] = 0;
- pc_setpos(dstsd, map_id2index(src->m), src->x+dx[j], src->y+dy[j], 2);
+ pc_setpos(dstsd, map_id2index(src->m), src->x+dx[j], src->y+dy[j], CLR_RESPAWN);
}
}
if (sd)
@@ -5720,8 +5721,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
{
if( sd->state.arrow_atk ) //Consume arrow on last invocation to this skill.
battle_consume_ammo(sd, skillid, skilllv);
- if( !sd->state.skillonskill )
- skill_onskillusage(sd, bl, skillid, tick);
+ skill_onskillusage(sd, bl, skillid, tick);
skill_consume_requirement(sd,skillid,skilllv,2);
}
@@ -6585,8 +6585,7 @@ int skill_castend_pos2(struct block_list* src, int x, int y, int skillid, int sk
{
if( sd->state.arrow_atk && !(flag&1) ) //Consume arrow if a ground skill was not invoked. [Skotlex]
battle_consume_ammo(sd, skillid, skilllv);
- if( !sd->state.skillonskill )
- skill_onskillusage(sd, NULL, skillid, tick);
+ skill_onskillusage(sd, NULL, skillid, tick);
skill_consume_requirement(sd,skillid,skilllv,2);
}
@@ -6643,9 +6642,9 @@ int skill_castend_map (struct map_session_data *sd, short skill_num, const char
{
case AL_TELEPORT:
if(strcmp(map,"Random")==0)
- pc_randomwarp(sd,3);
+ pc_randomwarp(sd,CLR_TELEPORT);
else if (sd->menuskill_val > 1) //Need lv2 to be able to warp here.
- pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,3);
+ pc_setpos(sd,sd->status.save_point.map,sd->status.save_point.x,sd->status.save_point.y,CLR_TELEPORT);
break;
case AL_WARP:
@@ -7259,7 +7258,7 @@ static int skill_unit_onplace (struct skill_unit *src, struct block_list *bl, un
if( --sg->val1 <= 0 )
skill_delunitgroup(sg);
- pc_setpos(sd,m,x,y,3);
+ pc_setpos(sd,m,x,y,CLR_TELEPORT);
sg = src->group; // avoid dangling pointer (pc_setpos can cause deletion of 'sg')
}
} else
@@ -7267,7 +7266,7 @@ static int skill_unit_onplace (struct skill_unit *src, struct block_list *bl, un
{
int m = map_mapindex2mapid(sg->val3);
if (m < 0) break; //Map not available on this map-server.
- unit_warp(bl,m,sg->val2>>16,sg->val2&0xffff,3);
+ unit_warp(bl,m,sg->val2>>16,sg->val2&0xffff,CLR_TELEPORT);
}
break;
@@ -7569,7 +7568,7 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns
}
else
sec = 3000; //Couldn't trap it?
- clif_01ac(&src->bl); // mysterious packet
+ clif_skillunit_update(&src->bl);
sg->limit = DIFF_TICK(tick,sg->tick)+sec;
sg->interval = -1;
src->range = 0;
@@ -9307,7 +9306,7 @@ void skill_repairweapon (struct map_session_data *sd, int idx)
return;
}
- if (itemdb_type(item->nameid)==4)
+ if (itemdb_type(item->nameid)==IT_WEAPON)
material = materials [itemdb_wlv(item->nameid)-1]; // Lv1/2/3/4 weapons consume 1 Iron Ore/Iron/Steel/Rough Oridecon
else
material = materials [2]; // Armors consume 1 Steel
@@ -9358,7 +9357,7 @@ void skill_weaponrefine (struct map_session_data *sd, int idx)
struct item_data *ditem = sd->inventory_data[idx];
item = &sd->status.inventory[idx];
- if(item->nameid > 0 && ditem->type == 4)
+ if(item->nameid > 0 && ditem->type == IT_WEAPON)
{
if( item->refine >= sd->menuskill_val
|| item->refine >= MAX_REFINE // if it's no longer refineable
@@ -9408,7 +9407,7 @@ void skill_weaponrefine (struct map_session_data *sd, int idx)
clif_refine(sd->fd,1,idx,item->refine);
pc_delitem(sd,idx,1,0,2);
clif_misceffect(&sd->bl,2);
- clif_emotion(&sd->bl, 23);
+ clif_emotion(&sd->bl, E_OMG);
}
}
}
@@ -10162,13 +10161,17 @@ struct skill_unit_group* skill_initunitgroup (struct block_list* src, int count,
/*==========================================
*
*------------------------------------------*/
-int skill_delunitgroup (struct skill_unit_group *group)
+int skill_delunitgroup_(struct skill_unit_group *group, const char* file, int line, const char* func)
{
struct block_list* src;
struct unit_data *ud;
int i,j;
- nullpo_ret(group);
+ if( group == NULL )
+ {
+ ShowDebug("skill_delunitgroup: group is NULL (source=%s:%d, %s)! Please report this! (#3504)\n", file, line, func);
+ return 0;
+ }
src=map_id2bl(group->src_id);
ud = unit_bl2ud(src);
@@ -10404,13 +10407,13 @@ static int skill_unit_timer_sub (DBKey key, void* data, va_list ap)
sd = map_charid2sd(group->val1);
group->val1 = 0;
if (sd && !map[sd->bl.m].flag.nowarp)
- pc_setpos(sd,map_id2index(unit->bl.m),unit->bl.x,unit->bl.y,3);
+ pc_setpos(sd,map_id2index(unit->bl.m),unit->bl.x,unit->bl.y,CLR_TELEPORT);
}
if(group->val2) {
sd = map_charid2sd(group->val2);
group->val2 = 0;
if (sd && !map[sd->bl.m].flag.nowarp)
- pc_setpos(sd,map_id2index(unit->bl.m),unit->bl.x,unit->bl.y,3);
+ pc_setpos(sd,map_id2index(unit->bl.m),unit->bl.x,unit->bl.y,CLR_TELEPORT);
}
skill_delunit(unit);
}
diff --git a/src/map/skill.h b/src/map/skill.h
index 04f2e8d28..fc7877be3 100644
--- a/src/map/skill.h
+++ b/src/map/skill.h
@@ -272,7 +272,8 @@ struct skill_unit_group *skill_unitsetting(struct block_list* src, short skillid
struct skill_unit *skill_initunit (struct skill_unit_group *group, int idx, int x, int y, int val1, int val2);
int skill_delunit(struct skill_unit *unit);
struct skill_unit_group *skill_initunitgroup(struct block_list* src, int count, short skillid, short skilllv, int unit_id, int limit, int interval);
-int skill_delunitgroup(struct skill_unit_group *group);
+int skill_delunitgroup_(struct skill_unit_group *group, const char* file, int line, const char* func);
+#define skill_delunitgroup(group) skill_delunitgroup_(group,__FILE__,__LINE__,__func__)
int skill_clear_unitgroup(struct block_list *src);
int skill_clear_group(struct block_list *bl, int flag);
diff --git a/src/map/status.c b/src/map/status.c
index 95d7f3796..449ea8f56 100644
--- a/src/map/status.c
+++ b/src/map/status.c
@@ -8,6 +8,7 @@
#include "../common/malloc.h"
#include "../common/utils.h"
#include "../common/ers.h"
+#include "../common/strlib.h"
#include "map.h"
#include "path.h"
@@ -831,16 +832,16 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s
status_change_clear(target,0);
if(flag&4) //Delete from memory. (also invokes map removal code)
- unit_free(target,1);
+ unit_free(target,CLR_DEAD);
else
if(flag&2) //remove from map
- unit_remove_map(target,1);
+ unit_remove_map(target,CLR_DEAD);
else
{ //Some death states that would normally be handled by unit_remove_map
unit_stop_attack(target);
unit_stop_walking(target,1);
unit_skillcastcancel(target,0);
- clif_clearunit_area(target,1);
+ clif_clearunit_area(target,CLR_DEAD);
skill_unit_move(target,gettick(),4);
skill_cleartimerskill(target);
}
@@ -1083,7 +1084,7 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, int
if (sc->data[SC_WINKCHARM] && target && !flag)
{ //Prevents skill usage
- clif_emotion(src, 3);
+ clif_emotion(src, E_LV);
return 0;
}
@@ -1546,8 +1547,13 @@ int status_calc_pet_(struct pet_data *pd, bool first)
if (first) {
memcpy(&pd->status, &pd->db->status, sizeof(struct status_data));
- pd->status.mode|= MD_CANMOVE; //so they can chase their master!
+ pd->status.mode = MD_CANMOVE; // pets discard all modes, except walking
pd->status.speed = pd->petDB->speed;
+
+ if(battle_config.pet_attack_support || battle_config.pet_damage_support)
+ {// attack support requires the pet to be able to attack
+ pd->status.mode|= MD_CANATTACK;
+ }
}
if (battle_config.pet_lv_rate && pd->msd)
@@ -1840,6 +1846,7 @@ int status_calc_pc_(struct map_session_data* sd, bool first)
+ sizeof(sd->aspd_add)
+ sizeof(sd->setitem_hash)
+ sizeof(sd->setitem_hash2)
+ + sizeof(sd->itemhealrate2)
// shorts
+ sizeof(sd->splash_range)
+ sizeof(sd->splash_add_range)
@@ -1859,8 +1866,8 @@ int status_calc_pc_(struct map_session_data* sd, bool first)
// Autobonus
pc_delautobonus(sd,sd->autobonus,ARRAYLENGTH(sd->autobonus),true);
- pc_delautobonus(sd,sd->autobonus2,ARRAYLENGTH(sd->autobonus),true);
- pc_delautobonus(sd,sd->autobonus3,ARRAYLENGTH(sd->autobonus),true);
+ pc_delautobonus(sd,sd->autobonus2,ARRAYLENGTH(sd->autobonus2),true);
+ pc_delautobonus(sd,sd->autobonus3,ARRAYLENGTH(sd->autobonus3),true);
// Parse equipment.
for(i=0;i<EQI_MAX-1;i++) {
@@ -3091,6 +3098,9 @@ void status_calc_bl_(struct block_list* bl, enum scb_flag flag, bool first)
}
}
+ if( bl->type == BL_PET )
+ return; // pets are not affected by statuses
+
if( first && bl->type == BL_MOB )
return; // assume there will be no statuses active
@@ -4915,51 +4925,51 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
return 0; // Stats only for Mercenaries
break;
case SC_STRFOOD:
- if (sc->data[SC_FOOD_STR_CASH] && sc->data[SC_FOOD_STR_CASH]->val1 > sc->data[type]->val1)
+ if (sc->data[SC_FOOD_STR_CASH] && sc->data[SC_FOOD_STR_CASH]->val1 > val1)
return 0;
break;
case SC_AGIFOOD:
- if (sc->data[SC_FOOD_AGI_CASH] && sc->data[SC_FOOD_AGI_CASH]->val1 > sc->data[type]->val1)
+ if (sc->data[SC_FOOD_AGI_CASH] && sc->data[SC_FOOD_AGI_CASH]->val1 > val1)
return 0;
break;
case SC_VITFOOD:
- if (sc->data[SC_FOOD_VIT_CASH] && sc->data[SC_FOOD_VIT_CASH]->val1 > sc->data[type]->val1)
+ if (sc->data[SC_FOOD_VIT_CASH] && sc->data[SC_FOOD_VIT_CASH]->val1 > val1)
return 0;
break;
case SC_INTFOOD:
- if (sc->data[SC_FOOD_INT_CASH] && sc->data[SC_FOOD_INT_CASH]->val1 > sc->data[type]->val1)
+ if (sc->data[SC_FOOD_INT_CASH] && sc->data[SC_FOOD_INT_CASH]->val1 > val1)
return 0;
break;
case SC_DEXFOOD:
- if (sc->data[SC_FOOD_DEX_CASH] && sc->data[SC_FOOD_DEX_CASH]->val1 > sc->data[type]->val1)
+ if (sc->data[SC_FOOD_DEX_CASH] && sc->data[SC_FOOD_DEX_CASH]->val1 > val1)
return 0;
break;
case SC_LUKFOOD:
- if (sc->data[SC_FOOD_LUK_CASH] && sc->data[SC_FOOD_LUK_CASH]->val1 > sc->data[type]->val1)
+ if (sc->data[SC_FOOD_LUK_CASH] && sc->data[SC_FOOD_LUK_CASH]->val1 > val1)
return 0;
break;
case SC_FOOD_STR_CASH:
- if (sc->data[SC_STRFOOD] && sc->data[SC_STRFOOD]->val1 > sc->data[type]->val1)
+ if (sc->data[SC_STRFOOD] && sc->data[SC_STRFOOD]->val1 > val1)
return 0;
break;
case SC_FOOD_AGI_CASH:
- if (sc->data[SC_AGIFOOD] && sc->data[SC_AGIFOOD]->val1 > sc->data[type]->val1)
+ if (sc->data[SC_AGIFOOD] && sc->data[SC_AGIFOOD]->val1 > val1)
return 0;
break;
case SC_FOOD_VIT_CASH:
- if (sc->data[SC_VITFOOD] && sc->data[SC_VITFOOD]->val1 > sc->data[type]->val1)
+ if (sc->data[SC_VITFOOD] && sc->data[SC_VITFOOD]->val1 > val1)
return 0;
break;
case SC_FOOD_INT_CASH:
- if (sc->data[SC_INTFOOD] && sc->data[SC_INTFOOD]->val1 > sc->data[type]->val1)
+ if (sc->data[SC_INTFOOD] && sc->data[SC_INTFOOD]->val1 > val1)
return 0;
break;
case SC_FOOD_DEX_CASH:
- if (sc->data[SC_DEXFOOD] && sc->data[SC_DEXFOOD]->val1 > sc->data[type]->val1)
+ if (sc->data[SC_DEXFOOD] && sc->data[SC_DEXFOOD]->val1 > val1)
return 0;
break;
case SC_FOOD_LUK_CASH:
- if (sc->data[SC_LUKFOOD] && sc->data[SC_LUKFOOD]->val1 > sc->data[type]->val1)
+ if (sc->data[SC_LUKFOOD] && sc->data[SC_LUKFOOD]->val1 > val1)
return 0;
break;
}
@@ -5084,52 +5094,40 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
status_change_end(bl,SC_INCREASEAGI,-1);
break;
case SC_STRFOOD:
- if (sc->data[SC_FOOD_STR_CASH] && sc->data[SC_FOOD_STR_CASH]->val1 <= sc->data[type]->val1)
- status_change_end(bl,SC_FOOD_STR_CASH,-1);
+ status_change_end(bl,SC_FOOD_STR_CASH,-1);
break;
case SC_AGIFOOD:
- if (sc->data[SC_FOOD_AGI_CASH] && sc->data[SC_FOOD_AGI_CASH]->val1 <= sc->data[type]->val1)
- status_change_end(bl,SC_FOOD_AGI_CASH,-1);
+ status_change_end(bl,SC_FOOD_AGI_CASH,-1);
break;
case SC_VITFOOD:
- if (sc->data[SC_FOOD_VIT_CASH] && sc->data[SC_FOOD_VIT_CASH]->val1 <= sc->data[type]->val1)
- status_change_end(bl,SC_FOOD_VIT_CASH,-1);
+ status_change_end(bl,SC_FOOD_VIT_CASH,-1);
break;
case SC_INTFOOD:
- if (sc->data[SC_FOOD_INT_CASH] && sc->data[SC_FOOD_INT_CASH]->val1 <= sc->data[type]->val1)
- status_change_end(bl,SC_FOOD_INT_CASH,-1);
+ status_change_end(bl,SC_FOOD_INT_CASH,-1);
break;
case SC_DEXFOOD:
- if (sc->data[SC_FOOD_DEX_CASH] && sc->data[SC_FOOD_DEX_CASH]->val1 <= sc->data[type]->val1)
- status_change_end(bl,SC_FOOD_DEX_CASH,-1);
+ status_change_end(bl,SC_FOOD_DEX_CASH,-1);
break;
case SC_LUKFOOD:
- if (sc->data[SC_FOOD_LUK_CASH] && sc->data[SC_FOOD_LUK_CASH]->val1 <= sc->data[type]->val1)
- status_change_end(bl,SC_FOOD_LUK_CASH,-1);
+ status_change_end(bl,SC_FOOD_LUK_CASH,-1);
break;
case SC_FOOD_STR_CASH:
- if (sc->data[SC_STRFOOD] && sc->data[SC_STRFOOD]->val1 <= sc->data[type]->val1)
- status_change_end(bl,SC_STRFOOD,-1);
+ status_change_end(bl,SC_STRFOOD,-1);
break;
case SC_FOOD_AGI_CASH:
- if (sc->data[SC_AGIFOOD] && sc->data[SC_AGIFOOD]->val1 <= sc->data[type]->val1)
- status_change_end(bl,SC_AGIFOOD,-1);
+ status_change_end(bl,SC_AGIFOOD,-1);
break;
case SC_FOOD_VIT_CASH:
- if (sc->data[SC_VITFOOD] && sc->data[SC_VITFOOD]->val1 <= sc->data[type]->val1)
- status_change_end(bl,SC_VITFOOD,-1);
+ status_change_end(bl,SC_VITFOOD,-1);
break;
case SC_FOOD_INT_CASH:
- if (sc->data[SC_INTFOOD] && sc->data[SC_INTFOOD]->val1 <= sc->data[type]->val1)
- status_change_end(bl,SC_INTFOOD,-1);
+ status_change_end(bl,SC_INTFOOD,-1);
break;
case SC_FOOD_DEX_CASH:
- if (sc->data[SC_DEXFOOD] && sc->data[SC_DEXFOOD]->val1 <= sc->data[type]->val1)
- status_change_end(bl,SC_DEXFOOD,-1);
+ status_change_end(bl,SC_DEXFOOD,-1);
break;
case SC_FOOD_LUK_CASH:
- if (sc->data[SC_LUKFOOD] && sc->data[SC_LUKFOOD]->val1 <= sc->data[type]->val1)
- status_change_end(bl,SC_LUKFOOD,-1);
+ status_change_end(bl,SC_LUKFOOD,-1);
break;
}
@@ -5258,7 +5256,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
case SC_SIGNUMCRUCIS:
val2 = 10 + 4*val1; //Def reduction
tick = -1;
- clif_emotion(bl,4);
+ clif_emotion(bl,E_SWT);
break;
case SC_MAXIMIZEPOWER:
val2 = tick>0?tick:60000;
@@ -5475,7 +5473,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
break;
case SC_CONFUSION:
- clif_emotion(bl,1);
+ clif_emotion(bl,E_WHAT);
break;
case SC_BLEEDING:
val4 = tick/10000;
@@ -5945,7 +5943,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
int pos = (bl->x&0xFFFF)|(bl->y<<16), //Current Coordinates
map = sd->mapindex; //Current Map
//1. Place in Jail (val2 -> Jail Map, val3 -> x, val4 -> y
- pc_setpos(sd,(unsigned short)val2,val3,val4, 3);
+ pc_setpos(sd,(unsigned short)val2,val3,val4, CLR_TELEPORT);
//2. Set restore point (val3 -> return map, val4 return coords
val3 = map;
val4 = pos;
@@ -6607,6 +6605,15 @@ int status_change_end(struct block_list* bl, enum sc_type type, int tid)
if(sce->val2)
{// erase associated land skill
group = skill_id2group(sce->val2);
+
+ if( group == NULL )
+ {
+ ShowDebug("status_change_end: SC_DANCING is missing skill unit group (val1=%d, val2=%d, val3=%d, val4=%d, timer=%d, tid=%d, char_id=%d, map=%s, x=%d, y=%d). Please report this! (#3504)\n",
+ sce->val1, sce->val2, sce->val3, sce->val4, sce->timer, tid,
+ sd ? sd->status.char_id : 0,
+ mapindex_id2name(map_id2index(bl->m)), bl->x, bl->y);
+ }
+
sce->val2 = 0;
skill_delunitgroup(group);
}
@@ -6728,7 +6735,7 @@ int status_change_end(struct block_list* bl, enum sc_type type, int tid)
break;
//natural expiration.
if(sd && sd->mapindex == sce->val2)
- pc_setpos(sd,(unsigned short)sce->val3,sce->val4&0xFFFF, sce->val4>>16, 3);
+ pc_setpos(sd,(unsigned short)sce->val3,sce->val4&0xFFFF, sce->val4>>16, CLR_TELEPORT);
break; //guess hes not in jail :P
case SC_CHANGE:
if (tid == -1)
@@ -7668,146 +7675,124 @@ static int status_natural_heal_timer(int tid, unsigned int tick, int id, intptr
return 0;
}
-int status_readdb(void)
-{
- int i,j,class_;
- FILE *fp;
- char line[1024], path[1024],*p;
-
- sprintf(path, "%s/job_db1.txt", db_path);
- fp=fopen(path,"r"); // Job-specific values (weight, HP, SP, ASPD)
- if(fp==NULL){
- ShowError("can't read %s\n", path);
- return 1;
+/*==========================================
+ * DB reading.
+ * job_db1.txt - weight, hp, sp, aspd
+ * job_db2.txt - job level stat bonuses
+ * size_fix.txt - size adjustment table for weapons
+ * refine_db.txt - refining data table
+ *------------------------------------------*/
+static bool status_readdb_job1(char* fields[], int columns, int current)
+{// Job-specific values (weight, HP, SP, ASPD)
+ int idx, class_;
+ unsigned int i;
+
+ class_ = atoi(fields[0]);
+
+ if(!pcdb_checkid(class_))
+ {
+ ShowWarning("status_readdb_job1: Invalid job class %d specified.\n", class_);
+ return false;
}
- i = 0;
- while(fgets(line, sizeof(line), fp))
+ idx = pc_class2idx(class_);
+
+ max_weight_base[idx] = atoi(fields[1]);
+ hp_coefficient[idx] = atoi(fields[2]);
+ hp_coefficient2[idx] = atoi(fields[3]);
+ sp_coefficient[idx] = atoi(fields[4]);
+
+ for(i = 0; i < MAX_WEAPON_TYPE; i++)
{
- //NOTE: entry MAX_WEAPON_TYPE is not counted
- char* split[5 + MAX_WEAPON_TYPE];
- i++;
- if(line[0]=='/' && line[1]=='/')
- continue;
- for(j=0,p=line; j < 5 + MAX_WEAPON_TYPE && p; j++){
- split[j]=p;
- p=strchr(p,',');
- if(p) *p++=0;
- }
- if(j < 5 + MAX_WEAPON_TYPE)
- { //Weapon #.MAX_WEAPON_TYPE is constantly not load. Fix to that: replace < with <= [blackhole89]
- ShowDebug("%s: Not enough columns at line %d\n", path, i);
- continue;
- }
- class_ = atoi(split[0]);
- if(!pcdb_checkid(class_))
- continue;
- class_ = pc_class2idx(class_);
- max_weight_base[class_]=atoi(split[1]);
- hp_coefficient[class_]=atoi(split[2]);
- hp_coefficient2[class_]=atoi(split[3]);
- sp_coefficient[class_]=atoi(split[4]);
- for(j=0;j<MAX_WEAPON_TYPE;j++)
- aspd_base[class_][j]=atoi(split[j+5]);
+ aspd_base[idx][i] = atoi(fields[i+5]);
}
- fclose(fp);
- ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n",path);
+ return true;
+}
- memset(job_bonus,0,sizeof(job_bonus)); // Job-specific stats bonus
- sprintf(path, "%s/job_db2.txt", db_path);
- fp=fopen(path,"r");
- if(fp==NULL){
- ShowError("can't read %s\n", path);
- return 1;
+static bool status_readdb_job2(char* fields[], int columns, int current)
+{
+ int idx, class_, i;
+
+ class_ = atoi(fields[0]);
+
+ if(!pcdb_checkid(class_))
+ {
+ ShowWarning("status_readdb_job2: Invalid job class %d specified.\n", class_);
+ return false;
}
- while(fgets(line, sizeof(line), fp))
+ idx = pc_class2idx(class_);
+
+ for(i = 1; i < columns; i++)
{
- char *split[MAX_LEVEL+1]; //Job Level is limited to MAX_LEVEL, so the bonuses should likewise be limited to it. [Skotlex]
- if(line[0]=='/' && line[1]=='/')
- continue;
- for(j=0,p=line;j<MAX_LEVEL+1 && p;j++){
- split[j]=p;
- p=strchr(p,',');
- if(p) *p++=0;
- }
- class_ = atoi(split[0]);
- if(!pcdb_checkid(class_))
- continue;
- class_ = pc_class2idx(class_);
- for(i=1;i<j && split[i];i++)
- job_bonus[class_][i-1]=atoi(split[i]);
- }
- fclose(fp);
- ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n",path);
-
- // サイズ補正テ?ブル
- for(i=0;i<3;i++)
- for(j=0;j<MAX_WEAPON_TYPE;j++)
- atkmods[i][j]=100;
- sprintf(path, "%s/size_fix.txt", db_path);
- fp=fopen(path,"r");
- if(fp==NULL){
- ShowError("can't read %s\n", path);
- return 1;
+ job_bonus[idx][i-1] = atoi(fields[i]);
}
- i=0;
- while(fgets(line, sizeof(line), fp))
+ return true;
+}
+
+static bool status_readdb_sizefix(char* fields[], int columns, int current)
+{
+ unsigned int i;
+
+ for(i = 0; i < MAX_WEAPON_TYPE; i++)
{
- char *split[MAX_WEAPON_TYPE];
- if(line[0]=='/' && line[1]=='/')
- continue;
- if(atoi(line)<=0)
- continue;
- memset(split,0,sizeof(split));
- for(j=0,p=line;j<MAX_WEAPON_TYPE && p;j++){
- split[j]=p;
- p=strchr(p,',');
- if(p) *p++=0;
- atkmods[i][j]=atoi(split[j]);
- }
- i++;
+ atkmods[current][i] = atoi(fields[i]);
}
- fclose(fp);
- ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n",path);
+ return true;
+}
+
+static bool status_readdb_refine(char* fields[], int columns, int current)
+{
+ int i;
+
+ refinebonus[current][0] = atoi(fields[0]); // stats per safe-upgrade
+ refinebonus[current][1] = atoi(fields[1]); // stats after safe-limit
+ refinebonus[current][2] = atoi(fields[2]); // safe limit
+
+ for(i = 0; i < MAX_REFINE; i++)
+ {
+ percentrefinery[current][i] = atoi(fields[3+i]);
+ }
+ return true;
+}
- // 精?デ?タテ?ブル
- for(i=0;i<5;i++){
+int status_readdb(void)
+{
+ int i, j;
+
+ // initialize databases to default
+ //
+
+ // job_db1.txt
+ memset(max_weight_base, 0, sizeof(max_weight_base));
+ memset(hp_coefficient, 0, sizeof(hp_coefficient));
+ memset(hp_coefficient2, 0, sizeof(hp_coefficient2));
+ memset(sp_coefficient, 0, sizeof(sp_coefficient));
+ memset(aspd_base, 0, sizeof(aspd_base));
+
+ // job_db2.txt
+ memset(job_bonus,0,sizeof(job_bonus)); // Job-specific stats bonus
+
+ // size_fix.txt
+ for(i=0;i<ARRAYLENGTH(atkmods);i++)
+ for(j=0;j<MAX_WEAPON_TYPE;j++)
+ atkmods[i][j]=100;
+
+ // refine_db.txt
+ for(i=0;i<ARRAYLENGTH(percentrefinery);i++){
for(j=0;j<MAX_REFINE; j++)
- percentrefinery[i][j]=100;
+ percentrefinery[i][j]=100; // success chance
percentrefinery[i][j]=0; //Slot MAX+1 always has 0% success chance [Skotlex]
- refinebonus[i][0]=0;
- refinebonus[i][1]=0;
- refinebonus[i][2]=10;
+ refinebonus[i][0]=0; // stats per safe-upgrade
+ refinebonus[i][1]=0; // stats after safe-limit
+ refinebonus[i][2]=10; // safe limit
}
- sprintf(path, "%s/refine_db.txt", db_path);
- fp=fopen(path,"r");
- if(fp==NULL){
- ShowError("can't read %s\n", path);
- return 1;
- }
- i=0;
- while(fgets(line, sizeof(line), fp))
- {
- char *split[MAX_REFINE+4];
- if(line[0]=='/' && line[1]=='/')
- continue;
- if(atoi(line)<=0)
- continue;
- memset(split,0,sizeof(split));
- for(j=0,p=line;j<MAX_REFINE+4 && p;j++){
- split[j]=p;
- p=strchr(p,',');
- if(p) *p++=0;
- }
- refinebonus[i][0]=atoi(split[0]); // 精?ボ?ナス
- refinebonus[i][1]=atoi(split[1]); // 過?精?ボ?ナス
- refinebonus[i][2]=atoi(split[2]); // 安全精?限界
- for(j=0;j<MAX_REFINE && split[j+3];j++)
- percentrefinery[i][j]=atoi(split[j+3]);
- i++;
- }
- fclose(fp); //Lupus. close this file!!!
- ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n",path);
+ // read databases
+ //
+
+ sv_readdb(db_path, "job_db1.txt", ',', 5+MAX_WEAPON_TYPE, 5+MAX_WEAPON_TYPE, -1, &status_readdb_job1);
+ sv_readdb(db_path, "job_db2.txt", ',', 1, 1+MAX_LEVEL, -1, &status_readdb_job2);
+ sv_readdb(db_path, "size_fix.txt", ',', MAX_WEAPON_TYPE, MAX_WEAPON_TYPE, ARRAYLENGTH(atkmods), &status_readdb_sizefix);
+ sv_readdb(db_path, "refine_db.txt", ',', 3+MAX_REFINE+1, 3+MAX_REFINE+1, ARRAYLENGTH(percentrefinery), &status_readdb_refine);
return 0;
}
diff --git a/src/map/storage.c b/src/map/storage.c
index 8960f7203..eb64d3eb4 100644
--- a/src/map/storage.c
+++ b/src/map/storage.c
@@ -42,17 +42,15 @@ static int storage_comp_item(const void *_i1, const void *_i2)
return -1;
return i1->nameid - i2->nameid;
}
-/* In case someone wants to use it in the future.
-static void storage_sortitem(struct storage_data* stor)
-{
- nullpo_retv(stor);
- qsort(stor->items, MAX_STORAGE, sizeof(struct item), storage_comp_item);
-}
-*/
-static void storage_gsortitem(struct guild_storage* gstor)
+
+static void storage_sortitem(struct item* items, unsigned int size)
{
- nullpo_retv(gstor);
- qsort(gstor->storage_, MAX_GUILD_STORAGE, sizeof(struct item), storage_comp_item);
+ nullpo_retv(items);
+
+ if( battle_config.client_sort_storage )
+ {
+ qsort(items, size, sizeof(struct item), storage_comp_item);
+ }
}
/*==========================================
@@ -104,7 +102,8 @@ int storage_storageopen(struct map_session_data *sd)
}
sd->state.storage_flag = 1;
- clif_storagelist(sd,&sd->status.storage);
+ storage_sortitem(sd->status.storage.items, ARRAYLENGTH(sd->status.storage.items));
+ clif_storagelist(sd, sd->status.storage.items, ARRAYLENGTH(sd->status.storage.items));
clif_updatestorageamount(sd,sd->status.storage.storage_amount);
return 0;
}
@@ -380,7 +379,8 @@ int storage_guild_storageopen(struct map_session_data* sd)
gstor->storage_status = 1;
sd->state.storage_flag = 2;
- clif_guildstoragelist(sd,gstor);
+ storage_sortitem(gstor->items, ARRAYLENGTH(gstor->items));
+ clif_storagelist(sd, gstor->items, ARRAYLENGTH(gstor->items));
clif_updateguildstorageamount(sd,gstor->storage_amount);
return 0;
}
@@ -406,11 +406,11 @@ int guild_storage_additem(struct map_session_data* sd, struct guild_storage* sto
if(itemdb_isstackable2(data)){ //Stackable
for(i=0;i<MAX_GUILD_STORAGE;i++){
- if(compare_item(&stor->storage_[i], item_data)) {
- if(stor->storage_[i].amount+amount > MAX_AMOUNT)
+ if(compare_item(&stor->items[i], item_data)) {
+ if(stor->items[i].amount+amount > MAX_AMOUNT)
return 1;
- stor->storage_[i].amount+=amount;
- clif_guildstorageitemadded(sd,&stor->storage_[i],i,amount);
+ stor->items[i].amount+=amount;
+ clif_storageitemadded(sd,&stor->items[i],i,amount);
stor->dirty = 1;
if(log_config.enable_logs&0x1000)
log_pick_pc(sd, "G", item_data->nameid, -amount, item_data);
@@ -419,15 +419,15 @@ int guild_storage_additem(struct map_session_data* sd, struct guild_storage* sto
}
}
//Add item
- for(i=0;i<MAX_GUILD_STORAGE && stor->storage_[i].nameid;i++);
+ for(i=0;i<MAX_GUILD_STORAGE && stor->items[i].nameid;i++);
if(i>=MAX_GUILD_STORAGE)
return 1;
- memcpy(&stor->storage_[i],item_data,sizeof(stor->storage_[0]));
- stor->storage_[i].amount=amount;
+ memcpy(&stor->items[i],item_data,sizeof(stor->items[0]));
+ stor->items[i].amount=amount;
stor->storage_amount++;
- clif_guildstorageitemadded(sd,&stor->storage_[i],i,amount);
+ clif_storageitemadded(sd,&stor->items[i],i,amount);
clif_updateguildstorageamount(sd,stor->storage_amount);
stor->dirty = 1;
if(log_config.enable_logs&0x1000)
@@ -440,14 +440,14 @@ int guild_storage_delitem(struct map_session_data* sd, struct guild_storage* sto
nullpo_retr(1, sd);
nullpo_retr(1, stor);
- if(stor->storage_[n].nameid==0 || stor->storage_[n].amount<amount)
+ if(stor->items[n].nameid==0 || stor->items[n].amount<amount)
return 1;
- stor->storage_[n].amount-=amount;
+ stor->items[n].amount-=amount;
if(log_config.enable_logs&0x1000)
- log_pick_pc(sd, "G", stor->storage_[n].nameid, amount, &stor->storage_[n]);
- if(stor->storage_[n].amount==0){
- memset(&stor->storage_[n],0,sizeof(stor->storage_[0]));
+ log_pick_pc(sd, "G", stor->items[n].nameid, amount, &stor->items[n]);
+ if(stor->items[n].amount==0){
+ memset(&stor->items[n],0,sizeof(stor->items[0]));
stor->storage_amount--;
clif_updateguildstorageamount(sd,stor->storage_amount);
}
@@ -496,13 +496,13 @@ int storage_guild_storageget(struct map_session_data* sd, int index, int amount)
if(index<0 || index>=MAX_GUILD_STORAGE)
return 0;
- if(stor->storage_[index].nameid <= 0)
+ if(stor->items[index].nameid <= 0)
return 0;
- if(amount < 1 || amount > stor->storage_[index].amount)
+ if(amount < 1 || amount > stor->items[index].amount)
return 0;
- if((flag = pc_additem(sd,&stor->storage_[index],amount)) == 0)
+ if((flag = pc_additem(sd,&stor->items[index],amount)) == 0)
guild_storage_delitem(sd,stor,index,amount);
else
clif_additem(sd,0,0,flag);
@@ -549,13 +549,13 @@ int storage_guild_storagegettocart(struct map_session_data* sd, int index, int a
if(index<0 || index>=MAX_GUILD_STORAGE)
return 0;
- if(stor->storage_[index].nameid<=0)
+ if(stor->items[index].nameid<=0)
return 0;
- if(amount < 1 || amount > stor->storage_[index].amount)
+ if(amount < 1 || amount > stor->items[index].amount)
return 0;
- if(pc_cart_additem(sd,&stor->storage_[index],amount)==0)
+ if(pc_cart_additem(sd,&stor->items[index],amount)==0)
guild_storage_delitem(sd,stor,index,amount);
return 1;
@@ -584,7 +584,6 @@ int storage_guild_storagesaved(int guild_id)
if (stor->dirty && stor->storage_status == 0)
{ //Storage has been correctly saved.
stor->dirty = 0;
- storage_gsortitem(stor);
}
return 1;
}
diff --git a/src/map/unit.c b/src/map/unit.c
index 05c0bcb16..df4efef8e 100644
--- a/src/map/unit.c
+++ b/src/map/unit.c
@@ -641,7 +641,7 @@ int unit_blown(struct block_list* bl, int dx, int dy, int count, int flag)
//Warps a unit/ud to a given map/position.
//In the case of players, pc_setpos is used.
//it respects the no warp flags, so it is safe to call this without doing nowarpto/nowarp checks.
-int unit_warp(struct block_list *bl,short m,short x,short y,int type)
+int unit_warp(struct block_list *bl,short m,short x,short y,clr_type type)
{
struct unit_data *ud;
nullpo_ret(bl);
@@ -650,7 +650,7 @@ int unit_warp(struct block_list *bl,short m,short x,short y,int type)
if(bl->prev==NULL || !ud)
return 1;
- if (type < 0 || type == 1)
+ if (type == CLR_DEAD)
//Type 1 is invalid, since you shouldn't warp a bl with the "death"
//animation, it messes up with unit_remove_map! [Skotlex]
return 1;
@@ -1305,8 +1305,6 @@ int unit_skilluse_pos2( struct block_list *src, short skill_x, short skill_y, sh
return 1;
}
-static int unit_attack_timer(int tid, unsigned int tick, int id, intptr data);
-
int unit_stop_attack(struct block_list *bl)
{
struct unit_data *ud = unit_bl2ud(bl);
@@ -1800,7 +1798,7 @@ int unit_changeviewsize(struct block_list *bl,short size)
} else
return 0;
if(size!=0)
- clif_misceffect2(bl,421+size);
+ clif_specialeffect(bl,421+size, AREA);
return 0;
}
@@ -1811,7 +1809,7 @@ int unit_changeviewsize(struct block_list *bl,short size)
* Otherwise it is assumed bl is being warped.
* On-Kill specific stuff is not performed here, look at status_damage for that.
*------------------------------------------*/
-int unit_remove_map_(struct block_list *bl, int clrtype, const char* file, int line, const char* func)
+int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file, int line, const char* func)
{
struct unit_data *ud = unit_bl2ud(bl);
struct status_change *sc = status_get_sc(bl);
@@ -1960,7 +1958,7 @@ int unit_remove_map_(struct block_list *bl, int clrtype, const char* file, int l
{ //If logging out, this is deleted on unit_free
clif_clearunit_area(bl,clrtype);
map_delblock(bl);
- unit_free(bl,0);
+ unit_free(bl,CLR_OUTSIGHT);
map_freeblock_unlock();
return 0;
}
@@ -1973,10 +1971,10 @@ int unit_remove_map_(struct block_list *bl, int clrtype, const char* file, int l
ud->canact_tick = ud->canmove_tick; //It appears HOM do reset the can-act tick.
if( !hd->homunculus.intimacy && !(hd->master && !hd->master->state.active) )
{ //If logging out, this is deleted on unit_free
- clif_emotion(bl, 28) ; //sob
+ clif_emotion(bl, E_SOB);
clif_clearunit_area(bl,clrtype);
map_delblock(bl);
- unit_free(bl,0);
+ unit_free(bl,CLR_OUTSIGHT);
map_freeblock_unlock();
return 0;
}
@@ -1990,7 +1988,7 @@ int unit_remove_map_(struct block_list *bl, int clrtype, const char* file, int l
{
clif_clearunit_area(bl,clrtype);
map_delblock(bl);
- unit_free(bl,0);
+ unit_free(bl,CLR_OUTSIGHT);
map_freeblock_unlock();
return 0;
}
@@ -2005,11 +2003,11 @@ int unit_remove_map_(struct block_list *bl, int clrtype, const char* file, int l
return 1;
}
-void unit_remove_map_pc(struct map_session_data *sd, int clrtype)
+void unit_remove_map_pc(struct map_session_data *sd, clr_type clrtype)
{
unit_remove_map(&sd->bl,clrtype);
- if (clrtype == 3) clrtype = 0; //3 is the warp from logging out, but pets/homunc need to just 'vanish' instead of showing the warping out animation.
+ if (clrtype == CLR_TELEPORT) clrtype = CLR_OUTSIGHT; //CLR_TELEPORT is the warp from logging out, but pets/homunc need to just 'vanish' instead of showing the warping out animation.
if(sd->pd)
unit_remove_map(&sd->pd->bl, clrtype);
@@ -2021,19 +2019,17 @@ void unit_remove_map_pc(struct map_session_data *sd, int clrtype)
void unit_free_pc(struct map_session_data *sd)
{
- if (sd->pd) unit_free(&sd->pd->bl,0);
- if (sd->hd) unit_free(&sd->hd->bl,0);
- if (sd->md) unit_free(&sd->md->bl,0);
- unit_free(&sd->bl,3);
+ if (sd->pd) unit_free(&sd->pd->bl,CLR_OUTSIGHT);
+ if (sd->hd) unit_free(&sd->hd->bl,CLR_OUTSIGHT);
+ if (sd->md) unit_free(&sd->md->bl,CLR_OUTSIGHT);
+ unit_free(&sd->bl,CLR_TELEPORT);
}
/*==========================================
* Function to free all related resources to the bl
* if unit is on map, it is removed using the clrtype specified
- * If clrtype is <0, no saving is performed. This is only for non-authed
- * objects that shouldn't be on a map yet.
*------------------------------------------*/
-int unit_free(struct block_list *bl, int clrtype)
+int unit_free(struct block_list *bl, clr_type clrtype)
{
struct unit_data *ud = unit_bl2ud( bl );
nullpo_ret(ud);
@@ -2053,8 +2049,8 @@ int unit_free(struct block_list *bl, int clrtype)
pc_delinvincibletimer(sd);
pc_delautobonus(sd,sd->autobonus,ARRAYLENGTH(sd->autobonus),false);
- pc_delautobonus(sd,sd->autobonus2,ARRAYLENGTH(sd->autobonus),false);
- pc_delautobonus(sd,sd->autobonus3,ARRAYLENGTH(sd->autobonus),false);
+ pc_delautobonus(sd,sd->autobonus2,ARRAYLENGTH(sd->autobonus2),false);
+ pc_delautobonus(sd,sd->autobonus3,ARRAYLENGTH(sd->autobonus3),false);
if( sd->followtimer != -1 )
pc_stop_following(sd);
@@ -2138,15 +2134,12 @@ int unit_free(struct block_list *bl, int clrtype)
aFree (pd->loot);
pd->loot = NULL;
}
- if( clrtype >= 0 )
- {
- if( pd->pet.intimate > 0 )
- intif_save_petdata(pd->pet.account_id,&pd->pet);
- else
- { //Remove pet.
- intif_delete_petdata(pd->pet.pet_id);
- if (sd) sd->status.pet_id = 0;
- }
+ if( pd->pet.intimate > 0 )
+ intif_save_petdata(pd->pet.account_id,&pd->pet);
+ else
+ { //Remove pet.
+ intif_delete_petdata(pd->pet.pet_id);
+ if (sd) sd->status.pet_id = 0;
}
if( sd )
sd->pd = NULL;
@@ -2213,16 +2206,13 @@ int unit_free(struct block_list *bl, int clrtype)
struct homun_data *hd = (TBL_HOM*)bl;
struct map_session_data *sd = hd->master;
merc_hom_hungry_timer_delete(hd);
- if( clrtype >= 0 )
+ if( hd->homunculus.intimacy > 0 )
+ merc_save(hd);
+ else
{
- if( hd->homunculus.intimacy > 0 )
- merc_save(hd);
- else
- {
- intif_homunculus_requestdelete(hd->homunculus.hom_id);
- if( sd )
- sd->status.hom_id = 0;
- }
+ intif_homunculus_requestdelete(hd->homunculus.hom_id);
+ if( sd )
+ sd->status.hom_id = 0;
}
if( sd )
sd->hd = NULL;
@@ -2232,16 +2222,13 @@ int unit_free(struct block_list *bl, int clrtype)
{
struct mercenary_data *md = (TBL_MER*)bl;
struct map_session_data *sd = md->master;
- if( clrtype >= 0 )
+ if( mercenary_get_lifetime(md) > 0 )
+ mercenary_save(md);
+ else
{
- if( mercenary_get_lifetime(md) > 0 )
- mercenary_save(md);
- else
- {
- intif_mercenary_delete(md->mercenary.mercenary_id);
- if( sd )
- sd->status.mer_id = 0;
- }
+ intif_mercenary_delete(md->mercenary.mercenary_id);
+ if( sd )
+ sd->status.mer_id = 0;
}
if( sd )
sd->md = NULL;
diff --git a/src/map/unit.h b/src/map/unit.h
index 3b82dce56..fd5a83208 100644
--- a/src/map/unit.h
+++ b/src/map/unit.h
@@ -9,6 +9,7 @@ struct block_list;
struct unit_data;
struct map_session_data;
+#include "clif.h" // clr_type
#include "map.h" // struct block_list
#include "path.h" // struct walkpath_data
#include "skill.h" // struct skill_timerskill, struct skill_unit_group, struct skill_unit_group_tickset
@@ -81,7 +82,7 @@ int unit_set_walkdelay(struct block_list *bl, unsigned int tick, int delay, int
int unit_escape(struct block_list *bl, struct block_list *target, short dist);
// 位置の強制移動(吹き飛ばしなど)
int unit_movepos(struct block_list *bl, short dst_x, short dst_y, int easy, bool checkpath);
-int unit_warp(struct block_list *bl, short map, short x, short y, int type);
+int unit_warp(struct block_list *bl, short map, short x, short y, clr_type type);
int unit_setdir(struct block_list *bl,unsigned char dir);
uint8 unit_getdir(struct block_list *bl);
int unit_blown(struct block_list* bl, int dx, int dy, int count, int flag);
@@ -114,11 +115,11 @@ void unit_dataset(struct block_list *bl);
int unit_fixdamage(struct block_list *src,struct block_list *target,unsigned int tick,int sdelay,int ddelay,int damage,int div,int type,int damage2);
// その他
struct unit_data* unit_bl2ud(struct block_list *bl);
-void unit_remove_map_pc(struct map_session_data *sd, int clrtype);
+void unit_remove_map_pc(struct map_session_data *sd, clr_type clrtype);
void unit_free_pc(struct map_session_data *sd);
#define unit_remove_map(bl,clrtype) unit_remove_map_(bl,clrtype,__FILE__,__LINE__,__func__)
-int unit_remove_map_(struct block_list *bl, int clrtype, const char* file, int line, const char* func);
-int unit_free(struct block_list *bl, int clrtype);
+int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file, int line, const char* func);
+int unit_free(struct block_list *bl, clr_type clrtype);
int unit_changeviewsize(struct block_list *bl,short size);
// 初期化ルーチン
diff --git a/src/map/vending.c b/src/map/vending.c
index 67e5ebf19..90bff7399 100644
--- a/src/map/vending.c
+++ b/src/map/vending.c
@@ -275,7 +275,7 @@ void vending_openvending(struct map_session_data* sd, const char* message, bool
sd->vending[i].index = index;
sd->vending[i].amount = amount;
- sd->vending[i].value = cap_value(value, 1, (unsigned int)battle_config.vending_max_value);
+ sd->vending[i].value = cap_value(value, 0, (unsigned int)battle_config.vending_max_value);
i++; // item successfully added
}
diff --git a/src/plugins/sig.c b/src/plugins/sig.c
index 1872d48ff..9db0638ca 100644
--- a/src/plugins/sig.c
+++ b/src/plugins/sig.c
@@ -3,6 +3,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
+#define __USE_GNU // required to enable strsignal on some platforms
#include <string.h>
#include <time.h>
#include "../common/plugin.h"
@@ -52,7 +53,6 @@ unsigned long (*getuptime)();
char *server_name;
int crash_flag = 0;
-extern const char *strsignal(int);
int sig_final ();
// by Gabuzomeu
@@ -60,9 +60,6 @@ int sig_final ();
// (sigaction() is POSIX; signal() is not.) Taken from Stevens' _Advanced
// Programming in the UNIX Environment_.
//
-#ifdef WIN32 // windows don't have SIGPIPE
-#define SIGPIPE SIGINT
-#endif
#ifndef POSIX
#define compat_signal(signo, func) signal(signo, func)
@@ -203,9 +200,7 @@ int sig_init ()
compat_signal(SIGSEGV, func);
compat_signal(SIGFPE, func);
compat_signal(SIGILL, func);
- #ifndef __WIN32
- compat_signal(SIGBUS, func);
- #endif
+ compat_signal(SIGBUS, func);
return 1;
}
diff --git a/src/tool/adduser.c b/src/tool/adduser.c
index 2c7461930..5f4dfb6a5 100644
--- a/src/tool/adduser.c
+++ b/src/tool/adduser.c
@@ -75,7 +75,7 @@ int main(int argc, char *argv[])
strcpy(username, "");
while (strlen(username) < 4 || strlen(username) > 23) {
printf("Enter an username (4-23 characters): ");
- scanf("%s", &username);
+ scanf("%s", username);
username[23] = 0;
remove_control_chars(username);
}
@@ -83,7 +83,7 @@ int main(int argc, char *argv[])
strcpy(password, "");
while (strlen(password) < 4 || strlen(password) > 23) {
printf("Enter a password (4-23 characters): ");
- scanf("%s", &password);
+ scanf("%s", password);
password[23] = 0;
remove_control_chars(password);
}
@@ -91,7 +91,7 @@ int main(int argc, char *argv[])
strcpy(sex, "");
while (strcmp(sex, "F") != 0 && strcmp(sex, "M") != 0) {
printf("Enter a gender (M for male, F for female): ");
- scanf("%s", &sex);
+ scanf("%s", sex);
}
FPaccout = fopen(account_txt, "r+");
diff --git a/src/txt-converter/Makefile.in b/src/txt-converter/Makefile.in
index 089d9d276..50e89e34e 100644
--- a/src/txt-converter/Makefile.in
+++ b/src/txt-converter/Makefile.in
@@ -10,6 +10,7 @@ LOGIN_CONVERTER_OBJ = \
../common/obj_all/showmsg.o \
../common/obj_all/strlib.o \
../common/obj_all/timer.o \
+ ../common/obj_all/utils.o \
../common/obj_sql/sql.o
LOGIN_CONVERTER_H = \
../login/account.h \
@@ -23,6 +24,7 @@ LOGIN_CONVERTER_H = \
../common/showmsg.h \
../common/strlib.h \
../common/timer.h \
+ ../common/utils.h \
../common/sql.h
CHAR_CONVERTER_OBJ = \