summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md161
-rw-r--r--conf/battle/items.conf5
-rw-r--r--conf/battle/skill.conf2
-rw-r--r--conf/inter-server.conf12
-rw-r--r--src/char/char.c29
-rw-r--r--src/char/int_guild.c7
-rw-r--r--src/char/int_pet.c7
-rw-r--r--src/common/core.c7
-rw-r--r--src/common/mapindex.c9
-rw-r--r--src/common/sql.c79
-rw-r--r--src/common/sql.h6
-rw-r--r--src/login/login.c7
-rw-r--r--src/map/battle.c8
-rw-r--r--src/map/battle.h1
-rw-r--r--src/map/chrif.c7
-rw-r--r--src/map/clif.c28
-rw-r--r--src/map/elemental.c10
-rw-r--r--src/map/homunculus.c11
-rw-r--r--src/map/map.c9
-rw-r--r--src/map/mercenary.c9
-rw-r--r--src/map/mob.c7
-rw-r--r--src/map/npc.c12
-rw-r--r--src/map/pc.c122
-rw-r--r--src/map/pc.h9
-rw-r--r--src/map/script.c34
-rw-r--r--src/map/skill.c342
-rw-r--r--src/map/status.c53
-rw-r--r--src/map/unit.c9
28 files changed, 650 insertions, 352 deletions
diff --git a/README.md b/README.md
index 3d7b996b5..da3077d15 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,161 @@
Hercules
-======== \ No newline at end of file
+========
+Table of Contents
+---------
+* 1 What is Hercules?
+* 2 Prerequisites
+* 3 Installation
+* 4 Troubleshooting
+* 5 Helpful Links
+* 6 More Documentation
+
+1. What is Hercules?
+---------
+Hercules is a collaborative software development project revolving around the
+creation of a robust massively multiplayer online role playing game (MMORPG)
+server package. Written in C, the program is very versatile and provides NPCs,
+warps and modifications. The project is jointly managed by a group of volunteers
+located around the world as well as a tremendous community providing QA and
+support. Hercules is a continuation of the original Athena project.
+
+2. Prerequisites
+---------
+Before installing Hercules there are certain tools and applications you will need.
+This differs between the varying operating systems available, so the following
+is broken down into Windows and Linux prerequisites.
+
+* Windows
+ * TortoiseGIT ( http://code.google.com/p/tortoisegit/ )
+ * MSysGit ( http://code.google.com/p/msysgit/downloads/list?can=2 )
+ * MySQL ( http://www.mysql.com/downloads/mysql/ )
+ * MySQL Workbench ( http://www.mysql.com/downloads/workbench/ )
+ * MS Visual C++ ( http://www.microsoft.com/visualstudio/en-us/products/2010-editions/visual-cpp-express )
+
+* Linux (names of packages may require specific version numbers on certain distributions)
+ * gcc
+ * make
+ * mysql
+ * mysql-devel
+ * mysql-server
+ * pcre-devel
+ * git
+ * zlib-devel
+
+3. Installation
+---------
+This section is a very brief set of installation instructions. For more concise guides
+relevant to your Operation System, please refer to the Wiki (links at the end of this file).
+
+* Windows
+ * Install prerequisites
+ * Create a folder to download Hercules into (e.g. C:\Hercules)
+ * Right click this folder and select "Git Clone".
+ * Paste the GIT URL into the box: https://github.com/HerculesWS/Hercules.git
+ * Open MySQL Workbench and create an instance to connect to your MySQL Server
+ * Create a database (hercules), a user (hercules), give permissions (GRANT SELECT,INSERT,UPDATE,DELETE)
+ and then login using the new user
+ * Use MySQL Workbench to run the .sql files in /sql-files/ on the new Hercules database
+
+* Linux
+ * (For CentOS)
+ * Step 1: yum install gcc make mysql mysql-devel mysql-server pcre-devel zlib-devel
+ * Step 2: rpm -Uvhhttp://repo.webtatic.com/yum/centos/5/latest.rpm
+ * Step 3: yum install --enablerepo=webtatic git-all
+ * Step 4: yum install --enablerepo=webtatic --disableexcludes=main git-all
+ (For Debian) Type: apt-get install git make gcc libmysqlclient-dev zlib1g-dev libpcre3-dev
+ * Type: mysql_secure_installation
+ * Start your MySQL server
+ * Setup a MySQL user:
+
+ CREATE USER 'hercules'@'localhost' IDENTIFIED BY 'password';
+ * Assign permissions:
+
+ GRANT SELECT,INSERT,UPDATE,DELETE ON `hercules\_rag`.* TO 'hercules'@'localhost';
+ * Type: git clone https://github.com/HerculesWS/Hercules.git ~/Hercules
+ * Insert SQL files: mysql --user=root -p hercules_rag < trunk/sql-files/main.sql (and others)
+ * Type: cd trunk && ./configure && make clean && make sql
+ * When you're ready, type: ./athena-start start
+
+
+
+4. Troubleshooting
+---------
+If you're having problems with starting your server, the first thing you should
+do is check what's happening on your consoles. More often that not, all support issues
+can be solved simply by looking at the error messages given.
+
+Examples:
+
+* You get an error on your map-server_sql that looks something like this:
+
+ [Error]: npc_parsesrcfile: Unable to parse, probably a missing or extra TAB in
+ file 'npc/custom/jobmaster.txt', line '17'. Skipping line...
+ * w1=prontera,153,193,6 script
+ * w2=Job Master
+ * w3=123,{
+ * w4=
+
+ If you look at the error, it's telling you that you're missing (or have an extra) TAB.
+ This is easily fixed by looking at this part of the error: * w1=prontera,153,193,6 script
+ If there was a TAB where it's supposed to be, that line would have prontera,153,193,6 at w1
+ and 'script' at w2. As there's a space instead of a TAB, the two sections are read as a
+ single parameter.
+
+* You have a default user/password warning similar to the following:
+
+ [Warning]: Using the default user/password s1/p1 is NOT RECOMMENDED.
+ [Notice]: Please edit your 'login' table to create a proper inter-server user/pa
+ ssword (gender 'S')
+ [Notice]: and then edit your user/password in conf/map_athena.conf (or conf/impo
+ rt/map_conf.txt)
+
+ Relax. This is just indicating that you're using the default username and password. To
+ fix this, check over the part in the installation instructions relevant to the `login` table.
+
+* Your Map Server says the following:
+
+ [Error]: make_connection: connect failed (socket #2, error 10061: No connection
+ could be made because the target machine actively refused it.
+ )!
+
+ If this shows up on the map server, it generally means that there is no Char Server available
+ to accept the connection.
+
+5. Helpful Links
+---------
+The following list of links point to various help files within the GIT, articles or
+pages on the Wiki or topics within the Hercules forum.
+
+* Hercules Forums
+ http://hercules.ws/board/
+
+* GIT Repository URL:
+ https://github.com/HerculesWS/Hercules
+
+* Hercules IRC Channel
+ irc.rizon.net
+ Channel: #Hercules
+
+
+
+6. More Documentation
+---------
+Hercules has a large collection of help files and sample NPC scripts located in /doc/
+
+* Scripting
+ It is recommended to look through /doc/script_commands.txt for help, pointers or
+ even for ideas for your next NPC script. Most script commands have a usage example.
+
+* @commands
+ In-game, Game Masters have the ability to use Atcommands (@) to control players,
+ create items, spawn mobs, reload configuration files and even control the weather.
+ For an in-depth explanation, please see /doc/atcommands.txt
+
+* Permissions
+ The Hercules emulator has a permission system that enables certain groups of players
+ to perform certain actions, or have access to certain visual enhancements or in-game
+ activity. To see what permissions are available, they are detailed in /doc/permissions.txt
+
+There are more files in the /doc/ directory that will help you to create scripts or update the
+mapcache, or even explain how the job system and item bonuses work. Before posting a topic asking
+for help on the forums, we recommend that all users take the time to look over this directory. \ No newline at end of file
diff --git a/conf/battle/items.conf b/conf/battle/items.conf
index 9bc2e37cc..343b4212e 100644
--- a/conf/battle/items.conf
+++ b/conf/battle/items.conf
@@ -75,3 +75,8 @@ gtb_sc_immunity: 50
// NOTE: Different cards that grant the same skill will both
// always work independently of each other regardless of setting.
autospell_stacking: no
+
+// Will disabled consumables (disabled by item_noequip.txt) be consumed when trying to use them?
+// 1 (official): yes
+// 0: no
+item_restricted_consumption_type:1 \ No newline at end of file
diff --git a/conf/battle/skill.conf b/conf/battle/skill.conf
index 03aae2ad1..0dd97610e 100644
--- a/conf/battle/skill.conf
+++ b/conf/battle/skill.conf
@@ -278,5 +278,5 @@ dancing_weaponswitch_fix: yes
// Skill Trap Type
// 0: (official) traps only makes player unable to move after its walk path is complete, and it activates other traps on the way.
-// 1: trap makes player stops moving right when stepping over it.
+// 1: trap makes player stop moving right when stepping over it.
skill_trap_type: 0
diff --git a/conf/inter-server.conf b/conf/inter-server.conf
index 70bf80e5c..523437007 100644
--- a/conf/inter-server.conf
+++ b/conf/inter-server.conf
@@ -56,6 +56,18 @@ log_db_db: ragnarok
log_codepage:
log_login_db: loginlog
+// == MySQL Reconnect Settings
+// ===========================
+// - mysql_reconnect_type
+// - 1: when mysql disconnects during runtime, the server tries to reconnect mysql_reconnect_count times and,
+// -- if unsuccessful, the server is shut down
+// - 2: when mysql disconnects during runtime it tries to reconnect indefinitely
+mysql_reconnect_type:2
+// - mysql_reconnect_count
+// - number of reconnect attempts the server should do when the database disconnects during runtime
+// - only used when mysql_reconnect_type is 1
+mysql_reconnect_count:1
+
// DO NOT CHANGE ANYTHING BEYOND THIS LINE UNLESS YOU KNOW YOUR DATABASE DAMN WELL
// this is meant for people who KNOW their stuff, and for some reason want to change their
// database layout. [CLOWNISIUS]
diff --git a/src/char/char.c b/src/char/char.c
index 83b58a0a7..d454e8bd0 100644
--- a/src/char/char.c
+++ b/src/char/char.c
@@ -3991,6 +3991,35 @@ int parse_char(int fd)
return 0;
RFIFOSKIP(fd,6);
break;
+ // char rename request
+ // R 08fc <char ID>.l <new name>.24B
+ case 0x8fc:
+ FIFOSD_CHECK(30);
+ {
+ int i, cid =RFIFOL(fd,2);
+ char name[NAME_LENGTH];
+ char esc_name[NAME_LENGTH*2+1];
+ safestrncpy(name, (char *)RFIFOP(fd,6), NAME_LENGTH);
+ RFIFOSKIP(fd,30);
+
+ ARR_FIND( 0, MAX_CHARS, i, sd->found_char[i] == cid );
+ if( i == MAX_CHARS )
+ break;
+
+ normalize_name(name,TRIM_CHARS);
+ Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH));
+ if( !check_char_name(name,esc_name) ) {
+ i = 1;
+ safestrncpy(sd->new_name, name, NAME_LENGTH);
+ } else
+ i = 0;
+
+ WFIFOHEAD(fd, 4);
+ WFIFOW(fd,0) = 0x28e;
+ WFIFOW(fd,2) = i;
+ WFIFOSET(fd,4);
+ }
+ break;
// char rename request
// R 028d <account ID>.l <char ID>.l <new name>.24B
diff --git a/src/char/int_guild.c b/src/char/int_guild.c
index 7090af5ee..9cb17dca8 100644
--- a/src/char/int_guild.c
+++ b/src/char/int_guild.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 team
#include "../common/cbasetypes.h"
#include "../common/mmo.h"
@@ -1815,7 +1816,7 @@ int mapif_parse_GuildMasterChange(int fd, int guild_id, const char* name, int le
g->member[0].position = 0; //Position 0: guild Master.
g->member[0].modified = GS_MEMBER_MODIFIED;
- strncpy(g->master, name, len);
+ safestrncpy(g->master, name, len);
if (len < NAME_LENGTH)
g->master[len] = '\0';
diff --git a/src/char/int_pet.c b/src/char/int_pet.c
index 114398290..d9b0cf5ef 100644
--- a/src/char/int_pet.c
+++ b/src/char/int_pet.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 team
#include "../common/mmo.h"
#include "../common/malloc.h"
@@ -184,7 +185,7 @@ int mapif_create_pet(int fd, int account_id, int char_id, short pet_class, short
short pet_equip, short intimate, short hungry, char rename_flag, char incuvate, char *pet_name)
{
memset(pet_pt, 0, sizeof(struct s_pet));
- strncpy(pet_pt->name, pet_name, NAME_LENGTH);
+ safestrncpy(pet_pt->name, pet_name, NAME_LENGTH);
if(incuvate == 1)
pet_pt->account_id = pet_pt->char_id = 0;
else {
diff --git a/src/common/core.c b/src/common/core.c
index 1e3dbb3d7..b1714b7a5 100644
--- a/src/common/core.c
+++ b/src/common/core.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 team
#include "../common/mmo.h"
#include "../common/showmsg.h"
@@ -11,6 +12,7 @@
#include "../common/timer.h"
#include "../common/thread.h"
#include "../common/mempool.h"
+#include "../common/sql.h"
#endif
#include <stdio.h>
@@ -319,6 +321,7 @@ int main (int argc, char **argv)
display_title();
usercheck();
+ Sql_Init();
rathread_init();
mempool_init();
db_init();
diff --git a/src/common/mapindex.c b/src/common/mapindex.c
index d46047833..cea945ac0 100644
--- a/src/common/mapindex.c
+++ b/src/common/mapindex.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 team
#include "../common/mmo.h"
#include "../common/showmsg.h"
@@ -37,7 +38,7 @@ const char* mapindex_getmapname(const char* string, char* output)
len -= 4; // strip .gat extension
len = min(len, MAP_NAME_LENGTH-1);
- strncpy(dest, string, len+1);
+ safestrncpy(dest, string, len+1);
memset(&dest[len], '\0', MAP_NAME_LENGTH-len);
return dest;
@@ -61,7 +62,7 @@ const char* mapindex_getmapname_ext(const char* string, char* output)
ShowWarning("(mapindex_normalize_name) Map name '%*s' is too long!\n", 2*MAP_NAME_LENGTH, buf);
len--;
}
- strncpy(dest, buf, len+1);
+ safestrncpy(dest, buf, len+1);
if (len < 4 || stricmp(&dest[len-4], ".gat") != 0) {
strcpy(&dest[len], ".gat");
diff --git a/src/common/sql.c b/src/common/sql.c
index 800aa89b0..73c4181d9 100644
--- a/src/common/sql.c
+++ b/src/common/sql.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 team
#include "../common/cbasetypes.h"
#include "../common/malloc.h"
@@ -15,7 +16,10 @@
#include <string.h>// strlen/strnlen/memcpy/memset
#include <stdlib.h>// strtoul
+void hercules_mysql_error_handler(unsigned int ecode);
+int mysql_reconnect_type;
+unsigned int mysql_reconnect_count;
/// Sql handle
struct Sql
@@ -74,7 +78,7 @@ Sql* Sql_Malloc(void)
self->lengths = NULL;
self->result = NULL;
self->keepalive = INVALID_TIMER;
-
+ self->handle.reconnect = 1;
return self;
}
@@ -266,12 +270,14 @@ int Sql_QueryV(Sql* self, const char* query, va_list args)
if( mysql_real_query(&self->handle, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf)) )
{
ShowSQL("DB error - %s\n", mysql_error(&self->handle));
+ hercules_mysql_error_handler(mysql_errno(&self->handle));
return SQL_ERROR;
}
self->result = mysql_store_result(&self->handle);
if( mysql_errno(&self->handle) != 0 )
{
ShowSQL("DB error - %s\n", mysql_error(&self->handle));
+ hercules_mysql_error_handler(mysql_errno(&self->handle));
return SQL_ERROR;
}
return SQL_SUCCESS;
@@ -291,12 +297,14 @@ int Sql_QueryStr(Sql* self, const char* query)
if( mysql_real_query(&self->handle, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf)) )
{
ShowSQL("DB error - %s\n", mysql_error(&self->handle));
+ hercules_mysql_error_handler(mysql_errno(&self->handle));
return SQL_ERROR;
}
self->result = mysql_store_result(&self->handle);
if( mysql_errno(&self->handle) != 0 )
{
ShowSQL("DB error - %s\n", mysql_error(&self->handle));
+ hercules_mysql_error_handler(mysql_errno(&self->handle));
return SQL_ERROR;
}
return SQL_SUCCESS;
@@ -639,6 +647,7 @@ int SqlStmt_PrepareV(SqlStmt* self, const char* query, va_list args)
if( mysql_stmt_prepare(self->stmt, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf)) )
{
ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt));
+ hercules_mysql_error_handler(mysql_stmt_errno(self->stmt));
return SQL_ERROR;
}
self->bind_params = false;
@@ -660,6 +669,7 @@ int SqlStmt_PrepareStr(SqlStmt* self, const char* query)
if( mysql_stmt_prepare(self->stmt, StringBuf_Value(&self->buf), (unsigned long)StringBuf_Length(&self->buf)) )
{
ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt));
+ hercules_mysql_error_handler(mysql_stmt_errno(self->stmt));
return SQL_ERROR;
}
self->bind_params = false;
@@ -721,12 +731,14 @@ int SqlStmt_Execute(SqlStmt* self)
mysql_stmt_execute(self->stmt) )
{
ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt));
+ hercules_mysql_error_handler(mysql_stmt_errno(self->stmt));
return SQL_ERROR;
}
self->bind_columns = false;
if( mysql_stmt_store_result(self->stmt) )// store all the data
{
ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt));
+ hercules_mysql_error_handler(mysql_stmt_errno(self->stmt));
return SQL_ERROR;
}
@@ -868,6 +880,7 @@ int SqlStmt_NextRow(SqlStmt* self)
if( err )
{
ShowSQL("DB error - %s\n", mysql_stmt_error(self->stmt));
+ hercules_mysql_error_handler(mysql_stmt_errno(self->stmt));
return SQL_ERROR;
}
@@ -946,3 +959,63 @@ void SqlStmt_Free(SqlStmt* self)
aFree(self);
}
}
+/* receives mysql error codes during runtime (not on first-time-connects) */
+void hercules_mysql_error_handler(unsigned int ecode) {
+ static unsigned int retry = 1;
+ switch( ecode ) {
+ case 2003:/* Can't connect to MySQL (this error only happens here when failing to reconnect) */
+ if( mysql_reconnect_type == 1 ) {
+ if( ++retry > mysql_reconnect_count ) {
+ ShowFatalError("MySQL has been unreachable for too long, %d reconnects were attempted. Shutting Down\n", retry);
+ exit(EXIT_FAILURE);
+ }
+ }
+ break;
+ }
+}
+void Sql_inter_server_read(const char* cfgName, bool first) {
+ int i;
+ char line[1024], w1[1024], w2[1024];
+ FILE* fp;
+
+ fp = fopen(cfgName, "r");
+ if(fp == NULL) {
+ if( first ) {
+ ShowFatalError("File not found: %s\n", cfgName);
+ exit(EXIT_FAILURE);
+ } else
+ ShowError("File not found: %s\n", cfgName);
+ return;
+ }
+
+ while(fgets(line, sizeof(line), fp)) {
+ i = sscanf(line, "%[^:]: %[^\r\n]", w1, w2);
+ if(i != 2)
+ continue;
+
+ if(!strcmpi(w1,"mysql_reconnect_type")) {
+ mysql_reconnect_type = atoi(w2);
+ switch( mysql_reconnect_type ) {
+ case 1:
+ case 2:
+ break;
+ default:
+ ShowError("%s::mysql_reconnect_type is set to %d which is not valid, defaulting to 1...\n", cfgName, mysql_reconnect_type);
+ mysql_reconnect_type = 1;
+ break;
+ }
+ } else if(!strcmpi(w1,"mysql_reconnect_count")) {
+ mysql_reconnect_count = atoi(w2);
+ if( mysql_reconnect_count < 1 )
+ mysql_reconnect_count = 1;
+ } else if(!strcmpi(w1,"import"))
+ Sql_inter_server_read(w2,false);
+ }
+ fclose(fp);
+
+ return;
+}
+
+void Sql_Init(void) {
+ Sql_inter_server_read("conf/inter-server.conf",true);
+}
diff --git a/src/common/sql.h b/src/common/sql.h
index 898e2c778..5ac92665e 100644
--- a/src/common/sql.h
+++ b/src/common/sql.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 team
#ifndef _COMMON_SQL_H_
#define _COMMON_SQL_H_
@@ -339,6 +340,7 @@ void SqlStmt_ShowDebug_(SqlStmt* self, const char* debug_file, const unsigned lo
/// Frees a SqlStmt returned by SqlStmt_Malloc.
void SqlStmt_Free(SqlStmt* self);
+void Sql_Init(void);
#endif /* _COMMON_SQL_H_ */
diff --git a/src/login/login.c b/src/login/login.c
index e079dbaf2..625e0f5c6 100644
--- a/src/login/login.c
+++ b/src/login/login.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 team
#include "../common/core.h"
#include "../common/db.h"
@@ -1596,7 +1597,7 @@ int login_config_read(const char* cfgName)
continue;
if(!strcmpi(w1,"timestamp_format"))
- strncpy(timestamp_format, w2, 20);
+ safestrncpy(timestamp_format, w2, 20);
else if(!strcmpi(w1,"stdout_with_ansisequence"))
stdout_with_ansisequence = config_switch(w2);
else if(!strcmpi(w1,"console_silent")) {
diff --git a/src/map/battle.c b/src/map/battle.c
index 2198b25ec..0506f2fe9 100644
--- a/src/map/battle.c
+++ b/src/map/battle.c
@@ -808,13 +808,12 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag
* in RE, SW possesses a lifetime equal to 3 times the caster's health
**/
#ifdef RENEWAL
+ d->dmg_lv = ATK_BLOCK;
if ( ( group->val2 - damage) > 0 ) {
group->val2 -= damage;
- d->dmg_lv = ATK_BLOCK;
- return 0;
} else
- damage -= group->val2;
- skill_delunitgroup(group);
+ skill_delunitgroup(group);
+ return 0;
#else
if (--group->val2<=0)
skill_delunitgroup(group);
@@ -5868,6 +5867,7 @@ static const struct _battle_data {
* Hercules
**/
{ "skill_trap_type", &battle_config.skill_trap_type, 0, 0, 1, },
+ { "item_restricted_consumption_type", &battle_config.item_restricted_consumption_type,1, 0, 1, },
};
#ifndef STATS_OPT_OUT
/**
diff --git a/src/map/battle.h b/src/map/battle.h
index 0943b1aa3..c5ca19b90 100644
--- a/src/map/battle.h
+++ b/src/map/battle.h
@@ -484,6 +484,7 @@ extern struct Battle_Config
int mob_size_influence; // Enable modifications on earned experience, drop rates and monster status depending on monster size. [mkbu95]
int skill_trap_type;
+ int item_restricted_consumption_type;
} battle_config;
void do_init_battle(void);
diff --git a/src/map/chrif.c b/src/map/chrif.c
index e109f7095..3ad164b89 100644
--- a/src/map/chrif.c
+++ b/src/map/chrif.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 team
#include "../common/cbasetypes.h"
#include "../common/malloc.h"
@@ -246,7 +247,7 @@ int chrif_setip(const char* ip) {
return 0;
}
- strncpy(char_ip_str, ip, sizeof(char_ip_str));
+ safestrncpy(char_ip_str, ip, sizeof(char_ip_str));
ShowInfo("Char Server IP Address : '"CL_WHITE"%s"CL_RESET"' -> '"CL_WHITE"%s"CL_RESET"'.\n", ip, ip2str(char_ip, ip_str));
diff --git a/src/map/clif.c b/src/map/clif.c
index 3f4ea8bc2..e04941336 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -203,7 +203,7 @@ int clif_setip(const char* ip)
return 0;
}
- strncpy(map_ip_str, ip, sizeof(map_ip_str));
+ safestrncpy(map_ip_str, ip, sizeof(map_ip_str));
ShowInfo("Map Server IP Address : '"CL_WHITE"%s"CL_RESET"' -> '"CL_WHITE"%s"CL_RESET"'.\n", ip, ip2str(map_ip, ip_str));
return 1;
}
@@ -9358,6 +9358,7 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd)
}
map_iwall_get(sd); // Updates Walls Info on this Map to Client
+ status_calc_pc(sd, false);/* some conditions are map-dependent so we must recalculate */
sd->state.changemap = false;
}
@@ -10141,7 +10142,7 @@ void clif_parse_DropItem(int fd, struct map_session_data *sd)
if (pc_isdead(sd))
break;
- if (pc_cant_act(sd))
+ if ( pc_cant_act2(sd) )
break;
if (sd->sc.count && (
@@ -10180,7 +10181,7 @@ void clif_parse_UseItem(int fd, struct map_session_data *sd)
if (sd->npc_id != sd->npc_item_flag)
return;
}
- else if (pc_istrading(sd))
+ else if ( pc_istrading(sd) || sd->chatID )
return;
//Whether the item is used or not is irrelevant, the char ain't idle. [Skotlex]
@@ -10213,7 +10214,7 @@ void clif_parse_EquipItem(int fd,struct map_session_data *sd)
return;
} else if (sd->state.storage_flag || sd->sc.opt1)
; //You can equip/unequip stuff while storage is open/under status changes
- else if (pc_cant_act(sd))
+ else if ( pc_cant_act2(sd) )
return;
if(!sd->status.inventory[index].identify) {
@@ -10250,7 +10251,7 @@ void clif_parse_UnequipItem(int fd,struct map_session_data *sd)
if (sd->state.storage_flag || sd->sc.opt1)
; //You can equip/unequip stuff while storage is open/under status changes
- else if (pc_cant_act(sd))
+ else if ( pc_cant_act2(sd) )
return;
index = RFIFOW(fd,2)-2;
@@ -10272,7 +10273,7 @@ void clif_parse_NpcClicked(int fd,struct map_session_data *sd)
return;
}
- if (pc_cant_act(sd))
+ if ( pc_cant_act2(sd) )
return;
bl = map_id2bl(RFIFOL(fd,2));
@@ -11111,11 +11112,16 @@ void clif_parse_NpcSelectMenu(int fd,struct map_session_data *sd)
int npc_id = RFIFOL(fd,2);
uint8 select = RFIFOB(fd,6);
- if( (select > sd->npc_menu && select != 0xff) || select == 0 )
- {
- TBL_NPC* nd = map_id2nd(npc_id);
- ShowWarning("Invalid menu selection on npc %d:'%s' - got %d, valid range is [%d..%d] (player AID:%d, CID:%d, name:'%s')!\n", npc_id, (nd)?nd->name:"invalid npc id", select, 1, sd->npc_menu, sd->bl.id, sd->status.char_id, sd->status.name);
- clif_GM_kick(NULL,sd);
+ if( (select > sd->npc_menu && select != 0xff) || select == 0 ) {
+#if SECURE_NPCTIMEOUT
+ if( sd->npc_idle_timer != INVALID_TIMER ) {
+#endif
+ TBL_NPC* nd = map_id2nd(npc_id);
+ ShowWarning("Invalid menu selection on npc %d:'%s' - got %d, valid range is [%d..%d] (player AID:%d, CID:%d, name:'%s')!\n", npc_id, (nd)?nd->name:"invalid npc id", select, 1, sd->npc_menu, sd->bl.id, sd->status.char_id, sd->status.name);
+ clif_GM_kick(NULL,sd);
+#if SECURE_NPCTIMEOUT
+ }
+#endif
return;
}
diff --git a/src/map/elemental.c b/src/map/elemental.c
index 90b90c1e3..f6c9eff84 100644
--- a/src/map/elemental.c
+++ b/src/map/elemental.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 team
#include "../common/cbasetypes.h"
#include "../common/malloc.h"
@@ -10,6 +11,7 @@
#include "../common/showmsg.h"
#include "../common/utils.h"
#include "../common/random.h"
+#include "../common/strlib.h"
#include "log.h"
#include "clif.h"
@@ -795,8 +797,8 @@ int read_elementaldb(void) {
db = &elemental_db[j];
db->class_ = atoi(str[0]);
- strncpy(db->sprite, str[1], NAME_LENGTH);
- strncpy(db->name, str[2], NAME_LENGTH);
+ safestrncpy(db->sprite, str[1], NAME_LENGTH);
+ safestrncpy(db->name, str[2], NAME_LENGTH);
db->lv = atoi(str[3]);
status = &db->status;
diff --git a/src/map/homunculus.c b/src/map/homunculus.c
index 081287d8a..c94a95775 100644
--- a/src/map/homunculus.c
+++ b/src/map/homunculus.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 team
#include "../common/cbasetypes.h"
#include "../common/malloc.h"
@@ -709,7 +710,7 @@ int merc_hom_change_name_ack(struct map_session_data *sd, char* name, int flag)
clif_displaymessage(sd->fd, msg_txt(280)); // You cannot use this name
return 0;
}
- strncpy(hd->homunculus.name,name,NAME_LENGTH);
+ safestrncpy(hd->homunculus.name,name,NAME_LENGTH);
clif_charnameack (0,&hd->bl);
hd->homunculus.rename_flag = 1;
clif_hominfo(sd,hd,0);
@@ -887,7 +888,7 @@ int merc_create_homunculus_request(struct map_session_data *sd, int class_)
memset(&homun, 0, sizeof(struct s_homunculus));
//Initial data
- strncpy(homun.name, homunculus_db[i].name, NAME_LENGTH-1);
+ safestrncpy(homun.name, homunculus_db[i].name, NAME_LENGTH-1);
homun.class_ = class_;
homun.level = 1;
homun.hunger = 32; //32%
@@ -1050,7 +1051,7 @@ static bool read_homunculusdb_sub(char* str[], int columns, int current)
}
db->evo_class = classid;
//Name, Food, Hungry Delay, Base Size, Evo Size, Race, Element, ASPD
- strncpy(db->name,str[2],NAME_LENGTH-1);
+ safestrncpy(db->name,str[2],NAME_LENGTH-1);
db->foodID = atoi(str[3]);
db->hungryDelay = atoi(str[4]);
db->base_size = atoi(str[5]);
diff --git a/src/map/map.c b/src/map/map.c
index a8521de7d..d2cc9c4a9 100644
--- a/src/map/map.c
+++ b/src/map/map.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 team
#include "../common/cbasetypes.h"
#include "../common/core.h"
@@ -3216,7 +3217,7 @@ int map_config_read(char *cfgName)
*ptr = '\0';
if(strcmpi(w1,"timestamp_format")==0)
- strncpy(timestamp_format, w2, 20);
+ safestrncpy(timestamp_format, w2, 20);
else if(strcmpi(w1,"stdout_with_ansisequence")==0)
stdout_with_ansisequence = config_switch(w2);
else if(strcmpi(w1,"console_silent")==0) {
@@ -3267,7 +3268,7 @@ int map_config_read(char *cfgName)
else if (strcmpi(w1, "charhelp_txt") == 0)
strcpy(charhelp_txt, w2);
else if(strcmpi(w1,"db_path") == 0)
- strncpy(db_path,w2,255);
+ safestrncpy(db_path,w2,255);
else if (strcmpi(w1, "console") == 0) {
console = config_switch(w2);
if (console)
diff --git a/src/map/mercenary.c b/src/map/mercenary.c
index 973dac33e..c3fb8e3e2 100644
--- a/src/map/mercenary.c
+++ b/src/map/mercenary.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 team
#include "../common/cbasetypes.h"
#include "../common/malloc.h"
@@ -404,8 +405,8 @@ static bool read_mercenarydb_sub(char* str[], int columns, int current)
db = &mercenary_db[current];
db->class_ = atoi(str[0]);
- strncpy(db->sprite, str[1], NAME_LENGTH);
- strncpy(db->name, str[2], NAME_LENGTH);
+ safestrncpy(db->sprite, str[1], NAME_LENGTH);
+ safestrncpy(db->name, str[2], NAME_LENGTH);
db->lv = atoi(str[3]);
status = &db->status;
diff --git a/src/map/mob.c b/src/map/mob.c
index ac3c1dfe3..6550d9b0e 100644
--- a/src/map/mob.c
+++ b/src/map/mob.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 team
#include "../common/cbasetypes.h"
#include "../common/timer.h"
@@ -4120,7 +4121,7 @@ static bool mob_parse_row_chatdb(char** str, const char* source, int line, int*
}
msg[len] = 0; // strip previously found EOL
- strncpy(ms->msg, str[2], CHAT_SIZE_MAX);
+ safestrncpy(ms->msg, str[2], CHAT_SIZE_MAX);
return true;
}
diff --git a/src/map/npc.c b/src/map/npc.c
index 5d8a0274e..3aabeaf98 100644
--- a/src/map/npc.c
+++ b/src/map/npc.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 team
#include "../common/cbasetypes.h"
#include "../common/timer.h"
@@ -231,6 +232,9 @@ int npc_rr_secure_timeout_timer(int tid, unsigned int tick, int id, intptr_t dat
**/
if( sd->st )
sd->st->state = END;
+ sd->state.menu_or_input = 0;
+ sd->npc_menu = 0;
+
/**
* This guy's been idle for longer than allowed, close him.
**/
@@ -1915,7 +1919,7 @@ void npc_addsrcfile(const char* name)
file = (struct npc_src_list*)aMalloc(sizeof(struct npc_src_list) + strlen(name));
file->next = NULL;
- strncpy(file->name, name, strlen(name) + 1);
+ safestrncpy(file->name, name, strlen(name) + 1);
if( file_prev == NULL )
npc_src_files = file;
else
@@ -3606,7 +3610,7 @@ void npc_read_event_script(void)
DBData *data;
char name[64]="::";
- strncpy(name+2,config[i].event_name,62);
+ safestrncpy(name+2,config[i].event_name,62);
script_event[i].event_count = 0;
iter = db_iterator(ev_db);
diff --git a/src/map/pc.c b/src/map/pc.c
index 89925f8f2..6f608cd49 100644
--- a/src/map/pc.c
+++ b/src/map/pc.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 team
#include "../common/cbasetypes.h"
#include "../common/core.h" // get_svn_revision()
@@ -700,24 +701,24 @@ int pc_setequipindex(struct map_session_data *sd)
return 0;
}
+//static int pc_isAllowedCardOn(struct map_session_data *sd,int s,int eqindex,int flag)
+//{
+// int i;
+// struct item *item = &sd->status.inventory[eqindex];
+// struct item_data *data;
+//
+// //Crafted/made/hatched items.
+// if (itemdb_isspecial(item->card[0]))
+// return 1;
+//
+// /* scan for enchant armor gems */
+// if( item->card[MAX_SLOTS - 1] && s < MAX_SLOTS - 1 )
+// s = MAX_SLOTS - 1;
+//
+// ARR_FIND( 0, s, i, item->card[i] && (data = itemdb_exists(item->card[i])) != NULL && data->flag.no_equip&flag );
+// return( i < s ) ? 0 : 1;
+//}
-static int pc_isAllowedCardOn(struct map_session_data *sd,int s,int eqindex,int flag)
-{
- int i;
- struct item *item = &sd->status.inventory[eqindex];
- struct item_data *data;
-
- //Crafted/made/hatched items.
- if (itemdb_isspecial(item->card[0]))
- return 1;
-
- /* scan for enchant armor gems */
- if( item->card[MAX_SLOTS - 1] && s < MAX_SLOTS - 1 )
- s = MAX_SLOTS - 1;
-
- ARR_FIND( 0, s, i, item->card[i] && (data = itemdb_exists(item->card[i])) != NULL && data->flag.no_equip&flag );
- return( i < s ) ? 0 : 1;
-}
bool pc_isequipped(struct map_session_data *sd, int nameid)
{
@@ -860,20 +861,6 @@ int pc_isequip(struct map_session_data *sd,int n)
#endif
if(item->sex != 2 && sd->status.sex != item->sex)
return 0;
- if(!map_flag_vs(sd->bl.m) && ((item->flag.no_equip&1) || !pc_isAllowedCardOn(sd,item->slot,n,1)))
- return 0;
- if(map[sd->bl.m].flag.pvp && ((item->flag.no_equip&2) || !pc_isAllowedCardOn(sd,item->slot,n,2)))
- return 0;
- if(map_flag_gvg(sd->bl.m) && ((item->flag.no_equip&4) || !pc_isAllowedCardOn(sd,item->slot,n,4)))
- return 0;
- if(map[sd->bl.m].flag.battleground && ((item->flag.no_equip&8) || !pc_isAllowedCardOn(sd,item->slot,n,8)))
- return 0;
- if(map[sd->bl.m].flag.restricted)
- {
- int flag =8*map[sd->bl.m].zone;
- if (item->flag.no_equip&flag || !pc_isAllowedCardOn(sd,item->slot,n,flag))
- return 0;
- }
if (sd->sc.count) {
@@ -4133,16 +4120,6 @@ int pc_isUseitem(struct map_session_data *sd,int n)
else if( itemdb_is_poison(nameid) && (sd->class_&MAPID_THIRDMASK) != MAPID_GUILLOTINE_CROSS )
return 0;
- //added item_noequip.txt items check by Maya&[Lupus]
- if (
- (!map_flag_vs(sd->bl.m) && item->flag.no_equip&1) || // Normal
- (map[sd->bl.m].flag.pvp && item->flag.no_equip&2) || // PVP
- (map_flag_gvg(sd->bl.m) && item->flag.no_equip&4) || // GVG
- (map[sd->bl.m].flag.battleground && item->flag.no_equip&8) || // Battleground
- (map[sd->bl.m].flag.restricted && item->flag.no_equip&(8*map[sd->bl.m].zone)) // Zone restriction
- )
- return 0;
-
//Gender check
if(item->sex != 2 && sd->status.sex != item->sex)
return 0;
@@ -4221,7 +4198,7 @@ int pc_useitem(struct map_session_data *sd,int n)
(itemdb_iscashfood(nameid) && DIFF_TICK(sd->canusecashfood_tick, tick) > 0)
)
return 0;
-
+
/* Items with delayed consume are not meant to work while in mounts except reins of mount(12622) */
if( sd->inventory_data[n]->flag.delay_consume ) {
if( nameid != ITEMID_REINS_OF_MOUNT && sd->sc.option&OPTION_MOUNTING )
@@ -4272,6 +4249,21 @@ int pc_useitem(struct map_session_data *sd,int n)
}
}
+ /* on restricted maps the item is consumed but the effect is not used */
+ if (
+ (!map_flag_vs(sd->bl.m) && sd->inventory_data[n]->flag.no_equip&1) || // Normal
+ (map[sd->bl.m].flag.pvp && sd->inventory_data[n]->flag.no_equip&2) || // PVP
+ (map_flag_gvg(sd->bl.m) && sd->inventory_data[n]->flag.no_equip&4) || // GVG
+ (map[sd->bl.m].flag.battleground && sd->inventory_data[n]->flag.no_equip&8) || // Battleground
+ (map[sd->bl.m].flag.restricted && sd->inventory_data[n]->flag.no_equip&(8*map[sd->bl.m].zone)) // Zone restriction
+ ) {
+ if( battle_config.item_restricted_consumption_type ) {
+ clif_useitemack(sd,n,sd->status.inventory[n].amount-1,true);
+ pc_delitem(sd,n,1,1,0,LOG_TYPE_CONSUME);
+ }
+ return 0;/* regardless, effect is not run */
+ }
+
sd->itemid = sd->status.inventory[n].nameid;
sd->itemindex = n;
if(sd->catch_target_class != -1) //Abort pet catching.
@@ -5518,6 +5510,8 @@ int pc_stop_following (struct map_session_data *sd)
sd->followtarget = -1;
sd->ud.target_to = 0;
+ unit_stop_walking(&sd->bl, 1);
+
return 0;
}
@@ -8609,41 +8603,33 @@ int pc_unequipitem(struct map_session_data *sd,int n,int flag) {
int pc_checkitem(struct map_session_data *sd)
{
int i,id,calc_flag = 0;
- struct item_data *it=NULL;
nullpo_ret(sd);
if( sd->state.vending ) //Avoid reorganizing items when we are vending, as that leads to exploits (pointed out by End of Exam)
return 0;
- if( battle_config.item_check )
- {// check for invalid(ated) items
- for( i = 0; i < MAX_INVENTORY; i++ )
- {
+ if( battle_config.item_check ) { // check for invalid(ated) items
+ for( i = 0; i < MAX_INVENTORY; i++ ) {
id = sd->status.inventory[i].nameid;
- if( id && !itemdb_available(id) )
- {
+ if( id && !itemdb_available(id) ) {
ShowWarning("Removed invalid/disabled item id %d from inventory (amount=%d, char_id=%d).\n", id, sd->status.inventory[i].amount, sd->status.char_id);
pc_delitem(sd, i, sd->status.inventory[i].amount, 0, 0, LOG_TYPE_OTHER);
}
}
- for( i = 0; i < MAX_CART; i++ )
- {
+ for( i = 0; i < MAX_CART; i++ ) {
id = sd->status.cart[i].nameid;
- if( id && !itemdb_available(id) )
- {
+ if( id && !itemdb_available(id) ) {
ShowWarning("Removed invalid/disabled item id %d from cart (amount=%d, char_id=%d).\n", id, sd->status.cart[i].amount, sd->status.char_id);
pc_cart_delitem(sd, i, sd->status.cart[i].amount, 0, LOG_TYPE_OTHER);
}
}
}
- for( i = 0; i < MAX_INVENTORY; i++)
- {
- it = sd->inventory_data[i];
+ for( i = 0; i < MAX_INVENTORY; i++) {
if( sd->status.inventory[i].nameid == 0 )
continue;
@@ -8651,31 +8637,15 @@ int pc_checkitem(struct map_session_data *sd)
if( !sd->status.inventory[i].equip )
continue;
- if( sd->status.inventory[i].equip&~pc_equippoint(sd,i) )
- {
+ if( sd->status.inventory[i].equip&~pc_equippoint(sd,i) ) {
pc_unequipitem(sd, i, 2);
calc_flag = 1;
continue;
}
- if( it )
- { // check for forbiden items.
- int flag =
- (map[sd->bl.m].flag.restricted?(8*map[sd->bl.m].zone):0)
- | (!map_flag_vs(sd->bl.m)?1:0)
- | (map[sd->bl.m].flag.pvp?2:0)
- | (map_flag_gvg(sd->bl.m)?4:0)
- | (map[sd->bl.m].flag.battleground?8:0);
- if( flag && (it->flag.no_equip&flag || !pc_isAllowedCardOn(sd,it->slot,i,flag)) )
- {
- pc_unequipitem(sd, i, 2);
- calc_flag = 1;
- }
- }
}
- if( calc_flag && sd->state.active )
- {
+ if( calc_flag && sd->state.active ) {
pc_checkallowskill(sd);
status_calc_pc(sd,0);
}
diff --git a/src/map/pc.h b/src/map/pc.h
index 3027c5f10..870945d73 100644
--- a/src/map/pc.h
+++ b/src/map/pc.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 team
#ifndef _PC_H_
#define _PC_H_
@@ -592,6 +593,10 @@ enum equip_index {
#define pc_isidle(sd) ( (sd)->chatID || (sd)->state.vending || (sd)->state.buyingstore || DIFF_TICK(last_tick, (sd)->idletime) >= battle_config.idle_no_share )
#define pc_istrading(sd) ( (sd)->npc_id || (sd)->state.vending || (sd)->state.buyingstore || (sd)->state.trading )
#define pc_cant_act(sd) ( (sd)->npc_id || (sd)->state.vending || (sd)->state.buyingstore || (sd)->chatID || ((sd)->sc.opt1 && (sd)->sc.opt1 != OPT1_BURNING) || (sd)->state.trading || (sd)->state.storage_flag )
+
+/* equals pc_cant_act except it doesn't check for chat rooms */
+#define pc_cant_act2(sd) ( (sd)->npc_id || (sd)->state.vending || (sd)->state.buyingstore || ((sd)->sc.opt1 && (sd)->sc.opt1 != OPT1_BURNING) || (sd)->state.trading || (sd)->state.storage_flag )
+
#define pc_setdir(sd,b,h) ( (sd)->ud.dir = (b) ,(sd)->head_dir = (h) )
#define pc_setchatid(sd,n) ( (sd)->chatID = n )
#define pc_ishiding(sd) ( (sd)->sc.option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) )
diff --git a/src/map/script.c b/src/map/script.c
index 4099820f1..60a61654a 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -3590,30 +3590,26 @@ static void script_detach_state(struct script_state* st, bool dequeue_event)
{
struct map_session_data* sd;
- if(st->rid && (sd = map_id2sd(st->rid))!=NULL)
- {
+ if(st->rid && (sd = map_id2sd(st->rid))!=NULL) {
sd->st = st->bk_st;
sd->npc_id = st->bk_npcid;
- /**
- * For the Secure NPC Timeout option (check config/Secure.h) [RR]
- **/
- #if SECURE_NPCTIMEOUT
- /**
- * We're done with this NPC session, so we cancel the timer (if existent) and move on
- **/
- if( sd->npc_idle_timer != INVALID_TIMER ) {
- delete_timer(sd->npc_idle_timer,npc_rr_secure_timeout_timer);
- sd->npc_idle_timer = INVALID_TIMER;
- }
- #endif
- if(st->bk_st)
- {
+ if(st->bk_st) {
//Remove tag for removal.
st->bk_st = NULL;
st->bk_npcid = 0;
- }
- else if(dequeue_event)
- {
+ } else if(dequeue_event) {
+ /**
+ * For the Secure NPC Timeout option (check config/Secure.h) [RR]
+ **/
+#if SECURE_NPCTIMEOUT
+ /**
+ * We're done with this NPC session, so we cancel the timer (if existent) and move on
+ **/
+ if( sd->npc_idle_timer != INVALID_TIMER ) {
+ delete_timer(sd->npc_idle_timer,npc_rr_secure_timeout_timer);
+ sd->npc_idle_timer = INVALID_TIMER;
+ }
+#endif
npc_event_dequeue(sd);
}
}
diff --git a/src/map/skill.c b/src/map/skill.c
index 752b1ece0..9c07390f3 100644
--- a/src/map/skill.c
+++ b/src/map/skill.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 team
#include "../common/cbasetypes.h"
#include "../common/timer.h"
@@ -1560,7 +1561,7 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, uint
if (skill == AS_SONICBLOW)
pc_stop_attack(sd); //Special case, Sonic Blow autospell should stop the player attacking.
- if (skill == PF_SPIDERWEB) //Special case, due to its nature of coding.
+ else if (skill == PF_SPIDERWEB) //Special case, due to its nature of coding.
type = CAST_GROUND;
sd->state.autocast = 1;
@@ -2251,6 +2252,7 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds
rmdamage = 1;
bl = src;
src = tbl;
+ dsrc = tbl;
sd = BL_CAST(BL_PC, src);
tsd = BL_CAST(BL_PC, bl);
sc = status_get_sc(bl);
@@ -9373,7 +9375,15 @@ int skill_castend_id(int tid, unsigned int tick, int id, intptr_t data)
}
if (target && target->m == src->m)
{ //Move character to target anyway.
- if (unit_movepos(src, src->x+3, src->y+3, 1, 1))
+ int dir, x, y;
+ dir = map_calc_dir(src,target->x,target->y);
+ if( dir > 0 && dir < 4) x = -2;
+ else if( dir > 4 ) x = 2;
+ else x = 0;
+ if( dir > 2 && dir < 6 ) y = -2;
+ else if( dir == 7 || dir < 2 ) y = 2;
+ else y = 0;
+ if (unit_movepos(src, src->x+x, src->y+y, 1, 1))
{ //Display movement + animation.
clif_slide(src,src->x,src->y);
clif_skill_damage(src,target,tick,sd->battle_status.amotion,0,0,1,ud->skill_id, ud->skill_lv, 5);
@@ -11041,195 +11051,191 @@ static int skill_unit_onplace (struct skill_unit *src, struct block_list *bl, un
type = status_skill2sc(sg->skill_id);
sce = (sc && type != -1)?sc->data[type]:NULL;
skill_id = sg->skill_id; //In case the group is deleted, we need to return the correct skill id, still.
- switch (sg->unit_id)
- {
- case UNT_SPIDERWEB:
- if( sc && sc->data[SC_SPIDERWEB] && sc->data[SC_SPIDERWEB]->val1 > 0 )
- { // If you are fiberlocked and can't move, it will only increase your fireweakness level. [Inkfish]
- sc->data[SC_SPIDERWEB]->val2++;
- break;
- }
- else if( sc )
- {
- int sec = skill_get_time2(sg->skill_id,sg->skill_lv);
- if( status_change_start(bl,type,10000,sg->skill_lv,1,sg->group_id,0,sec,8) )
- {
- const struct TimerData* td = sc->data[type]?get_timer(sc->data[type]->timer):NULL;
- if( td )
- sec = DIFF_TICK(td->tick, tick);
- map_moveblock(bl, src->bl.x, src->bl.y, tick);
- clif_fixpos(bl);
- sg->val2 = bl->id;
+ switch (sg->unit_id) {
+ case UNT_SPIDERWEB:
+ if( sc && sc->data[SC_SPIDERWEB] && sc->data[SC_SPIDERWEB]->val1 > 0 ) {
+ // If you are fiberlocked and can't move, it will only increase your fireweakness level. [Inkfish]
+ sc->data[SC_SPIDERWEB]->val2++;
+ break;
+ } else if( sc && battle_check_target(&sg->unit->bl,bl,sg->target_flag) > 0 ) {
+ int sec = skill_get_time2(sg->skill_id,sg->skill_lv);
+ if( status_change_start(bl,type,10000,sg->skill_lv,1,sg->group_id,0,sec,8) ) {
+ const struct TimerData* td = sc->data[type]?get_timer(sc->data[type]->timer):NULL;
+ if( td )
+ sec = DIFF_TICK(td->tick, tick);
+ map_moveblock(bl, src->bl.x, src->bl.y, tick);
+ clif_fixpos(bl);
+ sg->val2 = bl->id;
+ }
+ else
+ sec = 3000; //Couldn't trap it?
+ sg->limit = DIFF_TICK(tick,sg->tick)+sec;
}
- else
- sec = 3000; //Couldn't trap it?
- sg->limit = DIFF_TICK(tick,sg->tick)+sec;
- }
- break;
- case UNT_SAFETYWALL:
- if (!sce)
- sc_start4(bl,type,100,sg->skill_lv,sg->skill_id,sg->group_id,0,sg->limit);
- break;
+ break;
+ case UNT_SAFETYWALL:
+ if (!sce)
+ sc_start4(bl,type,100,sg->skill_lv,sg->skill_id,sg->group_id,0,sg->limit);
+ break;
- case UNT_PNEUMA:
- case UNT_CHAOSPANIC:
- case UNT_MAELSTROM:
- if (!sce)
- sc_start4(bl,type,100,sg->skill_lv,sg->group_id,0,0,sg->limit);
- break;
- case UNT_BLOODYLUST:
- if (sg->src_id == bl->id)
- break; //Does not affect the caster.
- if (!sce) {
- TBL_PC *sd = BL_CAST(BL_PC, bl); //prevent fullheal exploit
- if (sd && sd->bloodylust_tick && DIFF_TICK(gettick(), sd->bloodylust_tick) < skill_get_time2(SC_BLOODYLUST, 1))
- clif_skill_nodamage(&src->bl,bl,sg->skill_id,sg->skill_lv,
- sc_start4(bl, type, 100, sg->skill_lv, 1, 0, 0, skill_get_time(LK_BERSERK, sg->skill_lv)));
- else {
- if (sd) sd->bloodylust_tick = gettick();
+ case UNT_PNEUMA:
+ case UNT_CHAOSPANIC:
+ case UNT_MAELSTROM:
+ if (!sce)
+ sc_start4(bl,type,100,sg->skill_lv,sg->group_id,0,0,sg->limit);
+ break;
+ case UNT_BLOODYLUST:
+ if (sg->src_id == bl->id)
+ break; //Does not affect the caster.
+ if (!sce) {
+ TBL_PC *sd = BL_CAST(BL_PC, bl); //prevent fullheal exploit
+ if (sd && sd->bloodylust_tick && DIFF_TICK(gettick(), sd->bloodylust_tick) < skill_get_time2(SC_BLOODYLUST, 1))
clif_skill_nodamage(&src->bl,bl,sg->skill_id,sg->skill_lv,
- sc_start4(bl, type, 100, sg->skill_lv, 0, 0, 0, skill_get_time(LK_BERSERK, sg->skill_lv)));
+ sc_start4(bl, type, 100, sg->skill_lv, 1, 0, 0, skill_get_time(LK_BERSERK, sg->skill_lv)));
+ else {
+ if (sd) sd->bloodylust_tick = gettick();
+ clif_skill_nodamage(&src->bl,bl,sg->skill_id,sg->skill_lv,
+ sc_start4(bl, type, 100, sg->skill_lv, 0, 0, 0, skill_get_time(LK_BERSERK, sg->skill_lv)));
+ }
}
- }
- break;
+ break;
- case UNT_WARP_WAITING: {
- int working = sg->val1&0xffff;
+ case UNT_WARP_WAITING: {
+ int working = sg->val1&0xffff;
- if(bl->type==BL_PC && !working){
- struct map_session_data *sd = (struct map_session_data *)bl;
- if((!sd->chatID || battle_config.chat_warpportal)
- && sd->ud.to_x == src->bl.x && sd->ud.to_y == src->bl.y)
- {
- int x = sg->val2>>16;
- int y = sg->val2&0xffff;
- int count = sg->val1>>16;
- unsigned short m = sg->val3;
+ if(bl->type==BL_PC && !working){
+ struct map_session_data *sd = (struct map_session_data *)bl;
+ if((!sd->chatID || battle_config.chat_warpportal)
+ && sd->ud.to_x == src->bl.x && sd->ud.to_y == src->bl.y)
+ {
+ int x = sg->val2>>16;
+ int y = sg->val2&0xffff;
+ int count = sg->val1>>16;
+ unsigned short m = sg->val3;
- if( --count <= 0 )
- skill_delunitgroup(sg);
+ if( --count <= 0 )
+ skill_delunitgroup(sg);
- if ( map_mapindex2mapid(sg->val3) == sd->bl.m && x == sd->bl.x && y == sd->bl.y )
- working = 1;/* we break it because officials break it, lovely stuff. */
+ if ( map_mapindex2mapid(sg->val3) == sd->bl.m && x == sd->bl.x && y == sd->bl.y )
+ working = 1;/* we break it because officials break it, lovely stuff. */
- sg->val1 = (count<<16)|working;
+ sg->val1 = (count<<16)|working;
- pc_setpos(sd,m,x,y,CLR_TELEPORT);
+ pc_setpos(sd,m,x,y,CLR_TELEPORT);
+ }
+ } else if(bl->type == BL_MOB && battle_config.mob_warp&2) {
+ int16 m = map_mapindex2mapid(sg->val3);
+ if (m < 0) break; //Map not available on this map-server.
+ unit_warp(bl,m,sg->val2>>16,sg->val2&0xffff,CLR_TELEPORT);
}
- } else if(bl->type == BL_MOB && battle_config.mob_warp&2) {
- int16 m = map_mapindex2mapid(sg->val3);
- if (m < 0) break; //Map not available on this map-server.
- unit_warp(bl,m,sg->val2>>16,sg->val2&0xffff,CLR_TELEPORT);
}
- }
- break;
+ break;
- case UNT_QUAGMIRE:
- if( !sce && battle_check_target(&sg->unit->bl,bl,sg->target_flag) > 0 )
- sc_start4(bl,type,100,sg->skill_lv,sg->group_id,0,0,sg->limit);
- break;
+ case UNT_QUAGMIRE:
+ if( !sce && battle_check_target(&sg->unit->bl,bl,sg->target_flag) > 0 )
+ sc_start4(bl,type,100,sg->skill_lv,sg->group_id,0,0,sg->limit);
+ break;
- case UNT_VOLCANO:
- case UNT_DELUGE:
- case UNT_VIOLENTGALE:
- if(!sce)
- sc_start(bl,type,100,sg->skill_lv,sg->limit);
- break;
+ case UNT_VOLCANO:
+ case UNT_DELUGE:
+ case UNT_VIOLENTGALE:
+ if(!sce)
+ sc_start(bl,type,100,sg->skill_lv,sg->limit);
+ break;
- case UNT_SUITON:
- if(!sce)
- sc_start4(bl,type,100,sg->skill_lv,
- map_flag_vs(bl->m) || battle_check_target(&src->bl,bl,BCT_ENEMY)>0?1:0, //Send val3 =1 to reduce agi.
- 0,0,sg->limit);
- break;
+ case UNT_SUITON:
+ if(!sce)
+ sc_start4(bl,type,100,sg->skill_lv,
+ map_flag_vs(bl->m) || battle_check_target(&src->bl,bl,BCT_ENEMY)>0?1:0, //Send val3 =1 to reduce agi.
+ 0,0,sg->limit);
+ break;
- case UNT_HERMODE:
- if (sg->src_id!=bl->id && battle_check_target(&src->bl,bl,BCT_PARTY|BCT_GUILD) > 0)
- status_change_clear_buffs(bl,1); //Should dispell only allies.
- case UNT_RICHMANKIM:
- case UNT_ETERNALCHAOS:
- case UNT_DRUMBATTLEFIELD:
- case UNT_RINGNIBELUNGEN:
- case UNT_ROKISWEIL:
- case UNT_INTOABYSS:
- case UNT_SIEGFRIED:
- //Needed to check when a dancer/bard leaves their ensemble area.
- if (sg->src_id==bl->id && !(sc && sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_BARDDANCER))
- return skill_id;
- if (!sce)
- sc_start4(bl,type,100,sg->skill_lv,sg->val1,sg->val2,0,sg->limit);
- break;
- case UNT_WHISTLE:
- case UNT_ASSASSINCROSS:
- case UNT_POEMBRAGI:
- case UNT_APPLEIDUN:
- case UNT_HUMMING:
- case UNT_DONTFORGETME:
- case UNT_FORTUNEKISS:
- case UNT_SERVICEFORYOU:
- if (sg->src_id==bl->id && !(sc && sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_BARDDANCER))
- return 0;
+ case UNT_HERMODE:
+ if (sg->src_id!=bl->id && battle_check_target(&src->bl,bl,BCT_PARTY|BCT_GUILD) > 0)
+ status_change_clear_buffs(bl,1); //Should dispell only allies.
+ case UNT_RICHMANKIM:
+ case UNT_ETERNALCHAOS:
+ case UNT_DRUMBATTLEFIELD:
+ case UNT_RINGNIBELUNGEN:
+ case UNT_ROKISWEIL:
+ case UNT_INTOABYSS:
+ case UNT_SIEGFRIED:
+ //Needed to check when a dancer/bard leaves their ensemble area.
+ if (sg->src_id==bl->id && !(sc && sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_BARDDANCER))
+ return skill_id;
+ if (!sce)
+ sc_start4(bl,type,100,sg->skill_lv,sg->val1,sg->val2,0,sg->limit);
+ break;
+ case UNT_WHISTLE:
+ case UNT_ASSASSINCROSS:
+ case UNT_POEMBRAGI:
+ case UNT_APPLEIDUN:
+ case UNT_HUMMING:
+ case UNT_DONTFORGETME:
+ case UNT_FORTUNEKISS:
+ case UNT_SERVICEFORYOU:
+ if (sg->src_id==bl->id && !(sc && sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_BARDDANCER))
+ return 0;
- if (!sc) return 0;
- if (!sce)
- sc_start4(bl,type,100,sg->skill_lv,sg->val1,sg->val2,0,sg->limit);
- else if (sce->val4 == 1) {
- //Readjust timers since the effect will not last long.
- sce->val4 = 0;
- delete_timer(sce->timer, status_change_timer);
- sce->timer = add_timer(tick+sg->limit, status_change_timer, bl->id, type);
- }
- break;
+ if (!sc) return 0;
+ if (!sce)
+ sc_start4(bl,type,100,sg->skill_lv,sg->val1,sg->val2,0,sg->limit);
+ else if (sce->val4 == 1) {
+ //Readjust timers since the effect will not last long.
+ sce->val4 = 0;
+ delete_timer(sce->timer, status_change_timer);
+ sce->timer = add_timer(tick+sg->limit, status_change_timer, bl->id, type);
+ }
+ break;
- case UNT_FOGWALL:
- if (!sce)
- {
- sc_start4(bl, type, 100, sg->skill_lv, sg->val1, sg->val2, sg->group_id, sg->limit);
- if (battle_check_target(&src->bl,bl,BCT_ENEMY)>0)
- skill_additional_effect (ss, bl, sg->skill_id, sg->skill_lv, BF_MISC, ATK_DEF, tick);
- }
- break;
+ case UNT_FOGWALL:
+ if (!sce)
+ {
+ sc_start4(bl, type, 100, sg->skill_lv, sg->val1, sg->val2, sg->group_id, sg->limit);
+ if (battle_check_target(&src->bl,bl,BCT_ENEMY)>0)
+ skill_additional_effect (ss, bl, sg->skill_id, sg->skill_lv, BF_MISC, ATK_DEF, tick);
+ }
+ break;
- case UNT_GRAVITATION:
- if (!sce)
- sc_start4(bl,type,100,sg->skill_lv,0,BCT_ENEMY,sg->group_id,sg->limit);
- break;
+ case UNT_GRAVITATION:
+ if (!sce)
+ sc_start4(bl,type,100,sg->skill_lv,0,BCT_ENEMY,sg->group_id,sg->limit);
+ break;
-// officially, icewall has no problems existing on occupied cells [ultramage]
-// case UNT_ICEWALL: //Destroy the cell. [Skotlex]
-// src->val1 = 0;
-// if(src->limit + sg->tick > tick + 700)
-// src->limit = DIFF_TICK(tick+700,sg->tick);
-// break;
+ // officially, icewall has no problems existing on occupied cells [ultramage]
+ // case UNT_ICEWALL: //Destroy the cell. [Skotlex]
+ // src->val1 = 0;
+ // if(src->limit + sg->tick > tick + 700)
+ // src->limit = DIFF_TICK(tick+700,sg->tick);
+ // break;
- case UNT_MOONLIT:
- //Knockback out of area if affected char isn't in Moonlit effect
- if (sc && sc->data[SC_DANCING] && (sc->data[SC_DANCING]->val1&0xFFFF) == CG_MOONLIT)
- break;
- if (ss == bl) //Also needed to prevent infinite loop crash.
+ case UNT_MOONLIT:
+ //Knockback out of area if affected char isn't in Moonlit effect
+ if (sc && sc->data[SC_DANCING] && (sc->data[SC_DANCING]->val1&0xFFFF) == CG_MOONLIT)
+ break;
+ if (ss == bl) //Also needed to prevent infinite loop crash.
+ break;
+ skill_blown(ss,bl,skill_get_blewcount(sg->skill_id,sg->skill_lv),unit_getdir(bl),0);
break;
- skill_blown(ss,bl,skill_get_blewcount(sg->skill_id,sg->skill_lv),unit_getdir(bl),0);
- break;
- case UNT_WALLOFTHORN:
- if( status_get_mode(bl)&MD_BOSS )
- break; // iRO Wiki says that this skill don't affect to Boss monsters.
- if( map_flag_vs(bl->m) || bl->id == src->bl.id || battle_check_target(&src->bl,bl, BCT_ENEMY) == 1 )
- skill_attack(skill_get_type(sg->skill_id), ss, &src->bl, bl, sg->skill_id, sg->skill_lv, tick, 0);
- break;
+ case UNT_WALLOFTHORN:
+ if( status_get_mode(bl)&MD_BOSS )
+ break; // iRO Wiki says that this skill don't affect to Boss monsters.
+ if( map_flag_vs(bl->m) || bl->id == src->bl.id || battle_check_target(&src->bl,bl, BCT_ENEMY) == 1 )
+ skill_attack(skill_get_type(sg->skill_id), ss, &src->bl, bl, sg->skill_id, sg->skill_lv, tick, 0);
+ break;
- case UNT_VOLCANIC_ASH:
- if (!sce)
- sc_start(bl, SC_ASH, 100, sg->skill_lv, skill_get_time(MH_VOLCANIC_ASH, sg->skill_lv));
- break;
+ case UNT_VOLCANIC_ASH:
+ if (!sce)
+ sc_start(bl, SC_ASH, 100, sg->skill_lv, skill_get_time(MH_VOLCANIC_ASH, sg->skill_lv));
+ break;
- case UNT_GD_LEADERSHIP:
- case UNT_GD_GLORYWOUNDS:
- case UNT_GD_SOULCOLD:
- case UNT_GD_HAWKEYES:
- if ( !sce )
- sc_start4(bl,type,100,sg->skill_lv,0,0,0,1000);
- break;
+ case UNT_GD_LEADERSHIP:
+ case UNT_GD_GLORYWOUNDS:
+ case UNT_GD_SOULCOLD:
+ case UNT_GD_HAWKEYES:
+ if ( !sce )
+ sc_start4(bl,type,100,sg->skill_lv,0,0,0,1000);
+ break;
}
return skill_id;
}
diff --git a/src/map/status.c b/src/map/status.c
index 0379d05d2..7840a7a7f 100644
--- a/src/map/status.c
+++ b/src/map/status.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 team
#include "../common/cbasetypes.h"
#include "../common/timer.h"
@@ -1584,7 +1585,7 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, uin
if( sc && sc->count ) {
- if (skill_id != RK_REFRESH && sc->opt1 >0 && (sc->opt1 != OPT1_CRYSTALIZE && src->type != BL_MOB) && sc->opt1 != OPT1_BURNING && skill_id != SR_GENTLETOUCH_CURE) { //Stuned/Frozen/etc
+ if (skill_id != RK_REFRESH && sc->opt1 >0 && !(sc->opt1 == OPT1_CRYSTALIZE && src->type == BL_MOB) && sc->opt1 != OPT1_BURNING && skill_id != SR_GENTLETOUCH_CURE) { //Stuned/Frozen/etc
if (flag != 1) //Can't cast, casted stuff can't damage.
return 0;
if (!(skill_get_inf(skill_id)&INF_GROUND_SKILL))
@@ -1677,22 +1678,22 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, uin
}
}
- if (sc && sc->option)
- {
- if (sc->option&OPTION_HIDE)
- switch (skill_id) { //Usable skills while hiding.
- case TF_HIDING:
- case AS_GRIMTOOTH:
- case RG_BACKSTAP:
- case RG_RAID:
- case NJ_SHADOWJUMP:
- case NJ_KIRIKAGE:
- case KO_YAMIKUMO:
- break;
- default:
- //Non players can use all skills while hidden.
- if (!skill_id || src->type == BL_PC)
- return 0;
+ if (sc && sc->option) {
+ if (sc->option&OPTION_HIDE) {
+ switch (skill_id) { //Usable skills while hiding.
+ case TF_HIDING:
+ case AS_GRIMTOOTH:
+ case RG_BACKSTAP:
+ case RG_RAID:
+ case NJ_SHADOWJUMP:
+ case NJ_KIRIKAGE:
+ case KO_YAMIKUMO:
+ break;
+ default:
+ //Non players can use all skills while hidden.
+ if (!skill_id || src->type == BL_PC)
+ return 0;
+ }
}
if (sc->option&OPTION_CHASEWALK && skill_id != ST_CHASEWALK)
return 0;
@@ -2442,6 +2443,20 @@ int status_calc_pc_(struct map_session_data* sd, bool first)
if(!sd->inventory_data[index])
continue;
+ if(sd->inventory_data[index]->flag.no_equip) { // Items may be equipped, their effects however are nullified.
+ if(map[sd->bl.m].flag.restricted && sd->inventory_data[index]->flag.no_equip&(8*map[sd->bl.m].zone))
+ continue;
+ if(!map_flag_vs(sd->bl.m) && sd->inventory_data[index]->flag.no_equip&1)
+ continue;
+ if(map[sd->bl.m].flag.pvp && sd->inventory_data[index]->flag.no_equip&2)
+ continue;
+ if(map_flag_gvg(sd->bl.m) && sd->inventory_data[index]->flag.no_equip&4)
+ continue;
+ if(map[sd->bl.m].flag.battleground && sd->inventory_data[index]->flag.no_equip&8)
+ continue;
+ }
+
+
status->def += sd->inventory_data[index]->def;
if(first && sd->inventory_data[index]->equip_script)
diff --git a/src/map/unit.c b/src/map/unit.c
index 148a35782..e901d3138 100644
--- a/src/map/unit.c
+++ b/src/map/unit.c
@@ -325,7 +325,8 @@ int unit_walktoxy( struct block_list *bl, short x, short y, int flag)
if( ud == NULL) return 0;
#ifdef OFFICIAL_WALKPATH
- if( path_search(&wpd, bl->m, bl->x, bl->y, x, y, flag&1, CELL_CHKNOPASS) // Check if there is an obstacle between
+ path_search(&wpd, bl->m, bl->x, bl->y, x, y, flag&1, CELL_CHKNOPASS); // Count walk path cells
+ if( !path_search_long(NULL, bl->m, bl->x, bl->y, x, y, CELL_CHKNOPASS) // Check if there is an obstacle between
&& wpd.path_len > 14 ) // Official number of walkable cells is 14 if and only if there is an obstacle between. [malufett]
return 0;
#endif
@@ -350,7 +351,7 @@ int unit_walktoxy( struct block_list *bl, short x, short y, int flag)
map_random_dir(bl, &ud->to_x, &ud->to_y);
if(ud->walktimer != INVALID_TIMER) {
- if( !battle_config.skill_trap_type && sc->data[SC_ANKLE] ) // Ankle disallows you from changing your path
+ if( !battle_config.skill_trap_type && sc && sc->data[SC_ANKLE] ) // Ankle disallows you from changing your path
return 0;
// When you come to the center of the grid because the change of destination while you're walking right now
// Call a function from a timer unit_walktoxy_sub
@@ -427,7 +428,7 @@ int unit_walktobl(struct block_list *bl, struct block_list *tbl, int range, int
map_random_dir(bl, &ud->to_x, &ud->to_y);
if(ud->walktimer != INVALID_TIMER) {
- if( !battle_config.skill_trap_type && sc->data[SC_ANKLE] ) // Ankle disallows you from changing your path
+ if( !battle_config.skill_trap_type && sc && sc->data[SC_ANKLE] ) // Ankle disallows you from changing your path
return 0;
ud->state.change_walk_target = 1;
set_mobstate(bl, flag&2);
@@ -938,7 +939,7 @@ int unit_can_move(struct block_list *bl) {
if( sc->data[SC_ANKLE] && ( battle_config.skill_trap_type || !unit_is_walking(bl) ) ) // Ankle only stops you after you're done moving
return 0;
- if (sc->opt1 > 0 && sc->opt1 != OPT1_STONEWAIT && sc->opt1 != OPT1_BURNING && (sc->opt1 != OPT1_CRYSTALIZE && bl->type != BL_MOB))
+ if (sc->opt1 > 0 && sc->opt1 != OPT1_STONEWAIT && sc->opt1 != OPT1_BURNING && !(sc->opt1 == OPT1_CRYSTALIZE && bl->type == BL_MOB))
return 0;
if ((sc->option & OPTION_HIDE) && (!sd || pc_checkskill(sd, RG_TUNNELDRIVE) <= 0))