summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorshennetsind <ind@henn.et>2013-05-30 21:00:22 -0300
committershennetsind <ind@henn.et>2013-05-30 21:00:22 -0300
commit20bdc01fa687b174a732be4483ddea4982d67ce9 (patch)
tree3336c1c449a78d52d25d2534acbd319d10c56b45 /src
parent21bbfad48084190b8a6881ee3b277993418a5137 (diff)
downloadhercules-20bdc01fa687b174a732be4483ddea4982d67ce9.tar.gz
hercules-20bdc01fa687b174a732be4483ddea4982d67ce9.tar.bz2
hercules-20bdc01fa687b174a732be4483ddea4982d67ce9.tar.xz
hercules-20bdc01fa687b174a732be4483ddea4982d67ce9.zip
Memory Slasher - May 30 Patch
http://hercules.ws/board/topic/928-memory-slasher-may-30-patch/ Signed-off-by: shennetsind <ind@henn.et>
Diffstat (limited to 'src')
-rw-r--r--src/char/char.c46
-rw-r--r--src/char/char.h2
-rw-r--r--src/common/console.c6
-rw-r--r--src/common/malloc.c102
-rw-r--r--src/common/malloc.h2
-rw-r--r--src/common/mmo.h5
-rw-r--r--src/common/socket.c60
-rw-r--r--src/common/socket.h14
-rw-r--r--src/map/atcommand.c2
-rw-r--r--src/map/battleground.c508
-rw-r--r--src/map/battleground.h66
-rw-r--r--src/map/chrif.c7
-rw-r--r--src/map/clif.c248
-rw-r--r--src/map/clif.h41
-rw-r--r--src/map/guild.c10
-rw-r--r--src/map/instance.c484
-rw-r--r--src/map/instance.h76
-rw-r--r--src/map/intif.c2
-rw-r--r--src/map/irc-bot.c6
-rw-r--r--src/map/map.c467
-rw-r--r--src/map/map.h31
-rw-r--r--src/map/mob.c7
-rw-r--r--src/map/npc.c327
-rw-r--r--src/map/npc.h12
-rw-r--r--src/map/packets.h5
-rw-r--r--src/map/packets_struct.h62
-rw-r--r--src/map/party.c107
-rw-r--r--src/map/party.h3
-rw-r--r--src/map/path.c36
-rw-r--r--src/map/pc.c148
-rw-r--r--src/map/pc.h15
-rw-r--r--src/map/script.c709
-rw-r--r--src/map/script.h38
-rw-r--r--src/map/skill.c2
-rw-r--r--src/map/status.c17
-rw-r--r--src/map/unit.c37
36 files changed, 2637 insertions, 1073 deletions
diff --git a/src/char/char.c b/src/char/char.c
index 00fc633df..dc5352137 100644
--- a/src/char/char.c
+++ b/src/char/char.c
@@ -81,7 +81,8 @@ struct mmo_map_server {
uint32 ip;
uint16 port;
int users;
- unsigned short map[MAX_MAP_PER_SERVER];
+ unsigned short *map;
+ unsigned short maps;
} server[MAX_MAP_SERVERS];
int char_fd=-1;
@@ -2628,7 +2629,7 @@ int search_mapserver(unsigned short map, uint32 ip, uint16 port);
/// Initializes a server structure.
void mapif_server_init(int id)
{
- memset(&server[id], 0, sizeof(server[id]));
+ //memset(&server[id], 0, sizeof(server[id]));
server[id].fd = -1;
}
@@ -2655,7 +2656,7 @@ void mapif_server_reset(int id)
WBUFL(buf,4) = htonl(server[id].ip);
WBUFW(buf,8) = htons(server[id].port);
j = 0;
- for(i = 0; i < MAX_MAP_PER_SERVER; i++)
+ for(i = 0; i < server[id].maps; i++)
if (server[id].map[i])
WBUFW(buf,10+(j++)*4) = server[id].map[i];
if (j > 0) {
@@ -2725,8 +2726,11 @@ int parse_frommap(int fd)
case 0x2afa: // Receiving map names list from the map-server
if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
return 0;
-
- memset(server[id].map, 0, sizeof(server[id].map));
+ if( server[id].map != NULL ) { aFree(server[id].map); server[id].map = NULL; }
+
+ server[id].maps = ( RFIFOW(fd, 2) - 4 ) / 4;
+ CREATE(server[id].map, unsigned short, server[id].maps);
+
j = 0;
for(i = 4; i < RFIFOW(fd,2); i += 4) {
server[id].map[j] = RFIFOW(fd,i);
@@ -3392,10 +3396,14 @@ int parse_frommap(int fd)
if( RFIFOREST(fd) < RFIFOW(fd,4) )
return 0;/* packet wasn't fully received yet (still fragmented) */
else {
- int sfd;/* stat server fd */
+ int sfd;/* stat server fd */
+ struct hSockOpt opt;
RFIFOSKIP(fd, 2);/* we skip first 2 bytes which are the 0x3008, so we end up with a buffer equal to the one we send */
- if( (sfd = make_connection(host2ip("stats.hercules.ws"),(uint16)25427,true) ) == -1 ) {
+ opt.silent = 1;
+ opt.setTimeo = 1;
+
+ if( (sfd = make_connection(host2ip("stats.hercules.ws"),(uint16)25427,&opt) ) == -1 ) {
RFIFOSKIP(fd, RFIFOW(fd,2) );/* skip this packet */
RFIFOFLUSH(fd);
break;/* connection not possible, we drop the report */
@@ -4275,7 +4283,6 @@ int parse_char(int fd)
server[i].ip = ntohl(RFIFOL(fd,54));
server[i].port = ntohs(RFIFOW(fd,58));
server[i].users = 0;
- memset(server[i].map, 0, sizeof(server[i].map));
session[fd]->func_parse = parse_frommap;
session[fd]->flag.server = 1;
realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
@@ -4486,12 +4493,12 @@ int check_connect_login_server(int tid, unsigned int tick, int id, intptr_t data
return 0;
ShowInfo("Attempt to connect to login-server...\n");
- login_fd = make_connection(login_ip, login_port, false);
- if (login_fd == -1)
- { //Try again later. [Skotlex]
+
+ if ( (login_fd = make_connection(login_ip, login_port, NULL)) == -1) { //Try again later. [Skotlex]
login_fd = 0;
return 0;
}
+
session[login_fd]->func_parse = parse_fromlogin;
session[login_fd]->flag.server = 1;
realloc_fifo(login_fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
@@ -4858,8 +4865,8 @@ int char_config_read(const char* cfgName)
return 0;
}
-void do_final(void)
-{
+void do_final(void) {
+ int i;
ShowStatus("Terminating...\n");
set_all_offline(-1);
@@ -4879,8 +4886,7 @@ void do_final(void)
online_char_db->destroy(online_char_db, NULL);
auth_db->destroy(auth_db, NULL);
- if( char_fd != -1 )
- {
+ if( char_fd != -1 ) {
do_close(char_fd);
char_fd = -1;
}
@@ -4888,6 +4894,10 @@ void do_final(void)
SQL->Free(sql_handle);
mapindex_final();
+ for(i = 0; i < MAX_MAP_SERVERS; i++ )
+ if( server[i].map )
+ aFree(server[i].map);
+
ShowStatus("Finished.\n");
}
@@ -4923,11 +4933,17 @@ void do_shutdown(void)
int do_init(int argc, char **argv) {
+ int i;
memset(&skillid2idx, 0, sizeof(skillid2idx));
+
+ for(i = 0; i < MAX_MAP_SERVERS; i++ )
+ server[i].map = NULL;
+
//Read map indexes
mapindex_init();
start_point.map = mapindex_name2id("new_zone01");
+
pincode_defaults();
char_config_read((argc < 2) ? CHAR_CONF_NAME : argv[1]);
diff --git a/src/char/char.h b/src/char/char.h
index b48ea359c..996a0e845 100644
--- a/src/char/char.h
+++ b/src/char/char.h
@@ -45,7 +45,7 @@ struct online_char_data {
DBMap* online_char_db; // int account_id -> struct online_char_data*
-#define MAX_MAP_SERVERS 30
+#define MAX_MAP_SERVERS 2
#define DEFAULT_AUTOSAVE_INTERVAL 300*1000
diff --git a/src/common/console.c b/src/common/console.c
index ba93b8e09..33d485497 100644
--- a/src/common/console.c
+++ b/src/common/console.c
@@ -85,6 +85,9 @@ CPCMD(exit) {
CPCMD(ers_report) {
ers_report();
}
+CPCMD(mem_report) {
+ memmgr_report(line?atoi(line):0);
+}
CPCMD(help) {
unsigned int i = 0;
for ( i = 0; i < console->cmd_list_count; i++ ) {
@@ -115,6 +118,7 @@ void console_load_defaults(void) {
CP_DEF(help),
CP_DEF_C(server),
CP_DEF_S(ers_report,server),
+ CP_DEF_S(mem_report,server),
CP_DEF_S(malloc_usage,server),
CP_DEF_S(exit,server),
};
@@ -227,8 +231,10 @@ void console_parse_sub(char *line) {
char *tok;
char sublist[CP_CMD_LENGTH * 5];
unsigned int i, len = 0;
+
memcpy(bline, line, 200);
tok = strtok(line, " ");
+
for ( i = 0; i < console->cmd_list_count; i++ ) {
if( strcmpi(tok,console->cmd_list[i]->cmd) == 0 )
break;
diff --git a/src/common/malloc.c b/src/common/malloc.c
index 4874aa0f4..e98ec770a 100644
--- a/src/common/malloc.c
+++ b/src/common/malloc.c
@@ -200,6 +200,8 @@ static struct unit_head_large *unit_head_large_first = NULL;
static struct block* block_malloc(unsigned short hash);
static void block_free(struct block* p);
static size_t memmgr_usage_bytes;
+static size_t memmgr_usage_bytes_t;
+
#define block2unit(p, n) ((struct unit_head*)(&(p)->data[ p->unit_size * (n) ]))
#define memmgr_assert(v) do { if(!(v)) { ShowError("Memory manager: assertion '" #v "' failed!\n"); } } while(0)
@@ -245,6 +247,7 @@ void* _mmalloc(size_t size, const char *file, int line, const char *func )
/* At that time, the distinction by assigning NULL to unit_head.block */
if(hash2size(size_hash) > BLOCK_DATA_SIZE - sizeof(struct unit_head)) {
struct unit_head_large* p = (struct unit_head_large*)MALLOC(sizeof(struct unit_head_large)+size,file,line,func);
+ memmgr_usage_bytes_t += size+sizeof(struct unit_head_large);
if(p != NULL) {
p->size = size;
p->unit_head.block = NULL;
@@ -401,6 +404,7 @@ void _mfree(void *ptr, const char *file, int line, const char *func )
head_large->next->prev = head_large->prev;
}
memmgr_usage_bytes -= head_large->size;
+ memmgr_usage_bytes_t -= head_large->size + sizeof(struct unit_head_large);
#ifdef DEBUG_MEMMGR
// set freed memory to 0xfd
memset(ptr, 0xfd, head_large->size);
@@ -457,6 +461,7 @@ static struct block* block_malloc(unsigned short hash)
} else {
/* Newly allocated space for the block */
p = (struct block*)MALLOC(sizeof(struct block) * (BLOCK_ALLOC), __FILE__, __LINE__, __func__ );
+ memmgr_usage_bytes_t += sizeof(struct block) * (BLOCK_ALLOC);
if(p == NULL) {
ShowFatalError("Memory manager::block_alloc failed.\n");
exit(EXIT_FAILURE);
@@ -650,6 +655,86 @@ static void memmgr_final (void)
}
#endif /* LOG_MEMMGR */
}
+/* [Ind/Hercules] */
+void memmgr_report (int extra) {
+ struct block *block = block_first;
+ struct unit_head_large *large = unit_head_large_first;
+ unsigned int count = 0, size = 0;
+ int j;
+ unsigned short msize = 1024;
+ struct {
+ const char *file;
+ unsigned short line;
+ unsigned int size;
+ unsigned int count;
+ } data[100];
+ memset(&data, 0, sizeof(data));
+
+ if( extra != 0 )
+ msize = extra;
+
+ while (block) {
+ if (block->unit_used) {
+ int i;
+ for (i = 0; i < block->unit_maxused; i++) {
+ struct unit_head *head = block2unit(block, i);
+ if( head->block != NULL && head->size > msize ) {
+ for( j = 0; j < 100; j++ ) {
+ if( data[j].file == head->file && data[j].line == head->line ) {
+ data[j].size += head->size;
+ data[j].count += 1;
+ break;
+ } else if( data[j].size == 0 ) {
+ data[j].file = head->file;
+ data[j].line = head->line;
+ data[j].size = head->size;
+ data[j].count += 1;
+ break;
+ }
+ }
+ size += (unsigned int)head->size;
+ count++;
+ }
+ }
+ }
+ block = block->block_next;
+ }
+
+ while(large) {
+ if( large->size > msize ) {
+ for( j = 0; j < 100; j++ ) {
+ if( data[j].file == large->unit_head.file && data[j].line == large->unit_head.line ) {
+ data[j].size += large->size;
+ data[j].count += 1;
+ break;
+ } else if( data[j].size == 0 ) {
+ data[j].file = large->unit_head.file;
+ data[j].line = large->unit_head.line;
+ data[j].size = large->size;
+ data[j].count += 1;
+ break;
+ }
+ }
+ size += (unsigned int)large->size;
+ count++;
+ }
+ large = large->next;
+ }
+ for( j = 0; j < 100; j++ ) {
+ if( data[j].size != 0 ) {
+ ShowMessage("[malloc] : "CL_WHITE"%s"CL_RESET":"CL_WHITE"%d"CL_RESET" %d instances => %.2f MB\n",data[j].file,data[j].line,data[j].count,(double)((data[j].size)/1024)/1024);
+ }
+ }
+ ShowMessage("[malloc] : reporting %u instances | %.2f MB\n",count,(double)((size)/1024)/1024);
+ ShowMessage("[malloc] : internal usage %.2f MB | %.2f MB\n",(double)((memmgr_usage_bytes_t-memmgr_usage_bytes)/1024)/1024,(double)((memmgr_usage_bytes_t)/1024)/1024);
+
+ if( extra ) {
+ ShowMessage("[malloc] : unit_head_large: %d bytes\n",sizeof(struct unit_head_large));
+ ShowMessage("[malloc] : unit_head: %d bytes\n",sizeof(struct unit_head));
+ ShowMessage("[malloc] : block: %d bytes\n",sizeof(struct block));
+ }
+
+}
static void memmgr_init (void)
{
@@ -677,8 +762,7 @@ void malloc_memory_check(void)
/// Returns true if a pointer is valid.
/// The check is best-effort, false positives are possible.
-bool malloc_verify_ptr(void* ptr)
-{
+bool malloc_verify_ptr(void* ptr) {
#ifdef USE_MEMMGR
return memmgr_verify(ptr) && MEMORY_VERIFY(ptr);
#else
@@ -687,8 +771,7 @@ bool malloc_verify_ptr(void* ptr)
}
-size_t malloc_usage (void)
-{
+size_t malloc_usage (void) {
#ifdef USE_MEMMGR
return memmgr_usage ();
#else
@@ -696,16 +779,16 @@ size_t malloc_usage (void)
#endif
}
-void malloc_final (void)
-{
+void malloc_final (void) {
#ifdef USE_MEMMGR
memmgr_final ();
#endif
MEMORY_CHECK();
}
-void malloc_init (void)
-{
+void malloc_init (void) {
+ memmgr_usage_bytes_t = 0;
+ memmgr_usage_bytes = 0;
#if defined(DMALLOC) && defined(CYGWIN)
// http://dmalloc.com/docs/latest/online/dmalloc_19.html
dmalloc_debug_setup(getenv("DMALLOC_OPTIONS"));
@@ -720,8 +803,7 @@ void malloc_init (void)
#endif
}
-void malloc_defaults()
-{
+void malloc_defaults(void) {
malloclib = &malloclib_s;
malloclib->init = malloc_init;
malloclib->final = malloc_final;
diff --git a/src/common/malloc.h b/src/common/malloc.h
index 34a26b56e..1b8e82bd9 100644
--- a/src/common/malloc.h
+++ b/src/common/malloc.h
@@ -80,5 +80,7 @@ struct malloc_interface {
void (*final) (void);
} malloclib_s;
+void memmgr_report (int extra);
+
struct malloc_interface *malloclib;
#endif /* _MALLOC_H_ */
diff --git a/src/common/mmo.h b/src/common/mmo.h
index d45dea212..a86aba723 100644
--- a/src/common/mmo.h
+++ b/src/common/mmo.h
@@ -71,7 +71,6 @@
#define MAX_HOTKEYS 38
#endif
-#define MAX_MAP_PER_SERVER 1500 // Increased to allow creation of Instance Maps
#define MAX_INVENTORY 100
//Max number of characters per account. Note that changing this setting alone is not enough if the client is not hexed to support more characters as well.
#define MAX_CHARS 9
@@ -526,6 +525,10 @@ struct guild {
/* TODO: still used for something?|: */
unsigned short save_flag; // for TXT saving
+
+ unsigned short *instance;
+ unsigned short instances;
+
void *channel;
};
diff --git a/src/common/socket.c b/src/common/socket.c
index 5126d231b..0459004cc 100644
--- a/src/common/socket.c
+++ b/src/common/socket.c
@@ -280,9 +280,10 @@ void set_nonblocking(int fd, unsigned long yes)
ShowError("set_nonblocking: Failed to set socket #%d to non-blocking mode (%s) - Please report this!!!\n", fd, error_msg());
}
-void setsocketopts(int fd)
-{
+void setsocketopts(int fd, struct hSockOpt *opt) {
int yes = 1; // reuse fix
+ struct linger lopt;
+
#if !defined(WIN32)
// set SO_REAUSEADDR to true, unix only. on windows this option causes
// the previous owner of the socket to give up, which is not desirable
@@ -297,15 +298,22 @@ void setsocketopts(int fd)
// The RO protocol is mainly single-packet request/response, plus the FIFO model already does packet grouping anyway.
sSetsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&yes, sizeof(yes));
+ if( opt && opt->setTimeo ) {
+ struct timeval timeout;
+
+ timeout.tv_sec = 5;
+ timeout.tv_usec = 0;
+
+ sSetsockopt(fd,SOL_SOCKET,SO_RCVTIMEO,(char *)&timeout,sizeof(timeout));
+ sSetsockopt(fd,SOL_SOCKET,SO_SNDTIMEO,(char *)&timeout,sizeof(timeout));
+ }
+
// force the socket into no-wait, graceful-close mode (should be the default, but better make sure)
//(http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/winsock/closesocket_2.asp)
- {
- struct linger opt;
- opt.l_onoff = 0; // SO_DONTLINGER
- opt.l_linger = 0; // Do not care
- if( sSetsockopt(fd, SOL_SOCKET, SO_LINGER, (char*)&opt, sizeof(opt)) )
+ lopt.l_onoff = 0; // SO_DONTLINGER
+ lopt.l_linger = 0; // Do not care
+ if( sSetsockopt(fd, SOL_SOCKET, SO_LINGER, (char*)&lopt, sizeof(lopt)) )
ShowWarning("setsocketopts: Unable to set SO_LINGER mode for connection #%d!\n", fd);
- }
}
/*======================================
@@ -404,8 +412,7 @@ void flush_fifos(void)
/*======================================
* CORE : Connection functions
*--------------------------------------*/
-int connect_client(int listen_fd)
-{
+int connect_client(int listen_fd) {
int fd;
struct sockaddr_in client_address;
socklen_t len;
@@ -417,20 +424,18 @@ int connect_client(int listen_fd)
ShowError("connect_client: accept failed (%s)!\n", error_msg());
return -1;
}
- if( fd == 0 )
- {// reserved
+ if( fd == 0 ) { // reserved
ShowError("connect_client: Socket #0 is reserved - Please report this!!!\n");
sClose(fd);
return -1;
}
- if( fd >= FD_SETSIZE )
- {// socket number too big
+ if( fd >= FD_SETSIZE ) { // socket number too big
ShowError("connect_client: New socket #%d is greater than can we handle! Increase the value of FD_SETSIZE (currently %d) for your OS to fix this!\n", fd, FD_SETSIZE);
sClose(fd);
return -1;
}
- setsocketopts(fd);
+ setsocketopts(fd,NULL);
set_nonblocking(fd, 1);
#ifndef MINICORE
@@ -457,25 +462,22 @@ int make_listen_bind(uint32 ip, uint16 port)
fd = sSocket(AF_INET, SOCK_STREAM, 0);
- if( fd == -1 )
- {
+ if( fd == -1 ) {
ShowError("make_listen_bind: socket creation failed (%s)!\n", error_msg());
exit(EXIT_FAILURE);
}
- if( fd == 0 )
- {// reserved
+ if( fd == 0 ) { // reserved
ShowError("make_listen_bind: Socket #0 is reserved - Please report this!!!\n");
sClose(fd);
return -1;
}
- if( fd >= FD_SETSIZE )
- {// socket number too big
+ if( fd >= FD_SETSIZE ) { // socket number too big
ShowError("make_listen_bind: New socket #%d is greater than can we handle! Increase the value of FD_SETSIZE (currently %d) for your OS to fix this!\n", fd, FD_SETSIZE);
sClose(fd);
return -1;
}
- setsocketopts(fd);
+ setsocketopts(fd,NULL);
set_nonblocking(fd, 1);
server_address.sin_family = AF_INET;
@@ -503,7 +505,7 @@ int make_listen_bind(uint32 ip, uint16 port)
return fd;
}
-int make_connection(uint32 ip, uint16 port, bool silent) {
+int make_connection(uint32 ip, uint16 port, struct hSockOpt *opt) {
struct sockaddr_in remote_address;
int fd;
int result;
@@ -514,31 +516,29 @@ int make_connection(uint32 ip, uint16 port, bool silent) {
ShowError("make_connection: socket creation failed (%s)!\n", error_msg());
return -1;
}
- if( fd == 0 )
- {// reserved
+ if( fd == 0 ) {// reserved
ShowError("make_connection: Socket #0 is reserved - Please report this!!!\n");
sClose(fd);
return -1;
}
- if( fd >= FD_SETSIZE )
- {// socket number too big
+ if( fd >= FD_SETSIZE ) {// socket number too big
ShowError("make_connection: New socket #%d is greater than can we handle! Increase the value of FD_SETSIZE (currently %d) for your OS to fix this!\n", fd, FD_SETSIZE);
sClose(fd);
return -1;
}
- setsocketopts(fd);
+ setsocketopts(fd,opt);
remote_address.sin_family = AF_INET;
remote_address.sin_addr.s_addr = htonl(ip);
remote_address.sin_port = htons(port);
- if( !silent )
+ if( !( opt && opt->silent ) )
ShowStatus("Connecting to %d.%d.%d.%d:%i\n", CONVIP(ip), port);
result = sConnect(fd, (struct sockaddr *)(&remote_address), sizeof(struct sockaddr_in));
if( result == SOCKET_ERROR ) {
- if( !silent )
+ if( !( opt && opt->silent ) )
ShowError("make_connection: connect failed (socket #%d, %s)!\n", fd, error_msg());
do_close(fd);
return -1;
diff --git a/src/common/socket.h b/src/common/socket.h
index 4879cb109..b58cbdccf 100644
--- a/src/common/socket.h
+++ b/src/common/socket.h
@@ -1,5 +1,6 @@
-// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
-// For more information, see LICENCE in the main folder
+// Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// See the LICENSE file
+// Portions Copyright (c) Athena Dev Teams
#ifndef _SOCKET_H_
#define _SOCKET_H_
@@ -48,6 +49,9 @@
} \
} while(0)
+/* [Ind/Hercules] */
+#define RFIFO2PTR(fd,len) (void*)(session[fd]->rdata + len)
+
// buffer I/O macros
#define RBUFP(p,pos) (((uint8*)(p)) + (pos))
#define RBUFB(p,pos) (*(uint8*)RBUFP((p),(pos)))
@@ -94,6 +98,10 @@ struct socket_data
void* session_data; // stores application-specific data related to the session
};
+struct hSockOpt {
+ unsigned int silent : 1;
+ unsigned int setTimeo : 1;
+};
// Data prototype declaration
@@ -113,7 +121,7 @@ extern bool session_isActive(int fd);
// Function prototype declaration
int make_listen_bind(uint32 ip, uint16 port);
-int make_connection(uint32 ip, uint16 port, bool silent);
+int make_connection(uint32 ip, uint16 port, struct hSockOpt *opt);
int realloc_fifo(int fd, unsigned int rfifo_size, unsigned int wfifo_size);
int realloc_writefifo(int fd, size_t addition);
int WFIFOSET(int fd, size_t len);
diff --git a/src/map/atcommand.c b/src/map/atcommand.c
index 65da7aa24..796447633 100644
--- a/src/map/atcommand.c
+++ b/src/map/atcommand.c
@@ -3940,7 +3940,7 @@ ACMD(mapinfo) {
for (i = 0; i < map[m_id].npc_num;)
{
nd = map[m_id].npc[i];
- switch(nd->ud.dir) {
+ switch(nd->dir) {
case 0: strcpy(direction, msg_txt(1101)); break; // North
case 1: strcpy(direction, msg_txt(1102)); break; // North West
case 2: strcpy(direction, msg_txt(1103)); break; // West
diff --git a/src/map/battleground.c b/src/map/battleground.c
index 618679406..4bb6035ad 100644
--- a/src/map/battleground.c
+++ b/src/map/battleground.c
@@ -9,6 +9,7 @@
#include "../common/showmsg.h"
#include "../common/socket.h"
#include "../common/strlib.h"
+#include "../common/conf.h"
#include "battleground.h"
#include "battle.h"
@@ -16,6 +17,7 @@
#include "map.h"
#include "npc.h"
#include "pc.h"
+#include "party.h"
#include "pet.h"
#include "homunculus.h"
#include "mercenary.h"
@@ -26,14 +28,12 @@
static DBMap* bg_team_db; // int bg_id -> struct battleground_data*
static unsigned int bg_team_counter = 0; // Next bg_id
-struct battleground_data* bg_team_search(int bg_id)
-{ // Search a BG Team using bg_id
+struct battleground_data* bg_team_search(int bg_id) { // Search a BG Team using bg_id
if( !bg_id ) return NULL;
return (struct battleground_data *)idb_get(bg_team_db, bg_id);
}
-struct map_session_data* bg_getavailablesd(struct battleground_data *bg)
-{
+struct map_session_data* bg_getavailablesd(struct battleground_data *bg) {
int i;
nullpo_retr(NULL, bg);
ARR_FIND(0, MAX_BG_MEMBERS, i, bg->members[i].sd != NULL);
@@ -95,8 +95,7 @@ int bg_team_join(int bg_id, struct map_session_data *sd)
guild->send_dot_remove(sd);
- for( i = 0; i < MAX_BG_MEMBERS; i++ )
- {
+ for( i = 0; i < MAX_BG_MEMBERS; i++ ) {
if( (pl_sd = bg->members[i].sd) != NULL && pl_sd != sd )
clif->hpmeter_single(sd->fd, pl_sd->bl.id, pl_sd->battle_status.hp, pl_sd->battle_status.max_hp);
}
@@ -152,8 +151,7 @@ int bg_member_respawn(struct map_session_data *sd)
return 1; // Warped
}
-int bg_create(unsigned short mapindex, short rx, short ry, const char *ev, const char *dev)
-{
+int bg_create(unsigned short mapindex, short rx, short ry, const char *ev, const char *dev) {
struct battleground_data *bg;
bg_team_counter++;
@@ -226,12 +224,10 @@ int bg_send_xy_timer_sub(DBKey key, DBData *data, va_list ap)
struct map_session_data *sd;
int i;
nullpo_ret(bg);
- for( i = 0; i < MAX_BG_MEMBERS; i++ )
- {
+ for( i = 0; i < MAX_BG_MEMBERS; i++ ) {
if( (sd = bg->members[i].sd) == NULL )
continue;
- if( sd->bl.x != bg->members[i].x || sd->bl.y != bg->members[i].y )
- { // xy update
+ if( sd->bl.x != bg->members[i].x || sd->bl.y != bg->members[i].y ) { // xy update
bg->members[i].x = sd->bl.x;
bg->members[i].y = sd->bl.y;
clif->bg_xy(sd);
@@ -240,20 +236,496 @@ int bg_send_xy_timer_sub(DBKey key, DBData *data, va_list ap)
return 0;
}
-int bg_send_xy_timer(int tid, unsigned int tick, int id, intptr_t data)
-{
+int bg_send_xy_timer(int tid, unsigned int tick, int id, intptr_t data) {
bg_team_db->foreach(bg_team_db, bg_send_xy_timer_sub, tick);
return 0;
}
+void bg_config_read(void) {
+ config_t bg_conf;
+ config_setting_t *data = NULL;
+ const char *config_filename = "conf/battlegrounds.conf"; // FIXME hardcoded name
+
+ if (conf_read_file(&bg_conf, config_filename))
+ return;
+
+ data = config_lookup(&bg_conf, "battlegrounds");
+
+ if (data != NULL) {
+ config_setting_t *settings = config_setting_get_elem(data, 0);
+ config_setting_t *arenas;
+ const char *delay_var;
+ int i, arena_count = 0, total = 0, offline = 0;
+
+ if( !config_setting_lookup_string(settings, "global_delay_var", &delay_var) )
+ delay_var = "BG_Delay_Tick";
+
+ safestrncpy(bg->gdelay_var, delay_var, BG_DELAY_VAR_LENGTH);
+
+ config_setting_lookup_int(settings, "maximum_afk_seconds", &bg->mafksec);
+
+ config_setting_lookup_bool(settings, "feature_off", &offline);
+
+ if( offline == 0 )
+ bg->queue_on = true;
+
+ if( (arenas = config_setting_get_member(settings, "arenas")) != NULL ) {
+ arena_count = config_setting_length(arenas);
+ CREATE( bg->arena, struct bg_arena *, arena_count );
+ for(i = 0; i < arena_count; i++) {
+ config_setting_t *arena = config_setting_get_elem(arenas, i);
+ config_setting_t *reward;
+ const char *aName, *aEvent, *aDelayVar;
+ int minLevel = 0, maxLevel = 0;
+ int prizeWin, prizeLoss, prizeDraw;
+ int minPlayers, maxPlayers, minTeamPlayers;
+ int maxDuration;
+ int fillup_duration, pregame_duration;
+
+ bg->arena[i] = NULL;
+
+ if( !config_setting_lookup_string(arena, "name", &aName) ) {
+ ShowError("bg_config_read: failed to find 'name' for arena #%d\n",i);
+ continue;
+ }
+
+ if( !config_setting_lookup_string(arena, "event", &aEvent) ) {
+ ShowError("bg_config_read: failed to find 'event' for arena #%d\n",i);
+ continue;
+ }
+
+ config_setting_lookup_int(arena, "minLevel", &minLevel);
+ config_setting_lookup_int(arena, "maxLevel", &maxLevel);
+
+ if( minLevel < 0 ) {
+ ShowWarning("bg_config_read: invalid %d value for arena '%s' minLevel\n",minLevel,aName);
+ minLevel = 0;
+ }
+ if( maxLevel > MAX_LEVEL ) {
+ ShowWarning("bg_config_read: invalid %d value for arena '%s' maxLevel\n",maxLevel,aName);
+ maxLevel = MAX_LEVEL;
+ }
+
+ if( !(reward = config_setting_get_member(settings, "reward")) ) {
+ ShowError("bg_config_read: failed to find 'reward' for arena '%s'/#%d\n",aName,i);
+ continue;
+ }
+
+ config_setting_lookup_int(reward, "win", &prizeWin);
+ config_setting_lookup_int(reward, "loss", &prizeLoss);
+ config_setting_lookup_int(reward, "draw", &prizeDraw);
+
+ if( prizeWin < 0 ) {
+ ShowWarning("bg_config_read: invalid %d value for arena '%s' reward:win\n",prizeWin,aName);
+ prizeWin = 0;
+ }
+ if( prizeLoss < 0 ) {
+ ShowWarning("bg_config_read: invalid %d value for arena '%s' reward:loss\n",prizeLoss,aName);
+ prizeLoss = 0;
+ }
+ if( prizeDraw < 0 ) {
+ ShowWarning("bg_config_read: invalid %d value for arena '%s' reward:draw\n",prizeDraw,aName);
+ prizeDraw = 0;
+ }
+
+ config_setting_lookup_int(arena, "minPlayers", &minPlayers);
+ config_setting_lookup_int(arena, "maxPlayers", &maxPlayers);
+ config_setting_lookup_int(arena, "minTeamPlayers", &minTeamPlayers);
+
+ if( minPlayers < 0 ) {
+ ShowWarning("bg_config_read: invalid %d value for arena '%s' minPlayers\n",minPlayers,aName);
+ minPlayers = 0;
+ }
+ if( maxPlayers > MAX_BG_MEMBERS * 2 ) {
+ ShowWarning("bg_config_read: invalid %d value for arena '%s' maxPlayers, change #define MAX_BG_MEMBERS\n",maxPlayers,aName);
+ maxPlayers = 0;
+ }
+ if( minTeamPlayers < 0 ) {
+ ShowWarning("bg_config_read: invalid %d value for arena '%s' minTeamPlayers\n",minTeamPlayers,aName);
+ minTeamPlayers = 0;
+ }
+
+ if( !config_setting_lookup_string(arena, "delay_var", &aDelayVar) ) {
+ ShowError("bg_config_read: failed to find 'delay_var' for arena '%s'/#%d\n",aName,i);
+ continue;
+ }
+
+ config_setting_lookup_int(arena, "maxDuration", &maxDuration);
+
+ if( maxDuration < 0 ) {
+ ShowWarning("bg_config_read: invalid %d value for arena '%s' maxDuration\n",maxDuration,aName);
+ maxDuration = 30;
+ }
+
+ config_setting_lookup_int(arena, "fillDuration", &fillup_duration);
+ config_setting_lookup_int(arena, "pGameDuration", &pregame_duration);
+
+ if( fillup_duration < 20 ) {
+ ShowWarning("bg_config_read: invalid %d value for arena '%s' fillDuration, minimum has to be 20, defaulting to 20.\n",fillup_duration,aName);
+ fillup_duration = 20;
+ }
+
+ if( pregame_duration < 20 ) {
+ ShowWarning("bg_config_read: invalid %d value for arena '%s' pGameDuration, minimum has to be 20, defaulting to 20.\n",pregame_duration,aName);
+ pregame_duration = 20;
+ }
+
+
+ CREATE( bg->arena[i], struct bg_arena, 1 );
+
+ bg->arena[i]->id = i;
+ safestrncpy(bg->arena[i]->name, aName, NAME_LENGTH);
+ safestrncpy(bg->arena[i]->npc_event, aEvent, EVENT_NAME_LENGTH);
+ bg->arena[i]->min_level = minLevel;
+ bg->arena[i]->max_level = maxLevel;
+ bg->arena[i]->prize_win = prizeWin;
+ bg->arena[i]->prize_loss = prizeLoss;
+ bg->arena[i]->prize_draw = prizeDraw;
+ bg->arena[i]->min_players = minPlayers;
+ bg->arena[i]->max_players = maxPlayers;
+ bg->arena[i]->min_team_players = minTeamPlayers;
+ safestrncpy(bg->arena[i]->delay_var, aDelayVar, NAME_LENGTH);
+ bg->arena[i]->maxDuration = maxDuration;
+ bg->arena[i]->queue_id = -1;
+ bg->arena[i]->begin_timer = INVALID_TIMER;
+ bg->arena[i]->fillup_timer = INVALID_TIMER;
+ bg->arena[i]->pregame_duration = pregame_duration;
+ bg->arena[i]->fillup_duration = fillup_duration;
+
+ total++;
+ }
+ bg->arenas = arena_count;
+ }
+
+ ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' arenas in '"CL_WHITE"%s"CL_RESET"'.\n", total, config_filename);
+ config_destroy(&bg_conf);
+ }
+}
+struct bg_arena *bg_name2arena (char *name) {
+ int i;
+ for(i = 0; i < bg->arenas; i++) {
+ if( strcmpi(bg->arena[i]->name,name) == 0 )
+ return bg->arena[i];
+ }
+ return NULL;
+}
+int bg_id2pos ( int queue_id, int account_id ) {
+ struct hQueue *queue = script->queue(queue_id);
+ if( queue ) {
+ int i;
+ for(i = 0; i < queue->items; i++ ) {
+ if( queue->item[i] == account_id ) {
+ return i;
+ }
+ }
+ }
+ return 0;
+}
+void bg_queue_player_cleanup(struct map_session_data *sd) {
+ if ( sd->bg_queue.client_has_bg_data ) {
+ clif->bgqueue_notice_delete(sd,BGQND_CLOSEWINDOW, sd->bg_queue.arena->id);
+ }
+ script->queue_remove(sd->bg_queue.arena->queue_id,sd->status.account_id);
+ sd->bg_queue.arena = NULL;
+ sd->bg_queue.ready = 0;
+ sd->bg_queue.client_has_bg_data = 0;
+ sd->bg_queue.type = 0;
+}
+void bg_match_over(struct bg_arena *arena, bool canceled) {
+ struct hQueue *queue = &script->hq[arena->queue_id];
+ int i;//, count = 0;
+
+ /* if( !canceled ) <check time/score> */
+
+ for( i = 0; i < queue->items; i++ ) {
+ struct map_session_data * sd = NULL;
+
+ if( ( sd = map_id2sd(queue->item[i]) ) ) {
+ bg->queue_pc_cleanup(sd);
+ clif->colormes(sd->fd,COLOR_RED,"BG Match Cancelled: not enough players");
+ }
+ }
-void do_init_battleground(void)
-{
+ bg->arena[i]->begin_timer = INVALID_TIMER;
+ bg->arena[i]->fillup_timer = INVALID_TIMER;
+ /* reset queue */
+}
+void bg_begin(struct bg_arena *arena) {
+ struct hQueue *queue = &script->hq[arena->queue_id];
+ int i, count = 0;
+
+ for( i = 0; i < queue->items; i++ ) {
+ struct map_session_data * sd = NULL;
+
+ if( ( sd = map_id2sd(queue->item[i]) ) ) {
+ if( sd->bg_queue.ready == 1 )
+ count++;
+ else
+ bg->queue_pc_cleanup(sd);
+ }
+ }
+
+ if( count < arena->min_players ) {
+ bg_match_over(arena,true);
+ } else {
+ ;
+ /* we split evenly? */
+ /* but if a party of say 10 joins, it cant be split evenly unless by luck there are 10 soloers in the queue besides them */
+ /* not sure how to split T_T needs more info */
+ }
+}
+int bg_begin_timer(int tid, unsigned int tick, int id, intptr_t data) {
+ bg->begin(bg->arena[id]);
+ return 0;
+}
+
+void bg_queue_pregame(struct bg_arena *arena) {
+ struct hQueue *queue = &script->hq[arena->queue_id];
+ int i;
+
+ for( i = 0; i < queue->items; i++ ) {
+ struct map_session_data * sd = NULL;
+
+ if( ( sd = map_id2sd(queue->item[i]) ) ) {
+ clif->bgqueue_battlebegins(sd,arena->id,SELF);
+ }
+ }
+ arena->begin_timer = add_timer( gettick() + (arena->pregame_duration*1000), bg->begin_timer, arena->id, 0 );
+}
+int bg_fillup_timer(int tid, unsigned int tick, int id, intptr_t data) {
+ bg->queue_pregame(bg->arena[id]);
+ return 0;
+}
+
+void bg_queue_check(struct bg_arena *arena) {
+ int count = script->hq[arena->queue_id].items;
+
+ if( count == arena->max_players ) {
+ if( arena->fillup_timer != INVALID_TIMER ) {
+ delete_timer(arena->fillup_timer,bg_fillup_timer);
+ arena->fillup_timer = INVALID_TIMER;
+ }
+ bg->queue_pregame(arena);
+ } else if( count >= arena->min_players && arena->fillup_timer == INVALID_TIMER ) {
+ arena->fillup_timer = add_timer( gettick() + (arena->fillup_duration*1000), bg->fillup_timer, arena->id, 0 );
+ }
+}
+void bg_queue_add(struct map_session_data *sd, struct bg_arena *arena, enum bg_queue_types type) {
+ enum BATTLEGROUNDS_QUEUE_ACK result = bg->can_queue(sd,arena,type);
+ struct hQueue *queue;
+ int i, count = 0;
+
+ if( arena->begin_timer != INVALID_TIMER ) {
+ clif->bgqueue_ack(sd,BGQA_FAIL_QUEUING_FINISHED,arena->id);
+ return;
+ }
+
+ if( result != BGQA_SUCCESS ) {
+ clif->bgqueue_ack(sd,result,arena->id);
+ return;
+ }
+
+ switch( type ) { /* guild/party already validated in can_queue */
+ case BGQT_PARTY: {
+ struct party_data *p = party_search(sd->status.party_id);
+ for( i = 0; i < MAX_PARTY; i++ ) {
+ if( !p->data[i].sd || p->data[i].sd->bg_queue.arena != NULL ) continue;
+ count++;
+ }
+ }
+ break;
+ case BGQT_GUILD:
+ for ( i=0; i<sd->guild->max_member; i++ ) {
+ if ( !sd->guild->member[i].sd || sd->guild->member[i].sd->bg_queue.arena != NULL )
+ continue;
+ count++;
+ }
+ break;
+ case BGQT_INDIVIDUAL:
+ count = 1;
+ break;
+ }
+
+ if( !(queue = script->queue(arena->queue_id)) || (queue->items+count) >= arena->max_players ) {
+ clif->bgqueue_ack(sd,BGQA_FAIL_PPL_OVERAMOUNT,arena->id);
+ return;
+ }
+
+ switch( type ) {
+ case BGQT_INDIVIDUAL:
+ sd->bg_queue.type = type;
+ sd->bg_queue.arena = arena;
+ sd->bg_queue.ready = 0;
+ script->queue_add(arena->queue_id,sd->status.account_id);
+ clif->bgqueue_joined(sd,script->hq[arena->queue_id].items);
+ clif->bgqueue_update_info(sd,arena->id,script->hq[arena->queue_id].items);
+ break;
+ case BGQT_PARTY: {
+ struct party_data *p = party_search(sd->status.party_id);
+ for( i = 0; i < MAX_PARTY; i++ ) {
+ if( !p->data[i].sd || p->data[i].sd->bg_queue.arena != NULL ) continue;
+ p->data[i].sd->bg_queue.type = type;
+ p->data[i].sd->bg_queue.arena = arena;
+ p->data[i].sd->bg_queue.ready = 0;
+ script->queue_add(arena->queue_id,p->data[i].sd->status.account_id);
+ clif->bgqueue_joined(p->data[i].sd,script->hq[arena->queue_id].items);
+ clif->bgqueue_update_info(p->data[i].sd,arena->id,script->hq[arena->queue_id].items);
+ }
+ }
+ break;
+ case BGQT_GUILD:
+ for ( i=0; i<sd->guild->max_member; i++ ) {
+ if ( !sd->guild->member[i].sd || sd->guild->member[i].sd->bg_queue.arena != NULL )
+ continue;
+ sd->guild->member[i].sd->bg_queue.type = type;
+ sd->guild->member[i].sd->bg_queue.arena = arena;
+ sd->guild->member[i].sd->bg_queue.ready = 0;
+ script->queue_add(arena->queue_id,sd->guild->member[i].sd->status.account_id);
+ clif->bgqueue_joined(sd->guild->member[i].sd,script->hq[arena->queue_id].items);
+ clif->bgqueue_update_info(sd->guild->member[i].sd,arena->id,script->hq[arena->queue_id].items);
+ }
+ break;
+ }
+
+ clif->bgqueue_ack(sd,BGQA_SUCCESS,arena->id);
+
+}
+enum BATTLEGROUNDS_QUEUE_ACK bg_canqueue(struct map_session_data *sd, struct bg_arena *arena, enum bg_queue_types type) {
+ int tick;
+ unsigned int tsec;
+ if ( sd->status.base_level > arena->max_level || sd->status.base_level < arena->max_level )
+ return BGQA_FAIL_LEVEL_INCORRECT;
+
+ if ( !(sd->class_&JOBL_2) ) /* TODO: maybe make this a per-arena setting, so users may make custom arenas like baby-only,whatever. */
+ return BGQA_FAIL_CLASS_INVALID;
+
+ tsec = time(NULL);
+
+ if ( ( tick = pc_readglobalreg(sd, bg->gdelay_var) ) && tsec < tick ) {
+ char response[100];
+ if( (tick-tsec) > 60 )
+ sprintf(response, "You are a deserter! Wait %d minute(s) before you can apply again",(tick-tsec)/60);
+ else
+ sprintf(response, "You are a deserter! Wait %d seconds before you can apply again",(tick-tsec));
+ clif->colormes(sd->fd,COLOR_RED,response);
+ return BGQA_FAIL_DESERTER;
+ }
+
+ if ( ( tick = pc_readglobalreg(sd, arena->cooldown_variable) ) && tsec < tick ) {
+ char response[100];
+ if( (tick-tsec) > 60 )
+ sprintf(response, "You can't reapply to this arena so fast. Apply to the different arena or wait %d minute(s)",(tick-tsec)/60);
+ else
+ sprintf(response, "You can't reapply to this arena so fast. Apply to the different arena or wait %d seconds",(tick-tsec));
+ clif->colormes(sd->fd,COLOR_RED,response);
+ return BGQA_FAIL_COOLDOWN;
+ }
+
+ if( sd->bg_queue.arena != NULL )
+ return BGQA_DUPLICATE_REQUEST;
+
+ switch(type) {
+ case BGQT_GUILD:
+ if( !sd->guild || !sd->state.gmaster_flag )
+ return BGQA_NOT_PARTY_GUILD_LEADER;
+ else {
+ int i, count = 0;
+ for ( i=0; i<sd->guild->max_member; i++ ) {
+ if ( !sd->guild->member[i].sd || sd->guild->member[i].sd->bg_queue.arena != NULL )
+ continue;
+ count++;
+ }
+ if ( count < arena->min_team_players ) {
+ char response[100];
+ if( count != sd->guild->connect_member && sd->guild->connect_member >= arena->min_team_players )
+ sprintf(response, "Can't apply: not enough members in your team/guild that have not entered the queue in individual mode, minimum is %d",arena->min_team_players);
+ else
+ sprintf(response, "Can't apply: not enough members in your team/guild, minimum is %d",arena->min_team_players);
+ clif->colormes(sd->fd,COLOR_RED,response);
+ return BGQA_FAIL_TEAM_COUNT;
+ }
+ }
+ break;
+ case BGQT_PARTY:
+ if( !sd->status.party_id )
+ return BGQA_NOT_PARTY_GUILD_LEADER;
+ else {
+ struct party_data *p;
+ if( (p = party_search(sd->status.party_id) ) ) {
+ int i, count = 0;
+ bool is_leader = false;
+
+ for(i = 0; i < MAX_PARTY; i++) {
+ if( !p->data[i].sd )
+ continue;
+ if( p->party.member[i].leader && sd == p->data[i].sd )
+ is_leader = true;
+ if( p->data[i].sd->bg_queue.arena == NULL )
+ count++;
+ }
+
+ if( !is_leader )
+ return BGQA_NOT_PARTY_GUILD_LEADER;
+
+ if( count < arena->min_team_players ) {
+ char response[100];
+ if( count != p->party.count && p->party.count >= arena->min_team_players )
+ sprintf(response, "Can't apply: not enough members in your team/party that have not entered the queue in individual mode, minimum is %d",arena->min_team_players);
+ else
+ sprintf(response, "Can't apply: not enough members in your team/party, minimum is %d",arena->min_team_players);
+ clif->colormes(sd->fd,COLOR_RED,response);
+ return BGQA_FAIL_TEAM_COUNT;
+ }
+
+ } else
+ return BGQA_NOT_PARTY_GUILD_LEADER;
+ }
+ break;
+ case BGQT_INDIVIDUAL:/* already did */
+ break;
+ default:
+ ShowDebug("bg_canqueue: unknown/unsupported type %d\n",type);
+ return BGQA_DUPLICATE_REQUEST;
+ }
+
+ return BGQA_SUCCESS;
+}
+void do_init_battleground(void) {
bg_team_db = idb_alloc(DB_OPT_RELEASE_DATA);
add_timer_func_list(bg_send_xy_timer, "bg_send_xy_timer");
add_timer_interval(gettick() + battle_config.bg_update_interval, bg_send_xy_timer, 0, 0, battle_config.bg_update_interval);
}
-void do_final_battleground(void)
-{
+void do_final_battleground(void) {
+ int i;
+
bg_team_db->destroy(bg_team_db, NULL);
+
+ for( i = 0; i < bg->arenas; i++ ) {
+ if( bg->arena[i] )
+ aFree(bg->arena[i]);
+ }
+
+ if( bg->arena )
+ aFree(bg->arena);
+}
+void battleground_defaults(void) {
+ bg = &bg_s;
+
+ bg->queue_on = false;
+
+ bg->mafksec = 0;
+ bg->arena = NULL;
+ bg->arenas = 0;
+ /* */
+ bg->name2arena = bg_name2arena;
+ bg->queue_add = bg_queue_add;
+ bg->can_queue = bg_canqueue;
+ bg->id2pos = bg_id2pos;
+ bg->queue_pc_cleanup = bg_queue_player_cleanup;
+ bg->begin = bg_begin;
+ bg->begin_timer = bg_begin_timer;
+ bg->queue_pregame = bg_queue_pregame;
+ bg->fillup_timer = bg_fillup_timer;
+ /* */
+ bg->config_read = bg_config_read;
}
diff --git a/src/map/battleground.h b/src/map/battleground.h
index c2b74a534..8fe9f3b77 100644
--- a/src/map/battleground.h
+++ b/src/map/battleground.h
@@ -1,5 +1,6 @@
-// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
-// For more information, see LICENCE in the main folder
+// Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// See the LICENSE file
+// Portions Copyright (c) Athena Dev Teams
#ifndef _BATTLEGROUND_H_
#define _BATTLEGROUND_H_
@@ -7,7 +8,21 @@
#include "../common/mmo.h" // struct party
#include "guild.h"
+/**
+ * Defines
+ **/
#define MAX_BG_MEMBERS 30
+#define BG_DELAY_VAR_LENGTH 30
+
+/**
+ * Enumerations
+ **/
+enum bg_queue_types {
+ BGQT_INVALID,
+ BGQT_INDIVIDUAL,
+ BGQT_PARTY,
+ BGQT_GUILD
+};
struct battleground_member_data {
unsigned short x, y;
@@ -42,4 +57,51 @@ int bg_team_warp(int bg_id, unsigned short mapindex, short x, short y);
int bg_member_respawn(struct map_session_data *sd);
int bg_send_message(struct map_session_data *sd, const char *mes, int len);
+struct bg_arena {
+ char name[NAME_LENGTH];
+ unsigned char id;
+ char npc_event[EVENT_NAME_LENGTH];
+ short min_level, max_level;
+ short prize_win, prize_loss, prize_draw;
+ short min_players;
+ short max_players;
+ short min_team_players;
+ char cooldown_variable[NAME_LENGTH];
+ char delay_var[NAME_LENGTH];
+ unsigned short maxDuration;
+ int queue_id;
+ int begin_timer;
+ int fillup_timer;
+ int game_timer;
+ unsigned short fillup_duration;
+ unsigned short pregame_duration;
+};
+
+/* battleground.c interface (incomplete) */
+struct battleground_interface {
+ bool queue_on;
+ /* */
+ int mafksec;
+ char gdelay_var[BG_DELAY_VAR_LENGTH];
+ /* */
+ struct bg_arena **arena;
+ unsigned char arenas;
+ /* */
+ struct bg_arena *(*name2arena) (char *name);
+ void (*queue_add) (struct map_session_data *sd, struct bg_arena *arena, enum bg_queue_types type);
+ enum BATTLEGROUNDS_QUEUE_ACK (*can_queue) (struct map_session_data *sd, struct bg_arena *arena, enum bg_queue_types type);
+ int (*id2pos) (int queue_id, int account_id);
+ void (*queue_pc_cleanup) (struct map_session_data *sd);
+ void (*begin) (struct bg_arena *arena);
+ int (*begin_timer) (int tid, unsigned int tick, int id, intptr_t data);
+ void (*queue_pregame) (struct bg_arena *arena);
+ int (*fillup_timer) (int tid, unsigned int tick, int id, intptr_t data);
+ /* */
+ void (*config_read) (void);
+} bg_s;
+
+struct battleground_interface *bg;
+
+void battleground_defaults(void);
+
#endif /* _BATTLEGROUND_H_ */
diff --git a/src/map/chrif.c b/src/map/chrif.c
index 06956e731..ee2e252c1 100644
--- a/src/map/chrif.c
+++ b/src/map/chrif.c
@@ -344,9 +344,9 @@ int chrif_sendmap(int fd) {
ShowStatus("Sending maps to char server...\n");
// Sending normal maps, not instances
- WFIFOHEAD(fd, 4 + instance_start * 4);
+ WFIFOHEAD(fd, 4 + instance->start_id * 4);
WFIFOW(fd,0) = 0x2afa;
- for(i = 0; i < instance_start; i++)
+ for(i = 0; i < instance->start_id; i++)
WFIFOW(fd,4+i*4) = map[i].index;
WFIFOW(fd,2) = 4 + i * 4;
WFIFOSET(fd,WFIFOW(fd,2));
@@ -1537,9 +1537,8 @@ static int check_connect_char_server(int tid, unsigned int tick, int id, intptr_
}
chrif_state = 0;
- char_fd = make_connection(char_ip, char_port,false);
- if (char_fd == -1)//Attempt to connect later. [Skotlex]
+ if ( ( char_fd = make_connection(char_ip, char_port,NULL) ) == -1) //Attempt to connect later. [Skotlex]
return 0;
session[char_fd]->func_parse = chrif_parse;
diff --git a/src/map/clif.c b/src/map/clif.c
index 2f69ce2fd..99b4d8c11 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -1333,7 +1333,7 @@ int clif_spawn(struct block_list *bl)
/**
* Hide NPC from maya purple card.
**/
- if(bl->type == BL_NPC && !((TBL_NPC*)bl)->chat_id && (((TBL_NPC*)bl)->sc.option&OPTION_INVISIBLE))
+ if(bl->type == BL_NPC && !((TBL_NPC*)bl)->chat_id && (((TBL_NPC*)bl)->option&OPTION_INVISIBLE))
return 0;
clif->spawn_unit(bl,AREA_WOS);
@@ -1612,7 +1612,7 @@ void clif_move(struct unit_data *ud)
/**
* Hide NPC from maya purple card.
**/
- if(bl->type == BL_NPC && !((TBL_NPC*)bl)->chat_id && (((TBL_NPC*)bl)->sc.option&OPTION_INVISIBLE))
+ if(bl->type == BL_NPC && !((TBL_NPC*)bl)->chat_id && (((TBL_NPC*)bl)->option&OPTION_INVISIBLE))
return;
if (ud->state.speed_changed) {
@@ -1666,15 +1666,14 @@ void clif_quitsave(int fd,struct map_session_data *sd) {
/// Notifies the client of a position change to coordinates on given map (ZC_NPCACK_MAPMOVE).
/// 0091 <map name>.16B <x>.W <y>.W
-void clif_changemap(struct map_session_data *sd, short map, int x, int y)
-{
+void clif_changemap(struct map_session_data *sd, short m, int x, int y) {
int fd;
nullpo_retv(sd);
fd = sd->fd;
WFIFOHEAD(fd,packet_len(0x91));
WFIFOW(fd,0) = 0x91;
- mapindex_getmapname_ext(mapindex_id2name(map), (char*)WFIFOP(fd,2));
+ mapindex_getmapname_ext(map[m].cName ? map[m].cName : map[m].name, (char*)WFIFOP(fd,2));
WFIFOW(fd,18) = x;
WFIFOW(fd,20) = y;
WFIFOSET(fd,packet_len(0x91));
@@ -1683,8 +1682,7 @@ void clif_changemap(struct map_session_data *sd, short map, int x, int y)
/// Notifies the client of a position change to coordinates on given map, which is on another map-server (ZC_NPCACK_SERVERMOVE).
/// 0092 <map name>.16B <x>.W <y>.W <ip>.L <port>.W
-void clif_changemapserver(struct map_session_data* sd, unsigned short map_index, int x, int y, uint32 ip, uint16 port)
-{
+void clif_changemapserver(struct map_session_data* sd, unsigned short map_index, int x, int y, uint32 ip, uint16 port) {
int fd;
nullpo_retv(sd);
fd = sd->fd;
@@ -4344,7 +4342,7 @@ void clif_getareachar_unit(struct map_session_data* sd,struct block_list *bl) {
/**
* Hide NPC from maya purple card.
**/
- if(bl->type == BL_NPC && !((TBL_NPC*)bl)->chat_id && (((TBL_NPC*)bl)->sc.option&OPTION_INVISIBLE))
+ if(bl->type == BL_NPC && !((TBL_NPC*)bl)->chat_id && (((TBL_NPC*)bl)->option&OPTION_INVISIBLE))
return;
if ( ( ud = unit_bl2ud(bl) ) && ud->walktimer != INVALID_TIMER )
@@ -4601,16 +4599,13 @@ void clif_changemapcell(int fd, int16 m, int x, int y, int type, enum send_targe
WBUFW(buf,2) = x;
WBUFW(buf,4) = y;
WBUFW(buf,6) = type;
- mapindex_getmapname_ext(map[m].name,(char*)WBUFP(buf,8));
+ mapindex_getmapname_ext(map[m].cName ? map[m].cName : map[m].name,(char*)WBUFP(buf,8));
- if( fd )
- {
+ if( fd ) {
WFIFOHEAD(fd,packet_len(0x192));
memcpy(WFIFOP(fd,0), buf, packet_len(0x192));
WFIFOSET(fd,packet_len(0x192));
- }
- else
- {
+ } else {
struct block_list dummy_bl;
dummy_bl.type = BL_NUL;
dummy_bl.x = x;
@@ -4799,7 +4794,7 @@ int clif_outsight(struct block_list *bl,va_list ap)
clif->clearchar_skillunit((struct skill_unit *)bl,tsd->fd);
break;
case BL_NPC:
- if( !(((TBL_NPC*)bl)->sc.option&OPTION_INVISIBLE) )
+ if( !(((TBL_NPC*)bl)->option&OPTION_INVISIBLE) )
clif->clearunit_single(bl->id,CLR_OUTSIGHT,tsd->fd);
break;
default:
@@ -4810,7 +4805,7 @@ int clif_outsight(struct block_list *bl,va_list ap)
}
if (sd && sd->fd) { //sd is watching tbl go out of view.
if (((vd=status_get_viewdata(tbl)) && vd->class_ != INVISIBLE_CLASS) &&
- !(tbl->type == BL_NPC && (((TBL_NPC*)tbl)->sc.option&OPTION_INVISIBLE)))
+ !(tbl->type == BL_NPC && (((TBL_NPC*)tbl)->option&OPTION_INVISIBLE)))
clif->clearunit_single(tbl->id,CLR_OUTSIGHT,sd->fd);
}
return 0;
@@ -6529,7 +6524,7 @@ void clif_party_member_info(struct party_data *p, struct map_session_data *sd)
WBUFB(buf,14) = (p->party.member[i].online)?0:1;
memcpy(WBUFP(buf,15), p->party.name, NAME_LENGTH);
memcpy(WBUFP(buf,39), sd->status.name, NAME_LENGTH);
- mapindex_getmapname_ext(map[sd->bl.m].name, (char*)WBUFP(buf,63));
+ mapindex_getmapname_ext(map[sd->bl.m].cName ? map[sd->bl.m].cName : map[sd->bl.m].name, (char*)WBUFP(buf,63));
WBUFB(buf,79) = (p->party.item&1)?1:0;
WBUFB(buf,80) = (p->party.item&2)?1:0;
clif->send(buf,packet_len(0x1e9),&sd->bl,PARTY);
@@ -8485,7 +8480,7 @@ void clif_refresh(struct map_session_data *sd)
int i;
nullpo_retv(sd);
- clif->changemap(sd,sd->mapindex,sd->bl.x,sd->bl.y);
+ clif->changemap(sd,sd->bl.m,sd->bl.x,sd->bl.y);
clif->inventorylist(sd);
if(pc_iscarton(sd)) {
clif->cartlist(sd);
@@ -9328,7 +9323,7 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd)
if (sd->state.rewarp) { //Rewarp player.
sd->state.rewarp = 0;
- clif->changemap(sd, sd->mapindex, sd->bl.x, sd->bl.y);
+ clif->changemap(sd, sd->bl.m, sd->bl.x, sd->bl.y);
return;
}
@@ -9372,9 +9367,9 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd)
if( !(sd->sc.option&OPTION_INVISIBLE) ) { // increment the number of pvp players on the map
map[sd->bl.m].users_pvp++;
}
- if( map[sd->bl.m].instance_id ) {
- instance[map[sd->bl.m].instance_id].users++;
- instance_check_idle(map[sd->bl.m].instance_id);
+ if( map[sd->bl.m].instance_id >= 0 ) {
+ instances[map[sd->bl.m].instance_id].users++;
+ instance->check_idle(map[sd->bl.m].instance_id);
}
sd->state.debug_remove_map = 0; // temporary state to track double remove_map's [FlavioJS]
@@ -15573,48 +15568,61 @@ void clif_font(struct map_session_data *sd)
/*==========================================
* Instancing Window
*------------------------------------------*/
-int clif_instance(int instance_id, int type, int flag)
-{
+int clif_instance(int instance_id, int type, int flag) {
struct map_session_data *sd;
- struct party_data *p;
unsigned char buf[255];
+ enum send_target target = PARTY;
+
+ switch( instances[instance_id].owner_type ) {
+ case IOT_NONE:
+ return 0;
+ case IOT_GUILD:
+ target = GUILD;
+ sd = guild->getavailablesd(guild->search(instances[instance_id].owner_id));
+ break;
+ case IOT_PARTY:
+ /* default is already PARTY */
+ sd = party_getavailablesd(party_search(instances[instance_id].owner_id));
+ break;
+ case IOT_CHAR:
+ target = SELF;
+ sd = map_id2sd(instances[instance_id].owner_id);
+ break;
+ }
- if( (p = party_search(instance[instance_id].party_id)) == NULL || (sd = party_getavailablesd(p)) == NULL )
+ if( !sd )
return 0;
-
+
switch( type ) {
case 1:
// S 0x2cb <Instance name>.61B <Standby Position>.W
// Required to start the instancing information window on Client
// This window re-appear each "refresh" of client automatically until type 4 is send to client.
WBUFW(buf,0) = 0x02CB;
- memcpy(WBUFP(buf,2),instance[instance_id].name,INSTANCE_NAME_LENGTH);
+ memcpy(WBUFP(buf,2),instances[instance_id].name,INSTANCE_NAME_LENGTH);
WBUFW(buf,63) = flag;
- clif->send(buf,packet_len(0x02CB),&sd->bl,PARTY);
+ clif->send(buf,packet_len(0x02CB),&sd->bl,target);
break;
case 2:
// S 0x2cc <Standby Position>.W
// To announce Instancing queue creation if no maps available
WBUFW(buf,0) = 0x02CC;
WBUFW(buf,2) = flag;
- clif->send(buf,packet_len(0x02CC),&sd->bl,PARTY);
+ clif->send(buf,packet_len(0x02CC),&sd->bl,target);
break;
case 3:
case 4:
// S 0x2cd <Instance Name>.61B <Instance Remaining Time>.L <Instance Noplayers close time>.L
WBUFW(buf,0) = 0x02CD;
- memcpy(WBUFP(buf,2),instance[instance_id].name,61);
- if( type == 3 )
- {
- WBUFL(buf,63) = (uint32)instance[instance_id].progress_timeout;
+ memcpy(WBUFP(buf,2),instances[instance_id].name,61);
+ if( type == 3 ) {
+ WBUFL(buf,63) = instances[instance_id].progress_timeout;
WBUFL(buf,67) = 0;
- }
- else
- {
+ } else {
WBUFL(buf,63) = 0;
- WBUFL(buf,67) = (uint32)instance[instance_id].idle_timeout;
+ WBUFL(buf,67) = instances[instance_id].idle_timeout;
}
- clif->send(buf,packet_len(0x02CD),&sd->bl,PARTY);
+ clif->send(buf,packet_len(0x02CD),&sd->bl,target);
break;
case 5:
// S 0x2ce <Message ID>.L
@@ -15626,7 +15634,7 @@ int clif_instance(int instance_id, int type, int flag)
WBUFW(buf,0) = 0x02CE;
WBUFL(buf,2) = flag;
//WBUFL(buf,6) = EnterLimitDate;
- clif->send(buf,packet_len(0x02CE),&sd->bl,PARTY);
+ clif->send(buf,packet_len(0x02CE),&sd->bl,target);
break;
}
return 0;
@@ -15634,24 +15642,24 @@ int clif_instance(int instance_id, int type, int flag)
void clif_instance_join(int fd, int instance_id)
{
- if( instance[instance_id].idle_timer != INVALID_TIMER ) {
+ if( instances[instance_id].idle_timer != INVALID_TIMER ) {
WFIFOHEAD(fd,packet_len(0x02CD));
WFIFOW(fd,0) = 0x02CD;
- memcpy(WFIFOP(fd,2),instance[instance_id].name,61);
+ memcpy(WFIFOP(fd,2),instances[instance_id].name,61);
WFIFOL(fd,63) = 0;
- WFIFOL(fd,67) = (uint32)instance[instance_id].idle_timeout;
+ WFIFOL(fd,67) = instances[instance_id].idle_timeout;
WFIFOSET(fd,packet_len(0x02CD));
- } else if( instance[instance_id].progress_timer != INVALID_TIMER ) {
+ } else if( instances[instance_id].progress_timer != INVALID_TIMER ) {
WFIFOHEAD(fd,packet_len(0x02CD));
WFIFOW(fd,0) = 0x02CD;
- memcpy(WFIFOP(fd,2),instance[instance_id].name,61);
- WFIFOL(fd,63) = (uint32)instance[instance_id].progress_timeout;;
+ memcpy(WFIFOP(fd,2),instances[instance_id].name,61);
+ WFIFOL(fd,63) = instances[instance_id].progress_timeout;
WFIFOL(fd,67) = 0;
WFIFOSET(fd,packet_len(0x02CD));
} else {
WFIFOHEAD(fd,packet_len(0x02CB));
WFIFOW(fd,0) = 0x02CB;
- memcpy(WFIFOP(fd,2),instance[instance_id].name,61);
+ memcpy(WFIFOP(fd,2),instances[instance_id].name,61);
WFIFOW(fd,63) = 0;
WFIFOSET(fd,packet_len(0x02CB));
}
@@ -16949,6 +16957,124 @@ void clif_status_change_end(struct block_list *bl, int tid, enum send_target tar
clif->send(&p,sizeof(p), bl, target);
}
+void clif_bgqueue_ack(struct map_session_data *sd, enum BATTLEGROUNDS_QUEUE_ACK response, unsigned char arena_id) {
+
+ switch (response) {
+ case BGQA_FAIL_COOLDOWN:
+ case BGQA_FAIL_DESERTER:
+ case BGQA_FAIL_TEAM_COUNT:
+ break;
+ default: {
+ struct packet_bgqueue_ack p;
+
+ p.PacketType = bgqueue_ackType;
+ p.type = response;
+ safestrncpy(p.bg_name, bg->arena[arena_id]->name, sizeof(p.bg_name));
+
+ clif->send(&p,sizeof(p), &sd->bl, SELF);
+ }
+ break;
+ }
+}
+
+
+void clif_bgqueue_notice_delete(struct map_session_data *sd, enum BATTLEGROUNDS_QUEUE_NOTICE_DELETED response, unsigned char arena_id) {
+ struct packet_bgqueue_notice_delete p;
+
+ p.PacketType = bgqueue_notice_deleteType;
+ p.type = response;
+ safestrncpy(p.bg_name, bg->arena[arena_id]->name, sizeof(p.bg_name));
+
+ clif->send(&p,sizeof(p), &sd->bl, SELF);
+}
+
+void clif_parse_bgqueue_register(int fd, struct map_session_data *sd) {
+ struct packet_bgqueue_register *p = P2PTR(fd, bgqueue_registerType);
+ struct bg_arena *arena = NULL;
+
+ if( !bg->queue_on ) return; /* temp, until feature is complete */
+
+ if( !(arena = bg->name2arena(p->bg_name)) ) {
+ clif->bgqueue_ack(sd,BGQA_FAIL_BGNAME_INVALID,0);
+ return;
+ }
+
+ switch( (enum bg_queue_types)p->type ) {
+ case BGQT_INDIVIDUAL:
+ case BGQT_PARTY:
+ case BGQT_GUILD:
+ break;
+ default:
+ clif->bgqueue_ack(sd,BGQA_FAIL_TYPE_INVALID, arena->id);
+ return;
+ }
+
+ bg->queue_add(sd, arena, (enum bg_queue_types)p->type);
+}
+
+void clif_bgqueue_update_info(struct map_session_data *sd, unsigned char arena_id, int position) {
+ struct packet_bgqueue_update_info p;
+
+ p.PacketType = bgqueue_updateinfoType;
+ safestrncpy(p.bg_name, bg->arena[arena_id]->name, sizeof(p.bg_name));
+ p.position = position;
+
+ sd->bg_queue.client_has_bg_data = true; // Client creates bg data when this packet arrives
+
+ clif->send(&p,sizeof(p), &sd->bl, SELF);
+}
+
+void clif_parse_bgqueue_checkstate(int fd, struct map_session_data *sd) {
+ //struct packet_bgqueue_checkstate *p = P2PTR(fd, bgqueue_checkstateType); /* TODO: bgqueue_notice_delete should use this p->bg_name */
+ if( !bg->queue_on ) return; /* temp, until feature is complete */
+ if ( sd->bg_queue.arena && sd->bg_queue.type ) {
+ sd->bg_queue.client_has_bg_data = true;
+ clif->bgqueue_update_info(sd,sd->bg_queue.arena->id,bg->id2pos(sd->bg_queue.arena->queue_id,sd->status.account_id));
+ } else
+ clif->bgqueue_notice_delete(sd, BGQND_FAIL_NOT_QUEUING,0);/* TODO: wrong response, should respond with p->bg_name not id 0 */
+}
+
+void clif_parse_bgqueue_revoke_req(int fd, struct map_session_data *sd) {
+ //struct packet_bgqueue_revoke_req *p = P2PTR(fd, bgqueue_revokereqType);
+ return;
+ //bg->queue_leave(sd, p->bg_name);
+}
+
+void clif_parse_bgqueue_battlebegin_ack(int fd, struct map_session_data *sd) {
+ //struct packet_bgqueue_battlebegin_ack *p = P2PTR(fd, bgqueue_checkstateType);
+ return;
+ //if ( p->result == 1 )
+ // bg->queue_pc_ready(sd);
+ //else
+ // bg->queue_leave(sd, p->bg_name);
+}
+
+void clif_bgqueue_joined(struct map_session_data *sd, int pos) {
+ struct packet_bgqueue_notify_entry p;
+
+ p.PacketType = bgqueue_notify_entryType;
+ safestrncpy(p.name,sd->status.name,sizeof(p.name));
+ p.position = pos;
+
+ clif->send(&p,sizeof(p), &sd->bl, BG_QUEUE);
+}
+
+void clif_bgqueue_pcleft(struct map_session_data *sd) {
+ /* no idea */
+ return;
+}
+
+// Sends BG ready req to all with same bg arena/type as sd
+void clif_bgqueue_battlebegins(struct map_session_data *sd, unsigned char arena_id, enum send_target target) {
+ struct packet_bgqueue_battlebegins p;
+
+ p.PacketType = bgqueue_battlebegins;
+ safestrncpy(p.bg_name, bg->arena[arena_id]->name, sizeof(p.bg_name));
+ safestrncpy(p.game_name, bg->arena[arena_id]->name, sizeof(p.game_name));
+
+ clif->send(&p,sizeof(p), &sd->bl, target);
+}
+
/*==========================================
* Main client packet processing function
*------------------------------------------*/
@@ -17124,6 +17250,7 @@ void clif_bc_ready(void) {
int do_init_clif(void) {
const char* colors[COLOR_MAX] = { "0xFF0000", "0x00ff00", "0xffffff" };
int i;
+
/**
* Setup Color Table (saves unnecessary load of strtoul on every call)
**/
@@ -17613,13 +17740,7 @@ void clif_defaults(void) {
/* elemental-related */
clif->elemental_info = clif_elemental_info;
clif->elemental_updatestatus = clif_elemental_updatestatus;
- /* misc-handling */
- clif->adopt_reply = clif_Adopt_reply;
- clif->adopt_request = clif_Adopt_request;
- clif->readbook = clif_readbook;
- clif->notify_time = clif_notify_time;
- clif->user_count = clif_user_count;
- clif->noask_sub = clif_noask_sub;
+ /* Hercules Channel System */
clif->chsys_create = clif_hercules_chsys_create;
clif->chsys_msg = clif_hercules_chsys_msg;
clif->chsys_msg2 = clif_hercules_chsys_msg2;
@@ -17632,6 +17753,20 @@ void clif_defaults(void) {
clif->chsys_quitg = clif_hercules_chsys_quitg;
clif->chsys_gjoin = clif_hercules_chsys_gjoin;
clif->chsys_gleave = clif_hercules_chsys_gleave;
+ /* bgqueue */
+ clif->bgqueue_ack = clif_bgqueue_ack;
+ clif->bgqueue_notice_delete = clif_bgqueue_notice_delete;
+ clif->bgqueue_update_info = clif_bgqueue_update_info;
+ clif->bgqueue_joined = clif_bgqueue_joined;
+ clif->bgqueue_pcleft = clif_bgqueue_pcleft;
+ clif->bgqueue_battlebegins = clif_bgqueue_battlebegins;
+ /* misc-handling */
+ clif->adopt_reply = clif_Adopt_reply;
+ clif->adopt_request = clif_Adopt_request;
+ clif->readbook = clif_readbook;
+ clif->notify_time = clif_notify_time;
+ clif->user_count = clif_user_count;
+ clif->noask_sub = clif_noask_sub;
clif->cashshop_load = clif_cashshop_db;
clif->bc_ready = clif_bc_ready;
clif->undisguise_timer = clif_undisguise_timer;
@@ -17837,6 +17972,11 @@ void clif_defaults(void) {
clif->pCashShopReqTab = clif_parse_CashShopReqTab;
clif->pCashShopSchedule = clif_parse_CashShopSchedule;
clif->pCashShopBuy = clif_parse_CashShopBuy;
+ /* BGQueue */
+ clif->pBGQueueRegister = clif_parse_bgqueue_register;
+ clif->pBGQueueCheckState = clif_parse_bgqueue_checkstate;
+ clif->pBGQueueRevokeReq = clif_parse_bgqueue_revoke_req;
+ clif->pBGQueueBattleBeginAck = clif_parse_bgqueue_battlebegin_ack;
/* */
clif->pPartyTick = clif_parse_PartyTick;
clif->pGuildInvite2 = clif_parse_GuildInvite2;
diff --git a/src/map/clif.h b/src/map/clif.h
index 3e3db98c1..4347ad743 100644
--- a/src/map/clif.h
+++ b/src/map/clif.h
@@ -8,6 +8,7 @@
#include "../common/cbasetypes.h"
#include "../common/db.h"
#include "../common/mmo.h"
+#include "../common/socket.h"
#include <stdarg.h>
/**
@@ -42,6 +43,7 @@ struct eri;
* Defines
**/
#define packet_len(cmd) packet_db[cmd].len
+#define P2PTR(fd,cmd) RFIFO2PTR(fd,packet_db[cmd].len)
#define clif_menuskill_clear(sd) (sd)->menuskill_id = (sd)->menuskill_val = (sd)->menuskill_val2 = 0;
#define HCHSYS_NAME_LENGTH 20
@@ -86,6 +88,8 @@ typedef enum send_target {
BG_SAMEMAP_WOS,
BG_AREA,
BG_AREA_WOS,
+
+ BG_QUEUE,
} send_target;
typedef enum emotion_type {
@@ -365,6 +369,29 @@ enum CASH_SHOP_BUY_RESULT {
CSBR_UNKNOWN = 0xb,
};
+enum BATTLEGROUNDS_QUEUE_ACK {
+ BGQA_SUCCESS = 1,
+ BGQA_FAIL_QUEUING_FINISHED,
+ BGQA_FAIL_BGNAME_INVALID,
+ BGQA_FAIL_TYPE_INVALID,
+ BGQA_FAIL_PPL_OVERAMOUNT,
+ BGQA_FAIL_LEVEL_INCORRECT,
+ BGQA_DUPLICATE_REQUEST,
+ BGQA_PLEASE_RELOGIN,
+ BGQA_NOT_PARTY_GUILD_LEADER,
+ BGQA_FAIL_CLASS_INVALID,
+ /* not official way to respond (gotta find packet?) */
+ BGQA_FAIL_DESERTER,
+ BGQA_FAIL_COOLDOWN,
+ BGQA_FAIL_TEAM_COUNT,
+};
+
+enum BATTLEGROUNDS_QUEUE_NOTICE_DELETED {
+ BGQND_CLOSEWINDOW = 1,
+ BGQND_FAIL_BGNAME_WRONG = 3,
+ BGQND_FAIL_NOT_QUEUING = 11,
+};
+
/**
* Structures
**/
@@ -499,7 +526,7 @@ struct clif_interface {
/* main unit spawn */
int (*spawn) (struct block_list *bl);
/* map-related */
- void (*changemap) (struct map_session_data *sd, short map, int x, int y);
+ void (*changemap) (struct map_session_data *sd, short m, int x, int y);
void (*changemapcell) (int fd, int16 m, int x, int y, int type, enum send_target target);
void (*map_property) (struct map_session_data* sd, enum map_property property);
void (*pvpset) (struct map_session_data *sd, int pvprank, int pvpnum,int type);
@@ -860,6 +887,13 @@ struct clif_interface {
/* elemental-related */
void (*elemental_info) (struct map_session_data *sd);
void (*elemental_updatestatus) (struct map_session_data *sd, int type);
+ /* bgqueue */
+ void (*bgqueue_ack) (struct map_session_data *sd, enum BATTLEGROUNDS_QUEUE_ACK response, unsigned char arena_id);
+ void (*bgqueue_notice_delete) (struct map_session_data *sd, enum BATTLEGROUNDS_QUEUE_NOTICE_DELETED response, unsigned char arena_id);
+ void (*bgqueue_update_info) (struct map_session_data *sd, unsigned char arena_id, int position);
+ void (*bgqueue_joined) (struct map_session_data *sd, int pos);
+ void (*bgqueue_pcleft) (struct map_session_data *sd);
+ void (*bgqueue_battlebegins) (struct map_session_data *sd, unsigned char arena_id, enum send_target target);
/* misc-handling */
void (*adopt_reply) (struct map_session_data *sd, int type);
void (*adopt_request) (struct map_session_data *sd, struct map_session_data *src, int p_id);
@@ -1078,6 +1112,11 @@ struct clif_interface {
void (*pSkillSelectMenu) (int fd, struct map_session_data *sd);
void (*pMoveItem) (int fd, struct map_session_data *sd);
void (*pDull) (int fd, struct map_session_data *sd);
+ /* BGQueue */
+ void (*pBGQueueRegister) (int fd, struct map_session_data *sd);
+ void (*pBGQueueCheckState) (int fd, struct map_session_data *sd);
+ void (*pBGQueueRevokeReq) (int fd, struct map_session_data *sd);
+ void (*pBGQueueBattleBeginAck) (int fd, struct map_session_data *sd);
/* RagExe Cash Shop [Ind/Hercules] */
void (*pCashShopOpen) (int fd, struct map_session_data *sd);
void (*pCashShopClose) (int fd, struct map_session_data *sd);
diff --git a/src/map/guild.c b/src/map/guild.c
index b83f05f00..a6c873861 100644
--- a/src/map/guild.c
+++ b/src/map/guild.c
@@ -24,6 +24,7 @@
#include "clif.h"
#include "skill.h"
#include "log.h"
+#include "instance.h"
#include <stdio.h>
#include <stdlib.h>
@@ -503,6 +504,8 @@ int guild_recv_info(struct guild *sg) {
if((g = (struct guild*)idb_get(guild_db,sg->guild_id))==NULL) {
guild_new = true;
g=(struct guild *)aCalloc(1,sizeof(struct guild));
+ g->instance = NULL;
+ g->instances = 0;
idb_put(guild_db,sg->guild_id,g);
if( hChSys.ally ) {
struct hChSysCh *channel;
@@ -926,7 +929,8 @@ int guild_member_withdraw(int guild_id, int account_id, int char_id, int flag, c
sd->status.guild_id = 0;
sd->guild = NULL;
sd->guild_emblem_id = 0;
-
+ if( g->instances )
+ instance->check_kick(sd);
clif->charnameupdate(sd); //Update display name [Skotlex]
//TODO: send emblem update to self and people around
}
@@ -2211,6 +2215,10 @@ void do_final_guild(void) {
for( g = dbi_first(iter); dbi_exists(iter); g = dbi_next(iter) ) {
if( g->channel != NULL )
clif->chsys_delete((struct hChSysCh *)g->channel);
+ if( g->instance != NULL ) {
+ aFree(g->instance);
+ g->instance = NULL;
+ }
}
dbi_destroy(iter);
diff --git a/src/map/instance.c b/src/map/instance.c
index 8ddde8b3e..7b3e2e800 100644
--- a/src/map/instance.c
+++ b/src/map/instance.c
@@ -1,5 +1,6 @@
-// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
-// For more information, see LICENCE in the main folder
+// Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// See the LICENSE file
+// Portions Copyright (c) Athena Dev Teams
#include "../common/cbasetypes.h"
#include "../common/socket.h"
@@ -24,20 +25,13 @@
#include <stdarg.h>
#include <time.h>
-int instance_start = 0; // To keep the last index + 1 of normal map inserted in the map[ARRAY]
-struct s_instance instance[MAX_INSTANCE];
-
-
/// Checks whether given instance id is valid or not.
-static bool instance_is_valid(int instance_id)
-{
- if( instance_id < 1 || instance_id >= ARRAYLENGTH(instance) )
- {// out of range
+bool instance_is_valid(int instance_id) {
+ if( instance_id < 0 || instance_id >= instance->instances ) {// out of range
return false;
}
- if( instance[instance_id].state == INSTANCE_FREE )
- {// uninitialized/freed instance slot
+ if( instances[instance_id].state == INSTANCE_FREE ) {// uninitialized/freed instance slot
return false;
}
@@ -48,56 +42,104 @@ static bool instance_is_valid(int instance_id)
/*--------------------------------------
* name : instance name
* Return value could be
- * -4 = already exists | -3 = no free instances | -2 = party not found | -1 = invalid type
+ * -4 = already exists | -3 = no free instances | -2 = owner not found | -1 = invalid type
* On success return instance_id
*--------------------------------------*/
-int instance_create(int party_id, const char *name)
-{
- int i;
- struct party_data* p;
-
- if( ( p = party_search(party_id) ) == NULL )
- {
- ShowError("instance_create: party %d not found for instance '%s'.\n", party_id, name);
- return -2;
+int instance_create(int owner_id, const char *name, enum instance_owner_type type) {
+ unsigned short *iptr = NULL, *icptr = NULL;
+ struct map_session_data *sd = NULL;
+ struct party_data *p = NULL;
+ struct guild *g = NULL;
+ int i, j;
+
+ switch ( type ) {
+ case IOT_NONE:
+ break;
+ case IOT_CHAR:
+ if( ( sd = map_id2sd(owner_id) ) == NULL ) {
+ ShowError("instance_create: character %d not found for instance '%s'.\n", owner_id, name);
+ return -2;
+ }
+ iptr = sd->instance;
+ icptr = &sd->instances;
+ break;
+ case IOT_PARTY:
+ if( ( p = party_search(owner_id) ) == NULL ) {
+ ShowError("instance_create: party %d not found for instance '%s'.\n", owner_id, name);
+ return -2;
+ }
+ iptr = p->instance;
+ icptr = &p->instances;
+ break;
+ case IOT_GUILD:
+ if( ( g = guild->search(owner_id) ) == NULL ) {
+ ShowError("instance_create: guild %d not found for instance '%s'.\n", owner_id, name);
+ return -2;
+ }
+ iptr = g->instance;
+ icptr = &g->instances;
+ break;
+ default:
+ ShowError("instance_create: unknown type %d for owner_id %d and name %s.\n", type,owner_id,name);
+ return -1;
}
-
- if( p->instance_id )
- return -4; // Party already instancing
-
- // Searching a Free Instance
- // 0 is ignored as this mean "no instance" on maps
- ARR_FIND(1, MAX_INSTANCE, i, instance[i].state == INSTANCE_FREE);
- if( i == MAX_INSTANCE )
- {
- ShowError("instance_create: no free instances, consider increasing MAX_INSTANCE.\n");
- return -3;
+
+ if( type != IOT_NONE && *icptr ) {
+ ARR_FIND(0, *icptr, i, strcmp(instances[iptr[i]].name,name) == 0 );
+ if( i != *icptr )
+ return -4;/* already got this instance */
}
-
- instance[i].state = INSTANCE_IDLE;
- instance[i].instance_id = i;
- instance[i].idle_timer = INVALID_TIMER;
- instance[i].idle_timeout = instance[i].idle_timeoutval = 0;
- instance[i].progress_timer = INVALID_TIMER;
- instance[i].progress_timeout = 0;
- instance[i].users = 0;
- instance[i].party_id = party_id;
- instance[i].vars = idb_alloc(DB_OPT_RELEASE_DATA);
-
- safestrncpy( instance[i].name, name, sizeof(instance[i].name) );
- memset( instance[i].map, 0x00, sizeof(instance[i].map) );
- p->instance_id = i;
-
+
+ ARR_FIND(0, instance->instances, i, instances[i].state == INSTANCE_FREE);
+
+ if( i == instance->instances )
+ RECREATE(instances, struct instance_data, ++instance->instances);
+
+ instances[i].state = INSTANCE_IDLE;
+ instances[i].id = i;
+ instances[i].idle_timer = INVALID_TIMER;
+ instances[i].idle_timeout = instances[i].idle_timeoutval = 0;
+ instances[i].progress_timer = INVALID_TIMER;
+ instances[i].progress_timeout = 0;
+ instances[i].users = 0;
+ instances[i].map = NULL;
+ instances[i].num_map = 0;
+ instances[i].owner_id = owner_id;
+ instances[i].owner_type = type;
+ instances[i].vars = idb_alloc(DB_OPT_RELEASE_DATA);
+
+ safestrncpy( instances[i].name, name, sizeof(instances[i].name) );
+ instances[i].map = NULL;
+
+ if( type != IOT_NONE ) {
+ ARR_FIND(0, *icptr, j, iptr[j] == 0);
+ if( j == *icptr ) {
+ switch( type ) {
+ case IOT_CHAR:
+ RECREATE(sd->instance, unsigned short, ++*icptr);
+ sd->instance[sd->instances-1] = i;
+ break;
+ case IOT_PARTY:
+ RECREATE(p->instance, unsigned short, ++*icptr);
+ p->instance[p->instances-1] = i;
+ break;
+ case IOT_GUILD:
+ RECREATE(g->instance, unsigned short, ++*icptr);
+ g->instance[g->instances-1] = i;
+ break;
+ }
+ } else
+ iptr[j] = i;
+ }
+
clif->instance(i, 1, 0); // Start instancing window
- ShowInfo("[Instance] Created: %s.\n", name);
return i;
}
/*--------------------------------------
* Add a map to the instance using src map "name"
*--------------------------------------*/
-int instance_add_map(const char *name, int instance_id, bool usebasename)
-{
+int instance_add_map(const char *name, int instance_id, bool usebasename, const char *map_name) {
int16 m = map_mapname2mapid(name);
int i, im = -1;
size_t num_cell, size;
@@ -105,42 +147,49 @@ int instance_add_map(const char *name, int instance_id, bool usebasename)
if( m < 0 )
return -1; // source map not found
- if( !instance_is_valid(instance_id) )
- {
+ if( !instance->valid(instance_id) ) {
ShowError("instance_add_map: trying to attach '%s' map to non-existing instance %d.\n", name, instance_id);
return -1;
}
- if( instance[instance_id].num_map >= MAX_MAP_PER_INSTANCE )
- {
- ShowError("instance_add_map: trying to add '%s' map to instance %d (%s) failed. Please increase MAX_MAP_PER_INSTANCE.\n", name, instance_id, instance[instance_id].name);
+
+ if( map_name != NULL && strdb_iget(mapindex_db, map_name) ) {
+ ShowError("instance_add_map: trying to create instanced map with existent name '%s'\n", map_name);
return -2;
}
- if( map[m].instance_id != 0 )
- { // Source map already belong to a Instance.
+
+ if( map[m].instance_id >= 0 ) { // Source map already belong to a Instance.
ShowError("instance_add_map: trying to instance already instanced map %s.\n", name);
return -4;
}
-
- ARR_FIND( instance_start, map_num, i, !map[i].name[0] ); // Searching for a Free Map
- if( i < map_num ) im = i; // Unused map found (old instance)
- else if( map_num - 1 >= MAX_MAP_PER_SERVER )
- { // No more free maps
- ShowError("instance_add_map: no more free space to create maps on this server.\n");
- return -5;
+
+ ARR_FIND( instance->start_id, map_num, i, !map[i].name[0] ); // Searching for a Free Map
+
+ if( i < map_num )
+ im = i; // Unused map found (old instance)
+ else {
+ im = map_num; // Using next map index
+ RECREATE(map,struct map_data,++map_num);
}
- else im = map_num++; // Using next map index
+
+ if( map[m].cell == (struct mapcell *)0xdeadbeaf )
+ map_cellfromcache(&map[m]);
memcpy( &map[im], &map[m], sizeof(struct map_data) ); // Copy source map
- snprintf(map[im].name, MAP_NAME_LENGTH, (usebasename ? "%.3d#%s" : "%.3d%s"), instance_id, name); // Generate Name for Instance Map
+ if( map_name != NULL ) {
+ snprintf(map[im].name, MAP_NAME_LENGTH, "%s", map_name);
+ map[im].cName = map[m].name;
+ } else
+ snprintf(map[im].name, MAP_NAME_LENGTH, (usebasename ? "%.3d#%s" : "%.3d%s"), instance_id, name); // Generate Name for Instance Map
map[im].index = mapindex_addmap(-1, map[im].name); // Add map index
- if( !map[im].index )
- {
+ map[im].channel = NULL;
+
+ if( !map[im].index ) {
map[im].name[0] = '\0';
ShowError("instance_add_map: no more free map indexes.\n");
return -3; // No free map index
}
-
+
// Reallocate cells
num_cell = map[im].xs * map[im].ys;
CREATE( map[im].cell, struct mapcell, num_cell );
@@ -161,9 +210,11 @@ int instance_add_map(const char *name, int instance_id, bool usebasename)
map[im].instance_src_map = m;
map[m].flag.src4instance = 1; // Flag this map as a src map for instances
- instance[instance_id].map[instance[instance_id].num_map++] = im; // Attach to actual instance
- map_addmap2db(&map[im]);
+ RECREATE(instances[instance_id].map, unsigned short, ++instances[instance_id].num_map);
+ instances[instance_id].map[instances[instance_id].num_map - 1] = im; // Attach to actual instance
+ map_addmap2db(&map[im]);
+
return im;
}
@@ -172,19 +223,16 @@ int instance_add_map(const char *name, int instance_id, bool usebasename)
* party_id : source party of this instance
* type : result (0 = map id | 1 = instance id)
*--------------------------------------*/
-int instance_map2imap(int16 m, int instance_id)
-{
+int instance_map2imap(int16 m, int instance_id) {
int i;
- if( !instance_is_valid(instance_id) )
- {
+ if( !instance->valid(instance_id) ) {
return -1;
}
- for( i = 0; i < instance[instance_id].num_map; i++ )
- {
- if( instance[instance_id].map[i] && map[instance[instance_id].map[i]].instance_src_map == m )
- return instance[instance_id].map[i];
+ for( i = 0; i < instances[instance_id].num_map; i++ ) {
+ if( instances[instance_id].map[i] && map[instances[instance_id].map[i]].instance_src_map == m )
+ return instances[instance_id].map[i];
}
return -1;
}
@@ -194,59 +242,56 @@ int instance_map2imap(int16 m, int instance_id)
* instance_id : where to search
* result : mapid of map "m" in this instance
*--------------------------------------*/
-int instance_mapid2imapid(int16 m, int instance_id)
-{
+int instance_mapid2imapid(int16 m, int instance_id) {
if( map[m].flag.src4instance == 0 )
return m; // not instances found for this map
- else if( map[m].instance_id )
- { // This map is a instance, not a src map instance
+ else if( map[m].instance_id >= 0 ) { // This map is a instance, not a src map instance
ShowError("map_instance_mapid2imapid: already instanced (%d / %d)\n", m, instance_id);
return -1;
}
- if( !instance_is_valid(instance_id) )
+ if( !instance->valid(instance_id) )
return -1;
- return instance_map2imap(m, instance_id);
+ return instance->map2imap(m, instance_id);
}
/*--------------------------------------
* map_instance_map_npcsub
* Used on Init instance. Duplicates each script on source map
*--------------------------------------*/
-int instance_map_npcsub(struct block_list* bl, va_list args)
-{
+int instance_map_npcsub(struct block_list* bl, va_list args) {
struct npc_data* nd = (struct npc_data*)bl;
int16 m = va_arg(args, int); // Destination Map
- npc_duplicate4instance(nd, m);
+ if ( npc_duplicate4instance(nd, m) )
+ ShowDebug("instance_map_npcsub:npc_duplicate4instance failed (%s/%d)\n",nd->name,m);
+
return 1;
}
/*--------------------------------------
* Init all map on the instance. Npcs are created here
*--------------------------------------*/
-void instance_init(int instance_id)
-{
+void instance_init(int instance_id) {
int i;
- if( !instance_is_valid(instance_id) )
+ if( !instance->valid(instance_id) )
return; // nothing to do
- for( i = 0; i < instance[instance_id].num_map; i++ )
- map_foreachinmap(instance_map_npcsub, map[instance[instance_id].map[i]].instance_src_map, BL_NPC, instance[instance_id].map[i]);
+ for( i = 0; i < instances[instance_id].num_map; i++ )
+ map_foreachinmap(instance_map_npcsub, map[instances[instance_id].map[i]].instance_src_map, BL_NPC, instances[instance_id].map[i]);
- instance[instance_id].state = INSTANCE_BUSY;
- ShowInfo("[Instance] Initialized %s.\n", instance[instance_id].name);
+ instances[instance_id].state = INSTANCE_BUSY;
}
/*--------------------------------------
* Used on instance deleting process.
* Warps all players on each instance map to its save points.
*--------------------------------------*/
-int instance_del_load(struct map_session_data* sd, va_list args)
-{
+int instance_del_load(struct map_session_data* sd, va_list args) {
int16 m = va_arg(args,int);
+
if( !sd || sd->bl.m != m )
return 0;
@@ -285,12 +330,11 @@ int instance_cleanup_sub(struct block_list *bl, va_list ap) {
/*--------------------------------------
* Removes a simple instance map
*--------------------------------------*/
-void instance_del_map(int16 m)
-{
+void instance_del_map(int16 m) {
int i;
- if( m <= 0 || !map[m].instance_id )
- {
- ShowError("Tried to remove non-existing instance map (%d)\n", m);
+
+ if( m <= 0 || map[m].instance_id == -1 ) {
+ ShowError("instance_del_map: tried to remove non-existing instance map (%d)\n", m);
return;
}
@@ -299,116 +343,145 @@ void instance_del_map(int16 m)
if( map[m].mob_delete_timer != INVALID_TIMER )
delete_timer(map[m].mob_delete_timer, map_removemobs_timer);
-
+
mapindex_removemap( map[m].index );
// Free memory
aFree(map[m].cell);
aFree(map[m].block);
aFree(map[m].block_mob);
-
+
// Remove from instance
- for( i = 0; i < instance[map[m].instance_id].num_map; i++ )
- {
- if( instance[map[m].instance_id].map[i] == m )
- {
- instance[map[m].instance_id].num_map--;
- for( ; i < instance[map[m].instance_id].num_map; i++ )
- instance[map[m].instance_id].map[i] = instance[map[m].instance_id].map[i+1];
+ for( i = 0; i < instances[map[m].instance_id].num_map; i++ ) {
+ if( instances[map[m].instance_id].map[i] == m ) {
+ instances[map[m].instance_id].num_map--;
+ for( ; i < instances[map[m].instance_id].num_map; i++ )
+ instances[map[m].instance_id].map[i] = instances[map[m].instance_id].map[i+1];
i = -1;
break;
}
}
- if( i == instance[map[m].instance_id].num_map )
- ShowError("map_instance_del: failed to remove %s from instance list (%s): %d\n", map[m].name, instance[map[m].instance_id].name, m);
+
+ if( i == instances[map[m].instance_id].num_map )
+ ShowError("map_instance_del: failed to remove %s from instance list (%s): %d\n", map[m].name, instances[map[m].instance_id].name, m);
+
+ if( map[m].channel )
+ clif->chsys_delete(map[m].channel);
map_removemapdb(&map[m]);
memset(&map[m], 0x00, sizeof(map[0]));
-
- /* for it is default and makes it not try to delete a non-existent timer since we did not delete this entry. */
+ map[m].instance_id = -1;
map[m].mob_delete_timer = INVALID_TIMER;
}
/*--------------------------------------
* Timer to destroy instance by process or idle
*--------------------------------------*/
-int instance_destroy_timer(int tid, unsigned int tick, int id, intptr_t data)
-{
- instance_destroy(id);
+int instance_destroy_timer(int tid, unsigned int tick, int id, intptr_t data) {
+ instance->destroy(id);
return 0;
}
/*--------------------------------------
* Removes a instance, all its maps and npcs.
*--------------------------------------*/
-void instance_destroy(int instance_id)
-{
- int last = 0, type;
- struct party_data *p;
- time_t now = time(NULL);
-
- if( !instance_is_valid(instance_id) )
+void instance_destroy(int instance_id) {
+ unsigned short *iptr = NULL, *icptr = NULL;
+ struct map_session_data *sd = NULL;
+ struct party_data *p = NULL;
+ struct guild *g = NULL;
+ int last = 0, type, j;
+ unsigned int now = (unsigned int)time(NULL);
+
+ if( !instance->valid(instance_id) )
return; // nothing to do
- if( instance[instance_id].progress_timeout && instance[instance_id].progress_timeout <= now )
+ if( instances[instance_id].progress_timeout && instances[instance_id].progress_timeout <= now )
type = 1;
- else if( instance[instance_id].idle_timeout && instance[instance_id].idle_timeout <= now )
+ else if( instances[instance_id].idle_timeout && instances[instance_id].idle_timeout <= now )
type = 2;
else
type = 3;
clif->instance(instance_id, 5, type); // Report users this instance has been destroyed
- while( instance[instance_id].num_map && last != instance[instance_id].map[0] )
- { // Remove all maps from instance
- last = instance[instance_id].map[0];
- instance_del_map( instance[instance_id].map[0] );
+ switch ( instances[instance_id].owner_type ) {
+ case IOT_NONE:
+ break;
+ case IOT_CHAR:
+ if( ( sd = map_id2sd(instances[instance_id].owner_id) ) == NULL ) {
+ break;
+ }
+ iptr = sd->instance;
+ icptr = &sd->instances;
+ break;
+ case IOT_PARTY:
+ if( ( p = party_search(instances[instance_id].owner_id) ) == NULL ) {
+ break;
+ }
+ iptr = p->instance;
+ icptr = &p->instances;
+ break;
+ case IOT_GUILD:
+ if( ( g = guild->search(instances[instance_id].owner_id) ) == NULL ) {
+ break;
+ }
+ iptr = g->instance;
+ icptr = &g->instances;
+ break;
+ default:
+ ShowError("instance_destroy: unknown type %d for owner_id %d and name %s.\n", instances[instance_id].owner_type,instances[instance_id].owner_id,instances[instance_id].name);
+ break;
+ }
+
+ if( iptr != NULL ) {
+ ARR_FIND(0, *icptr, j, iptr[j] == instance_id);
+ if( j != *icptr )
+ iptr[j] = 0;
+ }
+
+ while( instances[instance_id].num_map && last != instances[instance_id].map[0] ) { // Remove all maps from instance
+ last = instances[instance_id].map[0];
+ instance->del_map( instances[instance_id].map[0] );
}
- if( instance[instance_id].vars )
- db_destroy(instance[instance_id].vars);
-
- if( instance[instance_id].progress_timer != INVALID_TIMER )
- delete_timer( instance[instance_id].progress_timer, instance_destroy_timer);
- if( instance[instance_id].idle_timer != INVALID_TIMER )
- delete_timer( instance[instance_id].idle_timer, instance_destroy_timer);
+ if( instances[instance_id].vars )
+ db_destroy(instances[instance_id].vars);
- instance[instance_id].vars = NULL;
+ if( instances[instance_id].progress_timer != INVALID_TIMER )
+ delete_timer( instances[instance_id].progress_timer, instance_destroy_timer);
+ if( instances[instance_id].idle_timer != INVALID_TIMER )
+ delete_timer( instances[instance_id].idle_timer, instance_destroy_timer);
- if( instance[instance_id].party_id && (p = party_search(instance[instance_id].party_id)) != NULL )
- p->instance_id = 0; // Update Party information
+ instances[instance_id].vars = NULL;
- ShowInfo("[Instance] Destroyed %s.\n", instance[instance_id].name);
- memset( &instance[instance_id], 0x00, sizeof(instance[0]) );
+ aFree(instances[instance_id].map);
+
+ memset( &instances[instance_id], 0x00, sizeof(struct instance_data) );
- instance[instance_id].state = INSTANCE_FREE;
}
/*--------------------------------------
* Checks if there are users in the instance or not to start idle timer
*--------------------------------------*/
-void instance_check_idle(int instance_id)
-{
+void instance_check_idle(int instance_id) {
bool idle = true;
- time_t now = time(NULL);
+ unsigned int now = (unsigned int)time(NULL);
- if( !instance_is_valid(instance_id) || instance[instance_id].idle_timeoutval == 0 )
+ if( !instance->valid(instance_id) || instances[instance_id].idle_timeoutval == 0 )
return;
- if( instance[instance_id].users )
+ if( instances[instance_id].users )
idle = false;
- if( instance[instance_id].idle_timer != INVALID_TIMER && !idle )
- {
- delete_timer(instance[instance_id].idle_timer, instance_destroy_timer);
- instance[instance_id].idle_timer = INVALID_TIMER;
- instance[instance_id].idle_timeout = 0;
+ if( instances[instance_id].idle_timer != INVALID_TIMER && !idle ) {
+ delete_timer(instances[instance_id].idle_timer, instance_destroy_timer);
+ instances[instance_id].idle_timer = INVALID_TIMER;
+ instances[instance_id].idle_timeout = 0;
clif->instance(instance_id, 3, 0); // Notify instance users normal instance expiration
- }
- else if( instance[instance_id].idle_timer == INVALID_TIMER && idle )
- {
- instance[instance_id].idle_timeout = now + instance[instance_id].idle_timeoutval;
- instance[instance_id].idle_timer = add_timer( gettick() + (unsigned int)instance[instance_id].idle_timeoutval * 1000, instance_destroy_timer, instance_id, 0);
+ } else if( instances[instance_id].idle_timer == INVALID_TIMER && idle ) {
+ instances[instance_id].idle_timeout = now + instances[instance_id].idle_timeoutval;
+ instances[instance_id].idle_timer = add_timer( gettick() + instances[instance_id].idle_timeoutval * 1000, instance_destroy_timer, instance_id, 0);
clif->instance(instance_id, 4, 0); // Notify instance users it will be destroyed of no user join it again in "X" time
}
}
@@ -418,54 +491,46 @@ void instance_check_idle(int instance_id)
*--------------------------------------*/
void instance_set_timeout(int instance_id, unsigned int progress_timeout, unsigned int idle_timeout)
{
- time_t now = time(0);
+ unsigned int now = time(0);
- if( !instance_is_valid(instance_id) )
+ if( !instance->valid(instance_id) )
return;
- if( instance[instance_id].progress_timer != INVALID_TIMER )
- delete_timer( instance[instance_id].progress_timer, instance_destroy_timer);
- if( instance[instance_id].idle_timer != INVALID_TIMER )
- delete_timer( instance[instance_id].idle_timer, instance_destroy_timer);
-
- if( progress_timeout )
- {
- instance[instance_id].progress_timeout = now + progress_timeout;
- instance[instance_id].progress_timer = add_timer( gettick() + progress_timeout * 1000, instance_destroy_timer, instance_id, 0);
- }
- else
- {
- instance[instance_id].progress_timeout = 0;
- instance[instance_id].progress_timer = INVALID_TIMER;
+ if( instances[instance_id].progress_timer != INVALID_TIMER )
+ delete_timer( instances[instance_id].progress_timer, instance_destroy_timer);
+ if( instances[instance_id].idle_timer != INVALID_TIMER )
+ delete_timer( instances[instance_id].idle_timer, instance_destroy_timer);
+
+ if( progress_timeout ) {
+ instances[instance_id].progress_timeout = now + progress_timeout;
+ instances[instance_id].progress_timer = add_timer( gettick() + progress_timeout * 1000, instance_destroy_timer, instance_id, 0);
+ } else {
+ instances[instance_id].progress_timeout = 0;
+ instances[instance_id].progress_timer = INVALID_TIMER;
}
- if( idle_timeout )
- {
- instance[instance_id].idle_timeoutval = idle_timeout;
- instance[instance_id].idle_timer = INVALID_TIMER;
+ if( idle_timeout ) {
+ instances[instance_id].idle_timeoutval = idle_timeout;
+ instances[instance_id].idle_timer = INVALID_TIMER;
instance_check_idle(instance_id);
- }
- else
- {
- instance[instance_id].idle_timeoutval = 0;
- instance[instance_id].idle_timeout = 0;
- instance[instance_id].idle_timer = INVALID_TIMER;
+ } else {
+ instances[instance_id].idle_timeoutval = 0;
+ instances[instance_id].idle_timeout = 0;
+ instances[instance_id].idle_timer = INVALID_TIMER;
}
- if( instance[instance_id].idle_timer == INVALID_TIMER && instance[instance_id].progress_timer != INVALID_TIMER )
+ if( instances[instance_id].idle_timer == INVALID_TIMER && instances[instance_id].progress_timer != INVALID_TIMER )
clif->instance(instance_id, 3, 0);
}
/*--------------------------------------
* Checks if sd in on a instance and should be kicked from it
*--------------------------------------*/
-void instance_check_kick(struct map_session_data *sd)
-{
+void instance_check_kick(struct map_session_data *sd) {
int16 m = sd->bl.m;
clif->instance_leave(sd->fd);
- if( map[m].instance_id )
- { // User was on the instance map
+ if( map[m].instance_id >= 0 ) { // 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, CLR_TELEPORT);
else
@@ -473,16 +538,41 @@ void instance_check_kick(struct map_session_data *sd)
}
}
-void do_final_instance(void)
-{
+void do_final_instance(void) {
int i;
- for( i = 1; i < MAX_INSTANCE; i++ )
+ for(i = 0; i < instance->instances; i++) {
instance_destroy(i);
+ }
+
+ aFree(instances);
}
-void do_init_instance(void)
-{
- memset(instance, 0x00, sizeof(instance));
+void do_init_instance(void) {
add_timer_func_list(instance_destroy_timer, "instance_destroy_timer");
}
+
+void instance_defaults(void) {
+ instance = &instance_s;
+
+ instance->init = do_init_instance;
+ instance->final = do_final_instance;
+
+ /* start point */
+ instance->start_id = 0;
+ /* count */
+ instance->instances = 0;
+
+ /* */
+ instance->create = instance_create;
+ instance->add_map = instance_add_map;
+ instance->del_map = instance_del_map;
+ instance->map2imap = instance_map2imap;
+ instance->mapid2imapid = instance_mapid2imapid;
+ instance->destroy = instance_destroy;
+ instance->start = instance_init;
+ instance->check_idle = instance_check_idle;
+ instance->check_kick = instance_check_kick;
+ instance->set_timeout = instance_set_timeout;
+ instance->valid = instance_is_valid;
+}
diff --git a/src/map/instance.h b/src/map/instance.h
index 03b0d0898..e86586e44 100644
--- a/src/map/instance.h
+++ b/src/map/instance.h
@@ -1,51 +1,71 @@
-// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
-// For more information, see LICENCE in the main folder
+// Copyright (c) Hercules Dev Team, licensed under GNU GPL.
+// See the LICENSE file
+// Portions Copyright (c) Athena Dev Teams
#ifndef _INSTANCE_H_
#define _INSTANCE_H_
-#define MAX_MAP_PER_INSTANCE 10
-#define MAX_INSTANCE 500
-
#define INSTANCE_NAME_LENGTH (60+1)
-typedef enum instance_state { INSTANCE_FREE, INSTANCE_IDLE, INSTANCE_BUSY } instance_state;
+typedef enum instance_state {
+ INSTANCE_FREE,
+ INSTANCE_IDLE,
+ INSTANCE_BUSY
+} instance_state;
+
+enum instance_owner_type {
+ IOT_NONE,
+ IOT_CHAR,
+ IOT_PARTY,
+ IOT_GUILD,
+ /* ... */
+ IOT_MAX,
+};
-struct s_instance {
+struct instance_data {
+ unsigned short id;
char name[INSTANCE_NAME_LENGTH]; // Instance Name - required for clif functions.
instance_state state;
- short instance_id;
- int party_id;
+ enum instance_owner_type owner_type;
+ int owner_id;
- int map[MAX_MAP_PER_INSTANCE];
- int num_map;
- int users;
+ unsigned short *map;
+ unsigned short num_map;
+ unsigned short users;
struct DBMap* vars; // Instance Variable for scripts
int progress_timer;
- time_t progress_timeout;
+ unsigned int progress_timeout;
int idle_timer;
- time_t idle_timeout, idle_timeoutval;
+ unsigned int idle_timeout, idle_timeoutval;
};
-extern int instance_start;
-extern struct s_instance instance[MAX_INSTANCE];
+struct instance_data *instances;
-int instance_create(int party_id, const char *name);
-int instance_add_map(const char *name, int instance_id, bool usebasename);
-void instance_del_map(int16 m);
-int instance_map2imap(int16 m, int instance_id);
-int instance_mapid2imapid(int16 m, int instance_id);
-void instance_destroy(int instance_id);
-void instance_init(int instance_id);
+struct instance_interface {
+ void (*init) (void);
+ void (*final) (void);
+ /* start point */
+ unsigned short start_id;
+ unsigned short instances;
+ /* */
+ int (*create) (int party_id, const char *name, enum instance_owner_type type);
+ int (*add_map) (const char *name, int instance_id, bool usebasename, const char *map_name);
+ void (*del_map) (int16 m);
+ int (*map2imap) (int16 m, int instance_id);
+ int (*mapid2imapid) (int16 m, int instance_id);
+ void (*destroy) (int instance_id);
+ void (*start) (int instance_id);
+ void (*check_idle) (int instance_id);
+ void (*check_kick) (struct map_session_data *sd);
+ void (*set_timeout) (int instance_id, unsigned int progress_timeout, unsigned int idle_timeout);
+ bool (*valid) (int instance_id);
+} instance_s;
-void instance_check_idle(int instance_id);
-void instance_check_kick(struct map_session_data *sd);
-void instance_set_timeout(int instance_id, unsigned int progress_timeout, unsigned int idle_timeout);
+struct instance_interface *instance;
-void do_final_instance(void);
-void do_init_instance(void);
+void instance_defaults(void);
#endif
diff --git a/src/map/intif.c b/src/map/intif.c
index 93bb8add7..9e6403f10 100644
--- a/src/map/intif.c
+++ b/src/map/intif.c
@@ -467,7 +467,7 @@ int intif_party_changemap(struct map_session_data *sd,int online)
if(!sd)
return 0;
- if( (m=map_mapindex2mapid(sd->mapindex)) >= 0 && map[m].instance_id )
+ if( (m=map_mapindex2mapid(sd->mapindex)) >= 0 && map[m].instance_id >= 0 )
mapindex = map[map[m].instance_src_map].index;
else
mapindex = sd->mapindex;
diff --git a/src/map/irc-bot.c b/src/map/irc-bot.c
index 0e155011e..bfaf18af0 100644
--- a/src/map/irc-bot.c
+++ b/src/map/irc-bot.c
@@ -22,12 +22,16 @@
char send_string[200];
int irc_connect_timer(int tid, unsigned int tick, int id, intptr_t data) {
+ struct hSockOpt opt;
if( ircbot->isOn || ++ircbot->fails >= 3 )
return 0;
+ opt.silent = 1;
+ opt.setTimeo = 0;
+
ircbot->last_try = gettick();
- if( ( ircbot->fd = make_connection(ircbot->ip,hChSys.irc_server_port,true) ) > 0 ){
+ if( ( ircbot->fd = make_connection(ircbot->ip,hChSys.irc_server_port,&opt) ) > 0 ){
session[ircbot->fd]->func_parse = ircbot->parse;
session[ircbot->fd]->flag.server = 1;
add_timer(gettick() + 3000, ircbot->identify_timer, 0, 0);
diff --git a/src/map/map.c b/src/map/map.c
index d4c15cd6e..54646d1c3 100644
--- a/src/map/map.c
+++ b/src/map/map.c
@@ -101,7 +101,7 @@ static DBMap* id_db=NULL; // int id -> struct block_list*
static DBMap* pc_db=NULL; // int id -> struct map_session_data*
static DBMap* mobid_db=NULL; // int id -> struct mob_data*
static DBMap* bossid_db=NULL; // int id -> struct mob_data* (MVP db)
-static DBMap* map_db=NULL; // unsigned int mapindex -> struct map_data*
+static DBMap* map_db=NULL; // unsigned int mapindex -> struct map_data_other_server*
static DBMap* nick_db=NULL; // int char_id -> struct charid2nick* (requested names of offline characters)
static DBMap* charid_db=NULL; // int char_id -> struct map_session_data*
static DBMap* regen_db=NULL; // int id -> struct block_list* (status_natural_heal processing)
@@ -150,6 +150,8 @@ struct map_cache_map_info {
int32 len;
};
+uint16 index2mapid[MAX_MAPINDEX];
+
char db_path[256] = "db";
char help_txt[256] = "conf/help.txt";
char help2_txt[256] = "conf/help2.txt";
@@ -162,6 +164,7 @@ int enable_grf = 0; //To enable/disable reading maps from GRF files, bypassing m
/* [Ind/Hercules] */
struct eri *map_iterator_ers;
+char *map_cache_buffer = NULL; // Has the uncompressed gat data of all maps, so just one allocation has to be made
/*==========================================
* server player count (of all mapservers)
@@ -397,8 +400,7 @@ int map_moveblock(struct block_list *bl, int x1, int y1, unsigned int tick)
if (sc->data[SC_PROPERTYWALK] &&
sc->data[SC_PROPERTYWALK]->val3 >= skill->get_maxcount(sc->data[SC_PROPERTYWALK]->val1,sc->data[SC_PROPERTYWALK]->val2) )
status_change_end(bl,SC_PROPERTYWALK,INVALID_TIMER);
- } else
- if (bl->type == BL_NPC)
+ } else if (bl->type == BL_NPC)
npc_unsetcells((TBL_NPC*)bl);
if (moveblock) map_delblock(bl);
@@ -469,8 +471,7 @@ int map_moveblock(struct block_list *bl, int x1, int y1, unsigned int tick)
skill->unit_move_unit_group(skill->id2group(sc->data[SC_HAWKEYES]->val4), bl->m, x1-x0, y1-y0);
}
}
- } else
- if (bl->type == BL_NPC)
+ } else if (bl->type == BL_NPC)
npc_setcells((TBL_NPC*)bl);
return 0;
@@ -1194,8 +1195,7 @@ int map_foreachinpath(int (*func)(struct block_list*,va_list),int16 m,int16 x0,i
}
// Copy of map_foreachincell, but applied to the whole map. [Skotlex]
-int map_foreachinmap(int (*func)(struct block_list*,va_list), int16 m, int type,...)
-{
+int map_foreachinmap(int (*func)(struct block_list*,va_list), int16 m, int type,...) {
int b, bsize;
int returnCount = 0; //total sum of returned values of func() [Skotlex]
struct block_list *bl;
@@ -1233,6 +1233,52 @@ int map_foreachinmap(int (*func)(struct block_list*,va_list), int16 m, int type,
bl_list_count = blockcount;
return returnCount;
}
+// Copy of map_foreachinmap, but applied to all maps in a instance id. [Ind/Hercules]
+int map_foreachininstance(int (*func)(struct block_list*,va_list), int16 instance_id, int type,...) {
+ int b, bsize;
+ int returnCount = 0; //total sum of returned values of func() [Skotlex]
+ struct block_list *bl;
+ int blockcount = bl_list_count, i, j;
+ int16 m;
+ va_list ap;
+
+ for( j = 0; j < instances[instance_id].num_map; j++ ) {
+
+ m = instances[instance_id].map[j];
+
+ bsize = map[ m ].bxs * map[ m ].bys;
+
+ if( type&~BL_MOB )
+ for( b = 0; b < bsize; b++ )
+ for( bl = map[ m ].block[ b ]; bl != NULL; bl = bl->next )
+ if( bl->type&type && bl_list_count < BL_LIST_MAX )
+ bl_list[ bl_list_count++ ] = bl;
+
+ if( type&BL_MOB )
+ for( b = 0; b < bsize; b++ )
+ for( bl = map[ m ].block_mob[ b ]; bl != NULL; bl = bl->next )
+ if( bl_list_count < BL_LIST_MAX )
+ bl_list[ bl_list_count++ ] = bl;
+
+ if( bl_list_count >= BL_LIST_MAX )
+ ShowWarning("map_foreachininstance: block count too many!\n");
+
+ map_freeblock_lock();
+
+ for( i = blockcount; i < bl_list_count ; i++ )
+ if( bl_list[ i ]->prev ) { //func() may delete this bl_list[] slot, checking for prev ensures it wasnt queued for deletion.
+ va_start(ap, type);
+ returnCount += func(bl_list[ i ], ap);
+ va_end(ap);
+ }
+
+ map_freeblock_unlock();
+
+ }
+
+ bl_list_count = blockcount;
+ return returnCount;
+}
/// Generates a new flooritem object id from the interval [MIN_FLOORITEM, MAX_FLOORITEM).
@@ -1637,8 +1683,19 @@ int map_quit(struct map_session_data *sd) {
pc_itemcd_do(sd,false);
+ for( i = 0; i < sd->queues_count; i++ ) {
+ struct hQueue *queue;
+ if( (queue = script->queue(sd->queues[i])) && queue->onLogOut[0] != '\0' ) {
+ npc_event(sd, queue->onLogOut, 0);
+ }
+ }
+ /* two times, the npc event above may assign a new one or delete others */
+ for( i = 0; i < sd->queues_count; i++ ) {
+ script->queue_remove(sd->queues[i],sd->status.account_id);
+ }
+
npc_script_event(sd, NPCE_LOGOUT);
-
+
//Unit_free handles clearing the player related data,
//map_quit handles extra specific data which is related to quitting normally
//(changing map-servers invokes unit_free but bypasses map_quit)
@@ -1712,7 +1769,7 @@ int map_quit(struct map_session_data *sd) {
unit_remove_map_pc(sd,CLR_TELEPORT);
- if( map[sd->bl.m].instance_id ) { // Avoid map conflicts and warnings on next login
+ if( map[sd->bl.m].instance_id >= 0 ) { // Avoid map conflicts and warnings on next login
int16 m;
struct point *pt;
if( map[sd->bl.m].save.map )
@@ -1720,8 +1777,7 @@ int map_quit(struct map_session_data *sd) {
else
pt = &sd->status.save_point;
- if( (m=map_mapindex2mapid(pt->map)) >= 0 )
- {
+ if( (m=map_mapindex2mapid(pt->map)) >= 0 ) {
sd->bl.m = m;
sd->bl.x = pt->x;
sd->bl.y = pt->y;
@@ -2160,8 +2216,7 @@ bool mapit_exists(struct s_mapiterator* mapit)
/*==========================================
* Add npc-bl to id_db, basically register npc to map
*------------------------------------------*/
-bool map_addnpc(int16 m,struct npc_data *nd)
-{
+bool map_addnpc(int16 m,struct npc_data *nd) {
nullpo_ret(nd);
if( m < 0 || m >= map_num )
@@ -2188,8 +2243,7 @@ int map_addmobtolist(unsigned short m, struct spawn_data *spawn)
{
size_t i;
ARR_FIND( 0, MAX_MOB_LIST_PER_MAP, i, map[m].moblist[i] == NULL );
- if( i < MAX_MOB_LIST_PER_MAP )
- {
+ if( i < MAX_MOB_LIST_PER_MAP ) {
map[m].moblist[i] = spawn;
return i;
}
@@ -2250,13 +2304,11 @@ int map_removemobs_timer(int tid, unsigned int tick, int id, intptr_t data)
int count;
const int16 m = id;
- if (m < 0 || m >= MAX_MAP_PER_SERVER)
- { //Incorrect map id!
+ if (m < 0 || m >= map_num) { //Incorrect map id!
ShowError("map_removemobs_timer error: timer %d points to invalid map %d\n",tid, m);
return 0;
}
- if (map[m].mob_delete_timer != tid)
- { //Incorrect timer call!
+ if (map[m].mob_delete_timer != tid) { //Incorrect timer call!
ShowError("map_removemobs_timer mismatch: %d != %d (map %s)\n",map[m].mob_delete_timer, tid, map[m].name);
return 0;
}
@@ -2283,8 +2335,7 @@ void map_removemobs(int16 m)
/*==========================================
* Hookup, get map_id from map_name
*------------------------------------------*/
-int16 map_mapname2mapid(const char* name)
-{
+int16 map_mapname2mapid(const char* name) {
unsigned short map_index;
map_index = mapindex_name2id(name);
if (!map_index)
@@ -2295,24 +2346,18 @@ int16 map_mapname2mapid(const char* name)
/*==========================================
* Returns the map of the given mapindex. [Skotlex]
*------------------------------------------*/
-int16 map_mapindex2mapid(unsigned short mapindex)
-{
- struct map_data *md=NULL;
+int16 map_mapindex2mapid(unsigned short mapindex) {
- if (!mapindex)
+ if (!mapindex || mapindex > MAX_MAPINDEX)
return -1;
- md = (struct map_data*)uidb_get(map_db,(unsigned int)mapindex);
- if(md==NULL || md->cell==NULL)
- return -1;
- return md->m;
+ return index2mapid[mapindex] == 0 ? -1 : index2mapid[mapindex];
}
/*==========================================
* Switching Ip, port ? (like changing map_server) get ip/port from map_name
*------------------------------------------*/
-int map_mapname2ipport(unsigned short name, uint32* ip, uint16* port)
-{
+int map_mapname2ipport(unsigned short name, uint32* ip, uint16* port) {
struct map_data_other_server *mdos;
mdos = (struct map_data_other_server*)uidb_get(map_db,(unsigned int)name);
@@ -2443,8 +2488,7 @@ inline static struct mapcell map_gat2cell(int gat) {
return cell;
}
-static int map_cell2gat(struct mapcell cell)
-{
+static int map_cell2gat(struct mapcell cell) {
if( cell.walkable == 1 && cell.shootable == 1 && cell.water == 0 ) return 0;
if( cell.walkable == 0 && cell.shootable == 0 && cell.water == 0 ) return 1;
if( cell.walkable == 1 && cell.shootable == 1 && cell.water == 1 ) return 3;
@@ -2453,17 +2497,42 @@ static int map_cell2gat(struct mapcell cell)
ShowWarning("map_cell2gat: cell has no matching gat type\n");
return 1; // default to 'wall'
}
+int map_getcellp(struct map_data* m,int16 x,int16 y,cell_chk cellchk);
+void map_setcell(int16 m, int16 x, int16 y, cell_t cell, bool flag);
+void map_cellfromcache(struct map_data *m) {
+ char decode_buffer[MAX_MAP_SIZE];
+ struct map_cache_map_info *info = NULL;
+
+ if( (info = (struct map_cache_map_info *)m->cellPos) ) {
+ unsigned long size, xy;
+ int i;
+
+ size = (unsigned long)info->xs*(unsigned long)info->ys;
+
+ // TO-DO: Maybe handle the scenario, if the decoded buffer isn't the same size as expected? [Shinryo]
+ decode_zip(decode_buffer, &size, m->cellPos+sizeof(struct map_cache_map_info), info->len);
+ CREATE(m->cell, struct mapcell, size);
+
+ for( xy = 0; xy < size; ++xy )
+ m->cell[xy] = map_gat2cell(decode_buffer[xy]);
+
+ m->getcellp = map_getcellp;
+ m->setcell = map_setcell;
+
+ for(i = 0; i < m->npc_num; i++) {
+ npc_setcells(m->npc[i]);
+ }
+ }
+}
/*==========================================
* Confirm if celltype in (m,x,y) match the one given in cellchk
*------------------------------------------*/
-int map_getcell(int16 m,int16 x,int16 y,cell_chk cellchk)
-{
- return (m < 0 || m >= MAX_MAP_PER_SERVER) ? 0 : map_getcellp(&map[m],x,y,cellchk);
+int map_getcell(int16 m,int16 x,int16 y,cell_chk cellchk) {
+ return (m < 0 || m >= map_num) ? 0 : map[m].getcellp(&map[m],x,y,cellchk);
}
-int map_getcellp(struct map_data* m,int16 x,int16 y,cell_chk cellchk)
-{
+int map_getcellp(struct map_data* m,int16 x,int16 y,cell_chk cellchk) {
struct mapcell cell;
nullpo_ret(m);
@@ -2474,8 +2543,7 @@ int map_getcellp(struct map_data* m,int16 x,int16 y,cell_chk cellchk)
cell = m->cell[x + y*m->xs];
- switch(cellchk)
- {
+ switch(cellchk) {
// gat type retrieval
case CELL_GETTYPE:
return map_cell2gat(cell);
@@ -2534,13 +2602,19 @@ int map_getcellp(struct map_data* m,int16 x,int16 y,cell_chk cellchk)
}
}
+/* [Ind/Hercules] */
+int map_sub_getcellp(struct map_data* m,int16 x,int16 y,cell_chk cellchk) {
+ map_cellfromcache(m);
+ m->getcellp = map_getcellp;
+ m->setcell = map_setcell;
+ return m->getcellp(m,x,y,cellchk);
+}
/*==========================================
* Change the type/flags of a map cell
* 'cell' - which flag to modify
* 'flag' - true = on, false = off
*------------------------------------------*/
-void map_setcell(int16 m, int16 x, int16 y, cell_t cell, bool flag)
-{
+void map_setcell(int16 m, int16 x, int16 y, cell_t cell, bool flag) {
int j;
if( m < 0 || m >= map_num || x < 0 || x >= map[m].xs || y < 0 || y >= map[m].ys )
@@ -2565,7 +2639,16 @@ void map_setcell(int16 m, int16 x, int16 y, cell_t cell, bool flag)
break;
}
}
-
+void map_sub_setcell(int16 m, int16 x, int16 y, cell_t cell, bool flag) {
+
+ if( m < 0 || m >= map_num || x < 0 || x >= map[m].xs || y < 0 || y >= map[m].ys )
+ return;
+
+ map_cellfromcache(&map[m]);
+ map[m].setcell = map_setcell;
+ map[m].getcellp = map_getcellp;
+ map[m].setcell(m,x,y,cell,flag);
+}
void map_setgatcell(int16 m, int16 x, int16 y, int gat)
{
int j;
@@ -2635,8 +2718,8 @@ bool map_iwall_set(int16 m, int16 x, int16 y, int size, int8 dir, bool shootable
if( map_getcell(m, x1, y1, CELL_CHKNOREACH) )
break; // Collision
- map_setcell(m, x1, y1, CELL_WALKABLE, false);
- map_setcell(m, x1, y1, CELL_SHOOTABLE, shootable);
+ map[m].setcell(m, x1, y1, CELL_WALKABLE, false);
+ map[m].setcell(m, x1, y1, CELL_SHOOTABLE, shootable);
clif->changemapcell(0, m, x1, y1, map_getcell(m, x1, y1, CELL_GETTYPE), ALL_SAMEMAP);
}
@@ -2682,8 +2765,8 @@ void map_iwall_remove(const char *wall_name)
for( i = 0; i < iwall->size; i++ ) {
map_iwall_nextxy(iwall->x, iwall->y, iwall->dir, i, &x1, &y1);
- map_setcell(iwall->m, x1, y1, CELL_SHOOTABLE, true);
- map_setcell(iwall->m, x1, y1, CELL_WALKABLE, true);
+ map[iwall->m].setcell(iwall->m, x1, y1, CELL_SHOOTABLE, true);
+ map[iwall->m].setcell(iwall->m, x1, y1, CELL_WALKABLE, true);
clif->changemapcell(0, iwall->m, x1, y1, map_getcell(iwall->m, x1, y1, CELL_GETTYPE), ALL_SAMEMAP);
}
@@ -2740,8 +2823,7 @@ int map_eraseallipport_sub(DBKey key, DBData *data, va_list va)
return 0;
}
-int map_eraseallipport(void)
-{
+int map_eraseallipport(void) {
map_db->foreach(map_db,map_eraseallipport_sub);
return 1;
}
@@ -2749,8 +2831,7 @@ int map_eraseallipport(void)
/*==========================================
* Delete mapindex from db of another map server
*------------------------------------------*/
-int map_eraseipport(unsigned short mapindex, uint32 ip, uint16 port)
-{
+int map_eraseipport(unsigned short mapindex, uint32 ip, uint16 port) {
struct map_data_other_server *mdos;
mdos = (struct map_data_other_server*)uidb_get(map_db,(unsigned int)mapindex);
@@ -2800,13 +2881,12 @@ static char *map_init_mapcache(FILE *fp)
* Map cache reading
* [Shinryo]: Optimized some behaviour to speed this up
*==========================================*/
-int map_readfromcache(struct map_data *m, char *buffer, char *decode_buffer)
-{
+int map_readfromcache(struct map_data *m, char *buffer) {
int i;
struct map_cache_main_header *header = (struct map_cache_main_header *)buffer;
struct map_cache_map_info *info = NULL;
char *p = buffer + sizeof(struct map_cache_main_header);
-
+
for(i = 0; i < header->map_count; i++) {
info = (struct map_cache_map_info *)p;
@@ -2818,8 +2898,8 @@ int map_readfromcache(struct map_data *m, char *buffer, char *decode_buffer)
}
if( info && i < header->map_count ) {
- unsigned long size, xy;
-
+ unsigned long size;
+
if( info->xs <= 0 || info->ys <= 0 )
return 0;// Invalid
@@ -2831,51 +2911,30 @@ int map_readfromcache(struct map_data *m, char *buffer, char *decode_buffer)
ShowWarning("map_readfromcache: %s exceeded MAX_MAP_SIZE of %d\n", info->name, MAX_MAP_SIZE);
return 0; // Say not found to remove it from list.. [Shinryo]
}
-
- // TO-DO: Maybe handle the scenario, if the decoded buffer isn't the same size as expected? [Shinryo]
- decode_zip(decode_buffer, &size, p+sizeof(struct map_cache_map_info), info->len);
-
- CREATE(m->cell, struct mapcell, size);
-
-
- for( xy = 0; xy < size; ++xy )
- m->cell[xy] = map_gat2cell(decode_buffer[xy]);
-
+
+ m->cellPos = p;
+ m->cell = (struct mapcell *)0xdeadbeaf;
+
return 1;
}
return 0; // Not found
}
-int map_addmap(char* mapname)
-{
- if( strcmpi(mapname,"clear")==0 )
- {
- map_num = 0;
- instance_start = 0;
- return 0;
- }
-
- if( map_num >= MAX_MAP_PER_SERVER - 1 )
- {
- ShowError("Could not add map '"CL_WHITE"%s"CL_RESET"', the limit of maps has been reached.\n",mapname);
- return 1;
- }
- mapindex_getmapname(mapname, map[map_num].name);
- map_num++;
+int map_addmap(char* mapname) {
+ map[map_num].instance_id = -1;
+ mapindex_getmapname(mapname, map[map_num++].name);
return 0;
}
-static void map_delmapid(int id)
-{
+static void map_delmapid(int id) {
ShowNotice("Removing map [ %s ] from maplist"CL_CLL"\n",map[id].name);
memmove(map+id, map+id+1, sizeof(map[0])*(map_num-id-1));
map_num--;
}
-int map_delmap(char* mapname)
-{
+int map_delmap(char* mapname) {
int i;
char map_name[MAP_NAME_LENGTH];
@@ -2958,13 +3017,62 @@ void map_zone_db_clear(void) {
}
aFree(map_zone_all.capped_skills);
}
-
+void map_clean(int i) {
+ int v;
+ if(map[i].cell && map[i].cell != (struct mapcell *)0xdeadbeaf) aFree(map[i].cell);
+ if(map[i].block) aFree(map[i].block);
+ if(map[i].block_mob) aFree(map[i].block_mob);
+
+ if(battle_config.dynamic_mobs) { //Dynamic mobs flag by [random]
+ int j;
+ if(map[i].mob_delete_timer != INVALID_TIMER)
+ delete_timer(map[i].mob_delete_timer, map_removemobs_timer);
+ for (j=0; j<MAX_MOB_LIST_PER_MAP; j++)
+ if (map[i].moblist[j]) aFree(map[i].moblist[j]);
+ }
+
+ if( map[i].unit_count ) {
+ for(v = 0; v < map[i].unit_count; v++) {
+ aFree(map[i].units[v]);
+ }
+ if( map[i].units ) {
+ aFree(map[i].units);
+ map[i].units = NULL;
+ }
+ map[i].unit_count = 0;
+ }
+
+ if( map[i].skill_count ) {
+ for(v = 0; v < map[i].skill_count; v++) {
+ aFree(map[i].skills[v]);
+ }
+ if( map[i].skills ) {
+ aFree(map[i].skills);
+ map[i].skills = NULL;
+ }
+ map[i].skill_count = 0;
+ }
+
+ if( map[i].zone_mf_count ) {
+ for(v = 0; v < map[i].zone_mf_count; v++) {
+ aFree(map[i].zone_mf[v]);
+ }
+ if( map[i].zone_mf ) {
+ aFree(map[i].zone_mf);
+ map[i].zone_mf = NULL;
+ }
+ map[i].zone_mf_count = 0;
+ }
+
+ if( map[i].channel )
+ clif->chsys_delete(map[i].channel);
+}
void do_final_maps(void) {
int i, v = 0;
for( i = 0; i < map_num; i++ ) {
- if(map[i].cell) aFree(map[i].cell);
+ if(map[i].cell && map[i].cell != (struct mapcell *)0xdeadbeaf ) aFree(map[i].cell);
if(map[i].block) aFree(map[i].block);
if(map[i].block_mob) aFree(map[i].block_mob);
@@ -3009,6 +3117,12 @@ void do_final_maps(void) {
map[i].zone_mf_count = 0;
}
+ if( map[i].drop_list_count ) {
+ map[i].drop_list_count = 0;
+ }
+ if( map[i].drop_list != NULL )
+ aFree(map[i].drop_list);
+
if( map[i].channel )
clif->chsys_delete(map[i].channel);
}
@@ -3028,7 +3142,10 @@ void map_flags_init(void) {
map[i].nocommand = 0; // nocommand mapflag level
map[i].bexp = 100; // per map base exp multiplicator
map[i].jexp = 100; // per map job exp multiplicator
- memset(map[i].drop_list, 0, sizeof(map[i].drop_list)); // pvp nightmare drop list
+ if( map[i].drop_list != NULL )
+ aFree(map[i].drop_list);
+ map[i].drop_list = NULL;
+ map[i].drop_list_count = 0;
if( map[i].unit_count ) {
for(v = 0; v < map[i].unit_count; v++) {
@@ -3153,14 +3270,12 @@ int map_readgat (struct map_data* m)
/*======================================
* Add/Remove map to the map_db
*--------------------------------------*/
-void map_addmap2db(struct map_data *m)
-{
- uidb_put(map_db, (unsigned int)m->index, m);
+void map_addmap2db(struct map_data *m) {
+ index2mapid[m->index] = m->m;
}
-void map_removemapdb(struct map_data *m)
-{
- uidb_remove(map_db, (unsigned int)m->index);
+void map_removemapdb(struct map_data *m) {
+ index2mapid[m->index] = 0;
}
/*======================================
@@ -3170,8 +3285,6 @@ int map_readallmaps (void) {
int i;
FILE* fp=NULL;
int maps_removed = 0;
- char *map_cache_buffer = NULL; // Has the uncompressed gat data of all maps, so just one allocation has to be made
- char map_cache_decode_buffer[MAX_MAP_SIZE];
if( enable_grf )
ShowStatus("Loading maps (using GRF files)...\n");
@@ -3203,7 +3316,7 @@ int map_readallmaps (void) {
if( !
(enable_grf?
map_readgat(&map[i])
- :map_readfromcache(&map[i], map_cache_buffer, map_cache_decode_buffer))
+ :map_readfromcache(&map[i], map_cache_buffer))
) {
map_delmapid(i);
maps_removed++;
@@ -3213,10 +3326,9 @@ int map_readallmaps (void) {
map[i].index = mapindex_name2id(map[i].name);
- if (uidb_get(map_db,(unsigned int)map[i].index) != NULL)
- {
+ if ( index2mapid[map[i].index] != 0 ) {
ShowWarning("Map %s already loaded!"CL_CLL"\n", map[i].name);
- if (map[i].cell) {
+ if (map[i].cell && map[i].cell != (struct mapcell *)0xdeadbeaf) {
aFree(map[i].cell);
map[i].cell = NULL;
}
@@ -3225,10 +3337,10 @@ int map_readallmaps (void) {
i--;
continue;
}
-
+
+ map[i].m = i;
map_addmap2db(&map[i]);
- 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]
@@ -3238,6 +3350,9 @@ int map_readallmaps (void) {
size = map[i].bxs * map[i].bys * sizeof(struct block_list*);
map[i].block = (struct block_list**)aCalloc(size, 1);
map[i].block_mob = (struct block_list**)aCalloc(size, 1);
+
+ map[i].getcellp = map_sub_getcellp;
+ map[i].setcell = map_sub_setcell;
}
// intialization and configuration-dependent adjustments of mapflags
@@ -3245,14 +3360,11 @@ int map_readallmaps (void) {
if( !enable_grf ) {
fclose(fp);
-
- // The cache isn't needed anymore, so free it.. [Shinryo]
- aFree(map_cache_buffer);
}
// finished map loading
ShowInfo("Successfully loaded '"CL_WHITE"%d"CL_RESET"' maps."CL_CLL"\n",map_num);
- instance_start = map_num; // Next Map Index will be instances
+ instance->start_id = map_num; // Next Map Index will be instances
if (maps_removed)
ShowNotice("Maps removed: '"CL_WHITE"%d"CL_RESET"'\n",maps_removed);
@@ -3267,20 +3379,17 @@ static int char_ip_set = 0;
/*==========================================
* Read map server configuration files (conf/map_server.conf...)
*------------------------------------------*/
-int map_config_read(char *cfgName)
-{
+int map_config_read(char *cfgName) {
char line[1024], w1[1024], w2[1024];
FILE *fp;
fp = fopen(cfgName,"r");
- if( fp == NULL )
- {
+ if( fp == NULL ) {
ShowError("Map configuration file not found at: %s\n", cfgName);
return 1;
}
- while( fgets(line, sizeof(line), fp) )
- {
+ while( fgets(line, sizeof(line), fp) ) {
char* ptr;
if( line[0] == '/' && line[1] == '/' )
@@ -3320,9 +3429,9 @@ int map_config_read(char *cfgName)
clif->setport(atoi(w2));
map_port = (atoi(w2));
} else if (strcmpi(w1, "map") == 0)
- map_addmap(w2);
+ map_num++;
else if (strcmpi(w1, "delmap") == 0)
- map_delmap(w2);
+ map_num--;
else if (strcmpi(w1, "npc") == 0)
npc_addsrcfile(w2);
else if (strcmpi(w1, "delnpc") == 0)
@@ -3362,7 +3471,43 @@ int map_config_read(char *cfgName)
fclose(fp);
return 0;
}
-
+int map_config_read_sub(char *cfgName) {
+ char line[1024], w1[1024], w2[1024];
+ FILE *fp;
+
+ fp = fopen(cfgName,"r");
+ if( fp == NULL ) {
+ ShowError("Map configuration file not found at: %s\n", cfgName);
+ return 1;
+ }
+
+ while( fgets(line, sizeof(line), fp) ) {
+ char* ptr;
+
+ if( line[0] == '/' && line[1] == '/' )
+ continue;
+ if( (ptr = strstr(line, "//")) != NULL )
+ *ptr = '\n'; //Strip comments
+ if( sscanf(line, "%[^:]: %[^\t\r\n]", w1, w2) < 2 )
+ continue;
+
+ //Strip trailing spaces
+ ptr = w2 + strlen(w2);
+ while (--ptr >= w2 && *ptr == ' ');
+ ptr++;
+ *ptr = '\0';
+
+ if (strcmpi(w1, "map") == 0)
+ map_addmap(w2);
+ else if (strcmpi(w1, "delmap") == 0)
+ map_delmap(w2);
+ else if (strcmpi(w1, "import") == 0)
+ map_config_read_sub(w2);
+ }
+
+ fclose(fp);
+ return 0;
+}
void map_reloadnpc_sub(char *cfgName)
{
char line[1024], w1[1024], w2[1024];
@@ -4849,11 +4994,12 @@ void read_map_zone_db(void) {
/**
* @see DBApply
*/
-int map_db_final(DBKey key, DBData *data, va_list ap)
-{
+int map_db_final(DBKey key, DBData *data, va_list ap) {
struct map_data_other_server *mdos = DB->data2ptr(data);
- if(mdos && mdos->cell == NULL)
+
+ if(mdos && malloclib->verify_ptr(mdos) && mdos->cell == NULL)
aFree(mdos);
+
return 0;
}
@@ -4877,8 +5023,7 @@ int nick_db_final(DBKey key, DBData *data, va_list args)
return 0;
}
-int cleanup_sub(struct block_list *bl, va_list ap)
-{
+int cleanup_sub(struct block_list *bl, va_list ap) {
nullpo_ret(bl);
switch(bl->type) {
@@ -4932,6 +5077,8 @@ void do_final(void)
map_quit(sd);
mapit->free(iter);
+ instance->final();
+
/* prepares npcs for a faster shutdown process */
do_clear_npc();
@@ -4954,7 +5101,6 @@ void do_final(void)
clif->final();
do_final_npc();
script->final();
- do_final_instance();
do_final_itemdb();
do_final_storage();
guild->final();
@@ -4993,6 +5139,9 @@ void do_final(void)
aFree(map);
+ if( !enable_grf )
+ aFree(map_cache_buffer);
+
ShowStatus("Finished.\n");
}
@@ -5196,10 +5345,12 @@ void map_defaults(void) {
void load_defaults(void) {
atcommand_defaults();
battle_defaults();
+ battleground_defaults();
buyingstore_defaults();
clif_defaults();
guild_defaults();
homunculus_defaults();
+ instance_defaults();
ircbot_defaults();
log_defaults();
map_defaults();
@@ -5228,79 +5379,50 @@ int do_init(int argc, char *argv[])
rnd_init();
- for( i = 1; i < argc ; i++ )
- {
+ for( i = 1; i < argc ; i++ ) {
const char* arg = argv[i];
- if( arg[0] != '-' && ( arg[0] != '/' || arg[1] == '-' ) )
- {// -, -- and /
+ if( arg[0] != '-' && ( arg[0] != '/' || arg[1] == '-' ) ) {// -, -- and /
ShowError("Unknown option '%s'.\n", argv[i]);
exit(EXIT_FAILURE);
- }
- else if( (++arg)[0] == '-' )
- {// long option
+ } else if( (++arg)[0] == '-' ) {// long option
arg++;
- if( strcmp(arg, "help") == 0 )
- {
+ if( strcmp(arg, "help") == 0 ) {
map_helpscreen(true);
- }
- else if( strcmp(arg, "version") == 0 )
- {
+ } else if( strcmp(arg, "version") == 0 ) {
map_versionscreen(true);
- }
- else if( strcmp(arg, "map-config") == 0 )
- {
+ } else if( strcmp(arg, "map-config") == 0 ) {
if( map_arg_next_value(arg, i, argc) )
MAP_CONF_NAME = argv[++i];
- }
- else if( strcmp(arg, "battle-config") == 0 )
- {
+ } else if( strcmp(arg, "battle-config") == 0 ) {
if( map_arg_next_value(arg, i, argc) )
BATTLE_CONF_FILENAME = argv[++i];
- }
- else if( strcmp(arg, "atcommand-config") == 0 )
- {
+ } else if( strcmp(arg, "atcommand-config") == 0 ) {
if( map_arg_next_value(arg, i, argc) )
ATCOMMAND_CONF_FILENAME = argv[++i];
- }
- else if( strcmp(arg, "script-config") == 0 )
- {
+ } else if( strcmp(arg, "script-config") == 0 ) {
if( map_arg_next_value(arg, i, argc) )
SCRIPT_CONF_NAME = argv[++i];
- }
- else if( strcmp(arg, "msg-config") == 0 )
- {
+ } else if( strcmp(arg, "msg-config") == 0 ) {
if( map_arg_next_value(arg, i, argc) )
MSG_CONF_NAME = argv[++i];
- }
- else if( strcmp(arg, "grf-path-file") == 0 )
- {
+ } else if( strcmp(arg, "grf-path-file") == 0 ) {
if( map_arg_next_value(arg, i, argc) )
GRF_PATH_FILENAME = argv[++i];
- }
- else if( strcmp(arg, "inter-config") == 0 )
- {
+ } else if( strcmp(arg, "inter-config") == 0 ) {
if( map_arg_next_value(arg, i, argc) )
INTER_CONF_NAME = argv[++i];
- }
- else if( strcmp(arg, "log-config") == 0 )
- {
+ } else if( strcmp(arg, "log-config") == 0 ) {
if( map_arg_next_value(arg, i, argc) )
LOG_CONF_NAME = argv[++i];
- }
- else if( strcmp(arg, "run-once") == 0 ) // close the map-server as soon as its done.. for testing [Celest]
- {
+ } else if( strcmp(arg, "run-once") == 0 ) { // close the map-server as soon as its done.. for testing [Celest]
runflag = CORE_ST_STOP;
- }
- else
- {
+ } else {
ShowError("Unknown option '%s'.\n", argv[i]);
exit(EXIT_FAILURE);
}
- }
- else switch( arg[0] )
- {// short option
+ } else switch( arg[0] ) {// short option
case '?':
case 'h':
map_helpscreen(true);
@@ -5313,12 +5435,13 @@ int do_init(int argc, char *argv[])
exit(EXIT_FAILURE);
}
}
-
- CREATE(map,struct map_data,MAX_MAP_PER_SERVER);
-
+ memset(&index2mapid, 0, sizeof(index2mapid));
+
load_defaults();
-
map_config_read(MAP_CONF_NAME);
+ CREATE(map,struct map_data,map_num);
+ map_num = 0;
+ map_config_read_sub(MAP_CONF_NAME);
// loads npcs
map_reloadnpc(false);
@@ -5384,7 +5507,7 @@ int do_init(int argc, char *argv[])
atcommand->init();
battle->init();
- do_init_instance();
+ instance->init();
do_init_chrif();
clif->init();
ircbot->init();
diff --git a/src/map/map.h b/src/map/map.h
index f524e8840..850913474 100644
--- a/src/map/map.h
+++ b/src/map/map.h
@@ -27,20 +27,18 @@ enum E_MAPSERVER_ST {
MAPSERVER_ST_LAST
};
-
#define MAX_NPC_PER_MAP 512
#define AREA_SIZE battle_config.area_size
#define DAMAGELOG_SIZE 30
#define LOOTITEM_SIZE 10
#define MAX_MOBSKILL 50 //Max 128, see mob skill_idx type if need this higher
-#define MAX_MOB_LIST_PER_MAP 128
+#define MAX_MOB_LIST_PER_MAP 100
#define MAX_EVENTQUEUE 2
#define MAX_EVENTTIMER 32
#define NATURAL_HEAL_INTERVAL 500
#define MIN_FLOORITEM 2
#define MAX_FLOORITEM START_ACCOUNT_NUM
#define MAX_LEVEL 150
-#define MAX_DROP_PER_MAP 48
#define MAX_IGNORE_LIST 20 // official is 14
#define MAX_VENDING 12
#define MAX_MAP_SIZE 512*512 // Wasn't there something like this already? Can't find it.. [Shinryo]
@@ -558,6 +556,12 @@ void map_zone_change2(int m, struct map_zone_data *zone);
struct map_zone_data map_zone_all;/* used as a base on all maps */
struct map_zone_data map_zone_pk;/* used for (pk_mode) */
+struct map_drop_list {
+ int drop_id;
+ int drop_type;
+ int drop_per;
+};
+
struct map_data {
char name[MAP_NAME_LENGTH];
@@ -625,11 +629,8 @@ struct map_data {
} flag;
struct point save;
struct npc_data *npc[MAX_NPC_PER_MAP];
- struct {
- int drop_id;
- int drop_type;
- int drop_per;
- } drop_list[MAX_DROP_PER_MAP];
+ struct map_drop_list *drop_list;
+ unsigned short drop_list_count;
struct spawn_data *moblist[MAX_MOB_LIST_PER_MAP]; // [Wizputer]
int mob_delete_timer; // [Skotlex]
@@ -676,6 +677,14 @@ struct map_data {
unsigned short short_damage_rate;
/* long_damage_rate mapflag */
unsigned short long_damage_rate;
+
+ /* instance unique name */
+ char *cName;
+
+ /* */
+ int (*getcellp)(struct map_data* m,int16 x,int16 y,cell_chk cellchk);
+ void (*setcell) (int16 m, int16 x, int16 y, cell_t cell, bool flag);
+ char *cellPos;
};
/// Stores information about a remote map (for multi-mapserver setups).
@@ -689,8 +698,6 @@ struct map_data_other_server {
};
int map_getcell(int16 m,int16 x,int16 y,cell_chk cellchk);
-int map_getcellp(struct map_data* m,int16 x,int16 y,cell_chk cellchk);
-void map_setcell(int16 m, int16 x, int16 y, cell_t cell, bool flag);
void map_setgatcell(int16 m, int16 x, int16 y, int gat);
struct map_data *map;
@@ -711,6 +718,8 @@ extern char charhelp_txt[];
extern char wisp_server_name[];
+void map_cellfromcache(struct map_data *m);
+
// users
void map_setusers(int);
int map_getusers(void);
@@ -733,6 +742,7 @@ int map_foreachinmovearea(int (*func)(struct block_list*,va_list), struct block_
int map_foreachincell(int (*func)(struct block_list*,va_list), int16 m, int16 x, int16 y, int type, ...);
int map_foreachinpath(int (*func)(struct block_list*,va_list), int16 m, int16 x0, int16 y0, int16 x1, int16 y1, int16 range, int length, int type, ...);
int map_foreachinmap(int (*func)(struct block_list*,va_list), int16 m, int type, ...);
+int map_foreachininstance(int (*func)(struct block_list*,va_list), int16 instance_id, int type,...);
//blocklist nb in one cell
int map_count_oncell(int16 m,int16 x,int16 y,int type);
struct skill_unit *map_find_skill_unit_oncell(struct block_list *,int16 x,int16 y,uint16 skill_id,struct skill_unit *, int flag);
@@ -831,6 +841,7 @@ void map_removemobs(int16 m); // [Wizputer]
void do_reconnect_map(void); //Invoked on map-char reconnection [Skotlex]
void map_addmap2db(struct map_data *m);
void map_removemapdb(struct map_data *m);
+void map_clean(int i);
extern char *INTER_CONF_NAME;
extern char *LOG_CONF_NAME;
diff --git a/src/map/mob.c b/src/map/mob.c
index 57325ba1c..433e979f3 100644
--- a/src/map/mob.c
+++ b/src/map/mob.c
@@ -137,7 +137,7 @@ void mvptomb_create(struct mob_data *md, char *killer, time_t time)
nd->bl.id = md->tomb_nid = npc_get_new_npc_id();
- nd->ud.dir = md->ud.dir;
+ nd->dir = md->ud.dir;
nd->bl.m = md->bl.m;
nd->bl.x = md->bl.x;
nd->bl.y = md->bl.y;
@@ -262,8 +262,7 @@ int mob_parse_dataset(struct spawn_data *data)
/*==========================================
* Generates the basic mob data using the spawn_data provided.
*------------------------------------------*/
-struct mob_data* mob_spawn_dataset(struct spawn_data *data)
-{
+struct mob_data* mob_spawn_dataset(struct spawn_data *data) {
struct mob_data *md = (struct mob_data*)aCalloc(1, sizeof(struct mob_data));
md->bl.id= npc_get_new_npc_id();
md->bl.type = BL_MOB;
@@ -290,7 +289,7 @@ struct mob_data* mob_spawn_dataset(struct spawn_data *data)
status_set_viewdata(&md->bl, md->class_);
status_change_init(&md->bl);
unit_dataset(&md->bl);
-
+
map_addiddb(&md->bl);
return md;
}
diff --git a/src/map/npc.c b/src/map/npc.c
index 7d0d5c6e1..bff6be30c 100644
--- a/src/map/npc.c
+++ b/src/map/npc.c
@@ -122,7 +122,7 @@ struct view_data* npc_get_viewdata(int class_)
static int npc_isnear_sub(struct block_list* bl, va_list args) {
struct npc_data *nd = (struct npc_data*)bl;
- if( nd->sc.option & (OPTION_HIDE|OPTION_INVISIBLE) )
+ if( nd->option & (OPTION_HIDE|OPTION_INVISIBLE) )
return 0;
return 1;
@@ -175,7 +175,7 @@ int npc_enable_sub(struct block_list *bl, va_list ap)
{
TBL_PC *sd = (TBL_PC*)bl;
- if (nd->sc.option&OPTION_INVISIBLE)
+ if (nd->option&OPTION_INVISIBLE)
return 1;
if( npc_ontouch_event(sd,nd) > 0 && npc_ontouch2_event(sd,nd) > 0 )
@@ -204,20 +204,20 @@ int npc_enable(const char* name, int flag)
}
if (flag&1) {
- nd->sc.option&=~OPTION_INVISIBLE;
+ nd->option&=~OPTION_INVISIBLE;
clif->spawn(&nd->bl);
} else if (flag&2)
- nd->sc.option&=~OPTION_HIDE;
+ nd->option&=~OPTION_HIDE;
else if (flag&4)
- nd->sc.option|= OPTION_HIDE;
+ nd->option|= OPTION_HIDE;
else { //Can't change the view_data to invisible class because the view_data for all npcs is shared! [Skotlex]
- nd->sc.option|= OPTION_INVISIBLE;
+ nd->option|= OPTION_INVISIBLE;
clif->clearunit_area(&nd->bl,CLR_OUTSIGHT); // Hack to trick maya purple card [Xazax]
}
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))
+ if (nd->option&(OPTION_HIDE|OPTION_INVISIBLE))
clif->clearunit_area(&nd->bl, CLR_OUTSIGHT);
else
clif->spawn(&nd->bl);
@@ -385,8 +385,7 @@ static int npc_event_do_sub(DBKey key, DBData *data, va_list ap)
nullpo_ret(c = va_arg(ap, int *));
nullpo_ret(name = va_arg(ap, const char *));
- if( p && strcmpi(name, p) == 0 )
- {
+ if( p && strcmpi(name, p) == 0 ) {
run_script(ev->nd->u.scr.script,ev->pos,0,ev->nd->bl.id);
(*c)++;
}
@@ -815,7 +814,7 @@ int npc_event_sub(struct map_session_data* sd, struct event_data* ev, const char
ShowWarning("npc_event: player's event queue is full, can't add event '%s' !\n", eventname);
return 1;
}
- if( ev->nd->sc.option&OPTION_INVISIBLE )
+ if( ev->nd->option&OPTION_INVISIBLE )
{
//Disabled npc, shouldn't trigger event.
npc_event_dequeue(sd);
@@ -835,22 +834,20 @@ int npc_event(struct map_session_data* sd, const char* eventname, int ontouch)
nullpo_ret(sd);
- if( ev == NULL || (nd = ev->nd) == NULL )
- {
+ if( ev == NULL || (nd = ev->nd) == NULL ) {
if( !ontouch )
ShowError("npc_event: event not found [%s]\n", eventname);
return ontouch;
}
- switch(ontouch)
- {
- case 1:
- nd->touching_id = sd->bl.id;
- sd->touching_id = nd->bl.id;
- break;
- case 2:
- sd->areanpc_id = nd->bl.id;
- break;
+ switch(ontouch) {
+ case 1:
+ nd->touching_id = sd->bl.id;
+ sd->touching_id = nd->bl.id;
+ break;
+ case 2:
+ sd->areanpc_id = nd->bl.id;
+ break;
}
return npc_event_sub(sd,ev,eventname);
@@ -928,9 +925,8 @@ int npc_touch_areanpc(struct map_session_data* sd, int16 m, int16 x, int16 y)
//if(sd->npc_id)
// return 1;
- for(i=0;i<map[m].npc_num;i++)
- {
- if (map[m].npc[i]->sc.option&OPTION_INVISIBLE) {
+ for(i=0;i<map[m].npc_num;i++) {
+ if (map[m].npc[i]->option&OPTION_INVISIBLE) {
f=0; // a npc was found, but it is disabled; don't print warning
continue;
}
@@ -1008,13 +1004,11 @@ int npc_touch_areanpc2(struct mob_data *md)
struct event_data* ev;
int xs, ys;
- for( i = 0; i < map[m].npc_num; i++ )
- {
- if( map[m].npc[i]->sc.option&OPTION_INVISIBLE )
+ for( i = 0; i < map[m].npc_num; i++ ) {
+ if( map[m].npc[i]->option&OPTION_INVISIBLE )
continue;
- switch( map[m].npc[i]->subtype )
- {
+ switch( map[m].npc[i]->subtype ) {
case WARP:
if( !( battle_config.mob_warp&1 ) )
continue;
@@ -1087,27 +1081,25 @@ int npc_check_areanpc(int flag, int16 m, int16 x, int16 y, int16 range)
if (!i) return 0; //No NPC_CELLs.
//Now check for the actual NPC on said range.
- for(i=0;i<map[m].npc_num;i++)
- {
- if (map[m].npc[i]->sc.option&OPTION_INVISIBLE)
+ for(i=0;i<map[m].npc_num;i++) {
+ if (map[m].npc[i]->option&OPTION_INVISIBLE)
continue;
- switch(map[m].npc[i]->subtype)
- {
- case WARP:
- if (!(flag&1))
- continue;
- xs=map[m].npc[i]->u.warp.xs;
- ys=map[m].npc[i]->u.warp.ys;
- break;
- case SCRIPT:
- if (!(flag&2))
+ switch(map[m].npc[i]->subtype) {
+ case WARP:
+ if (!(flag&1))
+ continue;
+ xs=map[m].npc[i]->u.warp.xs;
+ ys=map[m].npc[i]->u.warp.ys;
+ break;
+ case SCRIPT:
+ if (!(flag&2))
+ continue;
+ xs=map[m].npc[i]->u.scr.xs;
+ ys=map[m].npc[i]->u.scr.ys;
+ break;
+ default:
continue;
- xs=map[m].npc[i]->u.scr.xs;
- ys=map[m].npc[i]->u.scr.ys;
- break;
- default:
- continue;
}
if( x1 >= map[m].npc[i]->bl.x-xs && x0 <= map[m].npc[i]->bl.x+xs
@@ -1206,7 +1198,7 @@ int npc_click(struct map_session_data* sd, struct npc_data* nd)
if ((nd = npc_checknear(sd,&nd->bl)) == NULL)
return 1;
//Hidden/Disabled npc.
- if (nd->class_ < 0 || nd->sc.option&(OPTION_INVISIBLE|OPTION_HIDE))
+ if (nd->class_ < 0 || nd->option&(OPTION_INVISIBLE|OPTION_HIDE))
return 1;
switch(nd->subtype) {
@@ -1291,7 +1283,7 @@ int npc_buysellsel(struct map_session_data* sd, int id, int type)
sd->npc_id=0;
return 1;
}
- if (nd->sc.option & OPTION_INVISIBLE) // can't buy if npc is not visible (hack?)
+ if (nd->option & OPTION_INVISIBLE) // can't buy if npc is not visible (hack?)
return 1;
if( nd->class_ < 0 && !sd->state.callshop )
{// not called through a script and is not a visible NPC so an invalid call
@@ -1759,8 +1751,7 @@ int npc_selllist(struct map_session_data* sd, int n, unsigned short* item_list)
//Atempt to remove an npc from a map
//This doesn't remove it from map_db
-int npc_remove_map(struct npc_data* nd)
-{
+int npc_remove_map(struct npc_data* nd) {
int16 m,i;
nullpo_retr(1, nd);
@@ -1892,6 +1883,11 @@ int npc_unload(struct npc_data* nd, bool single) {
guild->flag_remove(nd);
}
+ if( nd->ud != &npc_base_ud ) {
+ aFree(nd->ud);
+ nd->ud = NULL;
+ }
+
script_stop_sleeptimers(nd->bl.id);
aFree(nd);
@@ -2060,8 +2056,7 @@ static void npc_parsename(struct npc_data* nd, const char* name, const char* sta
}
//Add then display an npc warp on map
-struct npc_data* npc_add_warp(char* name, short from_mapid, short from_x, short from_y, short xs, short ys, unsigned short to_mapindex, short to_x, short to_y)
-{
+struct npc_data* npc_add_warp(char* name, short from_mapid, short from_x, short from_y, short xs, short ys, unsigned short to_mapindex, short to_x, short to_y) {
int i, flag = 0;
struct npc_data *nd;
@@ -2100,8 +2095,7 @@ struct npc_data* npc_add_warp(char* name, short from_mapid, short from_x, short
npc_setcells(nd);
map_addblock(&nd->bl);
status_set_viewdata(&nd->bl, nd->class_);
- status_change_init(&nd->bl);
- unit_dataset(&nd->bl);
+ nd->ud = &npc_base_ud;
if( map[nd->bl.m].users )
clif->spawn(&nd->bl);
strdb_put(npcname_db, nd->exname, nd);
@@ -2166,8 +2160,7 @@ static const char* npc_parse_warp(char* w1, char* w2, char* w3, char* w4, const
npc_setcells(nd);
map_addblock(&nd->bl);
status_set_viewdata(&nd->bl, nd->class_);
- status_change_init(&nd->bl);
- unit_dataset(&nd->bl);
+ nd->ud = &npc_base_ud;
if( map[nd->bl.m].users )
clif->spawn(&nd->bl);
strdb_put(npcname_db, nd->exname, nd);
@@ -2275,18 +2268,15 @@ static const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const
++npc_shop;
nd->bl.type = BL_NPC;
nd->subtype = type;
- if( m >= 0 )
- {// normal shop npc
+ if( m >= 0 ) {// normal shop npc
map_addnpc(m,nd);
map_addblock(&nd->bl);
status_set_viewdata(&nd->bl, nd->class_);
- status_change_init(&nd->bl);
- unit_dataset(&nd->bl);
- nd->ud.dir = dir;
+ nd->ud = &npc_base_ud;
+ nd->dir = dir;
if( map[nd->bl.m].users )
clif->spawn(&nd->bl);
- } else
- {// 'floating' shop?
+ } else {// 'floating' shop?
map_addiddb(&nd->bl);
}
strdb_put(npcname_db, nd->exname, nd);
@@ -2485,23 +2475,18 @@ static const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, cons
nd->bl.type = BL_NPC;
nd->subtype = SCRIPT;
- if( m >= 0 )
- {
+ if( m >= 0 ) {
map_addnpc(m, nd);
- status_change_init(&nd->bl);
- unit_dataset(&nd->bl);
- nd->ud.dir = dir;
+ nd->ud = &npc_base_ud;
+ nd->dir = dir;
npc_setcells(nd);
map_addblock(&nd->bl);
- if( class_ >= 0 )
- {
+ if( class_ >= 0 ) {
status_set_viewdata(&nd->bl, nd->class_);
if( map[nd->bl.m].users )
clif->spawn(&nd->bl);
}
- }
- else
- {
+ } else {
// we skip map_addnpc, but still add it to the list of ID's
map_addiddb(&nd->bl);
}
@@ -2576,13 +2561,10 @@ const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const ch
type = dnd->subtype;
// get placement
- if( (type==SHOP || type==CASHSHOP || type==SCRIPT) && strcmp(w1, "-") == 0 )
- {// floating shop/chashshop/script
+ if( (type==SHOP || type==CASHSHOP || type==SCRIPT) && strcmp(w1, "-") == 0 ) {// floating shop/chashshop/script
x = y = dir = 0;
m = -1;
- }
- else
- {
+ } else {
if( sscanf(w1, "%31[^,],%d,%d,%d", mapname, &x, &y, &dir) != 4 )// <map name>,<x>,<y>,<facing>
{
ShowError("npc_parse_duplicate: Invalid placement format for duplicate in file '%s', line '%d'. Skipping line...\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4);
@@ -2599,8 +2581,7 @@ const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const ch
if( type == WARP && sscanf(w4, "%d,%d", &xs, &ys) == 2 );// <spanx>,<spany>
else if( type == SCRIPT && sscanf(w4, "%d,%d,%d", &class_, &xs, &ys) == 3);// <sprite id>,<triggerX>,<triggerY>
else if( type != WARP ) class_ = atoi(w4);// <sprite id>
- else
- {
+ else {
ShowError("npc_parse_duplicate: Invalid span format for duplicate warp in file '%s', line '%d'. Skipping line...\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4);
return end;// next line, try to continue
}
@@ -2618,56 +2599,50 @@ const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const ch
nd->src_id = src_id;
nd->bl.type = BL_NPC;
nd->subtype = (enum npc_subtype)type;
- switch( type )
- {
- case SCRIPT:
- ++npc_script;
- nd->u.scr.xs = xs;
- nd->u.scr.ys = ys;
- nd->u.scr.script = dnd->u.scr.script;
- nd->u.scr.label_list = dnd->u.scr.label_list;
- nd->u.scr.label_list_num = dnd->u.scr.label_list_num;
- break;
-
- case SHOP:
- case CASHSHOP:
- ++npc_shop;
- nd->u.shop.shop_item = dnd->u.shop.shop_item;
- nd->u.shop.count = dnd->u.shop.count;
- break;
-
- case WARP:
- ++npc_warp;
- if( !battle_config.warp_point_debug )
- nd->class_ = WARP_CLASS;
- else
- nd->class_ = WARP_DEBUG_CLASS;
- nd->u.warp.xs = xs;
- nd->u.warp.ys = ys;
- nd->u.warp.mapindex = dnd->u.warp.mapindex;
- nd->u.warp.x = dnd->u.warp.x;
- nd->u.warp.y = dnd->u.warp.y;
- break;
+ switch( type ) {
+ case SCRIPT:
+ ++npc_script;
+ nd->u.scr.xs = xs;
+ nd->u.scr.ys = ys;
+ nd->u.scr.script = dnd->u.scr.script;
+ nd->u.scr.label_list = dnd->u.scr.label_list;
+ nd->u.scr.label_list_num = dnd->u.scr.label_list_num;
+ break;
+
+ case SHOP:
+ case CASHSHOP:
+ ++npc_shop;
+ nd->u.shop.shop_item = dnd->u.shop.shop_item;
+ nd->u.shop.count = dnd->u.shop.count;
+ break;
+
+ case WARP:
+ ++npc_warp;
+ if( !battle_config.warp_point_debug )
+ nd->class_ = WARP_CLASS;
+ else
+ nd->class_ = WARP_DEBUG_CLASS;
+ nd->u.warp.xs = xs;
+ nd->u.warp.ys = ys;
+ nd->u.warp.mapindex = dnd->u.warp.mapindex;
+ nd->u.warp.x = dnd->u.warp.x;
+ nd->u.warp.y = dnd->u.warp.y;
+ break;
}
//Add the npc to its location
- if( m >= 0 )
- {
+ if( m >= 0 ) {
map_addnpc(m, nd);
- status_change_init(&nd->bl);
- unit_dataset(&nd->bl);
- nd->ud.dir = dir;
+ nd->ud = &npc_base_ud;
+ nd->dir = dir;
npc_setcells(nd);
map_addblock(&nd->bl);
- if( class_ >= 0 )
- {
+ if( class_ >= 0 ) {
status_set_viewdata(&nd->bl, nd->class_);
if( map[nd->bl.m].users )
clif->spawn(&nd->bl);
}
- }
- else
- {
+ } else {
// we skip map_addnpc, but still add it to the list of ID's
map_addiddb(&nd->bl);
}
@@ -2694,25 +2669,21 @@ const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const ch
int npc_duplicate4instance(struct npc_data *snd, int16 m) {
char newname[NAME_LENGTH];
- if( map[m].instance_id == 0 )
+ if( map[m].instance_id == -1 )
return 1;
snprintf(newname, ARRAYLENGTH(newname), "dup_%d_%d", map[m].instance_id, snd->bl.id);
- if( npc_name2id(newname) != NULL )
- { // Name already in use
+ if( npc_name2id(newname) != NULL ) { // Name already in use
ShowError("npc_duplicate4instance: the npcname (%s) is already in use while trying to duplicate npc %s in instance %d.\n", newname, snd->exname, map[m].instance_id);
return 1;
}
- if( snd->subtype == WARP )
- { // Adjust destination, if instanced
+ if( snd->subtype == WARP ) { // Adjust destination, if instanced
struct npc_data *wnd = NULL; // New NPC
int dm = map_mapindex2mapid(snd->u.warp.mapindex), im;
if( dm < 0 ) return 1;
- im = instance_mapid2imapid(dm, map[m].instance_id);
- if( im == -1 )
- {
+ if( ( im = instance->mapid2imapid(dm, map[m].instance_id) ) == -1 ) {
ShowError("npc_duplicate4instance: warp (%s) leading to instanced map (%s), but instance map is not attached to current instance.\n", map[dm].name, snd->exname);
return 1;
}
@@ -2738,18 +2709,15 @@ int npc_duplicate4instance(struct npc_data *snd, int16 m) {
npc_setcells(wnd);
map_addblock(&wnd->bl);
status_set_viewdata(&wnd->bl, wnd->class_);
- status_change_init(&wnd->bl);
- unit_dataset(&wnd->bl);
+ wnd->ud = &npc_base_ud;
if( map[wnd->bl.m].users )
clif->spawn(&wnd->bl);
strdb_put(npcname_db, wnd->exname, wnd);
- }
- else
- {
+ } else {
static char w1[50], w2[50], w3[50], w4[50];
const char* stat_buf = "- call from instancing subsystem -\n";
- snprintf(w1, sizeof(w1), "%s,%d,%d,%d", map[m].name, snd->bl.x, snd->bl.y, snd->ud.dir);
+ snprintf(w1, sizeof(w1), "%s,%d,%d,%d", map[m].name, snd->bl.x, snd->bl.y, snd->dir);
snprintf(w2, sizeof(w2), "duplicate(%s)", snd->exname);
snprintf(w3, sizeof(w3), "%s::%s", snd->name, newname);
@@ -2765,39 +2733,36 @@ int npc_duplicate4instance(struct npc_data *snd, int16 m) {
}
//Set mapcell CELL_NPC to trigger event later
-void npc_setcells(struct npc_data* nd)
-{
+void npc_setcells(struct npc_data* nd) {
int16 m = nd->bl.m, x = nd->bl.x, y = nd->bl.y, xs, ys;
int i,j;
- switch(nd->subtype)
- {
- case WARP:
- xs = nd->u.warp.xs;
- ys = nd->u.warp.ys;
- break;
- case SCRIPT:
- xs = nd->u.scr.xs;
- ys = nd->u.scr.ys;
- break;
- default:
- return; // Other types doesn't have touch area
+ switch(nd->subtype) {
+ case WARP:
+ xs = nd->u.warp.xs;
+ ys = nd->u.warp.ys;
+ break;
+ case SCRIPT:
+ xs = nd->u.scr.xs;
+ ys = nd->u.scr.ys;
+ break;
+ default:
+ return; // Other types doesn't have touch area
}
- if (m < 0 || xs < 0 || ys < 0) //invalid range or map
+ if (m < 0 || xs < 0 || ys < 0 || map[m].cell == (struct mapcell *)0xdeadbeaf) //invalid range or map
return;
for (i = y-ys; i <= y+ys; i++) {
for (j = x-xs; j <= x+xs; j++) {
if (map_getcell(m, j, i, CELL_CHKNOPASS))
continue;
- map_setcell(m, j, i, CELL_NPC, true);
+ map[m].setcell(m, j, i, CELL_NPC, true);
}
}
}
-int npc_unsetcells_sub(struct block_list* bl, va_list ap)
-{
+int npc_unsetcells_sub(struct block_list* bl, va_list ap) {
struct npc_data *nd = (struct npc_data*)bl;
int id = va_arg(ap,int);
if (nd->bl.id == id) return 0;
@@ -2805,8 +2770,7 @@ int npc_unsetcells_sub(struct block_list* bl, va_list ap)
return 1;
}
-void npc_unsetcells(struct npc_data* nd)
-{
+void npc_unsetcells(struct npc_data* nd) {
int16 m = nd->bl.m, x = nd->bl.x, y = nd->bl.y, xs, ys;
int i,j, x0, x1, y0, y1;
@@ -2818,7 +2782,7 @@ void npc_unsetcells(struct npc_data* nd)
ys = nd->u.scr.ys;
}
- if (m < 0 || xs < 0 || ys < 0)
+ if (m < 0 || xs < 0 || ys < 0 || map[m].cell == (struct mapcell *)0xdeadbeaf)
return;
//Locate max range on which we can locate npc cells
@@ -2831,7 +2795,7 @@ void npc_unsetcells(struct npc_data* nd)
//Erase this npc's cells
for (i = y-ys; i <= y+ys; i++)
for (j = x-xs; j <= x+xs; j++)
- map_setcell(m, j, i, CELL_NPC, false);
+ map[m].setcell(m, j, i, CELL_NPC, false);
//Re-deploy NPC cells for other nearby npcs.
map_foreachinarea( npc_unsetcells_sub, m, x0, y0, x1, y1, BL_NPC, nd->bl.id );
@@ -2910,7 +2874,7 @@ int npc_do_atcmd_event(struct map_session_data* sd, const char* command, const c
return 1;
}
- if( ev->nd->sc.option&OPTION_INVISIBLE ) { // Disabled npc, shouldn't trigger event.
+ if( ev->nd->option&OPTION_INVISIBLE ) { // Disabled npc, shouldn't trigger event.
npc_event_dequeue(sd);
return 2;
}
@@ -2994,8 +2958,7 @@ void npc_parse_mob2(struct spawn_data* mob)
{
int i;
- for( i = mob->active; i < mob->num; ++i )
- {
+ for( i = mob->active; i < mob->num; ++i ) {
struct mob_data* md = mob_spawn_dataset(mob);
md->spawn = mob;
md->spawn->active++;
@@ -3150,19 +3113,17 @@ static const char* npc_parse_mob(char* w1, char* w2, char* w3, char* w4, const c
memcpy(data, &mob, sizeof(struct spawn_data));
// spawn / cache the new mobs
- if( battle_config.dynamic_mobs && map_addmobtolist(data->m, data) >= 0 )
- {
+ if( battle_config.dynamic_mobs && map_addmobtolist(data->m, data) >= 0 ) {
data->state.dynamic = true;
npc_cache_mob += data->num;
// check if target map has players
// (usually shouldn't occur when map server is just starting,
// but not the case when we do @reloadscript
- if( map[data->m].users > 0 )
+ if( map[data->m].users > 0 ) {
npc_parse_mob2(data);
- }
- else
- {
+ }
+ } else {
data->state.dynamic = false;
npc_parse_mob2(data);
npc_delay_mob += data->num;
@@ -3282,16 +3243,11 @@ const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, const char
else if (!strcmpi(drop_arg2,"all"))
drop_type = 3;
- if (drop_id != 0){
- int i;
- for (i = 0; i < MAX_DROP_PER_MAP; i++) {
- if (map[m].drop_list[i].drop_id == 0){
- map[m].drop_list[i].drop_id = drop_id;
- map[m].drop_list[i].drop_type = drop_type;
- map[m].drop_list[i].drop_per = drop_per;
- break;
- }
- }
+ if (drop_id != 0) {
+ RECREATE(map[m].drop_list, struct map_drop_list, ++map[m].drop_list_count);
+ map[m].drop_list[map[m].drop_list_count-1].drop_id = drop_id;
+ map[m].drop_list[map[m].drop_list_count-1].drop_type = drop_type;
+ map[m].drop_list[map[m].drop_list_count-1].drop_per = drop_per;
map[m].flag.pvp_nightmaredrop = 1;
}
} else if (!state) //Disable
@@ -3892,10 +3848,7 @@ int npc_reload(void) {
"\t-'"CL_WHITE"%d"CL_RESET"' Mobs Not Cached\n",
npc_id - npc_new_min, npc_warp, npc_shop, npc_script, npc_mob, npc_cache_mob, npc_delay_mob);
- do_final_instance();
-
- for( i = 0; i < ARRAYLENGTH(instance); ++i )
- instance_init(instance[i].instance_id);
+ instance->final();
map_zone_init();
@@ -4002,8 +3955,18 @@ int do_init_npc(void)
struct npc_src_list *file;
int i;
+ memset(&npc_base_ud, 0, sizeof( struct unit_data) );
+ npc_base_ud.bl = NULL;
+ npc_base_ud.walktimer = INVALID_TIMER;
+ npc_base_ud.skilltimer = INVALID_TIMER;
+ npc_base_ud.attacktimer = INVALID_TIMER;
+ npc_base_ud.attackabletime =
+ npc_base_ud.canact_tick =
+ npc_base_ud.canmove_tick = gettick();
+
//Stock view data for normal npcs.
memset(&npc_viewdb, 0, sizeof(npc_viewdb));
+
npc_viewdb[0].class_ = INVISIBLE_CLASS; //Invisible class is stored here.
for( i = 1; i < MAX_NPC_CLASS; i++ )
npc_viewdb[i].class_ = i;
@@ -4030,7 +3993,7 @@ int do_init_npc(void)
"\t-'"CL_WHITE"%d"CL_RESET"' Mobs Cached\n"
"\t-'"CL_WHITE"%d"CL_RESET"' Mobs Not Cached\n",
npc_id - START_NPC_NUM, npc_warp, npc_shop, npc_script, npc_mob, npc_cache_mob, npc_delay_mob);
-
+
map_zone_init();
npc->motd = npc_name2id("HerculesMOTD"); /* [Ind/Hercules] */
@@ -4068,6 +4031,6 @@ int do_init_npc(void)
}
void npc_defaults(void) {
npc = &npc_s;
-
+
npc->motd = NULL;
}
diff --git a/src/map/npc.h b/src/map/npc.h
index 8a8b14d6e..16e6fe74c 100644
--- a/src/map/npc.h
+++ b/src/map/npc.h
@@ -12,6 +12,7 @@ struct block_list;
struct npc_data;
struct view_data;
+struct unit_data npc_base_ud;
struct npc_timerevent_list {
int timer,pos;
@@ -26,9 +27,9 @@ struct npc_item_list {
struct npc_data {
struct block_list bl;
- struct unit_data ud; //Because they need to be able to move....
+ struct unit_data *ud;
struct view_data *vd;
- struct status_change sc; //They can't have status changes, but.. they want the visual opt values.
+ unsigned int option;
struct npc_data *master_nd;
short class_;
short speed;
@@ -37,12 +38,13 @@ struct npc_data {
int chat_id;
int touching_id;
unsigned int next_walktime;
-
+ uint8 dir;
+
unsigned size : 2;
struct status_data status;
- unsigned int level;
- unsigned int stat_point;
+ unsigned short level;
+ unsigned short stat_point;
void* chatdb; // pointer to a npc_parse struct (see npc_chat.c)
char* path;/* path dir */
diff --git a/src/map/packets.h b/src/map/packets.h
index 7e14305b7..92df54367 100644
--- a/src/map/packets.h
+++ b/src/map/packets.h
@@ -1869,6 +1869,10 @@ packet(0x020d,-1);
packet(0x0838,6,clif->pSolveCharName,2);
packet(0x0439,8,clif->pUseItem,2,4);
packet(0x08d2,10);
+ packet(0x08d7,28,clif->pBGQueueRegister,2);
+ packet(0x090a,26,clif->pBGQueueCheckState,2);
+ packet(0x08da,26,clif->pBGQueueRevokeReq,2);
+ packet(0x08e0,51,clif->pBGQueueBattleBeginAck,2);
#endif
//2011-11-02aRagexe
@@ -1985,7 +1989,6 @@ packet(0x020d,-1);
packet(0x08FB,6,clif->pDull,2); //bookingcanceljoinparty
packet(0x0907,5,clif->pMoveItem,2,4);
packet(0x0908,5);
- packet(0x08D7,28,clif->pDull,2,4); //battlegroundreg
packet(0x08CF,10);//Amulet spirits
packet(0x0977,14);//Monster HP Bar
#endif
diff --git a/src/map/packets_struct.h b/src/map/packets_struct.h
index c873d3ad3..9d1f9b280 100644
--- a/src/map/packets_struct.h
+++ b/src/map/packets_struct.h
@@ -87,6 +87,15 @@ enum packet_headers {
#else
unit_walkingType = 0x914,
#endif
+ bgqueue_ackType = 0x8d8,
+ bgqueue_notice_deleteType = 0x8db,
+ bgqueue_registerType = 0x8d7,
+ bgqueue_updateinfoType = 0x8d9,
+ bgqueue_checkstateType = 0x90a,
+ bgqueue_revokereqType = 0x8da,
+ bgqueue_battlebeginackType = 0x8e0,
+ bgqueue_notify_entryType = 0x8d9,
+ bgqueue_battlebegins = 0x8df,
#if PACKETVER > 20130000 /* not sure date */
dropflooritemType = 0x84b,
#else
@@ -391,6 +400,59 @@ struct packet_maptypeproperty2 {
} flag;
} __attribute__((packed));
+struct packet_bgqueue_ack {
+ short PacketType;
+ short type;
+ char bg_name[NAME_LENGTH];
+} __attribute__((packed));
+
+struct packet_bgqueue_notice_delete {
+ short PacketType;
+ short type;
+ char bg_name[NAME_LENGTH];
+} __attribute__((packed));
+
+struct packet_bgqueue_register {
+ short PacketType;
+ short type;
+ char bg_name[NAME_LENGTH];
+} __attribute__((packed));
+
+struct packet_bgqueue_update_info {
+ short PacketType;
+ char bg_name[NAME_LENGTH];
+ int position;
+} __attribute__((packed));
+
+struct packet_bgqueue_checkstate {
+ short PacketType;
+ char bg_name[NAME_LENGTH];
+} __attribute__((packed));
+
+struct packet_bgqueue_revoke_req {
+ short PacketType;
+ char bg_name[NAME_LENGTH];
+} __attribute__((packed));
+
+struct packet_bgqueue_battlebegin_ack {
+ short PacketType;
+ short result;
+ char bg_name[NAME_LENGTH];
+ char game_name[NAME_LENGTH];
+} __attribute__((packed));
+
+struct packet_bgqueue_notify_entry {
+ short PacketType;
+ char name[NAME_LENGTH];
+ int position;
+} __attribute__((packed));
+
+struct packet_bgqueue_battlebegins {
+ short PacketType;
+ char bg_name[NAME_LENGTH];
+ char game_name[NAME_LENGTH];
+} __attribute__((packed));
+
#pragma pack(pop)
#endif /* _PACKETS_STRUCT_H_ */
diff --git a/src/map/party.c b/src/map/party.c
index 8a632a8ef..4462d4f07 100644
--- a/src/map/party.c
+++ b/src/map/party.c
@@ -50,8 +50,6 @@ static void party_fill_member(struct party_member* member, struct map_session_da
member->online = 1;
member->leader = leader;
}
-
-
/// Get the member_id of a party member.
/// Return -1 if not in party.
int party_getmemberid(struct party_data* p, struct map_session_data* sd)
@@ -101,14 +99,21 @@ static TBL_PC* party_sd_check(int party_id, int account_id, int char_id)
return sd;
}
-
+int party_db_final(DBKey key, DBData *data, va_list ap) {
+ struct party_data *p;
+
+ if( ( p = DB->data2ptr(data) ) && p->instance )
+ aFree(p->instance);
+
+ return 0;
+}
/*==========================================
* Destructor
* Called in map shutdown, cleanup var
*------------------------------------------*/
void do_final_party(void)
{
- party_db->destroy(party_db,NULL);
+ party_db->destroy(party_db,party_db_final);
party_booking_db->destroy(party_booking_db,NULL); // Party Booking [Spiria]
}
// Constructor, init vars
@@ -251,16 +256,14 @@ int party_recv_info(struct party* sp, int char_id)
int removed_count = 0;
int added[MAX_PARTY];// member_id in new data
int added_count = 0;
- int i;
+ int i,j;
int member_id;
nullpo_ret(sp);
p = (struct party_data*)idb_get(party_db, sp->party_id);
- if( p != NULL )// diff members
- {
- for( member_id = 0; member_id < MAX_PARTY; ++member_id )
- {
+ if( p != NULL ) {// diff members
+ for( member_id = 0; member_id < MAX_PARTY; ++member_id ) {
member = &p->party.member[member_id];
if( member->char_id == 0 )
continue;// empty
@@ -270,8 +273,7 @@ int party_recv_info(struct party* sp, int char_id)
if( i == MAX_PARTY )
removed[removed_count++] = member_id;
}
- for( member_id = 0; member_id < MAX_PARTY; ++member_id )
- {
+ for( member_id = 0; member_id < MAX_PARTY; ++member_id ) {
member = &sp->member[member_id];
if( member->char_id == 0 )
continue;// empty
@@ -281,17 +283,16 @@ int party_recv_info(struct party* sp, int char_id)
if( i == MAX_PARTY )
added[added_count++] = member_id;
}
- }
- else
- {
+ } else {
for( member_id = 0; member_id < MAX_PARTY; ++member_id )
if( sp->member[member_id].char_id != 0 )
added[added_count++] = member_id;
CREATE(p, struct party_data, 1);
+ p->instance = NULL;
+ p->instances = 0;
idb_put(party_db, sp->party_id, p);
}
- while( removed_count > 0 )// no longer in party
- {
+ while( removed_count > 0 ) {// no longer in party
member_id = removed[--removed_count];
sd = p->data[member_id].sd;
if( sd == NULL )
@@ -301,16 +302,14 @@ int party_recv_info(struct party* sp, int char_id)
memcpy(&p->party, sp, sizeof(struct party));
memset(&p->state, 0, sizeof(p->state));
memset(&p->data, 0, sizeof(p->data));
- for( member_id = 0; member_id < MAX_PARTY; member_id++ )
- {
+ for( member_id = 0; member_id < MAX_PARTY; member_id++ ) {
member = &p->party.member[member_id];
if ( member->char_id == 0 )
continue;// empty
p->data[member_id].sd = party_sd_check(sp->party_id, member->account_id, member->char_id);
}
party_check_state(p);
- while( added_count > 0 )// new in party
- {
+ while( added_count > 0 ) { // new in party
member_id = added[--added_count];
sd = p->data[member_id].sd;
if( sd == NULL )
@@ -319,8 +318,12 @@ int party_recv_info(struct party* sp, int char_id)
clif->party_member_info(p,sd);
clif->party_option(p,sd,0x100);
clif->party_info(p,NULL);
- if( p->instance_id != 0 )
- clif->instance_join(sd->fd, p->instance_id);
+ for( j = 0; j < p->instances; j++ ) {
+ if( instances[p->instance[j]].idle_timer == INVALID_TIMER && instances[p->instance[j]].progress_timer == INVALID_TIMER )
+ continue;
+ clif->instance_join(sd->fd, p->instance[j]);
+ break;
+ }
}
if( char_id != 0 )// requester
{
@@ -429,19 +432,21 @@ void party_member_joined(struct map_session_data *sd)
{
struct party_data* p = party_search(sd->status.party_id);
int i;
- if (!p)
- {
+ if (!p) {
party_request_info(sd->status.party_id, sd->status.char_id);
return;
}
ARR_FIND( 0, MAX_PARTY, i, p->party.member[i].account_id == sd->status.account_id && p->party.member[i].char_id == sd->status.char_id );
- if (i < MAX_PARTY)
- {
+ if (i < MAX_PARTY) {
+ int j;
p->data[i].sd = sd;
- if( p->instance_id )
- clif->instance_join(sd->fd,p->instance_id);
- }
- else
+ for( j = 0; j < p->instances; j++ ) {
+ if( instances[p->instance[j]].idle_timer == INVALID_TIMER && instances[p->instance[j]].progress_timer == INVALID_TIMER )
+ continue;
+ clif->instance_join(sd->fd, p->instance[j]);
+ break;
+ }
+ } else
sd->status.party_id = 0; //He does not belongs to the party really?
}
@@ -451,7 +456,7 @@ int party_member_added(int party_id,int account_id,int char_id, int flag)
{
struct map_session_data *sd = map_id2sd(account_id),*sd2;
struct party_data *p = party_search(party_id);
- int i;
+ int i, j;
if(sd == NULL || sd->status.char_id != char_id || !sd->party_joining ) {
if (!flag) //Char logged off before being accepted into party.
@@ -496,9 +501,13 @@ int party_member_added(int party_id,int account_id,int char_id, int flag)
clif->party_xy(sd);
clif->charnameupdate(sd); //Update char name's display [Skotlex]
- if( p->instance_id )
- clif->instance_join(sd->fd, p->instance_id);
-
+ for( j = 0; j < p->instances; j++ ) {
+ if( instances[p->instance[j]].idle_timer == INVALID_TIMER && instances[p->instance[j]].progress_timer == INVALID_TIMER )
+ continue;
+ clif->instance_join(sd->fd, p->instance[j]);
+ break;
+ }
+
return 0;
}
@@ -551,12 +560,10 @@ int party_member_withdraw(int party_id, int account_id, int char_id)
struct map_session_data* sd = map_id2sd(account_id);
struct party_data* p = party_search(party_id);
- if( p )
- {
+ if( p ) {
int i;
ARR_FIND( 0, MAX_PARTY, i, p->party.member[i].account_id == account_id && p->party.member[i].char_id == char_id );
- if( i < MAX_PARTY )
- {
+ if( i < MAX_PARTY ) {
clif->party_withdraw(p,sd,account_id,p->party.member[i].name,0x0);
memset(&p->party.member[i], 0, sizeof(p->party.member[0]));
memset(&p->data[i], 0, sizeof(p->data[0]));
@@ -565,13 +572,12 @@ int party_member_withdraw(int party_id, int account_id, int char_id)
}
}
- if( sd && sd->status.party_id == party_id && sd->status.char_id == char_id )
- {
+ if( sd && sd->status.party_id == party_id && sd->status.char_id == char_id ) {
sd->status.party_id = 0;
clif->charnameupdate(sd); //Update name display [Skotlex]
//TODO: hp bars should be cleared too
- if( p->instance_id )
- instance_check_kick(sd);
+ if( p->instances )
+ instance->check_kick(sd);
}
return 0;
@@ -581,22 +587,19 @@ int party_member_withdraw(int party_id, int account_id, int char_id)
int party_broken(int party_id)
{
struct party_data* p;
- int i;
+ int i, j;
p = party_search(party_id);
if( p == NULL )
return 0;
- if( p->instance_id )
- {
- instance[p->instance_id].party_id = 0;
- instance_destroy( p->instance_id );
+ for( j = 0; j < p->instances; j++ ) {
+ instance->destroy( p->instance[j] );
+ instances[p->instance[j]].owner_id = 0;
}
-
- for( i = 0; i < MAX_PARTY; i++ )
- {
- if( p->data[i].sd!=NULL )
- {
+
+ for( i = 0; i < MAX_PARTY; i++ ) {
+ if( p->data[i].sd!=NULL ) {
clif->party_withdraw(p,p->data[i].sd,p->party.member[i].account_id,p->party.member[i].name,0x10);
p->data[i].sd->status.party_id=0;
}
diff --git a/src/map/party.h b/src/map/party.h
index 12fe7a2bc..3978324e4 100644
--- a/src/map/party.h
+++ b/src/map/party.h
@@ -25,7 +25,8 @@ struct party_data {
struct party party;
struct party_member_data data[MAX_PARTY];
uint8 itemc; //For item distribution, position of last picker in party
- unsigned int instance_id;
+ unsigned short *instance;
+ unsigned short instances;
struct {
unsigned monk : 1; //There's at least one monk in party?
unsigned sg : 1; //There's at least one Star Gladiator in party?
diff --git a/src/map/path.c b/src/map/path.c
index 3bbd8d20b..8ab63d390 100644
--- a/src/map/path.c
+++ b/src/map/path.c
@@ -167,12 +167,10 @@ int path_blownpos(int16 m,int16 x0,int16 y0,int16 dx,int16 dy,int count)
dy=(dy>0)?1:((dy<0)?-1:0);
}
- while( count > 0 && (dx != 0 || dy != 0) )
- {
- if( !map_getcellp(md,x0+dx,y0+dy,CELL_CHKPASS) )
- {// attempt partial movement
- int fx = ( dx != 0 && map_getcellp(md,x0+dx,y0,CELL_CHKPASS) );
- int fy = ( dy != 0 && map_getcellp(md,x0,y0+dy,CELL_CHKPASS) );
+ while( count > 0 && (dx != 0 || dy != 0) ) {
+ if( !md->getcellp(md,x0+dx,y0+dy,CELL_CHKPASS) ) {// attempt partial movement
+ int fx = ( dx != 0 && md->getcellp(md,x0+dx,y0,CELL_CHKPASS) );
+ int fy = ( dy != 0 && md->getcellp(md,x0,y0+dy,CELL_CHKPASS) );
if( fx && fy )
{
if(rnd()&1)
@@ -225,7 +223,7 @@ bool path_search_long(struct shootpath_data *spd,int16 m,int16 x0,int16 y0,int16
spd->x[0] = x0;
spd->y[0] = y0;
- if (map_getcellp(md,x1,y1,cell))
+ if (md->getcellp(md,x1,y1,cell))
return false;
if (dx > abs(dy)) {
@@ -238,7 +236,7 @@ bool path_search_long(struct shootpath_data *spd,int16 m,int16 x0,int16 y0,int16
while (x0 != x1 || y0 != y1)
{
- if (map_getcellp(md,x0,y0,cell))
+ if (md->getcellp(md,x0,y0,cell))
return false;
wx += dx;
wy += dy;
@@ -290,10 +288,10 @@ bool path_search(struct walkpath_data *wpd,int16 m,int16 x0,int16 y0,int16 x1,in
//Do not check starting cell as that would get you stuck.
if( x0 < 0 || x0 >= md->xs || y0 < 0 || y0 >= md->ys )
#else
- if( x0 < 0 || x0 >= md->xs || y0 < 0 || y0 >= md->ys /*|| map_getcellp(md,x0,y0,cell)*/ )
+ if( x0 < 0 || x0 >= md->xs || y0 < 0 || y0 >= md->ys /*|| md->getcellp(md,x0,y0,cell)*/ )
#endif
return false;
- if( x1 < 0 || x1 >= md->xs || y1 < 0 || y1 >= md->ys || map_getcellp(md,x1,y1,cell) )
+ if( x1 < 0 || x1 >= md->xs || y1 < 0 || y1 >= md->ys || md->getcellp(md,x1,y1,cell) )
return false;
// calculate (sgn(x1-x0), sgn(y1-y0))
@@ -317,7 +315,7 @@ bool path_search(struct walkpath_data *wpd,int16 m,int16 x0,int16 y0,int16 x1,in
if( dx == 0 && dy == 0 )
break; // success
- if( map_getcellp(md,x,y,cell) )
+ if( md->getcellp(md,x,y,cell) )
break; // obstacle = failure
}
@@ -365,29 +363,29 @@ bool path_search(struct walkpath_data *wpd,int16 m,int16 x0,int16 y0,int16 x1,in
// dc[2] : y--
// dc[3] : x++
- if(y < ys && !map_getcellp(md,x ,y+1,cell)) {
+ if(y < ys && !md->getcellp(md,x ,y+1,cell)) {
f |= 1; dc[0] = (y >= y1 ? 20 : 0);
e+=add_path(heap,tp,x ,y+1,dist,rp,cost+dc[0]); // (x, y+1)
}
- if(x > 0 && !map_getcellp(md,x-1,y ,cell)) {
+ if(x > 0 && !md->getcellp(md,x-1,y ,cell)) {
f |= 2; dc[1] = (x <= x1 ? 20 : 0);
e+=add_path(heap,tp,x-1,y ,dist,rp,cost+dc[1]); // (x-1, y )
}
- if(y > 0 && !map_getcellp(md,x ,y-1,cell)) {
+ if(y > 0 && !md->getcellp(md,x ,y-1,cell)) {
f |= 4; dc[2] = (y <= y1 ? 20 : 0);
e+=add_path(heap,tp,x ,y-1,dist,rp,cost+dc[2]); // (x , y-1)
}
- if(x < xs && !map_getcellp(md,x+1,y ,cell)) {
+ if(x < xs && !md->getcellp(md,x+1,y ,cell)) {
f |= 8; dc[3] = (x >= x1 ? 20 : 0);
e+=add_path(heap,tp,x+1,y ,dist,rp,cost+dc[3]); // (x+1, y )
}
- if( (f & (2+1)) == (2+1) && !map_getcellp(md,x-1,y+1,cell))
+ if( (f & (2+1)) == (2+1) && !md->getcellp(md,x-1,y+1,cell))
e+=add_path(heap,tp,x-1,y+1,dist+4,rp,cost+dc[1]+dc[0]-6); // (x-1, y+1)
- if( (f & (2+4)) == (2+4) && !map_getcellp(md,x-1,y-1,cell))
+ if( (f & (2+4)) == (2+4) && !md->getcellp(md,x-1,y-1,cell))
e+=add_path(heap,tp,x-1,y-1,dist+4,rp,cost+dc[1]+dc[2]-6); // (x-1, y-1)
- if( (f & (8+4)) == (8+4) && !map_getcellp(md,x+1,y-1,cell))
+ if( (f & (8+4)) == (8+4) && !md->getcellp(md,x+1,y-1,cell))
e+=add_path(heap,tp,x+1,y-1,dist+4,rp,cost+dc[3]+dc[2]-6); // (x+1, y-1)
- if( (f & (8+1)) == (8+1) && !map_getcellp(md,x+1,y+1,cell))
+ if( (f & (8+1)) == (8+1) && !md->getcellp(md,x+1,y+1,cell))
e+=add_path(heap,tp,x+1,y+1,dist+4,rp,cost+dc[3]+dc[0]-6); // (x+1, y+1)
tp[rp].flag=1;
if(e || heap[0]>=MAX_HEAP-5)
diff --git a/src/map/pc.c b/src/map/pc.c
index 55ce993b4..241e0fbb3 100644
--- a/src/map/pc.c
+++ b/src/map/pc.c
@@ -518,8 +518,7 @@ int pc_makesavestatus(struct map_session_data *sd)
#else
sd->status.option = sd->sc.option&(OPTION_INVISIBLE|OPTION_CART|OPTION_FALCON|OPTION_RIDING|OPTION_DRAGON|OPTION_WUG|OPTION_WUGRIDER|OPTION_MADOGEAR);
#endif
- if (sd->sc.data[SC_JAILED])
- { //When Jailed, do not move last point.
+ if (sd->sc.data[SC_JAILED]) { //When Jailed, do not move last point.
if(pc_isdead(sd)){
pc_setrestartvalue(sd,0);
} else {
@@ -543,13 +542,25 @@ int pc_makesavestatus(struct map_session_data *sd)
sd->status.last_point.y = sd->bl.y;
}
- if(map[sd->bl.m].flag.nosave){
+ if(map[sd->bl.m].flag.nosave || map[sd->bl.m].instance_id >= 0){
struct map_data *m=&map[sd->bl.m];
if(m->save.map)
memcpy(&sd->status.last_point,&m->save,sizeof(sd->status.last_point));
else
memcpy(&sd->status.last_point,&sd->status.save_point,sizeof(sd->status.last_point));
}
+ if( sd->status.last_point.map == 0 ) {
+ sd->status.last_point.map = 1;
+ sd->status.last_point.x = 0;
+ sd->status.last_point.y = 0;
+ }
+
+ if( sd->status.save_point.map == 0 ) {
+ sd->status.save_point.map = 1;
+ sd->status.save_point.x = 0;
+ sd->status.save_point.y = 0;
+ }
+
return 0;
}
@@ -905,8 +916,7 @@ int pc_isequip(struct map_session_data *sd,int n)
* No problem with the session id
* set the status that has been sent from char server
*------------------------------------------*/
-bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_time, int group_id, struct mmo_charstatus *st, bool changing_mapservers)
-{
+bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_time, int group_id, struct mmo_charstatus *st, bool changing_mapservers) {
int i;
unsigned long tick = gettick();
uint32 ip = session[sd->fd]->client_addr;
@@ -1014,6 +1024,17 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim
sd->disguise = -1;
+ sd->instance = NULL;
+ sd->instances = 0;
+
+ sd->bg_queue.arena = NULL;
+ sd->bg_queue.ready = 0;
+ sd->bg_queue.client_has_bg_data = 0;
+ sd->bg_queue.type = 0;
+
+ sd->queues = NULL;
+ sd->queues_count = 0;
+
// Event Timers
for( i = 0; i < MAX_EVENTTIMER; i++ )
sd->eventtimer[i] = INVALID_TIMER;
@@ -1075,7 +1096,7 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim
/**
* Fixes login-without-aura glitch (the screen won't blink at this point, don't worry :P)
**/
- clif->changemap(sd,sd->mapindex,sd->bl.x,sd->bl.y);
+ clif->changemap(sd,sd->bl.m,sd->bl.x,sd->bl.y);
}
/**
@@ -4680,36 +4701,62 @@ 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, clr_type clrtype)
-{
- struct party_data *p;
+int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y, clr_type clrtype) {
int16 m;
nullpo_ret(sd);
- if( !mapindex || !mapindex_id2name(mapindex) )
- {
+ if( !mapindex || !mapindex_id2name(mapindex) ) {
ShowDebug("pc_setpos: Passed mapindex(%d) is invalid!\n", mapindex);
return 1;
}
- if( pc_isdead(sd) )
- { //Revive dead people before warping them
+ if( pc_isdead(sd) ) { //Revive dead people before warping them
pc_setstand(sd);
pc_setrestartvalue(sd,1);
}
-
m = map_mapindex2mapid(mapindex);
- if( map[m].flag.src4instance && sd->status.party_id && (p = party_search(sd->status.party_id)) != NULL && p->instance_id )
- {
- // Request the mapid of this src map into the instance of the party
- int im = instance_map2imap(m, p->instance_id);
- if( im < 0 )
- ; // Player will enter the src map for instances
- else
- { // Changes destiny to the instance map, not the source map
- m = im;
- mapindex = map_id2index(m);
+
+ if( map[m].flag.src4instance ) {
+ struct party_data *p;
+ bool stop = false;
+ int i = 0, j = 0;
+
+ if( sd->instances ) {
+ for( i = 0; i < sd->instances; i++ ) {
+ ARR_FIND(0, instances[sd->instance[i]].num_map, j, map[instances[sd->instance[i]].map[j]].instance_src_map == m && !map[instances[sd->instance[i]].map[j]].cName);
+ if( j != instances[sd->instance[i]].num_map )
+ break;
+ }
+ if( i != sd->instances ) {
+ m = instances[sd->instance[i]].map[j];
+ mapindex = map[m].index;
+ stop = true;
+ }
+ }
+ if ( !stop && sd->status.party_id && (p = party_search(sd->status.party_id)) && p->instances ) {
+ for( i = 0; i < p->instances; i++ ) {
+ ARR_FIND(0, instances[p->instance[i]].num_map, j, map[instances[p->instance[i]].map[j]].instance_src_map == m && !map[instances[p->instance[i]].map[j]].cName);
+ if( j != instances[p->instance[i]].num_map )
+ break;
+ }
+ if( i != p->instances ) {
+ m = instances[p->instance[i]].map[j];
+ mapindex = map[m].index;
+ stop = true;
+ }
+ }
+ if ( !stop && sd->status.guild_id && sd->guild && sd->guild->instances ) {
+ for( i = 0; i < sd->guild->instances; i++ ) {
+ ARR_FIND(0, instances[sd->guild->instance[i]].num_map, j, map[instances[sd->guild->instance[i]].map[j]].instance_src_map == m && !map[instances[sd->guild->instance[i]].map[j]].cName);
+ if( j != instances[sd->guild->instance[i]].num_map )
+ break;
+ }
+ if( i != sd->guild->instances ) {
+ m = instances[sd->guild->instance[i]].map[j];
+ mapindex = map[m].index;
+ stop = true;
+ }
}
}
@@ -4718,6 +4765,17 @@ int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y
if( sd->state.changemap ) { // Misc map-changing settings
int i;
sd->state.pmap = sd->bl.m;
+
+ for( i = 0; i < sd->queues_count; i++ ) {
+ struct hQueue *queue;
+ if( (queue = script->queue(sd->queues[i])) && queue->onMapChange[0] != '\0' ) {
+ pc_setregstr(sd, add_str("QMapChangeTo"), map[m].name);
+ npc_event(sd, queue->onMapChange, 0);
+ }
+ }
+
+ if( map[m].cell == (struct mapcell *)0xdeadbeaf )
+ map_cellfromcache(&map[m]);
if (sd->sc.count) { // Cancel some map related stuff.
if (sd->sc.data[SC_JAILED])
return 1; //You may not get out!
@@ -4761,8 +4819,7 @@ int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y
}
- if( m < 0 )
- {
+ if( m < 0 ) {
uint32 ip;
uint16 port;
//if can't find any map-servers, just abort setting position.
@@ -4787,14 +4844,12 @@ int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y
return 0;
}
- if( x < 0 || x >= map[m].xs || y < 0 || y >= map[m].ys )
- {
+ if( x < 0 || x >= map[m].xs || y < 0 || y >= map[m].ys ) {
ShowError("pc_setpos: attempt to place player %s (%d:%d) on invalid coordinates (%s-%d,%d)\n", sd->status.name, sd->status.account_id, sd->status.char_id, mapindex_id2name(mapindex),x,y);
x = y = 0; // make it random
}
- if( x == 0 && y == 0 )
- {// pick a random walkable cell
+ if( x == 0 && y == 0 ) {// pick a random walkable cell
do {
x=rnd()%(map[m].xs-2)+1;
y=rnd()%(map[m].ys-2)+1;
@@ -4808,7 +4863,7 @@ int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y
if(sd->bl.prev != NULL){
unit_remove_map_pc(sd,clrtype);
- clif->changemap(sd,map[m].index,x,y); // [MouseJstr]
+ clif->changemap(sd,m,x,y); // [MouseJstr]
} else if(sd->state.active)
//Tag player for rewarping after map-loading is done. [Skotlex]
sd->state.rewarp = 1;
@@ -4818,31 +4873,27 @@ int pc_setpos(struct map_session_data* sd, unsigned short mapindex, int x, int y
sd->bl.x = sd->ud.to_x = x;
sd->bl.y = sd->ud.to_y = y;
- if( sd->status.guild_id > 0 && map[m].flag.gvg_castle )
- { // Increased guild castle regen [Valaris]
+ if( sd->status.guild_id > 0 && map[m].flag.gvg_castle ) { // Increased guild castle regen [Valaris]
struct guild_castle *gc = guild->mapindex2gc(sd->mapindex);
if(gc && gc->guild_id == sd->status.guild_id)
sd->regen.state.gc = 1;
}
- if( sd->status.pet_id > 0 && sd->pd && sd->pd->pet.intimate > 0 )
- {
+ if( sd->status.pet_id > 0 && sd->pd && sd->pd->pet.intimate > 0 ) {
sd->pd->bl.m = m;
sd->pd->bl.x = sd->pd->ud.to_x = x;
sd->pd->bl.y = sd->pd->ud.to_y = y;
sd->pd->ud.dir = sd->ud.dir;
}
- if( homun_alive(sd->hd) )
- {
+ if( homun_alive(sd->hd) ) {
sd->hd->bl.m = m;
sd->hd->bl.x = sd->hd->ud.to_x = x;
sd->hd->bl.y = sd->hd->ud.to_y = y;
sd->hd->ud.dir = sd->ud.dir;
}
- if( sd->md )
- {
+ if( sd->md ) {
sd->md->bl.m = m;
sd->md->bl.x = sd->md->ud.to_x = x;
sd->md->bl.y = sd->md->ud.to_y = y;
@@ -6588,15 +6639,22 @@ int pc_dead(struct map_session_data *sd,struct block_list *src)
pc_setglobalreg(sd,"PC_DIE_COUNTER",sd->die_counter+1);
pc_setparam(sd, SP_KILLERRID, src?src->id:0);
- if( sd->bg_id ) {
+ if( sd->bg_id ) {/* TODO: purge when bgqueue is deemed ok */
struct battleground_data *bg;
if( (bg = bg_team_search(sd->bg_id)) != NULL && bg->die_event[0] )
npc_event(sd, bg->die_event, 0);
}
-
+
+ for( i = 0; i < sd->queues_count; i++ ) {
+ struct hQueue *queue;
+ if( (queue = script->queue(sd->queues[i])) && queue->onDeath[0] != '\0' )
+ npc_event(sd, queue->onDeath, 0);
+ }
+
+ npc_script_event(sd,NPCE_DIE);
+
// Clear anything NPC-related when you die and was interacting with one.
- if (sd->npc_id)
- {
+ if (sd->npc_id) {
if (sd->state.using_fake_npc) {
clif->clearunit_single(sd->npc_id, CLR_OUTSIGHT, sd->fd);
sd->state.using_fake_npc = 0;
@@ -6611,8 +6669,6 @@ int pc_dead(struct map_session_data *sd,struct block_list *src)
sd->st->state = END;
}
- npc_script_event(sd,NPCE_DIE);
-
/* e.g. not killed thru pc_damage */
if( pc_issit(sd) ) {
clif->sc_end(&sd->bl,sd->bl.id,SELF,SI_SIT);
@@ -6788,7 +6844,7 @@ int pc_dead(struct map_session_data *sd,struct block_list *src)
if(map[sd->bl.m].flag.pvp_nightmaredrop)
{ // Moved this outside so it works when PVP isn't enabled and during pk mode [Ancyker]
- for(j=0;j<MAX_DROP_PER_MAP;j++){
+ for(j=0;j<map[sd->bl.m].drop_list_count;j++){
int id = map[sd->bl.m].drop_list[j].drop_id;
int type = map[sd->bl.m].drop_list[j].drop_type;
int per = map[sd->bl.m].drop_list[j].drop_per;
diff --git a/src/map/pc.h b/src/map/pc.h
index b1fa3e741..5207c4c34 100644
--- a/src/map/pc.h
+++ b/src/map/pc.h
@@ -10,6 +10,7 @@
#include "../common/timer.h" // INVALID_TIMER
#include "atcommand.h" // AtCommandType
#include "battle.h" // battle_config
+#include "battleground.h"
#include "buyingstore.h" // struct s_buyingstore
#include "itemdb.h" // MAX_ITEMGROUP
#include "map.h" // RC_MAX
@@ -519,6 +520,20 @@ struct map_session_data {
struct sc_display_entry **sc_display;
unsigned char sc_display_count;
+ unsigned short *instance;
+ unsigned short instances;
+
+ /* Possible Thanks to Yommy~! */
+ struct {
+ unsigned int ready : 1;/* did he accept the 'match is about to start, enter' dialog? */
+ unsigned int client_has_bg_data : 1; /* flags whether the client has the "in queue" window (aka the client knows it is in a queue) */
+ struct bg_arena *arena;
+ enum bg_queue_types type;
+ } bg_queue;
+
+ int *queues;
+ unsigned int queues_count;
+
// temporary debugging of bug #3504
const char* delunit_prevfile;
int delunit_prevline;
diff --git a/src/map/script.c b/src/map/script.c
index 41f8e7472..d42d3d3e3 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -816,10 +816,12 @@ const char* parse_callfunc(const char* p, int require_paren, int is_custom)
func = add_word(p);
if( str_data[func].type == C_FUNC ){
+ char argT = 0;
// buildin function
add_scriptl(func);
add_scriptc(C_ARG);
arg = script->buildin[str_data[func].val];
+ if( !arg ) arg = &argT;
} else if( str_data[func].type == C_USERFUNC || str_data[func].type == C_USERFUNC_POS ){
// script defined function
add_scriptl(buildin_callsub_ref);
@@ -2358,8 +2360,8 @@ void get_val(struct script_state* st, struct script_data* data)
}
break;
case '\'':
- if (st->instance_id) {
- data->u.str = (char*)idb_get(instance[st->instance_id].vars,reference_getuid(data));
+ if ( st->instance_id >= 0 ) {
+ data->u.str = (char*)idb_get(instances[st->instance_id].vars,reference_getuid(data));
} else {
ShowWarning("script:get_val: cannot access instance variable '%s', defaulting to \"\"\n", name);
data->u.str = NULL;
@@ -2423,8 +2425,8 @@ void get_val(struct script_state* st, struct script_data* data)
}
break;
case '\'':
- if( st->instance_id )
- data->u.num = (int)idb_iget(instance[st->instance_id].vars,reference_getuid(data));
+ if( st->instance_id >= 0 )
+ data->u.num = (int)idb_iget(instances[st->instance_id].vars,reference_getuid(data));
else {
ShowWarning("script:get_val: cannot access instance variable '%s', defaulting to 0\n", name);
data->u.num = 0;
@@ -2484,9 +2486,9 @@ static int set_reg(struct script_state* st, TBL_PC* sd, int num, const char* nam
}
return 1;
case '\'':
- if( st->instance_id ) {
- idb_remove(instance[st->instance_id].vars, num);
- if( str[0] ) idb_put(instance[st->instance_id].vars, num, aStrdup(str));
+ if( st->instance_id >= 0 ) {
+ idb_remove(instances[st->instance_id].vars, num);
+ if( str[0] ) idb_put(instances[st->instance_id].vars, num, aStrdup(str));
}
return 1;
default:
@@ -2532,10 +2534,10 @@ static int set_reg(struct script_state* st, TBL_PC* sd, int num, const char* nam
}
return 1;
case '\'':
- if( st->instance_id ) {
- idb_remove(instance[st->instance_id].vars, num);
+ if( st->instance_id >= 0 ) {
+ idb_remove(instances[st->instance_id].vars, num);
if( val != 0 )
- idb_iput(instance[st->instance_id].vars, num, val);
+ idb_iput(instances[st->instance_id].vars, num, val);
}
return 1;
default:
@@ -3462,7 +3464,7 @@ void run_script_main(struct script_state *st)
script_attach_state(st);
nd = map_id2nd(st->oid);
- if( nd && map[nd->bl.m].instance_id > 0 )
+ if( nd )
st->instance_id = map[nd->bl.m].instance_id;
if(st->state == RERUNLINE) {
@@ -3845,9 +3847,25 @@ void do_final_script(void) {
script->buildin[i] = NULL;
}
}
-
- aFree(script->buildin);
+ aFree(script->buildin);
+
+ if( script->hqs ) {
+ for( i = 0; i < script->hqs; i++ ) {
+ if( script->hq[i].item != NULL )
+ aFree(script->hq[i].item);
+ }
+ }
+ if( script->hqis ) {
+ for( i = 0; i < script->hqis; i++ ) {
+ if( script->hqi[i].item != NULL )
+ aFree(script->hqi[i].item);
+ }
+ }
+ if( script->hq != NULL )
+ aFree(script->hq);
+ if( script->hqi != NULL )
+ aFree(script->hqi);
}
/*==========================================
* Initialization
@@ -8457,13 +8475,10 @@ BUILDIN(monster)
if (sd && strcmp(mapn, "this") == 0)
m = sd->bl.m;
- else
- {
+ else {
m = map_mapname2mapid(mapn);
- if (map[m].flag.src4instance && st->instance_id)
- { // Try to redirect to the instance map, not the src map
- if ((m = instance_mapid2imapid(m, st->instance_id)) < 0)
- {
+ if (map[m].flag.src4instance && st->instance_id >= 0) { // Try to redirect to the instance map, not the src map
+ if ((m = instance->mapid2imapid(m, st->instance_id)) < 0) {
ShowError("buildin_monster: Trying to spawn monster (%d) on instance map (%s) without instance attached.\n", class_, mapn);
return false;
}
@@ -8528,27 +8543,22 @@ BUILDIN(areamonster)
struct map_session_data* sd;
int16 m;
- if (script_hasdata(st,10))
- {
+ if (script_hasdata(st,10)) {
event = script_getstr(st, 10);
check_event(st, event);
}
- if (script_hasdata(st, 11))
- {
+ if (script_hasdata(st, 11)) {
size = script_getnum(st, 11);
- if (size > 3)
- {
+ if (size > 3) {
ShowWarning("buildin_monster: Attempted to spawn non-existing size %d for monster class %d\n", size, class_);
return false;
}
}
- if (script_hasdata(st, 12))
- {
+ if (script_hasdata(st, 12)) {
ai = script_getnum(st, 12);
- if (ai > 4)
- {
+ if (ai > 4) {
ShowWarning("buildin_monster: Attempted to spawn non-existing ai %d for monster class %d\n", ai, class_);
return false;
}
@@ -8558,13 +8568,10 @@ BUILDIN(areamonster)
if (sd && strcmp(mapn, "this") == 0)
m = sd->bl.m;
- else
- {
+ else {
m = map_mapname2mapid(mapn);
- if (map[m].flag.src4instance && st->instance_id)
- { // Try to redirect to the instance map, not the src map
- if ((m = instance_mapid2imapid(m, st->instance_id)) < 0)
- {
+ if (map[m].flag.src4instance && st->instance_id >= 0) { // Try to redirect to the instance map, not the src map
+ if ((m = instance->mapid2imapid(m, st->instance_id)) < 0) {
ShowError("buildin_areamonster: Trying to spawn monster (%d) on instance map (%s) without instance attached.\n", class_, mapn);
return false;
}
@@ -8624,7 +8631,7 @@ BUILDIN(killmonster)
if( (m=map_mapname2mapid(mapname))<0 )
return true;
- if( map[m].flag.src4instance && st->instance_id && (m = instance_mapid2imapid(m, st->instance_id)) < 0 )
+ if( map[m].flag.src4instance && st->instance_id >= 0 && (m = instance->mapid2imapid(m, st->instance_id)) < 0 )
return true;
if( script_hasdata(st,4) ) {
@@ -8665,7 +8672,7 @@ BUILDIN(killmonsterall)
if( (m = map_mapname2mapid(mapname))<0 )
return true;
- if( map[m].flag.src4instance && st->instance_id && (m = instance_mapid2imapid(m, st->instance_id)) < 0 )
+ if( map[m].flag.src4instance && st->instance_id >= 0 && (m = instance->mapid2imapid(m, st->instance_id)) < 0 )
return true;
if( script_hasdata(st,3) ) {
@@ -11168,8 +11175,7 @@ BUILDIN(mobcount) // Added by RoVeRT
return true;
}
- if( map[m].flag.src4instance && map[m].instance_id == 0 && st->instance_id && (m = instance_mapid2imapid(m, st->instance_id)) < 0 )
- {
+ if( map[m].flag.src4instance && map[m].instance_id >= 0 && st->instance_id >= 0 && (m = instance->mapid2imapid(m, st->instance_id)) < 0 ) {
script_pushint(st,-1);
return true;
}
@@ -12491,8 +12497,7 @@ BUILDIN(jump_zero)
/*==========================================
* movenpc [MouseJstr]
*------------------------------------------*/
-BUILDIN(movenpc)
-{
+BUILDIN(movenpc) {
TBL_NPC *nd = NULL;
const char *npc;
int x,y;
@@ -12505,7 +12510,7 @@ BUILDIN(movenpc)
return -1;
if (script_hasdata(st,5))
- nd->ud.dir = script_getnum(st,5) % 8;
+ nd->dir = script_getnum(st,5) % 8;
npc_movenpc(nd, x, y);
return true;
}
@@ -12559,17 +12564,20 @@ BUILDIN(npcspeed)
speed = script_getnum(st,2);
nd =(struct npc_data *)map_id2bl(st->oid);
- if( nd )
- {
+ if( nd ) {
+ if( nd->ud == &npc_base_ud ) {
+ nd->ud = NULL;
+ CREATE(nd->ud, struct unit_data, 1);
+ unit_dataset(&nd->bl);
+ }
nd->speed = speed;
- nd->ud.state.speed_changed = 1;
+ nd->ud->state.speed_changed = 1;
}
return true;
}
// make an npc walk to a position [Valaris]
-BUILDIN(npcwalkto)
-{
+BUILDIN(npcwalkto) {
struct npc_data *nd=(struct npc_data *)map_id2bl(st->oid);
int x=0,y=0;
@@ -12577,6 +12585,12 @@ BUILDIN(npcwalkto)
y=script_getnum(st,3);
if(nd) {
+ if( nd->ud == &npc_base_ud ) {
+ nd->ud = NULL;
+ CREATE(nd->ud, struct unit_data, 1);
+ unit_dataset(&nd->bl);
+ }
+
if (!nd->status.hp) {
status_calc_npc(nd, true);
} else {
@@ -15341,7 +15355,7 @@ BUILDIN(setcell)
for( y = y1; y <= y2; ++y )
for( x = x1; x <= x2; ++x )
- map_setcell(m, x, y, type, flag);
+ map[m].setcell(m, x, y, type, flag);
return true;
}
@@ -15865,25 +15879,28 @@ BUILDIN(bg_get_data)
* Instancing Script Commands
*------------------------------------------*/
-BUILDIN(instance_create)
-{
+BUILDIN(instance_create) {
const char *name;
- int party_id, res;
+ int owner_id, res;
+ int type = IOT_PARTY;
name = script_getstr(st, 2);
- party_id = script_getnum(st, 3);
+ owner_id = script_getnum(st, 3);
+ if( script_hasdata(st,4) ) {
+ type = script_getnum(st, 4);
+ if( type < IOT_NONE || type >= IOT_MAX ) {
+ ShowError("buildin_instance_create: unknown instance type %d for '%s'\n",type,name);
+ return true;
+ }
+ }
- res = instance_create(party_id, name);
- if( res == -4 ) // Already exists
- {
+ res = instance->create(owner_id, name, (enum instance_owner_type) type);
+ if( res == -4 ) { // Already exists
script_pushint(st, -1);
return true;
- }
- else if( res < 0 )
- {
+ } else if( res < 0 ) {
const char *err;
- switch(res)
- {
+ switch(res) {
case -3: err = "No free instances"; break;
case -2: err = "Invalid party ID"; break;
case -1: err = "Invalid type"; break;
@@ -15898,44 +15915,39 @@ BUILDIN(instance_create)
return true;
}
-BUILDIN(instance_destroy)
-{
- int instance_id;
- struct map_session_data *sd;
- struct party_data *p;
+BUILDIN(instance_destroy) {
+ int instance_id = -1;
if( script_hasdata(st, 2) )
instance_id = script_getnum(st, 2);
- else if( st->instance_id )
+ else if( st->instance_id >= 0 )
instance_id = st->instance_id;
- else if( (sd = script_rid2sd(st)) != NULL && sd->status.party_id && (p = party_search(sd->status.party_id)) != NULL && p->instance_id )
- instance_id = p->instance_id;
else return true;
- if( instance_id <= 0 || instance_id >= MAX_INSTANCE )
- {
+ if( !instance->valid(instance_id) ) {
ShowError("buildin_instance_destroy: Trying to destroy invalid instance %d.\n", instance_id);
return true;
}
- instance_destroy(instance_id);
+ instance->destroy(instance_id);
return true;
}
-BUILDIN(instance_attachmap)
-{
- const char *name;
+BUILDIN(instance_attachmap) {
+ const char *name, *map_name = NULL;
int16 m;
- int instance_id;
+ int instance_id = -1;
bool usebasename = false;
name = script_getstr(st,2);
instance_id = script_getnum(st,3);
- if( script_hasdata(st,4) && script_getnum(st,4) > 0)
+ if( script_hasdata(st,4) && script_getnum(st,4) > 0 )
usebasename = true;
- if( (m = instance_add_map(name, instance_id, usebasename)) < 0 ) // [Saithis]
- {
+ if( script_hasdata(st, 5) )
+ map_name = script_getstr(st, 5);
+
+ if( (m = instance->add_map(name, instance_id, usebasename, map_name)) < 0 ) { // [Saithis]
ShowError("buildin_instance_attachmap: instance creation failed (%s): %d\n", name, m);
script_pushconststr(st, "");
return true;
@@ -15945,109 +15957,81 @@ BUILDIN(instance_attachmap)
return true;
}
-BUILDIN(instance_detachmap)
-{
- struct map_session_data *sd;
- struct party_data *p;
+BUILDIN(instance_detachmap) {
const char *str;
int16 m;
- int instance_id;
+ int instance_id = -1;
str = script_getstr(st, 2);
if( script_hasdata(st, 3) )
instance_id = script_getnum(st, 3);
- else if( st->instance_id )
+ else if( st->instance_id >= 0 )
instance_id = st->instance_id;
- else if( (sd = script_rid2sd(st)) != NULL && sd->status.party_id && (p = party_search(sd->status.party_id)) != NULL && p->instance_id )
- instance_id = p->instance_id;
else return true;
- if( (m = map_mapname2mapid(str)) < 0 || (m = instance_map2imap(m,instance_id)) < 0 )
- {
+ if( (m = map_mapname2mapid(str)) < 0 || (m = instance->map2imap(m,instance_id)) < 0 ) {
ShowError("buildin_instance_detachmap: Trying to detach invalid map %s\n", str);
return true;
}
- instance_del_map(m);
+ instance->del_map(m);
return true;
}
-BUILDIN(instance_attach)
-{
- int instance_id;
+BUILDIN(instance_attach) {
+ int instance_id = -1;
instance_id = script_getnum(st, 2);
- if( instance_id <= 0 || instance_id >= MAX_INSTANCE )
+ if( !instance->valid(instance_id) )
return true;
st->instance_id = instance_id;
return true;
}
-BUILDIN(instance_id)
-{
- int instance_id;
-
- if( script_hasdata(st, 2) )
- {
- struct party_data *p;
- struct map_session_data *sd;
- int type;
- type = script_getnum(st, 2);
- if( type == 0 )
- instance_id = st->instance_id;
- else if( type == 1 && (sd = script_rid2sd(st)) != NULL && sd->status.party_id && (p = party_search(sd->status.party_id)) != NULL )
- instance_id = p->instance_id;
- else
- instance_id = 0;
- }
- else
- instance_id = st->instance_id;
-
- script_pushint(st, instance_id);
+BUILDIN(instance_id) {
+ script_pushint(st, st->instance_id);
return true;
}
BUILDIN(instance_set_timeout)
{
int progress_timeout, idle_timeout;
- int instance_id;
- struct map_session_data *sd;
- struct party_data *p;
+ int instance_id = -1;
progress_timeout = script_getnum(st, 2);
idle_timeout = script_getnum(st, 3);
if( script_hasdata(st, 4) )
instance_id = script_getnum(st, 4);
- else if( st->instance_id )
+ else if( st->instance_id >= 0 )
instance_id = st->instance_id;
- else if( (sd = script_rid2sd(st)) != NULL && sd->status.party_id && (p = party_search(sd->status.party_id)) != NULL && p->instance_id )
- instance_id = p->instance_id;
else return true;
- if( instance_id > 0 )
- instance_set_timeout(instance_id, progress_timeout, idle_timeout);
+ if( instance_id >= 0 )
+ instance->set_timeout(instance_id, progress_timeout, idle_timeout);
return true;
}
-BUILDIN(instance_init)
-{
+BUILDIN(instance_init) {
int instance_id = script_getnum(st, 2);
- if( instance[instance_id].state != INSTANCE_IDLE )
- {
+ if( !instance->valid(instance_id) ) {
+ ShowError("instance_init: invalid instance id %d.\n",instance_id);
+ return true;
+ }
+
+ if( instances[instance_id].state != INSTANCE_IDLE ) {
ShowError("instance_init: instance already initialized.\n");
return true;
}
- instance_init(instance_id);
+ instance->start(instance_id);
return true;
}
-BUILDIN(instance_announce)
-{
+BUILDIN(instance_announce) {
int instance_id = script_getnum(st,2);
const char *mes = script_getstr(st,3);
int flag = script_getnum(st,4);
@@ -16058,53 +16042,40 @@ BUILDIN(instance_announce)
int fontY = script_hasdata(st,9) ? script_getnum(st,9) : 0; // default fontY
int i;
- struct map_session_data *sd;
- struct party_data *p;
- if( instance_id == 0 )
- {
- if( st->instance_id )
+ if( instance_id == -1 ) {
+ if( st->instance_id >= 0 )
instance_id = st->instance_id;
- else if( (sd = script_rid2sd(st)) != NULL && sd->status.party_id && (p = party_search(sd->status.party_id)) != NULL && p->instance_id )
- instance_id = p->instance_id;
- else return true;
+ else
+ return true;
}
- if( instance_id <= 0 || instance_id >= MAX_INSTANCE )
+ if( !instance->valid(instance_id) )
return true;
- for( i = 0; i < instance[instance_id].num_map; i++ )
- map_foreachinmap(buildin_announce_sub, instance[instance_id].map[i], BL_PC,
+ for( i = 0; i < instances[instance_id].num_map; i++ )
+ map_foreachinmap(buildin_announce_sub, instances[instance_id].map[i], BL_PC,
mes, strlen(mes)+1, flag&0xf0, fontColor, fontType, fontSize, fontAlign, fontY);
return true;
}
-BUILDIN(instance_npcname)
-{
+BUILDIN(instance_npcname) {
const char *str;
- int instance_id = 0;
-
- struct map_session_data *sd;
- struct party_data *p;
+ int instance_id = -1;
struct npc_data *nd;
str = script_getstr(st, 2);
if( script_hasdata(st, 3) )
instance_id = script_getnum(st, 3);
- else if( st->instance_id )
+ else if( st->instance_id >= 0 )
instance_id = st->instance_id;
- else if( (sd = script_rid2sd(st)) != NULL && sd->status.party_id && (p = party_search(sd->status.party_id)) != NULL && p->instance_id )
- instance_id = p->instance_id;
- if( instance_id && (nd = npc_name2id(str)) != NULL )
- {
+ if( instance_id >= 0 && (nd = npc_name2id(str)) != NULL ) {
static char npcname[NAME_LENGTH];
snprintf(npcname, sizeof(npcname), "dup_%d_%d", instance_id, nd->bl.id);
script_pushconststr(st,npcname);
- }
- else
- {
+ } else {
ShowError("script:instance_npcname: invalid instance NPC (instance_id: %d, NPC name: \"%s\".)\n", instance_id, str);
st->state = END;
return false;
@@ -16113,24 +16084,56 @@ BUILDIN(instance_npcname)
return true;
}
-BUILDIN(has_instance)
-{
+BUILDIN(has_instance) {
struct map_session_data *sd;
- struct party_data *p;
const char *str;
int16 m;
- int instance_id = 0;
+ int instance_id = -1;
str = script_getstr(st, 2);
+
+ if( (m = map_mapname2mapid(str)) < 0 ) {
+ script_pushconststr(st, "");
+ return true;
+ }
+
if( script_hasdata(st, 3) )
instance_id = script_getnum(st, 3);
- else if( st->instance_id )
+ else if( st->instance_id >= 0 )
instance_id = st->instance_id;
- else if( (sd = script_rid2sd(st)) != NULL && sd->status.party_id && (p = party_search(sd->status.party_id)) != NULL && p->instance_id )
- instance_id = p->instance_id;
+ else if( (sd = script_rid2sd(st)) != NULL ) {
+ struct party_data *p;
+ int i = 0, j = 0;
+ if( sd->instances ) {
+ for( i = 0; i < sd->instances; i++ ) {
+ ARR_FIND(0, instances[sd->instance[i]].num_map, j, map[instances[sd->instance[i]].map[j]].instance_src_map == m);
+ if( j != instances[sd->instance[i]].num_map )
+ break;
+ }
+ if( i != sd->instances )
+ instance_id = sd->instance[i];
+ }
+ if( instance_id == -1 && sd->status.party_id && (p = party_search(sd->status.party_id)) && p->instances ) {
+ for( i = 0; i < p->instances; i++ ) {
+ ARR_FIND(0, instances[p->instance[i]].num_map, j, map[instances[p->instance[i]].map[j]].instance_src_map == m);
+ if( j != instances[p->instance[i]].num_map )
+ break;
+ }
+ if( i != p->instances )
+ instance_id = p->instance[i];
+ }
+ if( instance_id == -1 && sd->guild && sd->guild->instances ) {
+ for( i = 0; i < sd->guild->instances; i++ ) {
+ ARR_FIND(0, instances[sd->guild->instance[i]].num_map, j, map[instances[sd->guild->instance[i]].map[j]].instance_src_map == m);
+ if( j != instances[sd->guild->instance[i]].num_map )
+ break;
+ }
+ if( i != sd->guild->instances )
+ instance_id = sd->guild->instance[i];
+ }
+ }
- if( !instance_id || (m = map_mapname2mapid(str)) < 0 || (m = instance_map2imap(m, instance_id)) < 0 )
- {
+ if( !instance->valid(instance_id) || (m = instance->map2imap(m, instance_id)) < 0 ) {
script_pushconststr(st, "");
return true;
}
@@ -16138,38 +16141,41 @@ BUILDIN(has_instance)
script_pushconststr(st, map[m].name);
return true;
}
-
-BUILDIN(instance_warpall)
-{
- struct map_session_data *pl_sd;
- int16 m, i;
- int instance_id;
+static int buildin_instance_warpall_sub(struct block_list *bl,va_list ap) {
+ struct map_session_data *sd = ((TBL_PC*)bl);
+ int mapindex = va_arg(ap,int);
+ int x = va_arg(ap,int);
+ int y = va_arg(ap,int);
+
+ pc_setpos(sd,mapindex,x,y,CLR_TELEPORT);
+
+ return 0;
+}
+BUILDIN(instance_warpall) {
+ int16 m;
+ int instance_id = -1;
const char *mapn;
int x, y;
- unsigned short mapindex;
- struct party_data *p = NULL;
+ int mapindex;
mapn = script_getstr(st,2);
x = script_getnum(st,3);
y = script_getnum(st,4);
+
if( script_hasdata(st,5) )
instance_id = script_getnum(st,5);
- else if( st->instance_id )
+ else if( st->instance_id >= 0 )
instance_id = st->instance_id;
- else if( (pl_sd = script_rid2sd(st)) != NULL && pl_sd->status.party_id && (p = party_search(pl_sd->status.party_id)) != NULL && p->instance_id )
- instance_id = p->instance_id;
- else return true;
-
- if( (m = map_mapname2mapid(mapn)) < 0 || (map[m].flag.src4instance && (m = instance_mapid2imapid(m, instance_id)) < 0) )
+ else
return true;
- if( !(p = party_search(instance[instance_id].party_id)) )
+ if( (m = map_mapname2mapid(mapn)) < 0 || (map[m].flag.src4instance && (m = instance->mapid2imapid(m, instance_id)) < 0) )
return true;
-
+
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,CLR_TELEPORT);
+ map_foreachininstance(buildin_instance_warpall_sub, instance_id, BL_PC,mapindex,x,y);
+
return true;
}
@@ -16183,8 +16189,7 @@ BUILDIN(instance_warpall)
* Example: instance_check_party (getcharid(1){,amount}{,min}{,max});
* Example 2: instance_check_party (getcharid(1),1,1,99);
*------------------------------------------*/
-BUILDIN(instance_check_party)
-{
+BUILDIN(instance_check_party) {
struct map_session_data *pl_sd;
int amount, min, max, i, party_id, c = 0;
struct party_data *p = NULL;
@@ -16298,13 +16303,12 @@ BUILDIN(areamobuseskill)
int16 m;
int range,mobid,skill_id,skill_lv,casttime,emotion,target,cancel;
- if( (m = map_mapname2mapid(script_getstr(st,2))) < 0 )
- {
+ if( (m = map_mapname2mapid(script_getstr(st,2))) < 0 ) {
ShowError("areamobuseskill: invalid map name.\n");
return true;
}
- if( map[m].flag.src4instance && st->instance_id && (m = instance_mapid2imapid(m, st->instance_id)) < 0 )
+ if( map[m].flag.src4instance && st->instance_id >= 0 && (m = instance->mapid2imapid(m, st->instance_id)) < 0 )
return true;
center.m = m;
@@ -16994,6 +16998,309 @@ BUILDIN(npcskill)
return true;
}
+struct hQueue *script_hqueue_get(int idx) {
+ if( idx < 0 || idx >= script->hqs || script->hq[idx].items == -1 )
+ return NULL;
+ return &script->hq[idx];
+}
+/* set .@id,queue(); */
+/* creates queue, returns created queue id */
+BUILDIN(queue) {
+ int idx = script->hqs;
+ int i;
+
+ for(i = 0; i < script->hqs; i++) {
+ if( script->hq[i].items == -1 ) {
+ break;
+ }
+ }
+
+ if( i == script->hqs ) {
+ RECREATE(script->hq, struct hQueue, ++script->hqs);
+ script->hq[ idx ].item = NULL;
+ } else
+ idx = i;
+
+ script->hq[ idx ].id = idx;
+ script->hq[ idx ].items = 0;
+ script->hq[ idx ].onDeath[0] = '\0';
+ script->hq[ idx ].onLogOut[0] = '\0';
+ script->hq[ idx ].onMapChange[0] = '\0';
+
+ script_pushint(st,idx);
+ return true;
+}
+/* set .@length,queuesize(.@queue_id); */
+/* returns queue length */
+BUILDIN(queuesize) {
+ int idx = script_getnum(st, 2);
+
+ if( idx < 0 || idx >= script->hqs || script->hq[idx].items == -1 ) {
+ ShowWarning("buildin_queuesize: unknown queue id %d\n",idx);
+ script_pushint(st, 0);
+ } else
+ script_pushint(st, script->hq[ idx ].items );
+
+ return true;
+}
+bool script_hqueue_add(int idx, int var) {
+ if( idx < 0 || idx >= script->hqs || script->hq[idx].items == -1 ) {
+ ShowWarning("script_hqueue_add: unknown queue id %d\n",idx);
+ return true;
+ } else {
+ struct map_session_data *sd;
+ int i;
+
+ for(i = 0; i < script->hq[idx].items; i++) {
+ if( script->hq[idx].item[i] == var ) {
+ return true;
+ }
+ }
+
+ if( i == script->hq[idx].items ) {
+
+ for(i = 0; i < script->hq[idx].items; i++) {
+ if( script->hq[idx].item[i] == 0 ) {
+ break;
+ }
+ }
+
+ if( i == script->hq[idx].items )
+ RECREATE(script->hq[idx].item, int, ++script->hq[idx].items);
+
+ script->hq[idx].item[i] = var;
+
+ if( var >= START_ACCOUNT_NUM && (sd = map_id2sd(var)) ) {
+ for(i = 0; i < sd->queues_count; i++) {
+ if( sd->queues[i] == -1 ) {
+ break;
+ }
+ }
+
+ if( i == sd->queues_count )
+ RECREATE(sd->queues, int, ++sd->queues_count);
+
+ sd->queues[i] = idx;
+ }
+
+ }
+ }
+ return false;
+}
+/* queueadd(.@queue_id,.@var_id); */
+/* adds a new entry to the queue, returns 1 if already in queue, 0 otherwise */
+BUILDIN(queueadd) {
+ int idx = script_getnum(st, 2);
+ int var = script_getnum(st, 3);
+
+ script_pushint(st,script->queue_add(idx,var)?1:0);
+
+ return true;
+}
+bool script_hqueue_remove(int idx, int var) {
+ if( idx < 0 || idx >= script->hqs || script->hq[idx].items == -1 ) {
+ ShowWarning("script_hqueue_remove: unknown queue id %d (used with var %d)\n",idx,var);
+ return true;
+ } else {
+ int i;
+
+ for(i = 0; i < script->hq[idx].items; i++) {
+ if( script->hq[idx].item[i] == var ) {
+ return true;
+ }
+ }
+
+ if( i != script->hq[idx].items ) {
+ struct map_session_data *sd;
+ script->hq[idx].item[i] = 0;
+
+ if( var >= START_ACCOUNT_NUM && (sd = map_id2sd(var)) ) {
+ for(i = 0; i < sd->queues_count; i++) {
+ if( sd->queues[i] == var ) {
+ break;
+ }
+ }
+
+ if( i != sd->queues_count )
+ sd->queues[i] = -1;
+ }
+
+ }
+ }
+ return false;
+}
+/* queueremove(.@queue_id,.@var_id); */
+/* removes a entry from the queue, returns 1 if not in queue, 0 otherwise */
+BUILDIN(queueremove) {
+ int idx = script_getnum(st, 2);
+ int var = script_getnum(st, 3);
+
+ script_pushint(st, script->queue_remove(idx,var)?1:0);
+
+ return true;
+}
+
+/* queueopt(.@queue_id,optionType,<optional val>); */
+/* modifies the queue's options, when val is not provided the option is removed */
+/* when OnMapChange event is triggered, it sets a temp char var @QMapChangeTo$ with the destination map name */
+/* returns 1 when fails, 0 on success */
+BUILDIN(queueopt) {
+ int idx = script_getnum(st, 2);
+ int var = script_getnum(st, 3);
+
+ if( idx < 0 || idx >= script->hqs || script->hq[idx].items == -1 ) {
+ ShowWarning("buildin_queueopt: unknown queue id %d\n",idx);
+ script_pushint(st, 1);
+ } else if( var <= HQO_NONE || var >= HQO_MAX ) {
+ ShowWarning("buildin_queueopt: unknown optionType %d\n",var);
+ script_pushint(st, 1);
+ } else {
+ switch( (enum hQueueOpt)var ) {
+ case HQO_OnDeath:
+ if( script_hasdata(st, 4) )
+ safestrncpy(script->hq[idx].onDeath, script_getstr(st, 4), EVENT_NAME_LENGTH);
+ else
+ script->hq[idx].onDeath[0] = '\0';
+ break;
+ case HQO_onLogOut:
+ if( script_hasdata(st, 4) )
+ safestrncpy(script->hq[idx].onLogOut, script_getstr(st, 4), EVENT_NAME_LENGTH);
+ else
+ script->hq[idx].onLogOut[0] = '\0';
+ break;
+ case HQO_OnMapChange:
+ if( script_hasdata(st, 4) )
+ safestrncpy(script->hq[idx].onMapChange, script_getstr(st, 4), EVENT_NAME_LENGTH);
+ else
+ script->hq[idx].onMapChange[0] = '\0';
+ break;
+ default:
+ ShowWarning("buildin_queueopt: unsupported optionType %d\n",var);
+ script_pushint(st, 1);
+ break;
+ }
+ }
+
+ return true;
+}
+bool script_hqueue_del(int idx) {
+ if( idx < 0 || idx >= script->hqs || script->hq[idx].items == -1 ) {
+ ShowWarning("script_queue_del: unknown queue id %d\n",idx);
+ return true;
+ } else {
+ struct map_session_data *sd;
+ int i;
+
+ for(i = 0; i < script->hq[idx].items; i++) {
+ if( script->hq[idx].item[i] >= START_ACCOUNT_NUM && (sd = map_id2sd(script->hq[idx].item[i])) ) {
+ int j;
+ for(j = 0; j < sd->queues_count; j++) {
+ if( sd->queues[j] == script->hq[idx].item[i] ) {
+ break;
+ }
+ }
+
+ if( j != sd->queues_count )
+ sd->queues[j] = -1;
+ }
+ }
+
+ script->hq[idx].items = -1;
+ }
+ return false;
+}
+/* queuedel(.@queue_id); */
+/* deletes queue of id .@queue_id, returns 1 if id not found, 0 otherwise */
+BUILDIN(queuedel) {
+ int idx = script_getnum(st, 2);
+
+ script_pushint(st,script->queue_del(idx)?1:0);
+
+ return true;
+}
+
+/* set .@id, queueiterator(.@queue_id); */
+/* creates a new queue iterator, returns its id */
+BUILDIN(queueiterator) {
+ int qid = script_getnum(st, 2);
+ struct hQueue *queue = NULL;
+ int idx = script->hqis;
+ int i;
+
+ if( qid < 0 || qid >= script->hqs || script->hq[idx].items == -1 || !(queue = script->queue(qid)) ) {
+ ShowWarning("queueiterator: invalid queue id %d\n",qid);
+ return true;
+ }
+
+ for(i = 0; i < script->hqis; i++) {
+ if( script->hqi[i].items == -1 ) {
+ break;
+ }
+ }
+
+ if( i == script->hqis )
+ RECREATE(script->hqi, struct hQueueIterator, ++script->hqis);
+ else
+ idx = i;
+
+ RECREATE(script->hqi[ idx ].item, int, queue->items);
+
+ memcpy(&script->hqi[idx].item, &queue->item, sizeof(int)*queue->items);
+
+ script->hqi[ idx ].items = queue->items;
+ script->hqi[ idx ].pos = 0;
+
+ script_pushint(st,idx);
+ return true;
+}
+/* Queue Iterator Get Next */
+/* returns next/first member in the iterator, 0 if none */
+BUILDIN(qiget) {
+ int idx = script_getnum(st, 2);
+
+ if( idx < 0 || idx >= script->hqis ) {
+ ShowWarning("buildin_qiget: unknown queue iterator id %d\n",idx);
+ script_pushint(st, 0);
+ } else if ( script->hqi[idx].pos == script->hqi[idx].items ) {
+ script_pushint(st, 0);
+ } else {
+ struct hQueueIterator *it = &script->hqi[idx];
+ script_pushint(st, it->item[it->pos++]);
+ }
+
+ return true;
+}
+/* Queue Iterator Check */
+/* returns 1:0 if there is a next member in the iterator */
+BUILDIN(qicheck) {
+ int idx = script_getnum(st, 2);
+
+ if( idx < 0 || idx >= script->hqis ) {
+ ShowWarning("buildin_qicheck: unknown queue iterator id %d\n",idx);
+ script_pushint(st, 0);
+ } else if ( script->hqi[idx].pos == script->hqi[idx].items ) {
+ script_pushint(st, 0);
+ } else {
+ script_pushint(st, 1);
+ }
+
+ return true;
+}
+/* Queue Iterator Check */
+BUILDIN(qiclear) {
+ int idx = script_getnum(st, 2);
+
+ if( idx < 0 || idx >= script->hqis ) {
+ ShowWarning("buildin_qiclear: unknown queue iterator id %d\n",idx);
+ script_pushint(st, 1);
+ } else {
+ script->hqi[idx].items = -1;
+ script_pushint(st, 0);
+ }
+
+ return true;
+}
+
// declarations that were supposed to be exported from npc_chat.c
#ifdef PCRE_SUPPORT
BUILDIN(defpattern);
@@ -17442,12 +17749,12 @@ void script_parse_builtin(void) {
BUILDIN_DEF(bg_updatescore,"sii"),
// Instancing
- BUILDIN_DEF(instance_create,"si"),
+ BUILDIN_DEF(instance_create,"si?"),
BUILDIN_DEF(instance_destroy,"?"),
- BUILDIN_DEF(instance_attachmap,"si?"),
+ BUILDIN_DEF(instance_attachmap,"si??"),
BUILDIN_DEF(instance_detachmap,"s?"),
BUILDIN_DEF(instance_attach,"i"),
- BUILDIN_DEF(instance_id,"?"),
+ BUILDIN_DEF(instance_id,""),
BUILDIN_DEF(instance_set_timeout,"ii?"),
BUILDIN_DEF(instance_init,"i"),
BUILDIN_DEF(instance_announce,"isi?????"),
@@ -17492,6 +17799,20 @@ void script_parse_builtin(void) {
BUILDIN_DEF(checkquest, "i?"),
BUILDIN_DEF(changequest, "ii"),
BUILDIN_DEF(showevent, "ii"),
+
+ /**
+ * hQueue [Ind/Hercules]
+ **/
+ BUILDIN_DEF(queue,""),
+ BUILDIN_DEF(queuesize,"i"),
+ BUILDIN_DEF(queueadd,"ii"),
+ BUILDIN_DEF(queueremove,"ii"),
+ BUILDIN_DEF(queueopt,"ii?"),
+ BUILDIN_DEF(queuedel,"i"),
+ BUILDIN_DEF(queueiterator,"i"),
+ BUILDIN_DEF(qicheck,"i"),
+ BUILDIN_DEF(qiget,"i"),
+ BUILDIN_DEF(qiclear,"i"),
};
int i,n, len = ARRAYLENGTH(BUILDIN), start = script->buildin_count;
char* p;
@@ -17545,6 +17866,11 @@ void script_parse_builtin(void) {
void script_defaults(void) {
script = &script_s;
+ script->hq = NULL;
+ script->hqi = NULL;
+ script->hqs = script->hqis = 0;
+ memset(&script->hqe, 0, sizeof(script->hqe));
+
script->buildin_count = 0;
script->buildin = NULL;
@@ -17555,4 +17881,9 @@ void script_defaults(void) {
script->addScript = script_hp_add;
script->conv_num = conv_num;
script->conv_str = conv_str;
+
+ script->queue = script_hqueue_get;
+ script->queue_add = script_hqueue_add;
+ script->queue_del = script_hqueue_del;
+ script->queue_remove = script_hqueue_remove;
}
diff --git a/src/map/script.h b/src/map/script.h
index a0d282bfe..70ced5d43 100644
--- a/src/map/script.h
+++ b/src/map/script.h
@@ -4,6 +4,8 @@
#ifndef _SCRIPT_H_
#define _SCRIPT_H_
+#include "map.h" //EVENT_NAME_LENGTH
+
#define NUM_WHISPER_VAR 10
struct map_session_data;
@@ -110,6 +112,30 @@ struct script_stack {
struct DBMap* var_function;// scope variables
};
+enum hQueueOpt {
+ HQO_NONE,
+ HQO_onLogOut,
+ HQO_OnDeath,
+ HQO_OnMapChange,
+ HQO_MAX,
+};
+
+/* [Ind/Hercules] */
+struct hQueue {
+ int id;
+ int *item;
+ int items;
+ /* events */
+ char onLogOut[EVENT_NAME_LENGTH];
+ char onDeath[EVENT_NAME_LENGTH];
+ char onMapChange[EVENT_NAME_LENGTH];
+};
+
+struct hQueueIterator {
+ int *item;
+ int items;
+ int pos;
+};
//
// Script state
@@ -129,6 +155,7 @@ struct script_state {
int instance_id;
//For backing up purposes
struct script_state *bk_st;
+ unsigned char hIterator;
int bk_npcid;
unsigned freeloop : 1;// used by buildin_freeloop
unsigned op2ref : 1;// used by op_2
@@ -291,8 +318,14 @@ struct script_function {
char *name;
char *arg;
};
+
/* script.c interface (incomplete) */
struct script_interface {
+ /* */
+ struct hQueue *hq;
+ struct hQueueIterator *hqi;
+ int hqs, hqis;
+ int hqe[HQO_MAX];
/* */
char **buildin;
unsigned int buildin_count;
@@ -304,6 +337,11 @@ struct script_interface {
bool (*addScript) (char *name, char *args, bool (*func)(struct script_state *st));
int (*conv_num) (struct script_state *st,struct script_data *data);
const char* (*conv_str) (struct script_state *st,struct script_data *data);
+ /* */
+ struct hQueue *(*queue) (int idx);
+ bool (*queue_add) (int idx, int var);
+ bool (*queue_del) (int idx);
+ bool (*queue_remove) (int idx, int var);
} script_s;
struct script_interface *script;
diff --git a/src/map/skill.c b/src/map/skill.c
index 06bfca5f8..911410727 100644
--- a/src/map/skill.c
+++ b/src/map/skill.c
@@ -14464,7 +14464,7 @@ void skill_unitsetmapcell (struct skill_unit *src, uint16 skill_id, uint16 skill
for( y = src->bl.y - range; y <= src->bl.y + range; ++y )
for( x = src->bl.x - range; x <= src->bl.x + range; ++x )
- map_setcell(src->bl.m, x, y, cell, flag);
+ map[src->bl.m].setcell(src->bl.m, x, y, cell, flag);
}
/*==========================================
diff --git a/src/map/status.c b/src/map/status.c
index b7e906910..30adf0d0f 100644
--- a/src/map/status.c
+++ b/src/map/status.c
@@ -6079,14 +6079,15 @@ void status_set_viewdata(struct block_list *bl, int class_)
/// Returns the status_change data of bl or NULL if it doesn't exist.
struct status_change *status_get_sc(struct block_list *bl) {
- if( bl )
- switch (bl->type) {
- case BL_PC: return &((TBL_PC*)bl)->sc;
- case BL_MOB: return &((TBL_MOB*)bl)->sc;
- case BL_NPC: return &((TBL_NPC*)bl)->sc;
- case BL_HOM: return &((TBL_HOM*)bl)->sc;
- case BL_MER: return &((TBL_MER*)bl)->sc;
- case BL_ELEM: return &((TBL_ELEM*)bl)->sc;
+ if( bl ) {
+ switch (bl->type) {
+ case BL_PC: return &((TBL_PC*)bl)->sc;
+ case BL_MOB: return &((TBL_MOB*)bl)->sc;
+ case BL_NPC: return NULL;
+ case BL_HOM: return &((TBL_HOM*)bl)->sc;
+ case BL_MER: return &((TBL_MER*)bl)->sc;
+ case BL_ELEM: return &((TBL_ELEM*)bl)->sc;
+ }
}
return NULL;
}
diff --git a/src/map/unit.c b/src/map/unit.c
index cbc695c4a..3ab1008cb 100644
--- a/src/map/unit.c
+++ b/src/map/unit.c
@@ -50,7 +50,7 @@ struct unit_data* unit_bl2ud(struct block_list *bl)
if( bl->type == BL_PC) return &((struct map_session_data*)bl)->ud;
if( bl->type == BL_MOB) return &((struct mob_data*)bl)->ud;
if( bl->type == BL_PET) return &((struct pet_data*)bl)->ud;
- if( bl->type == BL_NPC) return &((struct npc_data*)bl)->ud;
+ if( bl->type == BL_NPC) return ((struct npc_data*)bl)->ud;
if( bl->type == BL_HOM) return &((struct homun_data*)bl)->ud;
if( bl->type == BL_MER) return &((struct mercenary_data*)bl)->ud;
if( bl->type == BL_ELEM) return &((struct elemental_data*)bl)->ud;
@@ -678,10 +678,12 @@ int unit_setdir(struct block_list *bl,unsigned char dir)
return 0;
}
-uint8 unit_getdir(struct block_list *bl)
-{
+uint8 unit_getdir(struct block_list *bl) {
struct unit_data *ud;
- nullpo_ret(bl );
+ nullpo_ret(bl);
+
+ if( bl->type == BL_NPC )
+ return ((TBL_NPC*)bl)->dir;
ud = unit_bl2ud(bl);
if (!ud) return 0;
return ud->dir;
@@ -1961,8 +1963,7 @@ int unit_skillcastcancel(struct block_list *bl,int type)
}
// unit_data initialization process
-void unit_dataset(struct block_list *bl)
-{
+void unit_dataset(struct block_list *bl) {
struct unit_data *ud;
nullpo_retv(ud = unit_bl2ud(bl));
@@ -2121,8 +2122,7 @@ int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file,
npc_touchnext_areanpc(sd,true);
// Check if warping and not changing the map.
- if ( sd->state.warping && !sd->state.changemap )
- {
+ if ( sd->state.warping && !sd->state.changemap ) {
status_change_end(bl, SC_CLOAKING, INVALID_TIMER);
status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER);
}
@@ -2163,18 +2163,15 @@ int unit_remove_map_(struct block_list *bl, clr_type clrtype, const char* file,
sd->state.active, sd->state.connect_new, sd->state.rewarp, sd->state.changemap, sd->state.debug_remove_map,
map[bl->m].name, map[bl->m].users,
sd->debug_file, sd->debug_line, sd->debug_func, file, line, func);
- }
- else
- if (--map[bl->m].users == 0 && battle_config.dynamic_mobs) //[Skotlex]
+ } else if (--map[bl->m].users == 0 && battle_config.dynamic_mobs) //[Skotlex]
map_removemobs(bl->m);
if( !(sd->sc.option&OPTION_INVISIBLE) )
{// decrement the number of active pvp players on the map
--map[bl->m].users_pvp;
}
- if( map[bl->m].instance_id )
- {
- instance[map[bl->m].instance_id].users--;
- instance_check_idle(map[bl->m].instance_id);
+ if( map[bl->m].instance_id >= 0 ) {
+ instances[map[bl->m].instance_id].users--;
+ instance->check_idle(map[bl->m].instance_id);
}
sd->state.debug_remove_map = 1; // temporary state to track double remove_map's [FlavioJS]
sd->debug_file = file;
@@ -2356,9 +2353,19 @@ int unit_free(struct block_list *bl, clr_type clrtype)
ers_free(pc_sc_display_ers, sd->sc_display[i]);
}
sd->sc_display_count = 0;
+ }
+ if( sd->sc_display != NULL ) {
aFree(sd->sc_display);
sd->sc_display = NULL;
}
+ if( sd->instance != NULL ) {
+ aFree(sd->instance);
+ sd->instance = NULL;
+ }
+ if( sd->queues != NULL ) {
+ aFree(sd->queues);
+ sd->queues = NULL;
+ }
break;
}
case BL_PET: