summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorshennetsind <shennetsind@54d463be-8e91-2dee-dedb-b68131a5f0ec>2011-12-05 20:51:58 +0000
committershennetsind <shennetsind@54d463be-8e91-2dee-dedb-b68131a5f0ec>2011-12-05 20:51:58 +0000
commitce9b9e74f648f3dd52e4161d3183612ecd002f80 (patch)
treeb6069d2b4687cd979685c6d803ec93a5e54d0590 /src
parentd9a43b19b761c9d1726fc971044634cd3fa917b8 (diff)
downloadhercules-ce9b9e74f648f3dd52e4161d3183612ecd002f80.tar.gz
hercules-ce9b9e74f648f3dd52e4161d3183612ecd002f80.tar.bz2
hercules-ce9b9e74f648f3dd52e4161d3183612ecd002f80.tar.xz
hercules-ce9b9e74f648f3dd52e4161d3183612ecd002f80.zip
Merging RREmu into rAthena -- quite a few stuff yet to be renamed, but we'll get it sorted.
Some of the stuff included in RREmu that is now part of rAthena: - RE Drop Rate Modifier - RE Experience Rate Modifier - RE Weapon MATK - RE Shield ASPD job-specific penalty - RE Cast Time - Renewal-specific item DEF - 3.1 classes. - All-New Mounts - Official Magical Reflection - And other perks, such as fully-functional @mapflag also merged eAthena 15006 into rAthena. For Bugs, Comments and Suggestions: http://rathena.org/board/tracker/ git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@15009 54d463be-8e91-2dee-dedb-b68131a5f0ec
Diffstat (limited to 'src')
-rw-r--r--src/common/mmo.h55
-rw-r--r--src/common/showmsg.c27
-rw-r--r--src/common/showmsg.h1
-rw-r--r--src/map/Makefile.in4
-rw-r--r--src/map/RRConfig/Core.h28
-rw-r--r--src/map/RRConfig/Data/Const.h33
-rw-r--r--src/map/RRConfig/Renewal.h53
-rw-r--r--src/map/RRConfig/Secure.h36
-rw-r--r--src/map/RRConfig/Skills/General.h23
-rw-r--r--src/map/RRConfig/Skills/Mage_Classes.h19
-rw-r--r--src/map/RRConfig/Skills/Swordsman_Classes.h19
-rw-r--r--src/map/atcommand.c330
-rw-r--r--src/map/battle.c620
-rw-r--r--src/map/battle.h7
-rw-r--r--src/map/chrif.c8
-rw-r--r--src/map/clif.c696
-rw-r--r--src/map/clif.h30
-rw-r--r--src/map/itemdb.c49
-rw-r--r--src/map/itemdb.h42
-rw-r--r--src/map/map.c156
-rw-r--r--src/map/map.h43
-rw-r--r--src/map/mob.c27
-rw-r--r--src/map/mob.h5
-rw-r--r--src/map/npc.c44
-rw-r--r--src/map/npc.h7
-rw-r--r--src/map/party.c63
-rw-r--r--src/map/party.h5
-rw-r--r--src/map/pc.c228
-rw-r--r--src/map/pc.h47
-rw-r--r--src/map/script.c182
-rw-r--r--src/map/skill.c2476
-rw-r--r--src/map/skill.h59
-rw-r--r--src/map/status.c1764
-rw-r--r--src/map/status.h281
-rw-r--r--src/map/unit.c80
-rw-r--r--src/map/unit.h4
36 files changed, 6969 insertions, 582 deletions
diff --git a/src/common/mmo.h b/src/common/mmo.h
index 239e1dddd..f8ef63390 100644
--- a/src/common/mmo.h
+++ b/src/common/mmo.h
@@ -44,8 +44,8 @@
// 20110928 - 2011-09-28aRagexeRE+ - 0x6b, 0x6d
#ifndef PACKETVER
- #define PACKETVER 20081126
- //#define PACKETVER 20100707
+ #define PACKETVER 20110609
+ //#define PACKETVER 20100730
#endif
// backward compatible PACKETVER 8 and 9
#if PACKETVER == 8
@@ -176,6 +176,7 @@ enum item_types {
IT_UNKNOWN2,//9
IT_AMMO, //10
IT_DELAYCONSUME,//11
+ IT_THROWWEAPON= 17,//17
IT_CASH = 18,
IT_MAX
};
@@ -646,6 +647,56 @@ enum {
JOB_STAR_GLADIATOR,
JOB_STAR_GLADIATOR2,
JOB_SOUL_LINKER,
+ /**
+ * 3.1 (2.1)
+ **/
+ JOB_RUNE_KNIGHT = 4054,
+ JOB_WARLOCK,
+ JOB_RANGER,
+ JOB_ARCH_BISHOP,
+ JOB_MECHANIC,
+ JOB_GUILLOTINE_CROSS,
+ /**
+ * 3.1 (2.1 Trans)
+ **/
+ JOB_RUNE_KNIGHT_T,
+ JOB_WARLOCK_T,
+ JOB_RANGER_T,
+ JOB_ARCH_BISHOP_T,
+ JOB_MECHANIC_T,
+ JOB_GUILLOTINE_CROSS_T,
+ /**
+ * 3.2 (2.2)
+ **/
+ JOB_ROYAL_GUARD,
+ JOB_SORCERER,
+ JOB_MINSTREL,
+ JOB_WANDERER,
+ JOB_SURA,
+ JOB_GENETIC,
+ JOB_SHADOW_CHASER,
+ /**
+ * 3.2 (2.2 Trans)
+ **/
+ JOB_ROYAL_GUARD_T,
+ JOB_SORCERER_T,
+ JOB_MINSTREL_T,
+ JOB_WANDERER_T,
+ JOB_SURA_T,
+ JOB_GENETIC_T,
+ JOB_SHADOW_CHASER_T,
+ /**
+ * 3.x Mounts / Vehicles
+ **/
+ JOB_RUNE_KNIGHT2,
+ JOB_RUNE_KNIGHT_T2,
+ JOB_ROYAL_GUARD2,
+ JOB_ROYAL_GUARD_T2,
+ JOB_RANGER2,
+ JOB_RANGER_T2,
+ JOB_MECHANIC2,
+ JOB_MECHANIC_T2,
+
JOB_MAX,
};
diff --git a/src/common/showmsg.c b/src/common/showmsg.c
index fc1badd26..a69c73ba2 100644
--- a/src/common/showmsg.c
+++ b/src/common/showmsg.c
@@ -4,6 +4,8 @@
#include "../common/cbasetypes.h"
#include "../common/strlib.h" // StringBuf
#include "showmsg.h"
+#include "core.h" //[Ind] - For SERVER_TYPE
+#include "version.h" //[Ind] - For SERVER_TYPE values
#include <stdio.h>
#include <string.h>
@@ -51,6 +53,8 @@ int stdout_with_ansisequence = 0;
int msg_silent = 0; //Specifies how silent the console is.
+int console_msg_log = 0;//[Ind] msg error logging
+
///////////////////////////////////////////////////////////////////////////////
/// static/dynamic buffer for the messages
@@ -684,6 +688,29 @@ int _vShowMessage(enum msg_type flag, const char *string, va_list ap)
return 1;
}
if(
+ ( flag == MSG_WARNING && console_msg_log&1 ) ||
+ ( ( flag == MSG_ERROR || flag == MSG_SQL ) && console_msg_log&2 ) ||
+ ( flag == MSG_DEBUG && console_msg_log&4 ) ) {//[Ind]
+ FILE *log = NULL;
+ if( (log = fopen(SERVER_TYPE == ATHENA_SERVER_MAP ? "./log/map-msg_log.log" : "./log/unknown.log","a+")) ) {
+ char timestring[255];
+ time_t curtime;
+ time(&curtime);
+ strftime(timestring, 254, "%m/%d/%Y %H:%M:%S", localtime(&curtime));
+ fprintf(log,"(%s) [ %s ] : ",
+ timestring,
+ flag == MSG_WARNING ? "Warning" :
+ flag == MSG_ERROR ? "Error" :
+ flag == MSG_SQL ? "SQL Error" :
+ flag == MSG_DEBUG ? "Debug" :
+ "Unknown");
+ va_copy(apcopy, ap);
+ vfprintf(log,string,apcopy);
+ va_end(apcopy);
+ fclose(log);
+ }
+ }
+ if(
(flag == MSG_INFORMATION && msg_silent&1) ||
(flag == MSG_STATUS && msg_silent&2) ||
(flag == MSG_NOTICE && msg_silent&4) ||
diff --git a/src/common/showmsg.h b/src/common/showmsg.h
index 998296b66..5f80a4312 100644
--- a/src/common/showmsg.h
+++ b/src/common/showmsg.h
@@ -67,6 +67,7 @@
extern int stdout_with_ansisequence; //If the color ansi sequences are to be used. [flaviojs]
extern int msg_silent; //Specifies how silent the console is. [Skotlex]
+extern int console_msg_log; //Specifies what error messages to log. [Ind]
extern char timestamp_format[20]; //For displaying Timestamps [Skotlex]
enum msg_type {
diff --git a/src/map/Makefile.in b/src/map/Makefile.in
index 09e92dde2..60fc49f7c 100644
--- a/src/map/Makefile.in
+++ b/src/map/Makefile.in
@@ -34,7 +34,9 @@ MAP_H = map.h chrif.h clif.h pc.h status.h npc.h \
storage.h skill.h atcommand.h battle.h battleground.h \
intif.h trade.h party.h vending.h guild.h pet.h \
log.h mail.h date.h unit.h homunculus.h mercenary.h quest.h instance.h mapreg.h \
- buyingstore.h searchstore.h duel.h
+ buyingstore.h searchstore.h duel.h \
+ RRConfig/Core.h RRConfig/Renewal.h RRConfig/Secure.h RRConfig/Data/Const.h \
+ RRConfig/Skills/General.h RRConfig/Skills/Mage_Classes.h RRConfig/Skills/Swordsman_Classes.h
HAVE_MYSQL=@HAVE_MYSQL@
ifeq ($(HAVE_MYSQL),yes)
diff --git a/src/map/RRConfig/Core.h b/src/map/RRConfig/Core.h
new file mode 100644
index 000000000..9cb161a3f
--- /dev/null
+++ b/src/map/RRConfig/Core.h
@@ -0,0 +1,28 @@
+#ifndef _RRCONFIGS_
+#define _RRCONFIGS_
+/**
+ * Ragnarok Resources Configuration File (http://ro-resources.net)
+ * The following settings are applied upon compiling the program,
+ * therefore any settings you disable will not even be added to the program
+ * making these settings the most performance-effiecient possible
+ **/
+
+/**
+ * @INFO: RREmu Settings Core
+ * - For detailed guidance on these check http://trac.ro-resources.net/wiki/CoreConfiguration
+ **/
+
+/**
+ * No settings past this point
+ **/
+#include "./Renewal.h"
+#include "./Secure.h"
+#include "./Skills/General.h"
+/**
+ * Constants come last; so they process anything that could've been modified in early includes
+ **/
+#include "./Data/Const.h"
+/**
+ * End of File
+ **/
+#endif
diff --git a/src/map/RRConfig/Data/Const.h b/src/map/RRConfig/Data/Const.h
new file mode 100644
index 000000000..6da8cdf13
--- /dev/null
+++ b/src/map/RRConfig/Data/Const.h
@@ -0,0 +1,33 @@
+#ifndef _RRCONFIGS_CONST_
+#define _RRCONFIGS_CONST_
+/**
+ * Ragnarok Resources Configuration File (http://ro-resources.net)
+ * The following settings are applied upon compiling the program,
+ * therefore any settings you disable will not even be added to the program
+ * making these settings the most performance-effiecient possible
+ **/
+
+/**
+ * @INFO: This file holds constants that aims at making code smoother and more efficient
+ */
+
+/**
+ * "Constants"
+ **/
+#define CONST_CASTRATE_SCALE ( RECASTING ? RECASTING_VMIN : battle_config.castrate_dex_scale )
+#define CONST_CASTRATE_CALC ( RECASTING ? ((status_get_dex(bl)*2)+status_get_int(bl)) : status_get_dex(bl) )
+
+/**
+ * "Sane Checks" to save you from compiling with cool bugs
+ **/
+#if SECURE_NPCTIMEOUT_INTERVAL <= 0
+ #error SECURE_NPCTIMEOUT_INTERVAL should be at least 1 (1s)
+#endif
+#if SECURE_NPCTIMEOUT < 0
+ #error SECURE_NPCTIMEOUT cannot be lower than 0
+#endif
+
+/**
+ * End of File
+ **/
+#endif \ No newline at end of file
diff --git a/src/map/RRConfig/Renewal.h b/src/map/RRConfig/Renewal.h
new file mode 100644
index 000000000..db5a99008
--- /dev/null
+++ b/src/map/RRConfig/Renewal.h
@@ -0,0 +1,53 @@
+#ifndef _RRCONFIGS_RE_
+#define _RRCONFIGS_RE_
+/**
+ * Ragnarok Resources Configuration File (http://ro-resources.net)
+ * The following settings are applied upon compiling the program,
+ * therefore any settings you disable will not even be added to the program
+ * making these settings the most performance-effiecient possible
+ **/
+
+/**
+ * @INFO: This file holds general-purpose renewal settings, for class-specific ones check /src/map/RRConfig/Skills folder
+ **/
+
+/**
+ * Game Server Mode
+ * @values: 1 or 0
+ * 1 : renewal support, such as renewal-exclusive formulas
+ * -> Note some features may be enabled/disabled at this file despite this setting being ON
+ * 0 : renewal support disabled, use original formulas
+ **/
+#define RRMODE 1
+
+/**
+ * Renewal Cast Time
+ * @values: 1 (enabled) or 0 (disabled)
+ * 1 : Cast Time is decreased by DEX*2+INT, 20% of the cast time is not reduced by stats,
+ * - for example, on a skill whose cast time is 10s, only 8s may be reduced. other 2s are
+ * - part of a "fixed cast time" that is only reduced by special items and skills (such as
+ * - Arch Bishop's Sacrament skill).
+ * 0 : the old cast time method, influenced by dex, items and skills.
+ **/
+#define RECASTING 1
+
+/**
+ * Renewal Cast Time : Variable-Free
+ * - Value required for no variable cast time with stats.
+ * - Formula: (casterDex x 2) + (casterInt)
+ * Default: 530
+ **/
+#define RECASTING_VMIN 530
+
+/**
+ * Renewal Enchant Deadly Poison Change
+ * - In RE EDP no longer increases final damage by 400%.
+ * - it increases your weapon atk and your stat atk
+ * - it doesn't affect grimtooth
+ **/
+#define RE_EDP 1
+
+/**
+ * End of File
+ **/
+#endif \ No newline at end of file
diff --git a/src/map/RRConfig/Secure.h b/src/map/RRConfig/Secure.h
new file mode 100644
index 000000000..1288b259f
--- /dev/null
+++ b/src/map/RRConfig/Secure.h
@@ -0,0 +1,36 @@
+#ifndef _RRCONFIGS_SECURE_
+#define _RRCONFIGS_SECURE_
+/**
+ * Ragnarok Resources Configuration File (http://ro-resources.net)
+ * The following settings are applied upon compiling the program,
+ * therefore any settings you disable will not even be added to the program
+ * making these settings the most performance-effiecient possible
+ **/
+
+/**
+ * @INFO: This file holds optional security settings
+ **/
+
+/**
+ * Optional NPC Dialog Timer
+ * When enabled all npcs dialog will 'timeout' if user is on idle for longer than the amount of seconds allowed
+ * - On 'timeout' the npc dialog window changes it's next/menu to a 'close' button
+ * @values
+ * - ? : Desired idle time in seconds (e.g. 10)
+ * - 0 : Disabled
+ **/
+#define SECURE_NPCTIMEOUT 0
+
+/**
+ * (Secure) Optional NPC Dialog Timer
+ * @requirement : SECURE_NPCTIMEOUT must be enabled
+ * Minimum Interval Between timeout checks in seconds
+ * Default: 1s
+ **/
+#define SECURE_NPCTIMEOUT_INTERVAL 1
+
+
+/**
+ * End of File
+ **/
+#endif \ No newline at end of file
diff --git a/src/map/RRConfig/Skills/General.h b/src/map/RRConfig/Skills/General.h
new file mode 100644
index 000000000..5944d6844
--- /dev/null
+++ b/src/map/RRConfig/Skills/General.h
@@ -0,0 +1,23 @@
+#ifndef _RRCONFIGS_SKILLS_GENERAL_
+#define _RRCONFIGS_SKILLS_GENERAL_
+/**
+ * Ragnarok Resources Configuration File (http://ro-resources.net)
+ * The following settings are applied upon compiling the program,
+ * therefore any settings you disable will not even be added to the program
+ * making these settings the most performance-effiecient possible
+ **/
+
+/**
+ * Default Magical Reflection Behavior
+ * - When reflecting, reflected damage depends on gears caster is wearing, not target
+ * - When disabled damage depends on gears target is wearing, not caster.
+ * @values 1 (enabled) or 0 (disabled)
+ **/
+#define RR_MAGIC_REFLECTION 1
+
+/**
+ * No settings past this point
+ **/
+#include "Mage_Classes.h"
+#include "Swordsman_Classes.h"
+#endif
diff --git a/src/map/RRConfig/Skills/Mage_Classes.h b/src/map/RRConfig/Skills/Mage_Classes.h
new file mode 100644
index 000000000..cf0777787
--- /dev/null
+++ b/src/map/RRConfig/Skills/Mage_Classes.h
@@ -0,0 +1,19 @@
+#ifndef _RRCONFIGS_SKILLS_MAGE_
+#define _RRCONFIGS_SKILLS_MAGE_
+/**
+ * Ragnarok Resources Configuration File (http://ro-resources.net)
+ * The following settings are applied upon compiling the program,
+ * therefore any settings you disable will not even be added to the program
+ * making these settings the most performance-effiecient possible
+ **/
+
+/**
+ * (Wizard/HW/Warlock) enable Fire Ivy skill? (1 OR 0)
+ * Default: 0 (disabled)
+ **/
+#define FIREIVY_ON 0
+
+/**
+ * No settings past this point
+ **/
+#endif
diff --git a/src/map/RRConfig/Skills/Swordsman_Classes.h b/src/map/RRConfig/Skills/Swordsman_Classes.h
new file mode 100644
index 000000000..4dddeec54
--- /dev/null
+++ b/src/map/RRConfig/Skills/Swordsman_Classes.h
@@ -0,0 +1,19 @@
+#ifndef _RRCONFIGS_SKILLS_SWORDS_
+#define _RRCONFIGS_SKILLS_SWORDS_
+/**
+ * Ragnarok Resources Configuration File (http://ro-resources.net)
+ * The following settings are applied upon compiling the program,
+ * therefore any settings you disable will not even be added to the program
+ * making these settings the most performance-effiecient possible
+ **/
+
+/**
+ * (Rune Knight) the maximum rune items a character may have of the same type
+ * Default: 20
+ **/
+#define MAX_RUNE 20
+
+/**
+ * No settings past this point
+ **/
+#endif
diff --git a/src/map/atcommand.c b/src/map/atcommand.c
index e98481f22..e87074883 100644
--- a/src/map/atcommand.c
+++ b/src/map/atcommand.c
@@ -1255,7 +1255,7 @@ ACMD_FUNC(jobchange)
if (!message || !*message || sscanf(message, "%d %d", &job, &upper) < 1)
{
int i, found = 0;
- const struct { char name[16]; int id; } jobs[] = {
+ const struct { char name[24]; int id; } jobs[] = {
{ "novice", 0 },
{ "swordsman", 1 },
{ "mage", 2 },
@@ -1330,6 +1330,32 @@ ACMD_FUNC(jobchange)
{ "taekwon girl", 4046 },
{ "star gladiator", 4047 },
{ "soul linker", 4049 },
+ { "rune knight", 4054 },
+ { "warlock", 4055 },
+ { "ranger", 4056 },
+ { "arch bishop", 4057 },
+ { "mechanic", 4058 },
+ { "guillotine", 4059 },
+ { "rune knight (Trans)", 4060 },
+ { "warlock (Trans)", 4061 },
+ { "ranger (Trans)", 4062 },
+ { "arch bishop (Trans)", 4063 },
+ { "mechanic (Trans)", 4064 },
+ { "guillotine (Trans)", 4065 },
+ { "royal guard", 4066 },
+ { "sorcerer", 4067 },
+ { "minstrel", 4068 },
+ { "wanderer", 4069 },
+ { "sura", 4070 },
+ { "genetic", 4071 },
+ { "shadow chaser", 4072 },
+ { "royal guard (Trans)", 4073 },
+ { "sorcerer (Trans)", 4074 },
+ { "minstrel (Trans)", 4075 },
+ { "wanderer (Trans)", 4076 },
+ { "sura (Trans)", 4077 },
+ { "genetic (Trans)", 4078 },
+ { "shadow chaser (Trans)", 4079 },
};
for (i=0; i < ARRAYLENGTH(jobs); i++) {
@@ -1343,28 +1369,56 @@ ACMD_FUNC(jobchange)
if (!found) {
clif_displaymessage(fd, "Please, enter job ID (usage: @job/@jobchange <job name/ID>).");
- clif_displaymessage(fd, " 0 Novice 7 Knight 14 Crusader 21 N/A");
- clif_displaymessage(fd, " 1 Swordman 8 Priest 15 Monk 22 N/A");
- clif_displaymessage(fd, " 2 Mage 9 Wizard 16 Sage 23 Super Novice");
- clif_displaymessage(fd, " 3 Archer 10 Blacksmith 17 Rogue 24 Gunslinger");
- clif_displaymessage(fd, " 4 Acolyte 11 Hunter 18 Alchemist 25 Ninja");
- clif_displaymessage(fd, " 5 Merchant 12 Assassin 19 Bard 26 N/A");
- clif_displaymessage(fd, " 6 Thief 13 N/A 20 Dancer 27 N/A");
- clif_displaymessage(fd, "4001 Novice High 4008 Lord Knight 4015 Paladin 4022 N/A");
- clif_displaymessage(fd, "4002 Swordman High 4009 High Priest 4016 Champion");
- clif_displaymessage(fd, "4003 Mage High 4010 High Wizard 4017 Professor");
- clif_displaymessage(fd, "4004 Archer High 4011 Whitesmith 4018 Stalker");
- clif_displaymessage(fd, "4005 Acolyte High 4012 Sniper 4019 Creator");
- clif_displaymessage(fd, "4006 Merchant High 4013 Assassin Cross 4020 Clown");
- clif_displaymessage(fd, "4007 Thief High 4014 N/A 4021 Gypsy");
- clif_displaymessage(fd, "4023 Baby Novice 4030 Baby Knight 4037 Baby Crusader 4044 N/A");
- clif_displaymessage(fd, "4024 Baby Swordsman 4031 Baby Priest 4038 Baby Monk 4045 Super Baby");
- clif_displaymessage(fd, "4025 Baby Mage 4032 Baby Wizard 4039 Baby Sage 4046 Taekwon Kid");
- clif_displaymessage(fd, "4026 Baby Archer 4033 Baby Blacksmith 4040 Baby Rogue 4047 Taekwon Master");
- clif_displaymessage(fd, "4027 Baby Acolyte 4034 Baby Hunter 4041 Baby Alchemist 4048 N/A");
- clif_displaymessage(fd, "4028 Baby Merchant 4035 Baby Assassin 4042 Baby Bard 4049 Soul Linker");
- clif_displaymessage(fd, "4029 Baby Thief 4036 N/A 4043 Baby Dancer");
- clif_displaymessage(fd, "[upper]: -1 (default) to automatically determine the 'level', 0 to force normal job, 1 to force high job.");
+ clif_displaymessage(fd, "----- Novice / 1st Class -----");
+ clif_displaymessage(fd, " 0 Novice 1 Swordman 2 Mage 3 Archer");
+ clif_displaymessage(fd, " 4 Acolyte 5 Merchant 6 Thief");
+ clif_displaymessage(fd, "----- 2nd Class -----");
+ clif_displaymessage(fd, " 7 Knight 8 Priest 9 Wizard 10 Blacksmith");
+ clif_displaymessage(fd, " 11 Hunter 12 Assassin 14 Crusader 15 Monk");
+ clif_displaymessage(fd, " 16 Sage 17 Rogue 18 Alchemist 19 Bard");
+ clif_displaymessage(fd, " 20 Dancer");
+ clif_displaymessage(fd, "----- High Novice / High 1st Class -----");
+ clif_displaymessage(fd, "4001 Novice High 4002 Swordman High 4003 Mage High 4004 Archer High");
+ clif_displaymessage(fd, "4005 Acolyte High 4006 Merchant High 4007 Thief High");
+ clif_displaymessage(fd, "----- Transcendent 2nd Class -----");
+ clif_displaymessage(fd, "4008 Lord Knight 4009 High Priest 4010 High Wizard 4011 Whitesmith");
+ clif_displaymessage(fd, "4012 Sniper 4013 Assassin Cross 4015 Paladin 4016 Champion");
+ clif_displaymessage(fd, "4017 Professor 4018 Stalker 4019 Creator 4020 Clown");
+ clif_displaymessage(fd, "4021 Gypsy");
+ clif_displaymessage(fd, "----- 3rd Class (Regular to 3rd) -----");
+ clif_displaymessage(fd, "4054 Rune Knight 4055 Warlock 4056 Ranger 4057 Arch Bishop");
+ clif_displaymessage(fd, "4058 Mechanic 4059 Guillotine Cross 4066 Royal Guard 4067 Sorcerer");
+ clif_displaymessage(fd, "4068 Minstrel 4069 Wanderer 4070 Sura 4071 Genetic");
+ clif_displaymessage(fd, "4072 Shadow Chaser");
+ clif_displaymessage(fd, "----- 3rd Class (Transcendent to 3rd) -----");
+ clif_displaymessage(fd, "4060 Rune Knight 4061 Warlock 4062 Ranger 4063 Arch Bishop");
+ clif_displaymessage(fd, "4064 Mechanic 4065 Guillotine Cross 4073 Royal Guard 4074 Sorcerer");
+ clif_displaymessage(fd, "4075 Minstrel 4076 Wanderer 4077 Sura 4078 Genetic");
+ clif_displaymessage(fd, "4079 Shadow Chaser");
+ clif_displaymessage(fd, "----- Expanded Class -----");
+ clif_displaymessage(fd, " 23 Super Novice 24 Gunslinger 25 Ninja 26 Xmas");
+ clif_displaymessage(fd, " 27 Summer 4046 Taekwon 4047 Star Gladiator 4049 Soul Linker");
+ //clif_displaymessage(fd, "4050 Gangsi 4051 Death Knight 4052 Dark Collector");
+ clif_displaymessage(fd, "---- 1st And 2nd Baby Class ----");
+ clif_displaymessage(fd, "4023 Baby Novice 4024 Baby Swordsman 4025 Baby Mage 4026 Baby Archer");
+ clif_displaymessage(fd, "4027 Baby Acolyte 4028 Baby Merchant 4029 Baby Thief 4030 Baby Knight");
+ clif_displaymessage(fd, "4031 Baby Priest 4032 Baby Wizard 4033 Baby Blacksmith 4034 Baby Hunter");
+ clif_displaymessage(fd, "4035 Baby Assassin 4037 Baby Crusader 4038 Baby Monk 4039 Baby Sage");
+ clif_displaymessage(fd, "4040 Baby Rogue 4041 Baby Alchemist 4042 Baby Bard 4043 Baby Dancer");
+ clif_displaymessage(fd, "4045 Super Baby");
+ //clif_displaymessage(fd, "---- 3rd Baby Class ----");
+ //clif_displaymessage(fd, "4096 Baby Rune Knight 4097 Baby Warlock 4098 Baby Ranger");
+ //clif_displaymessage(fd, "4099 Baby Arch Bishop 4100 Baby Mechanic 4101 Baby Guillotine Cross");
+ //clif_displaymessage(fd, "4102 Baby Royal Guard 4103 Baby Sorcerer 4104 Baby Minstrel");
+ //clif_displaymessage(fd, "4105 Baby Wanderer 4106 Baby Sura 4107 Baby Genetic");
+ //clif_displaymessage(fd, "4108 Baby Shadow Chaser");
+ //clif_displaymessage(fd, "---- Mounts, Modes, And Others ----");
+ //clif_displaymessage(fd, " 13 Knight (Peco) 21 Crusader (Peco) 22 Wedding 26 Christmas");
+ //clif_displaymessage(fd, " 27 Summer 4014 Lord Knight (Peco) 4022 Paladin (Peco) 4036 Baby Knight (Peco)");
+ //clif_displaymessage(fd, "4044 Baby Crusader (Peco) 4048 Star Gladiator (Union) 4080 Rune Knight (Dragon)");
+ //clif_displaymessage(fd, "4081 Rune Knight Trans (Dragon) 4082 Royal Guard (Gryphon)");
+ //clif_displaymessage(fd, "4083 Royal Guard Trans (Gryphon) 4084 Ranger (Warg) 4085 Ranger Trans (Warg)");
+ //clif_displaymessage(fd, "4086 Mechanic (Mado) 4087 Mechanic Trans (Mado)");
return -1;
}
}
@@ -1384,28 +1438,56 @@ ACMD_FUNC(jobchange)
}
} else {
clif_displaymessage(fd, "Please, enter job ID (usage: @job/@jobchange <job name/ID>).");
- clif_displaymessage(fd, " 0 Novice 7 Knight 14 Crusader 21 N/A");
- clif_displaymessage(fd, " 1 Swordman 8 Priest 15 Monk 22 N/A");
- clif_displaymessage(fd, " 2 Mage 9 Wizard 16 Sage 23 Super Novice");
- clif_displaymessage(fd, " 3 Archer 10 Blacksmith 17 Rogue 24 Gunslinger");
- clif_displaymessage(fd, " 4 Acolyte 11 Hunter 18 Alchemist 25 Ninja");
- clif_displaymessage(fd, " 5 Merchant 12 Assassin 19 Bard 26 N/A");
- clif_displaymessage(fd, " 6 Thief 13 N/A 20 Dancer 27 N/A");
- clif_displaymessage(fd, "4001 Novice High 4008 Lord Knight 4015 Paladin 4022 N/A");
- clif_displaymessage(fd, "4002 Swordman High 4009 High Priest 4016 Champion");
- clif_displaymessage(fd, "4003 Mage High 4010 High Wizard 4017 Professor");
- clif_displaymessage(fd, "4004 Archer High 4011 Whitesmith 4018 Stalker");
- clif_displaymessage(fd, "4005 Acolyte High 4012 Sniper 4019 Creator");
- clif_displaymessage(fd, "4006 Merchant High 4013 Assassin Cross 4020 Clown");
- clif_displaymessage(fd, "4007 Thief High 4014 N/A 4021 Gypsy");
- clif_displaymessage(fd, "4023 Baby Novice 4030 Baby Knight 4037 Baby Crusader 4044 N/A");
- clif_displaymessage(fd, "4024 Baby Swordsman 4031 Baby Priest 4038 Baby Monk 4045 Super Baby");
- clif_displaymessage(fd, "4025 Baby Mage 4032 Baby Wizard 4039 Baby Sage 4046 Taekwon Kid");
- clif_displaymessage(fd, "4026 Baby Archer 4033 Baby Blacksmith 4040 Baby Rogue 4047 Taekwon Master");
- clif_displaymessage(fd, "4027 Baby Acolyte 4034 Baby Hunter 4041 Baby Alchemist 4048 N/A");
- clif_displaymessage(fd, "4028 Baby Merchant 4035 Baby Assassin 4042 Baby Bard 4049 Soul Linker");
- clif_displaymessage(fd, "4029 Baby Thief 4036 N/A 4043 Baby Dancer");
- clif_displaymessage(fd, "[upper]: -1 (default) to automatically determine the 'level', 0 to force normal job, 1 to force high job.");
+ clif_displaymessage(fd, "----- Novice / 1st Class -----");
+ clif_displaymessage(fd, " 0 Novice 1 Swordman 2 Mage 3 Archer");
+ clif_displaymessage(fd, " 4 Acolyte 5 Merchant 6 Thief");
+ clif_displaymessage(fd, "----- 2nd Class -----");
+ clif_displaymessage(fd, " 7 Knight 8 Priest 9 Wizard 10 Blacksmith");
+ clif_displaymessage(fd, " 11 Hunter 12 Assassin 14 Crusader 15 Monk");
+ clif_displaymessage(fd, " 16 Sage 17 Rogue 18 Alchemist 19 Bard");
+ clif_displaymessage(fd, " 20 Dancer");
+ clif_displaymessage(fd, "----- High Novice / High 1st Class -----");
+ clif_displaymessage(fd, "4001 Novice High 4002 Swordman High 4003 Mage High 4004 Archer High");
+ clif_displaymessage(fd, "4005 Acolyte High 4006 Merchant High 4007 Thief High");
+ clif_displaymessage(fd, "----- Transcendent 2nd Class -----");
+ clif_displaymessage(fd, "4008 Lord Knight 4009 High Priest 4010 High Wizard 4011 Whitesmith");
+ clif_displaymessage(fd, "4012 Sniper 4013 Assassin Cross 4015 Paladin 4016 Champion");
+ clif_displaymessage(fd, "4017 Professor 4018 Stalker 4019 Creator 4020 Clown");
+ clif_displaymessage(fd, "4021 Gypsy");
+ clif_displaymessage(fd, "----- 3rd Class (Regular to 3rd) -----");
+ clif_displaymessage(fd, "4054 Rune Knight 4055 Warlock 4056 Ranger 4057 Arch Bishop");
+ clif_displaymessage(fd, "4058 Mechanic 4059 Guillotine Cross 4066 Royal Guard 4067 Sorcerer");
+ clif_displaymessage(fd, "4068 Minstrel 4069 Wanderer 4070 Sura 4071 Genetic");
+ clif_displaymessage(fd, "4072 Shadow Chaser");
+ clif_displaymessage(fd, "----- 3rd Class (Transcendent to 3rd) -----");
+ clif_displaymessage(fd, "4060 Rune Knight 4061 Warlock 4062 Ranger 4063 Arch Bishop");
+ clif_displaymessage(fd, "4064 Mechanic 4065 Guillotine Cross 4073 Royal Guard 4074 Sorcerer");
+ clif_displaymessage(fd, "4075 Minstrel 4076 Wanderer 4077 Sura 4078 Genetic");
+ clif_displaymessage(fd, "4079 Shadow Chaser");
+ clif_displaymessage(fd, "----- Expanded Class -----");
+ clif_displaymessage(fd, " 23 Super Novice 24 Gunslinger 25 Ninja 26 Xmas");
+ clif_displaymessage(fd, " 27 Summer 4046 Taekwon 4047 Star Gladiator 4049 Soul Linker");
+ //clif_displaymessage(fd, "4050 Gangsi 4051 Death Knight 4052 Dark Collector");
+ clif_displaymessage(fd, "---- 1st And 2nd Baby Class ----");
+ clif_displaymessage(fd, "4023 Baby Novice 4024 Baby Swordsman 4025 Baby Mage 4026 Baby Archer");
+ clif_displaymessage(fd, "4027 Baby Acolyte 4028 Baby Merchant 4029 Baby Thief 4030 Baby Knight");
+ clif_displaymessage(fd, "4031 Baby Priest 4032 Baby Wizard 4033 Baby Blacksmith 4034 Baby Hunter");
+ clif_displaymessage(fd, "4035 Baby Assassin 4037 Baby Crusader 4038 Baby Monk 4039 Baby Sage");
+ clif_displaymessage(fd, "4040 Baby Rogue 4041 Baby Alchemist 4042 Baby Bard 4043 Baby Dancer");
+ clif_displaymessage(fd, "4045 Super Baby");
+ //clif_displaymessage(fd, "---- 3rd Baby Class ----");
+ //clif_displaymessage(fd, "4096 Baby Rune Knight 4097 Baby Warlock 4098 Baby Ranger");
+ //clif_displaymessage(fd, "4099 Baby Arch Bishop 4100 Baby Mechanic 4101 Baby Guillotine Cross");
+ //clif_displaymessage(fd, "4102 Baby Royal Guard 4103 Baby Sorcerer 4104 Baby Minstrel");
+ //clif_displaymessage(fd, "4105 Baby Wanderer 4106 Baby Sura 4107 Baby Genetic");
+ //clif_displaymessage(fd, "4108 Baby Shadow Chaser");
+ //clif_displaymessage(fd, "---- Mounts, Modes, And Others ----");
+ //clif_displaymessage(fd, " 13 Knight (Peco) 21 Crusader (Peco) 22 Wedding 26 Christmas");
+ //clif_displaymessage(fd, " 27 Summer 4014 Lord Knight (Peco) 4022 Paladin (Peco) 4036 Baby Knight (Peco)");
+ //clif_displaymessage(fd, "4044 Baby Crusader (Peco) 4048 Star Gladiator (Union) 4080 Rune Knight (Dragon)");
+ //clif_displaymessage(fd, "4081 Rune Knight Trans (Dragon) 4082 Royal Guard (Gryphon)");
+ //clif_displaymessage(fd, "4083 Royal Guard Trans (Gryphon) 4084 Ranger (Warg) 4085 Ranger Trans (Warg)");
+ //clif_displaymessage(fd, "4086 Mechanic (Mado) 4087 Mechanic Trans (Mado)");
return -1;
}
@@ -2842,7 +2924,7 @@ ACMD_FUNC(displaystatus)
if (i < 2) flag = 1;
if (i < 3) tick = 0;
- clif_status_change(&sd->bl, type, flag, tick);
+ clif_status_change(&sd->bl, type, flag, tick, 0, 0, 0);
return 0;
}
@@ -4395,8 +4477,11 @@ ACMD_FUNC(mapinfo)
strcat(atcmd_output, "Fireworks | ");
if (map[m_id].flag.leaves)
strcat(atcmd_output, "Leaves | ");
- if (map[m_id].flag.rain)
- strcat(atcmd_output, "Rain | ");
+ /**
+ * No longer available, keeping here just in case it's back someday. [Ind]
+ **/
+ //if (map[m_id].flag.rain)
+ // strcat(atcmd_output, "Rain | ");
if (map[m_id].flag.nightenabled)
strcat(atcmd_output, "Displays Night | ");
clif_displaymessage(fd, atcmd_output);
@@ -4510,7 +4595,26 @@ ACMD_FUNC(mapinfo)
ACMD_FUNC(mount_peco)
{
nullpo_retr(-1, sd);
-
+ if( pc_checkskill(sd,RK_DRAGONTRAINING) > 0 ) {
+ if( !(sd->sc.option&OPTION_DRAGON1) ) {
+ clif_displaymessage(sd->fd,"You have mounted your Dragon");
+ pc_setoption(sd, sd->sc.option|OPTION_DRAGON1);
+ } else {
+ clif_displaymessage(sd->fd,"You have released your Dragon");
+ pc_setoption(sd, sd->sc.option&~OPTION_DRAGON1);
+ }
+ return 0;
+ }
+ if( (sd->class_&MAPID_THIRDMASK) == MAPID_MECHANIC ) {
+ if( !(sd->sc.option&OPTION_MADOGEAR) ) {
+ clif_displaymessage(sd->fd,"You have mounted your Mado Gear");
+ pc_setoption(sd, sd->sc.option|OPTION_MADOGEAR);
+ } else {
+ clif_displaymessage(sd->fd,"You have released your Mado Gear");
+ pc_setoption(sd, sd->sc.option&~OPTION_MADOGEAR);
+ }
+ return 0;
+ }
if (!pc_isriding(sd)) { // if actually no peco
if (!pc_checkskill(sd, KN_RIDING))
{
@@ -6117,24 +6221,26 @@ ACMD_FUNC(autolootitem)
return 0;
}
-
+/**
+ * No longer available, keeping here just in case it's back someday. [Ind]
+ **/
/*==========================================
* It is made to rain.
*------------------------------------------*/
-ACMD_FUNC(rain)
-{
- nullpo_retr(-1, sd);
- if (map[sd->bl.m].flag.rain) {
- map[sd->bl.m].flag.rain=0;
- clif_weather(sd->bl.m);
- clif_displaymessage(fd, "The rain has stopped.");
- } else {
- map[sd->bl.m].flag.rain=1;
- clif_weather(sd->bl.m);
- clif_displaymessage(fd, "It is made to rain.");
- }
- return 0;
-}
+//ACMD_FUNC(rain)
+//{
+// nullpo_retr(-1, sd);
+// if (map[sd->bl.m].flag.rain) {
+// map[sd->bl.m].flag.rain=0;
+// clif_weather(sd->bl.m);
+// clif_displaymessage(fd, "The rain has stopped.");
+// } else {
+// map[sd->bl.m].flag.rain=1;
+// clif_weather(sd->bl.m);
+// clif_displaymessage(fd, "It is made to rain.");
+// }
+// return 0;
+//}
/*==========================================
* It is made to snow.
@@ -6273,7 +6379,10 @@ ACMD_FUNC(fireworks)
ACMD_FUNC(clearweather)
{
nullpo_retr(-1, sd);
- map[sd->bl.m].flag.rain=0;
+ /**
+ * No longer available, keeping here just in case it's back someday. [Ind]
+ **/
+ //map[sd->bl.m].flag.rain=0;
map[sd->bl.m].flag.snow=0;
map[sd->bl.m].flag.sakura=0;
map[sd->bl.m].flag.clouds=0;
@@ -7763,13 +7872,72 @@ ACMD_FUNC(fakename)
}
/*==========================================
- * @mapflag [flag name] [1|0|on|off] [map name] by Lupus
- * => Shows information about the map flags [map name]
- * Also set flags
+ * Ragnarok Resources
*------------------------------------------*/
-ACMD_FUNC(mapflag)
-{
-// WIP
+ACMD_FUNC(mapflag) {
+#define checkflag( cmd ) if ( map[ sd->bl.m ].flag.cmd ) clif_displaymessage(sd->fd,#cmd)
+#define setflag( cmd ) \
+ if ( strcmp( flag_name , #cmd ) == 0 && ( flag == 0 || flag == 1 ) ){\
+ map[ sd->bl.m ].flag.cmd = flag;\
+ sprintf(atcmd_output,"[ @mapflag ] %s flag has been set to %s",#cmd,flag?"On":"Off");\
+ clif_displaymessage(sd->fd,atcmd_output);\
+ return 0;\
+ }
+ unsigned char flag_name[100];
+ int flag=9,i;
+ nullpo_retr(-1, sd);
+ memset(flag_name, '\0', sizeof(flag_name));
+
+ if (!message || !*message || (sscanf(message, "%99s %d", flag_name, &flag) < 1)) {
+ clif_displaymessage(sd->fd,"Enabled Mapflags in this map:");
+ clif_displaymessage(sd->fd,"----------------------------------");
+ checkflag(autotrade); checkflag(allowks); checkflag(nomemo); checkflag(noteleport);
+ checkflag(noreturn); checkflag(monster_noteleport); checkflag(nosave); checkflag(nobranch);
+ checkflag(noexppenalty); checkflag(pvp); checkflag(pvp_noparty); checkflag(pvp_noguild);
+ checkflag(pvp_nightmaredrop); checkflag(pvp_nocalcrank); checkflag(gvg_castle); checkflag(gvg);
+ checkflag(gvg_dungeon); checkflag(gvg_noparty); checkflag(battleground);checkflag(nozenypenalty);
+ checkflag(notrade); checkflag(noskill); checkflag(nowarp); checkflag(nowarpto);
+ checkflag(noicewall); checkflag(snow); checkflag(clouds); checkflag(clouds2);
+ checkflag(fog); checkflag(fireworks); checkflag(sakura); checkflag(leaves);
+ checkflag(nogo); checkflag(nobaseexp);
+ checkflag(nojobexp); checkflag(nomobloot); checkflag(nomvploot); checkflag(nightenabled);
+ checkflag(restricted); checkflag(nodrop); checkflag(novending); checkflag(loadevent);
+ checkflag(nochat); checkflag(partylock); checkflag(guildlock); checkflag(src4instance);
+ clif_displaymessage(sd->fd," ");
+ clif_displaymessage(sd->fd,"Usage: \"@mapflag monster_teleport 1\" (0=Off 1=On)");
+ clif_displaymessage(sd->fd,"Use: \"@mapflag available\" to list the available mapflags");
+ return 1;
+ }
+ for (i = 0; flag_name[i]; i++) flag_name[i] = tolower(flag_name[i]); //lowercase
+
+ setflag(autotrade); setflag(allowks); setflag(nomemo); setflag(noteleport);
+ setflag(noreturn); setflag(monster_noteleport);setflag(nosave); setflag(nobranch);
+ setflag(noexppenalty); setflag(pvp); setflag(pvp_noparty); setflag(pvp_noguild);
+ setflag(pvp_nightmaredrop); setflag(pvp_nocalcrank); setflag(gvg_castle); setflag(gvg);
+ setflag(gvg_dungeon); setflag(gvg_noparty); setflag(battleground); setflag(nozenypenalty);
+ setflag(notrade); setflag(noskill); setflag(nowarp); setflag(nowarpto);
+ setflag(noicewall); setflag(snow); setflag(clouds); setflag(clouds2);
+ setflag(fog); setflag(fireworks); setflag(sakura); setflag(leaves);
+ setflag(nogo); setflag(nobaseexp);
+ setflag(nojobexp); setflag(nomobloot); setflag(nomvploot); setflag(nightenabled);
+ setflag(restricted); setflag(nodrop); setflag(novending); setflag(loadevent);
+ setflag(nochat); setflag(partylock); setflag(guildlock); setflag(src4instance);
+
+ clif_displaymessage(sd->fd,"Invalid flag name or flag");
+ clif_displaymessage(sd->fd,"Usage: \"@mapflag monster_teleport 1\" (0=Off | 1=On)");
+ clif_displaymessage(sd->fd,"Available Flags:");
+ clif_displaymessage(sd->fd,"----------------------------------");
+ clif_displaymessage(sd->fd,"town, autotrade, allowks, nomemo, noteleport, noreturn, monster_noteleport, nosave,");
+ clif_displaymessage(sd->fd,"nobranch, noexppenalty, pvp, pvp_noparty, pvp_noguild, pvp_nightmaredrop,");
+ clif_displaymessage(sd->fd,"pvp_nocalcrank, gvg_castle, gvg, gvg_dungeon, gvg_noparty, battleground,");
+ clif_displaymessage(sd->fd,"nozenypenalty, notrade, noskill, nowarp, nowarpto, noicewall, snow, clouds, clouds2,");
+ clif_displaymessage(sd->fd,"fog, fireworks, sakura, leaves, nogo, nobaseexp, nojobexp, nomobloot,");
+ clif_displaymessage(sd->fd,"nomvploot, nightenabled, restricted, nodrop, novending, loadevent, nochat, partylock,");
+ clif_displaymessage(sd->fd,"guildlock, src4instance");
+
+#undef checkflag
+#undef setflag
+
return 0;
}
@@ -8581,8 +8749,17 @@ ACMD_FUNC(font)
return 0;
}
-
-
+ACMD_FUNC(new_mount) {
+ clif_displaymessage(sd->fd,"NOTICE: If you crash with mount your LUA is outdated");
+ if( !(sd->sc.option&OPTION_MOUNTING) ) {
+ clif_displaymessage(sd->fd,"You have mounted.");
+ pc_setoption(sd, sd->sc.option|OPTION_MOUNTING);
+ } else {
+ clif_displaymessage(sd->fd,"You have released your mount");
+ pc_setoption(sd, sd->sc.option&~OPTION_MOUNTING);
+ }
+ return 0;
+}
/*==========================================
* atcommand_info[] structure definition
*------------------------------------------*/
@@ -8885,6 +9062,10 @@ AtCommandInfo atcommand_info[] = {
{ "delitem", 60,60, atcommand_delitem },
{ "charcommands", 1,1, atcommand_commands },
{ "font", 1,1, atcommand_font },
+ /**
+ * For Testing Purposes, not going to be here after we're done.
+ **/
+ { "newmount", 0,99, atcommand_new_mount },
};
@@ -9025,9 +9206,12 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message
info = get_atcommandinfo_byname(command);
if( info == NULL || info->func == NULL || ( type && ((*atcmd_msg == atcommand_symbol && pc_isGM(sd) < info->level) || (*atcmd_msg == charcommand_symbol && pc_isGM(sd) < info->level2)) ) )
{
+ if( pc_isGM(sd) ) {
sprintf(output, msg_txt(153), command); // "%s is Unknown Command."
clif_displaymessage(fd, output);
return true;
+ } else
+ return false;
}
//Attempt to use the command
diff --git a/src/map/battle.c b/src/map/battle.c
index b9a408a84..556b51bbd 100644
--- a/src/map/battle.c
+++ b/src/map/battle.c
@@ -118,7 +118,7 @@ static int battle_getenemy_sub(struct block_list *bl, va_list ap)
if (bl->id == target->id)
return 0;
- if (*c >= 24)
+ if (*c >= 23)
return 0;
if (status_isdead(bl))
return 0;
@@ -136,8 +136,47 @@ struct block_list* battle_getenemy(struct block_list *target, int type, int rang
int c = 0;
memset(bl_list, 0, sizeof(bl_list));
map_foreachinrange(battle_getenemy_sub, target, range, type, bl_list, &c, target);
- if (c == 0 || c > 24)
+ if (c == 0 )
+ return NULL;
+ if( c >= 24 )
+ c = 23;
+ return bl_list[rand()%c];
+}
+static int battle_getenemyarea_sub(struct block_list *bl, va_list ap)
+{
+ struct block_list **bl_list, *src;
+ int *c, ignore_id;
+
+ bl_list = va_arg(ap, struct block_list **);
+ c = va_arg(ap, int *);
+ src = va_arg(ap, struct block_list *);
+ ignore_id = va_arg(ap, int);
+
+ if( bl->id == src->id || bl->id == ignore_id )
+ return 0; // Ignores Caster and a possible pre-target
+ if( *c >= 23 )
+ return 0;
+ if( status_isdead(bl) )
+ return 0;
+ if( battle_check_target(src, bl, BCT_ENEMY) > 0 )
+ { // Is Enemy!...
+ bl_list[(*c)++] = bl;
+ return 1;
+ }
+ return 0;
+}
+
+// Pick a random enemy
+struct block_list* battle_getenemyarea(struct block_list *src, int x, int y, int range, int type, int ignore_id)
+{
+ struct block_list *bl_list[24];
+ int c = 0;
+ memset(bl_list, 0, sizeof(bl_list));
+ map_foreachinarea(battle_getenemyarea_sub, src->m, x - range, y - range, x + range, y + range, type, bl_list, &c, src, ignore_id);
+ if( c == 0 )
return NULL;
+ if( c >= 24 )
+ c = 23;
return bl_list[rand()%c];
}
@@ -212,7 +251,6 @@ int battle_delay_damage (unsigned int tick, int amotion, struct block_list *src,
return 0;
}
-
int battle_attr_ratio(int atk_elem,int def_type, int def_lv)
{
@@ -316,6 +354,20 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag
d->dmg_lv = ATK_BLOCK;
return 0;
}
+ if( sc->data[SC_WHITEIMPRISON] && skill_num != HW_GRAVITATION && skill_num != PA_PRESSURE ) { // Gravitation and Pressure do damage without removing the effect
+ if( skill_num == MG_NAPALMBEAT ||
+ skill_num == MG_SOULSTRIKE ||
+ skill_num == WL_SOULEXPANSION ||
+ (skill_num && skill_get_ele(skill_num, skill_lv) == ELE_GHOST) ||
+ (!skill_num && (status_get_status_data(src))->rhw.ele == ELE_GHOST)
+ )
+ status_change_end(bl,SC_WHITEIMPRISON,-1); // Those skills do damage and removes effect
+ else
+ {
+ d->dmg_lv = ATK_BLOCK;
+ return 0;
+ }
+ }
if( sc->data[SC_SAFETYWALL] && (flag&(BF_SHORT|BF_MAGIC))==BF_SHORT )
{
@@ -334,7 +386,13 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag
d->dmg_lv = ATK_BLOCK;
return 0;
}
-
+ if( sc->data[SC_WEAPONBLOCKING] && flag&(BF_SHORT|BF_WEAPON) && rand()%100 < sc->data[SC_WEAPONBLOCKING]->val2 )
+ {
+ clif_skill_nodamage(bl,src,GC_WEAPONBLOCKING,1,1);
+ d->dmg_lv = ATK_NONE;
+ sc_start2(bl,SC_COMBO,100,GC_WEAPONBLOCKING,src->id,2000);
+ return 0;
+ }
if( (sce=sc->data[SC_AUTOGUARD]) && flag&BF_WEAPON && !(skill_get_nk(skill_num)&NK_NO_CARDFIX_ATK) && rand()%100 < sce->val2 )
{
int delay;
@@ -487,6 +545,14 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag
status_change_end(bl, SC_REJECTSWORD, INVALID_TIMER);
}
+ //Finally added to remove the status of immobile when aimedbolt is used. [Jobbie]
+ if( skill_num == RA_AIMEDBOLT && (sc->data[SC_BITE] || sc->data[SC_ANKLE] || sc->data[SC_ELECTRICSHOCKER]) )
+ {
+ status_change_end(bl, SC_BITE, -1);
+ status_change_end(bl, SC_ANKLE, -1);
+ status_change_end(bl, SC_ELECTRICSHOCKER, -1);
+ }
+
//Finally Kyrie because it may, or not, reduce damage to 0.
if((sce = sc->data[SC_KYRIE]) && damage > 0){
sce->val2-=damage;
@@ -539,6 +605,8 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag
break;
}
}
+ if( sc->data[SC_POISONINGWEAPON] && skill_num != GC_VENOMPRESSURE && (flag&BF_WEAPON) && damage > 0 && rand()%100 < sc->data[SC_POISONINGWEAPON]->val3 )
+ sc_start(bl,sc->data[SC_POISONINGWEAPON]->val2,100,sc->data[SC_POISONINGWEAPON]->val1,skill_get_time2(GC_POISONINGWEAPON,sc->data[SC_POISONINGWEAPON]->val1));
}
if (battle_config.pk_mode && sd && bl->type == BL_PC && damage)
@@ -720,6 +788,12 @@ int battle_addmastery(struct map_session_data *sd,struct block_list *target,int
(battle_check_undead(status->race,status->def_ele) || status->race==RC_DEMON) )
damage += (skill*(int)(3+(sd->status.base_level+1)*0.05)); // submitted by orn
//damage += (skill * 3);
+ if( (skill = pc_checkskill(sd, RA_RANGERMAIN)) > 0 && (status->race == RC_BRUTE || status->race == RC_PLANT || status->race == RC_FISH) )
+ damage += (skill * 5);
+ if( (skill = pc_checkskill(sd,NC_RESEARCHFE)) > 0 && (status->def_ele == ELE_FIRE || status->def_ele == ELE_EARTH) )
+ damage += (skill * 10);
+ if( (sd->sc.option&OPTION_MADOGEAR) )
+ damage += 20 + 20 * pc_checkskill(sd, NC_MADOLICENCE);
if((skill = pc_checkskill(sd,HT_BEASTBANE)) > 0 && (status->race==RC_BRUTE || status->race==RC_INSECT) ) {
damage += (skill * 4);
@@ -755,11 +829,15 @@ int battle_addmastery(struct map_session_data *sd,struct block_list *target,int
case W_2HAXE:
if((skill = pc_checkskill(sd,AM_AXEMASTERY)) > 0)
damage += (skill * 3);
+ if((skill = pc_checkskill(sd,NC_TRAININGAXE)) > 0)
+ damage += (skill * 5);
break;
case W_MACE:
case W_2HMACE:
if((skill = pc_checkskill(sd,PR_MACEMASTERY)) > 0)
damage += (skill * 3);
+ if((skill = pc_checkskill(sd,NC_TRAININGAXE)) > 0)
+ damage += (skill * 5);
break;
case W_FIST:
if((skill = pc_checkskill(sd,TK_RUN)) > 0)
@@ -1278,6 +1356,9 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
if(sd && pc_checkskill(sd,AS_SONICACCEL)>0)
hitrate += hitrate * 50 / 100;
break;
+ case GC_VENOMPRESSURE:
+ hitrate += 10 + 4 * skill_lv;
+ break;
}
// Weaponry Research hidden bonus
@@ -1727,6 +1808,160 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
case NPC_VAMPIRE_GIFT:
skillratio += ((skill_lv-1)%5+1)*100;
break;
+ case RK_SONICWAVE: {
+ int level = status_get_lv(src);
+ skillratio += 400 + 100 * skill_lv;
+ if( level > 100 )
+ skillratio += skillratio * (level - 100) / 200;
+ }
+ break;
+ case RK_HUNDREDSPEAR: {
+ int level = status_get_lv(src);
+ skillratio += 500 + 40 * skill_lv;
+ if( level > 100 )
+ skillratio += skillratio * (level - 100) / 200;
+ }
+ break;
+ case RK_WINDCUTTER: {
+ int level = status_get_lv(src);
+ skillratio += 50 * skill_lv;
+ if( level > 100 )
+ skillratio += skillratio * (level - 50) / 200;
+ }
+ break;
+ case RK_IGNITIONBREAK: {
+ int level = status_get_lv(src);
+ i = distance_bl(src,target);
+ if( i < 2 )
+ skillratio = 200 + 200 * skill_lv;
+ else if( i < 4 )
+ skillratio = 100 + 200 * skill_lv;
+ else
+ skillratio = 100 + 100 * skill_lv;
+ if( level > 100 )
+ skillratio += skillratio * (level - 100) / 200;
+ if( sstatus->rhw.ele == ELE_FIRE )
+ skillratio += skillratio / 2;
+ }
+ break;
+ case RK_CRUSHSTRIKE:
+ if( sd )
+ {
+ short index = sd->equip_index[EQI_HAND_R];
+ if( index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_WEAPON )
+ skillratio = sstatus->rhw.atk + 100 * sd->inventory_data[index]->wlv * (sd->status.inventory[index].refine + 6);
+ }
+ break;
+ case RK_STORMBLAST:
+ skillratio = 100 * (sd ? pc_checkskill(sd,RK_RUNEMASTERY) : 1) + 100 * (sstatus->int_ / 4);
+ break;
+ case RK_PHANTOMTHRUST:
+ skillratio = 50 * skill_lv + 10 * ( sd ? pc_checkskill(sd,KN_SPEARMASTERY) : 10);
+ //if( s_level > 100 ) skillratio += skillratio * s_level / 150; // Base level bonus. This is official, but is disabled until I can confirm something with was changed or not. [Rytech]
+ //if( s_level > 100 ) skillratio += skillratio * (s_level - 100) / 200; // Base level bonus.
+ break;
+ /**
+ * GC Guilotine Cross
+ **/
+ case GC_CROSSIMPACT:
+ skillratio += 1050 + 50 * skill_lv;
+ break;
+ case GC_PHANTOMMENACE:
+ skillratio += 200;
+ break;
+ case GC_COUNTERSLASH:
+ skillratio += 200 + (100 * skill_lv) + sstatus->agi;
+ break;
+ case GC_ROLLINGCUTTER:
+ skillratio += 20 * skill_lv;
+ break;
+ case GC_CROSSRIPPERSLASHER:
+ skillratio += 60 + 40 * skill_lv;
+ if( sc && sc->data[SC_ROLLINGCUTTER] )
+ skillratio += 25 * sc->data[SC_ROLLINGCUTTER]->val1;
+ break;
+ /**
+ * Arch Bishop
+ **/
+ case AB_DUPLELIGHT_MELEE:
+ skillratio += 10 * skill_lv;
+ break;
+ /**
+ * Ranger
+ **/
+ case RA_ARROWSTORM:
+ skillratio += 100 + 50 * skill_lv;
+ if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus.
+ break;
+ case RA_AIMEDBOLT:
+ skillratio += 400 + 50 * skill_lv;
+ if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus.
+ if( tsc && (tsc->data[SC_BITE] || tsc->data[SC_ANKLE] || tsc->data[SC_ELECTRICSHOCKER]) )
+ wd.div_ = tstatus->size + 2 + rand()%2;
+ break;
+ case RA_CLUSTERBOMB:
+ skillratio += 100 + 100 * skill_lv;
+ break;
+ case RA_WUGDASH:
+ skillratio = 500;
+ break;
+ case RA_WUGSTRIKE:
+ skillratio = 200 * skill_lv;
+ break;
+ case RA_WUGBITE:
+ skillratio += 300 + 200 * skill_lv;
+ if ( skill_lv == 5 ) skillratio += 100;
+ break;
+ case RA_SENSITIVEKEEN:
+ skillratio += 50 * skill_lv;
+ break;
+ /**
+ * Mechanic
+ **/
+ case NC_BOOSTKNUCKLE:
+ skillratio += 100 + 100 * skill_lv + sstatus->dex;
+ if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus.
+ break;
+ case NC_PILEBUNKER:
+ skillratio += 200 + 100 * skill_lv + sstatus->str;
+ if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus.
+ break;
+ case NC_VULCANARM:
+ skillratio = 70 * skill_lv + sstatus->dex;
+ if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus.
+ break;
+ case NC_FLAMELAUNCHER:
+ case NC_COLDSLOWER:
+ skillratio += 200 + 300 * skill_lv;
+ if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus.
+ break;
+ case NC_ARMSCANNON:
+ switch( tstatus->size ) {
+ case 0: skillratio += 100 + 500 * skill_lv; break;// Small
+ case 1: skillratio += 100 + 400 * skill_lv; break;// Medium
+ case 2: skillratio += 100 + 300 * skill_lv; break;// Large
+ }
+ if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus.
+ //NOTE: Their's some other factors that affects damage, but not sure how exactly. Will recheck one day. [Rytech]
+ break;
+ case NC_AXEBOOMERANG:
+ skillratio += 60 + 40 * skill_lv;
+ if( sd ) {
+ short index = sd->equip_index[EQI_HAND_R];
+ if( index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_WEAPON )
+ skillratio += sd->inventory_data[index]->weight / 10;// Weight is divided by 10 since 10 weight in coding make 1 whole actural weight. [Rytech]
+ }
+ if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus.
+ break;
+ case NC_POWERSWING:
+ skillratio += 80 + 20 * skill_lv + sstatus->str + sstatus->dex;
+ if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus.
+ break;
+ case NC_AXETORNADO:
+ skillratio += 100 + 100 * skill_lv + sstatus->vit;
+ if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus.
+ break;
+
}
ATK_RATE(skillratio);
@@ -1755,6 +1990,16 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
case NJ_SYURIKEN:
ATK_ADD(4*skill_lv);
break;
+ /**
+ * Ranger
+ **/
+ case RA_WUGDASH:
+ case RA_WUGSTRIKE:
+ case RA_WUGBITE:
+ if(sd)
+ ATK_ADD(30*pc_checkskill(sd, RA_TOOTHOFWUG));
+ break;
+
}
}
//Div fix.
@@ -1764,13 +2009,17 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
if (sc) {
if(sc->data[SC_TRUESIGHT])
ATK_ADDRATE(2*sc->data[SC_TRUESIGHT]->val1);
-
+ #if RE_EDP == 0
+ /**
+ * In RE EDP doesn't affect your final damage but your atk and weapon atk
+ **/
if(sc->data[SC_EDP] &&
skill_num != ASC_BREAKER &&
skill_num != ASC_METEORASSAULT &&
skill_num != AS_SPLASHER &&
skill_num != AS_VENOMKNIFE)
ATK_ADDRATE(sc->data[SC_EDP]->val3);
+ #endif
}
switch (skill_num) {
@@ -1787,6 +2036,10 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
sc->data[SC_SPIRIT]->val2 == SL_CRUSADER)
ATK_ADDRATE(100);
break;
+ case NC_AXETORNADO:
+ if( (sstatus->rhw.ele) == ELE_WIND || (sstatus->lhw.ele) == ELE_WIND )
+ ATK_ADDRATE(50);
+ break;
}
if( sd )
@@ -1881,6 +2134,9 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
if((battle_check_undead(sstatus->race,sstatus->def_ele) || sstatus->race==RC_DEMON) && //This bonus already doesnt work vs players
src->type == BL_MOB && (skill=pc_checkskill(tsd,AL_DP)) > 0)
vit_def += skill*(int)(3 +(tsd->status.base_level+1)*0.04); // submitted by orn
+ if( src->type == BL_MOB && (skill=pc_checkskill(tsd,RA_RANGERMAIN))>0 &&
+ (sstatus->race == RC_BRUTE || sstatus->race == RC_FISH || sstatus->race == RC_PLANT) )
+ vit_def += skill*5;
} else { //Mob-Pet vit-eq
//VIT + rnd(0,[VIT/20]^2-1)
vit_def = (def2/20)*(def2/20);
@@ -2293,20 +2549,34 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
struct Damage md = battle_calc_misc_attack(src, target, skill_num, skill_lv, wflag);
wd.damage += md.damage;
}
-
- //SG_FUSION hp penalty [Komurka]
- if (sc && sc->data[SC_FUSION])
- {
- int hp= sstatus->max_hp;
- if (sd && tsd) {
- hp = 8*hp/100;
- if (100*sstatus->hp <= 20*sstatus->max_hp)
- hp = sstatus->hp;
- } else
- hp = 2*hp/100; //2% hp loss per hit
- status_zap(src, hp, 0);
+ if( sc ) {
+ //SG_FUSION hp penalty [Komurka]
+ if (sc->data[SC_FUSION])
+ {
+ int hp= sstatus->max_hp;
+ if (sd && tsd) {
+ hp = 8*hp/100;
+ if (100*sstatus->hp <= 20*sstatus->max_hp)
+ hp = sstatus->hp;
+ } else
+ hp = 2*hp/100; //2% hp loss per hit
+ status_zap(src, hp, 0);
+ }
+ /**
+ * affecting non-skills
+ **/
+ if( !skill_num ) {
+ /**
+ * RK Enchant Blade
+ **/
+ if( sc->data[SC_ENCHANTBLADE] && sd && ( (flag.rh && sd->weapontype1) || (flag.lh && sd->weapontype2) ) ) {
+ struct Damage md = battle_calc_magic_attack(src, target, RK_ENCHANTBLADE, pc_checkskill(sd,RK_ENCHANTBLADE), wflag);
+ wd.damage += md.damage;
+ wd.flag |= md.flag;
+ }
}
+ }
return wd;
}
@@ -2398,6 +2668,10 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
case AL_HEAL:
case PR_BENEDICTIO:
case PR_SANCTUARY:
+ /**
+ * Arch Bishop
+ **/
+ case AB_HIGHNESSHEAL:
ad.damage = skill_calc_heal(src, target, skill_num, skill_lv, false);
break;
case PR_ASPERSIO:
@@ -2417,14 +2691,31 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
case PF_SOULBURN:
ad.damage = tstatus->sp * 2;
break;
+ /**
+ * Arch Bishop
+ **/
+ case AB_RENOVATIO:
+ //Damage calculation from iRO wiki. [Jobbie]
+ ad.damage = (int)((15 * status_get_lv(src)) + (1.5 * sstatus->int_));
+ break;
default:
{
+ #if RRMODE //Renewal MATK Appliance according to doddler (?title=Renewal_Changes#Upgrade_MATK)
+ /**
+ * min: (weaponMATK+upgradeMATK) * 2 + 1.5 * statusMATK
+ * max: [weaponMATK+upgradeMATK+(wMatk*wLvl)/10] * 2 + 1.5 * statusMATK
+ * yes this formula MATCHES their site: matk_max already holds weaponmatk+upgradematk, and
+ * -> statusMATK holds the %Matk modifier stuff from earlier and lastly:
+ * -> the mdef part is not applied at this point, but later.
+ **/
+ MATK_ADD(sstatus->matk_max * 2 + 15/10 * sstatus->matk_min + rand()% ( sstatus->matk_max + (sstatus->matk_max*sstatus->wlv) / 10 * 2 * 10/15 * sstatus->matk_min ) );
+ #else //Ancient MATK Appliance
if (sstatus->matk_max > sstatus->matk_min) {
MATK_ADD(sstatus->matk_min+rand()%(1+sstatus->matk_max-sstatus->matk_min));
} else {
MATK_ADD(sstatus->matk_min);
}
-
+ #endif
if(nk&NK_SPLASHSPLIT){ // Divide MATK in case of multiple targets skill
if(mflag>0)
ad.damage/= mflag;
@@ -2470,6 +2761,11 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
case WZ_SIGHTRASHER:
skillratio += 20*skill_lv;
break;
+#if FIREIVY_ON
+ case WZ_FIREIVY:
+ skillratio += 20*skill_lv-15;
+ break;
+#endif
case WZ_VERMILION:
skillratio += 20*skill_lv-20;
break;
@@ -2513,6 +2809,193 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
case NPC_EARTHQUAKE:
skillratio += 100 +100*skill_lv +100*(skill_lv/2);
break;
+ /**
+ * Arch Bishop
+ **/
+ case AB_JUDEX:
+ skillratio += 180 + 20 * skill_lv;
+ if (skill_lv > 4) skillratio += 20;
+ if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus.
+ break;
+ case AB_ADORAMUS:
+ skillratio += 400 + 100 * skill_lv;
+ if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus.
+ break;
+ case AB_DUPLELIGHT_MAGIC:
+ skillratio += 100 + 20 * skill_lv;
+ break;
+ /**
+ * Warlock
+ **/
+ case WL_SOULEXPANSION:
+ skillratio += 300 + 100 * skill_lv + sstatus->int_;
+ if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus.
+ break;
+ case WL_FROSTMISTY:
+ skillratio += 100 + 100 * skill_lv;
+ if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus.
+ break;
+ case WL_JACKFROST:
+ {
+ struct status_change *tsc = status_get_sc(target);
+ if( tsc && tsc->data[SC_FREEZING] )
+ {
+ skillratio += 900 + 300 * skill_lv;
+ if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus.
+ }
+ else
+ skillratio += 400 + 100 * skill_lv;
+ if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus.
+ }
+ break;
+ case WL_DRAINLIFE:
+ skillratio = 200 * skill_lv + sstatus->int_;
+ if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus.
+ break;
+ case WL_CRIMSONROCK:
+ skillratio += 1200 + 300 * skill_lv;
+ if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus.
+ break;
+ case WL_HELLINFERNO:
+ if( status_get_element(target) == ELE_FIRE )
+ skillratio = 60 * skill_lv;
+ else
+ skillratio = 240 * skill_lv;
+ if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus.
+ break;
+ case WL_COMET: {
+ struct status_change * sc = status_get_sc(src);
+ if( sc )
+ i = distance_xy(target->x, target->y, sc->comet_x, sc->comet_y);
+ else
+ i = 8;
+ if( i < 2 ) skillratio = 2500 + 500 * skill_lv;
+ else
+ if( i < 4 ) skillratio = 1600 + 400 * skill_lv;
+ else
+ if( i < 6 ) skillratio = 1200 + 300 * skill_lv;
+ else
+ skillratio = 800 + 200 * skill_lv;
+ }
+ break;
+ case WL_CHAINLIGHTNING_ATK:
+ skillratio += 100 + 300 * skill_lv;
+ if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus.
+ break;
+ case WL_EARTHSTRAIN:
+ skillratio += 1900 + 100 * skill_lv;
+ if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus.
+ break;
+ case WL_TETRAVORTEX_FIRE:
+ case WL_TETRAVORTEX_WATER:
+ case WL_TETRAVORTEX_WIND:
+ case WL_TETRAVORTEX_GROUND:
+ skillratio += 400 + 500 * skill_lv;
+ break;
+ case WL_SUMMON_ATK_FIRE:
+ case WL_SUMMON_ATK_WATER:
+ case WL_SUMMON_ATK_WIND:
+ case WL_SUMMON_ATK_GROUND:
+ skillratio = skill_lv * (status_get_lv(src) + ( sd ? sd->status.job_level : 50 ));// This is close to official, but lacking a little info to finalize. [Rytech]
+ if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus.
+ break;
+ case LG_RAYOFGENESIS:
+ skillratio = (skillratio + 200) * skill_lv;
+ if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus.
+ break;
+ case WM_METALICSOUND:
+ skillratio += 120 * skill_lv + 60 * ( sd? pc_checkskill(sd, WM_LESSON) : 10 ) - 100;
+ break;
+ case WM_SEVERE_RAINSTORM:
+ skillratio += 50 * skill_lv;
+ break;
+ case WM_REVERBERATION_MAGIC:
+ skillratio += 100 * (sd ? pc_checkskill(sd, WM_REVERBERATION) : 1);
+ break;
+ case SO_FIREWALK: {
+ struct status_change * sc = status_get_sc(src);
+ skillratio = 300;
+ if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus.
+ if( sc && sc->data[SC_HEATER_OPTION] )
+ skillratio += skillratio * sc->data[SC_HEATER_OPTION]->val3 / 100;
+ }
+ break;
+ case SO_ELECTRICWALK: {
+ struct status_change * sc = status_get_sc(src);
+ skillratio = 300;
+ if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus.
+ if( sc && sc->data[SC_BLAST_OPTION] )
+ skillratio += skillratio * sc->data[SC_BLAST_OPTION]->val2 / 100;
+ }
+ break;
+ case SO_EARTHGRAVE: {
+ struct status_change * sc = status_get_sc(src);
+ skillratio = ( 200 * ( sd ? pc_checkskill(sd, SA_SEISMICWEAPON) : 10 ) + sstatus->int_ * skill_lv );
+ if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus.
+ if( sc && sc->data[SC_CURSED_SOIL_OPTION] )
+ skillratio += skillratio * sc->data[SC_CURSED_SOIL_OPTION]->val2 / 100;
+ }
+ break;
+ case SO_DIAMONDDUST: {
+ struct status_change * sc = status_get_sc(src);
+ skillratio = ( 200 * ( sd ? pc_checkskill(sd, SA_FROSTWEAPON) : 10 ) + sstatus->int_ * skill_lv );
+ if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus.
+ if( sc && sc->data[SC_COOLER_OPTION] )
+ skillratio += skillratio * sc->data[SC_COOLER_OPTION]->val3 / 100;
+ }
+ break;
+ case SO_POISON_BUSTER: {
+ struct status_change * sc = status_get_sc(src);
+ skillratio += 1100 + 300 * skill_lv;
+ if( sc && sc->data[SC_CURSED_SOIL_OPTION] )
+ skillratio += skillratio * sc->data[SC_CURSED_SOIL_OPTION]->val2 / 100;
+ }
+ break;
+ case SO_PSYCHIC_WAVE: {
+ struct status_change * sc = status_get_sc(src);
+ skillratio += -100 + skill_lv * 70 + (sstatus->int_ * 3);
+ if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus.
+ if( sc ){
+ if( sc->data[SC_HEATER_OPTION] )
+ skillratio += skillratio * sc->data[SC_HEATER_OPTION]->val3 / 100;
+ else if(sc->data[SC_COOLER_OPTION] )
+ skillratio += skillratio * sc->data[SC_COOLER_OPTION]->val3 / 100;
+ else if(sc->data[SC_BLAST_OPTION] )
+ skillratio += skillratio * sc->data[SC_BLAST_OPTION]->val2 / 100;
+ else if(sc->data[SC_CURSED_SOIL_OPTION] )
+ skillratio += skillratio * sc->data[SC_CURSED_SOIL_OPTION]->val3 / 100;
+ }
+ }
+ break;
+ case SO_VARETYR_SPEAR: {
+ struct status_change * sc = status_get_sc(src);
+ skillratio += -100 + ( 100 * ( sd ? pc_checkskill(sd, SA_LIGHTNINGLOADER) : 10 ) + sstatus->int_ * skill_lv );
+ if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus.
+ if( sc && sc->data[SC_BLAST_OPTION] )
+ skillratio += skillratio * sc->data[SC_BLAST_OPTION]->val2 / 100;
+ }
+ break;
+ case SO_CLOUD_KILL: {
+ struct status_change * sc = status_get_sc(src);
+ skillratio += -100 + skill_lv * 40;
+ if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus.
+ if( sc && sc->data[SC_CURSED_SOIL_OPTION] )
+ skillratio += skillratio * sc->data[SC_CURSED_SOIL_OPTION]->val2 / 100;
+ }
+ break;
+ case GN_DEMONIC_FIRE:
+ if( skill_lv > 20)
+ { // Fire expansion Lv.2
+ skillratio += 110 + 20 * (skill_lv - 20) + status_get_int(src) * 3; // Need official INT bonus. [LimitLine]
+ }
+ else if( skill_lv > 10 )
+ { // Fire expansion Lv.1
+ skillratio += 110 + 20 * (skill_lv - 10) / 2;
+ }
+ else
+ skillratio += 110 + 20 * skill_lv;
+ break;
+
}
MATK_RATE(skillratio);
@@ -2550,10 +3033,19 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
//mdef2-= mdef2* i/100;
}
}
+ #if RRMODE
+ /**
+ * RE MDEF Reduction (from doddler:?title=Renewal_Changes#MDEF)
+ * Damage from magic = Magic Attack * 111.5/(111.5+eMDEF)
+ * Damage = Magic Attack * 111.5/(111.5+eMDEF) - sMDEF
+ **/
+ ad.damage = ad.damage * ((1115/10) - mdef)/(1115/10) - mdef2;
+ #else
if(battle_config.magic_defense_type)
ad.damage = ad.damage - mdef*battle_config.magic_defense_type - mdef2;
else
ad.damage = ad.damage * (100-mdef)/100 - mdef2;
+ #endif
}
if (skill_num == NPC_EARTHQUAKE)
@@ -2805,6 +3297,32 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list *
case NPC_EVILLAND:
md.damage = skill_calc_heal(src,target,skill_num,skill_lv,false);
break;
+ case RK_DRAGONBREATH:
+ md.damage = ((status_get_hp(src) / 50) + (status_get_max_sp(src) / 4)) * skill_lv;
+ if (status_get_lv(src) > 100) md.damage = md.damage * status_get_lv(src) / 150;
+ if (sd) md.damage = md.damage * (100 + 5 * (pc_checkskill(sd,RK_DRAGONTRAINING) - 1)) / 100;
+ break;
+ /**
+ * Ranger
+ **/
+ case RA_CLUSTERBOMB:
+ case RA_FIRINGTRAP:
+ case RA_ICEBOUNDTRAP:
+ md.damage = (2 * skill_lv * (sstatus->dex + 100));
+ if (status_get_lv(src) > 100) md.damage += md.damage * (status_get_lv(src) - 50) / 200 + 15 / 10;
+ md.damage = md.damage * 2;// Without BaseLv Bonus
+ md.damage = md.damage + (5 * sstatus->int_) + (40 * ( sd ? pc_checkskill(sd,RA_RESEARCHTRAP) : 10 ) );
+ break;
+ /**
+ * Mechanic
+ **/
+ case NC_SELFDESTRUCTION:
+ md.damage = (sd?pc_checkskill(sd,NC_MAINFRAME):10) * skill_lv * (status_get_sp(src) + sstatus->vit);
+ if (status_get_lv(src) > 100) md.damage = md.damage * status_get_lv(src) / 150;// Base level bonus.
+ if (sd) md.damage = md.damage + status_get_hp(src);
+ status_set_sp(src, 0, 0);
+ break;
+
}
if (nk&NK_SPLASHSPLIT){ // Divide ATK among targets
@@ -2906,11 +3424,23 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list *
else if( map[target->m].flag.battleground )
md.damage=battle_calc_bg_damage(src,target,md.damage,md.div_,skill_num,skill_lv,md.flag);
- if (skill_num == NJ_ZENYNAGE && sd)
- { //Time to Pay Up.
- if ( md.damage > sd->status.zeny )
- md.damage=sd->status.zeny;
- pc_payzeny(sd, md.damage);
+ switch( skill_num ) {
+ case RA_CLUSTERBOMB:
+ case RA_FIRINGTRAP:
+ case RA_ICEBOUNDTRAP:
+ {
+ struct Damage wd;
+ wd = battle_calc_weapon_attack(src,target,skill_num,skill_lv,mflag);
+ md.damage += wd.damage;
+ }
+ break;
+ case NJ_ZENYNAGE:
+ if( sd ) {
+ if ( md.damage > sd->status.zeny )
+ md.damage = sd->status.zeny;
+ pc_payzeny(sd, md.damage);
+ }
+ break;
}
return md;
@@ -2943,10 +3473,10 @@ struct Damage battle_calc_attack(int attack_type,struct block_list *bl,struct bl
}
//Calculates BF_WEAPON returned damage.
-int battle_calc_return_damage(struct block_list* bl, int damage, int flag)
+int battle_calc_return_damage(struct block_list* bl, struct block_list *src, int *dmg, int flag)
{
struct map_session_data* sd = NULL;
- int rdamage = 0;
+ int rdamage = 0, damage = *dmg;
sd = BL_CAST(BL_PC, bl);
@@ -2959,10 +3489,24 @@ int battle_calc_return_damage(struct block_list* bl, int damage, int flag)
if(rdamage < 1) rdamage = 1;
}
sc = status_get_sc(bl);
- if (sc && sc->data[SC_REFLECTSHIELD])
- {
- rdamage += damage * sc->data[SC_REFLECTSHIELD]->val2 / 100;
- if (rdamage < 1) rdamage = 1;
+ if( sc && sc->count ) {
+ if (sc->data[SC_REFLECTSHIELD]) {
+ rdamage += damage * sc->data[SC_REFLECTSHIELD]->val2 / 100;
+ if (rdamage < 1) rdamage = 1;
+ }
+ if(sc->data[SC_DEATHBOUND] && !(src->type == BL_MOB && is_boss(src)) ) {
+ int dir = map_calc_dir(bl,src->x,src->y),
+ t_dir = unit_getdir(bl), rd1 = 0;
+
+ if( distance_bl(src,bl) <= 0 || !map_check_dir(dir,t_dir) ) {
+ rd1 = min(damage,status_get_max_hp(bl)) * sc->data[SC_DEATHBOUND]->val2 / 100; // Amplify damage.
+ *dmg = rd1 * 30 / 100; // Received damge = 30% of amplifly damage.
+ clif_skill_damage(src,bl,gettick(), status_get_amotion(src), 0, -30000, 1, RK_DEATHBOUND, sc->data[SC_DEATHBOUND]->val1,6);
+ status_change_end(bl,SC_DEATHBOUND,-1);
+ rdamage += rd1;
+ if (rdamage < 1) rdamage = 1;
+ }
+ }
}
} else {
if (sd && sd->long_weapon_damage_return)
@@ -3165,7 +3709,17 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t
damage = wd.damage + wd.damage2;
if( damage > 0 && src != target )
{
- rdamage = battle_calc_return_damage(target, damage, wd.flag);
+ if( sc && sc->data[SC_DUPLELIGHT] && (wd.flag&BF_SHORT) && rand()%100 <= 10+2*sc->data[SC_DUPLELIGHT]->val1 )
+ { // Activates it only from melee damage
+ int skillid;
+ if( rand()%2 == 1 )
+ skillid = AB_DUPLELIGHT_MELEE;
+ else
+ skillid = AB_DUPLELIGHT_MAGIC;
+ skill_attack(skill_get_type(skillid), src, src, target, skillid, sc->data[SC_DUPLELIGHT]->val1, tick, SD_LEVEL);
+ }
+
+ rdamage = battle_calc_return_damage(target,src, &damage, wd.flag);
if( rdamage > 0 )
{
rdelay = clif_damage(src, src, tick, wd.amotion, sstatus->dmotion, rdamage, 1, 4, 0);
@@ -3373,6 +3927,8 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f
case WZ_SIGHTBLASTER:
case SM_MAGNUM:
case MS_MAGNUM:
+ case RA_DETONATOR:
+ case RA_SENSITIVEKEEN:
state |= BCT_ENEMY;
strip_enemy = 0;
break;
@@ -4023,6 +4579,10 @@ static const struct _battle_data {
{ "bg_magic_attack_damage_rate", &battle_config.bg_magic_damage_rate, 60, 0, INT_MAX, },
{ "bg_misc_attack_damage_rate", &battle_config.bg_misc_damage_rate, 60, 0, INT_MAX, },
{ "bg_flee_penalty", &battle_config.bg_flee_penalty, 20, 0, INT_MAX, },
+ /**
+ * RR-Specific
+ **/
+ { "max_third_parameter", &battle_config.max_third_parameter, 20, 0, INT_MAX, },
};
diff --git a/src/map/battle.h b/src/map/battle.h
index 007499afe..a64c81041 100644
--- a/src/map/battle.h
+++ b/src/map/battle.h
@@ -35,7 +35,7 @@ struct block_list;
struct Damage battle_calc_attack(int attack_type,struct block_list *bl,struct block_list *target,int skill_num,int skill_lv,int count);
-int battle_calc_return_damage(struct block_list *bl, int damage, int flag);
+int battle_calc_return_damage(struct block_list *bl, struct block_list *src, int *, int flag);
void battle_drain(struct map_session_data *sd, struct block_list *tbl, int rdamage, int ldamage, int race, int boss);
@@ -497,6 +497,8 @@ extern struct Battle_Config
int bg_magic_damage_rate;
int bg_misc_damage_rate;
int bg_flee_penalty;
+ //[RR]
+ int max_third_parameter;
} battle_config;
void do_init_battle(void);
@@ -507,4 +509,7 @@ extern void battle_set_defaults(void);
int battle_set_value(const char* w1, const char* w2);
int battle_get_value(const char* w1);
+//
+struct block_list* battle_getenemyarea(struct block_list *src, int x, int y, int range, int type, int ignore_id);
+
#endif /* _BATTLE_H_ */
diff --git a/src/map/chrif.c b/src/map/chrif.c
index d1332fab2..947cb0bdc 100644
--- a/src/map/chrif.c
+++ b/src/map/chrif.c
@@ -505,7 +505,13 @@ void chrif_on_ready(void)
ShowStatus("Map Server is now online.\n");
chrif_state = 2;
chrif_check_shutdown();
-
+ /**
+ * while we're not fully ready
+ **/
+ ShowMessage(""CL_XXBL""CL_BT_YELLOW"============= WARNING ============="CL_XXBL""CL_CLL""CL_NORMAL"\n");
+ ShowMessage(""CL_XXBL"- "CL_BT_YELLOW"This version is under development and shouldn't be used as a real server"CL_XXBL""CL_CLL""CL_NORMAL"\n");
+ ShowMessage(""CL_XXBL"- "CL_BT_YELLOW"For bugs, comments and suggestions: http://ro-resources.net "CL_XXBL""CL_CLL""CL_NORMAL"\n");
+ ShowMessage(""CL_XXBL"- "CL_BT_YELLOW"Thank you for trying out"CL_XXBL""CL_CLL""CL_NORMAL"\n");
//If there are players online, send them to the char-server. [Skotlex]
send_users_tochar();
diff --git a/src/map/clif.c b/src/map/clif.c
index da2abe0f3..780b1af56 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -154,7 +154,8 @@ void clif_setbindip(const char* ip)
}
/*==========================================
- * map鯖のport設定
+ * Sets map port to 'port'
+ * is run from map.c upon loading map server configuration
*------------------------------------------*/
void clif_setport(uint16 port)
{
@@ -162,7 +163,7 @@ void clif_setport(uint16 port)
}
/*==========================================
- * map鯖のip読み出し
+ * Returns map server IP
*------------------------------------------*/
uint32 clif_getip(void)
{
@@ -184,7 +185,7 @@ uint32 clif_refresh_ip(void)
}
/*==========================================
- * map鯖のport読み出し
+ * Returns map port which is set by clif_setport()
*------------------------------------------*/
uint16 clif_getport(void)
{
@@ -210,7 +211,14 @@ static inline unsigned char clif_bl_type(struct block_list *bl) {
#endif
/*==========================================
- * clif_sendでAREA*指定時用
+ * sub process of clif_send
+ * Called from a map_foreachinarea (grabs all players in specific area and subjects them to this function)
+ * In order to send area-wise packets, such as:
+ * - AREA : everyone nearby your area
+ * - AREA_WOSC (AREA WITHOUT SAME CHAT) : Not run for people in the same chat as yours
+ * - AREA_WOC (AREA WITHOUT CHAT) : Not run for people inside a chat
+ * - AREA_WOS (AREA WITHOUT SELF) : Not run for self
+ * - AREA_CHAT_WOC : Everyone in the area of your chat without a chat
*------------------------------------------*/
int clif_send_sub(struct block_list *bl, va_list ap)
{
@@ -273,7 +281,8 @@ int clif_send_sub(struct block_list *bl, va_list ap)
}
/*==========================================
- *
+ * Packet Delegation (called on all packets that require data to be sent to more than one client)
+ * functions that are sent solely to one use whose ID it posses use WFIFOSET
*------------------------------------------*/
int clif_send(const uint8* buf, int len, struct block_list* bl, enum send_target type)
{
@@ -554,11 +563,10 @@ int clif_send(const uint8* buf, int len, struct block_list* bl, enum send_target
return 0;
}
-//
-// パケット作って送信
-//
+
/*==========================================
- *
+ * Tells client that its player is fully loaded and that it can proceed to the map screen
+ * Provides client with player position and facing direction
*------------------------------------------*/
int clif_authok(struct map_session_data *sd)
{
@@ -657,7 +665,8 @@ int clif_dropflooritem(struct flooritem_data* fitem)
}
/*==========================================
- *
+ * Server tells client to remove item of ID ('fitem->bl.id') from FD player area
+ * If FD is 0 it tells all clients nearby this item that it is gone
*------------------------------------------*/
int clif_clearflooritem(struct flooritem_data *fitem, int fd)
{
@@ -1105,7 +1114,8 @@ static void clif_setdisguise(struct block_list *bl, unsigned char *buf,int len)
}
/*==========================================
- * クラスチェンジ typeはMobの場合は1で他は0?
+ * Acronym for 'clif_mob_class_change' used to tell clients around the monster that it's identity changed
+ * for example, it's run when a pupa transforms into a creamy.
*------------------------------------------*/
int clif_class_change(struct block_list *bl,int class_,int type)
{
@@ -1124,7 +1134,7 @@ int clif_class_change(struct block_list *bl,int class_,int type)
}
/*==========================================
- *
+ * Server tells client to display (sd->spiritball) amount of spiritballs on target of account id (sd->bl.id)
*------------------------------------------*/
static void clif_spiritball_single(int fd, struct map_session_data *sd)
{
@@ -1136,7 +1146,8 @@ static void clif_spiritball_single(int fd, struct map_session_data *sd)
}
/*==========================================
- *
+ * Run when player changes map / refreshes
+ * Tells its client to display all weather settings being used by this map
*------------------------------------------*/
static void clif_weather_check(struct map_session_data *sd)
{
@@ -1148,7 +1159,10 @@ static void clif_weather_check(struct map_session_data *sd)
|| map[m].flag.fireworks
|| map[m].flag.sakura
|| map[m].flag.leaves
- || map[m].flag.rain
+ /**
+ * No longer available, keeping here just in case it's back someday. [Ind]
+ **/
+ //|| map[m].flag.rain
|| map[m].flag.clouds2)
{
if (map[m].flag.snow)
@@ -1168,11 +1182,16 @@ static void clif_weather_check(struct map_session_data *sd)
clif_specialeffect_single(&sd->bl, 163, fd);
if (map[m].flag.leaves)
clif_specialeffect_single(&sd->bl, 333, fd);
- if (map[m].flag.rain)
- clif_specialeffect_single(&sd->bl, 161, fd);
+ /**
+ * No longer available, keeping here just in case it's back someday. [Ind]
+ **/
+ //if (map[m].flag.rain)
+ // clif_specialeffect_single(&sd->bl, 161, fd);
}
}
-
+/**
+ * Run when the weather on a map changes, throws all players in map id 'm' to clif_weather_check function
+ **/
void clif_weather(int m)
{
struct s_mapiterator* iter;
@@ -1186,7 +1205,9 @@ void clif_weather(int m)
}
mapit_free(iter);
}
-
+/**
+ * Main function to spawn a unit on the client (player/mob/pet/etc)
+ **/
int clif_spawn(struct block_list *bl)
{
unsigned char buf[128];
@@ -1218,6 +1239,10 @@ int clif_spawn(struct block_list *bl)
clif_specialeffect(bl,421,AREA);
if( sd->bg_id && map[sd->bl.m].flag.battleground )
clif_sendbgemblem_area(sd);
+ if( sd->sc.option&OPTION_MOUNTING ) {
+ //New Mounts are not complaint to the original method, so we gotta tell this guy that he is mounting.
+ clif_status_load_notick(&sd->bl,SI_ALL_RIDING,2,1,0,0);
+ }
}
break;
case BL_MOB:
@@ -1873,7 +1898,7 @@ int clif_viewpoint(struct map_session_data *sd, int npc_id, int type, int x, int
}
/*==========================================
- *
+ * Server tells client to display cutin of name 'image' to client, in position 'type' (255, etc)
*------------------------------------------*/
int clif_cutin(struct map_session_data* sd, const char* image, int type)
{
@@ -1945,7 +1970,8 @@ static void clif_addcards(unsigned char* buf, struct item* item)
}
/*==========================================
- *
+ * Server tells client he got item of index 'n' and amount 'amount',
+ * when 'fail' is 1 it tells the client it failed to receive said item
*------------------------------------------*/
int clif_additem(struct map_session_data *sd, int n, int amount, int fail)
{
@@ -2014,7 +2040,7 @@ int clif_additem(struct map_session_data *sd, int n, int amount, int fail)
}
/*==========================================
- *
+ *
*------------------------------------------*/
int clif_dropitem(struct map_session_data *sd,int n,int amount)
{
@@ -2457,8 +2483,9 @@ int clif_guild_xy_remove(struct map_session_data *sd)
}
/*==========================================
- * ステータスを送りつける
- * 表示専用数字はこの中で計算して送る
+ * Server tells client that data 'type' has changed and sends it's new value
+ * For example, when server updates the client max weight, say, due to higher STR,
+ * It calls this function with SP_MAXWEIGHT type
*------------------------------------------*/
int clif_updatestatus(struct map_session_data *sd,int type)
{
@@ -2590,7 +2617,9 @@ int clif_updatestatus(struct map_session_data *sd,int type)
WFIFOL(fd,4)=pc_nextjobexp(sd);
break;
- // 00be 終了
+ /**
+ * SP_U<STAT> are used to update the amount of points necessary to increase that stat
+ **/
case SP_USTR:
case SP_UAGI:
case SP_UVIT:
@@ -2602,14 +2631,15 @@ int clif_updatestatus(struct map_session_data *sd,int type)
len=5;
break;
- // 013a 終了
+ /**
+ * Tells the client how far it is allowed to attack (weapon range)
+ **/
case SP_ATTACKRANGE:
WFIFOW(fd,0)=0x13a;
WFIFOW(fd,2)=sd->battle_status.rhw.range;
len=4;
break;
- // 0141 終了
case SP_STR:
WFIFOW(fd,0)=0x141;
WFIFOL(fd,2)=type;
@@ -2699,7 +2729,7 @@ int clif_changestatus(struct block_list *bl,int type,int val)
}
/*==========================================
- *
+ * Updates BL unit view data to nearby clients
*------------------------------------------*/
void clif_changelook(struct block_list *bl,int type,int val)
{
@@ -2926,7 +2956,7 @@ int clif_initialstatus(struct map_session_data *sd)
}
/*==========================================
- *矢装備
+ * Server tells client item idx 'val' is meant to be shown in equipment's window arrow slot
*------------------------------------------*/
int clif_arrowequip(struct map_session_data *sd,int val)
{
@@ -2968,7 +2998,8 @@ int clif_arrow_fail(struct map_session_data *sd,int type)
}
/*==========================================
- * 作成可能 矢リスト送信
+ * Server tells client to display a window similar to Mangifier (item) one
+ * Server populates the window with avilable arrow crafting options according to player's inventory
*------------------------------------------*/
int clif_arrow_create_list(struct map_session_data *sd)
{
@@ -3004,7 +3035,7 @@ int clif_arrow_create_list(struct map_session_data *sd)
}
/*==========================================
- *
+ * Server tells client his response regarding the earlier request to increase status
*------------------------------------------*/
int clif_statusupack(struct map_session_data *sd,int type,int ok,int val)
{
@@ -3090,7 +3121,7 @@ int clif_misceffect(struct block_list* bl,int type)
}
/*==========================================
- * 表示オプション変更
+ * Server tells BL unit and all nearby clients that his unit-view options (e.g. stone curse appearance) changed
*------------------------------------------*/
int clif_changeoption(struct block_list* bl)
{
@@ -3483,7 +3514,7 @@ void clif_tradestart(struct map_session_data* sd, uint8 type)
}
/*==========================================
- * 相手方からのアイテム追加
+ * Server tells 'tsd' player client info on the items 'sd' player just added to the trade window
*------------------------------------------*/
void clif_tradeadditem(struct map_session_data* sd, struct map_session_data* tsd, int index, int amount)
{
@@ -3547,7 +3578,9 @@ void clif_tradeadditem(struct map_session_data* sd, struct map_session_data* tsd
}
/*==========================================
- * アイテム追加成功/失敗
+ * Server tells client on the status of it's OK request
+ * fail 1 : the other person did 'ok'
+ * fail 0 : you did 'ok'
*------------------------------------------*/
void clif_tradeitemok(struct map_session_data* sd, int index, int fail)
{
@@ -3563,7 +3596,9 @@ void clif_tradeitemok(struct map_session_data* sd, int index, int fail)
}
/*==========================================
- * 取り引きok押し
+ * Server tells client on the status of it's lock request
+ * fail 1 : The other trader lock request
+ * fail 0 : Your lock request
*------------------------------------------*/
void clif_tradedeal_lock(struct map_session_data* sd, int fail)
{
@@ -3578,7 +3613,7 @@ void clif_tradedeal_lock(struct map_session_data* sd, int fail)
}
/*==========================================
- * 取り引きがキャンセルされました
+ * Server tells client it's trade request was cancelled
*------------------------------------------*/
void clif_tradecancelled(struct map_session_data* sd)
{
@@ -3592,7 +3627,7 @@ void clif_tradecancelled(struct map_session_data* sd)
}
/*==========================================
- * 取り引き完了
+ * Server tells client the final status on his trade request
*------------------------------------------*/
void clif_tradecompleted(struct map_session_data* sd, int fail)
{
@@ -3607,7 +3642,7 @@ void clif_tradecompleted(struct map_session_data* sd, int fail)
}
/*==========================================
- * カプラ倉庫のアイテム数を更新
+ * Server tells client it's quantity of items in storage changed
*------------------------------------------*/
void clif_updatestorageamount(struct map_session_data* sd, int amount)
{
@@ -3624,7 +3659,7 @@ void clif_updatestorageamount(struct map_session_data* sd, int amount)
}
/*==========================================
- * カプラ倉庫にアイテムを追加する
+ * Server tells client it's status on his request to add a item to storage
*------------------------------------------*/
void clif_storageitemadded(struct map_session_data* sd, struct item* i, int index, int amount)
{
@@ -3679,7 +3714,7 @@ void clif_updateguildstorageamount(struct map_session_data* sd, int amount)
}
/*==========================================
- * カプラ倉庫からアイテムを取り去る
+ * Server tells client its status on his request to remove a item from storage
*------------------------------------------*/
void clif_storageitemremoved(struct map_session_data* sd, int index, int amount)
{
@@ -3696,7 +3731,7 @@ void clif_storageitemremoved(struct map_session_data* sd, int index, int amount)
}
/*==========================================
- * カプラ倉庫を閉じる
+ * Server tells client his storage was closed
*------------------------------------------*/
void clif_storageclose(struct map_session_data* sd)
{
@@ -3709,9 +3744,9 @@ void clif_storageclose(struct map_session_data* sd)
WFIFOW(fd,0) = 0xf8; // Storage Closed
WFIFOSET(fd,packet_len(0xf8));
}
-
+int clif_status_load_single(int fd, int id,int type,int flag,int val1, int val2, int val3);
/*==========================================
- * PC表示
+ * Server tells 'sd' player client the abouts of 'dstsd' player
*------------------------------------------*/
static void clif_getareachar_pc(struct map_session_data* sd,struct map_session_data* dstsd)
{
@@ -3735,7 +3770,10 @@ static void clif_getareachar_pc(struct map_session_data* sd,struct map_session_d
if(dstsd->spiritball > 0)
clif_spiritball_single(sd->fd, dstsd);
-
+ if( dstsd->sc.option&OPTION_MOUNTING ) {
+ //New Mounts are not complaint to the original method, so we gotta tell this guy that I'm mounting.
+ clif_status_load_single(sd->fd,dstsd->bl.id,SI_ALL_RIDING,2,1,0,0);
+ }
if( (sd->status.party_id && dstsd->status.party_id == sd->status.party_id) || //Party-mate, or hpdisp setting.
(sd->bg_id && sd->bg_id == dstsd->bg_id) || //BattleGround
(battle_config.disp_hpmeter && (gmlvl = pc_isGM(sd)) >= battle_config.disp_hpmeter && gmlvl >= pc_isGM(dstsd)) )
@@ -4044,7 +4082,7 @@ void clif_getareachar_item(struct map_session_data* sd,struct flooritem_data* fi
}
/*==========================================
- * 場所スキルエフェクトが視界に入る
+ * Server tells client 'sd' of all nearby skill units (e.g. safety wall)
*------------------------------------------*/
static void clif_getareachar_skillunit(struct map_session_data *sd, struct skill_unit *unit)
{
@@ -4084,7 +4122,7 @@ static void clif_getareachar_skillunit(struct map_session_data *sd, struct skill
}
/*==========================================
- * 場所スキルエフェクトが視界から消える
+ * Server tells client to remove unit of id 'unit->bl.id'
*------------------------------------------*/
static void clif_clearchar_skillunit(struct skill_unit *unit, int fd)
{
@@ -4100,7 +4138,7 @@ static void clif_clearchar_skillunit(struct skill_unit *unit, int fd)
}
/*==========================================
- * 場所スキルエフェクト削除
+ * Server tells all clients in sight of 'unit->bl.id' ID to remove itself from sight (delete)
*------------------------------------------*/
void clif_skill_delunit(struct skill_unit *unit)
{
@@ -4245,7 +4283,7 @@ int clif_insight(struct block_list *bl,va_list ap)
}
/*==========================================
- * スキルリストを送信する
+ * Server tells the client information on 'sd' player's skill tree
*------------------------------------------*/
int clif_skillinfoblock(struct map_session_data *sd)
{
@@ -4282,7 +4320,9 @@ int clif_skillinfoblock(struct map_session_data *sd)
return 1;
}
-
+/**
+ * Server tells client 'sd' to add skill of id 'id' to it's skill tree (e.g. with Ice Falcion item)
+ **/
int clif_addskill(struct map_session_data *sd, int id )
{
int fd;
@@ -4333,7 +4373,7 @@ int clif_deleteskill(struct map_session_data *sd, int id)
}
/*==========================================
- * スキル割り振り通知
+ * Server tells client it's skill of id 'skill_num' level changed
*------------------------------------------*/
int clif_skillup(struct map_session_data *sd,int skill_num)
{
@@ -4668,7 +4708,7 @@ int clif_skill_damage2(struct block_list *src,struct block_list *dst,unsigned in
*/
/*==========================================
- * 支援/回復スキルエフェクト
+ * Server tells client(s) that 'src' casted a skill of nodamage type (e.g. heal) on 'dst'
*------------------------------------------*/
int clif_skill_nodamage(struct block_list *src,struct block_list *dst,int skill_id,int heal,int fail)
{
@@ -4701,7 +4741,8 @@ int clif_skill_nodamage(struct block_list *src,struct block_list *dst,int skill_
}
/*==========================================
- * 場所スキルエフェクト
+ * Server tells client 'src' to display effect of skill id 'skill_id' on location 'x' and 'y'
+ * 'val' is used for information that varies from skill to skill, usually it's the skill level
*------------------------------------------*/
int clif_skill_poseffect(struct block_list *src,int skill_id,int val,int x,int y,int tick)
{
@@ -4727,7 +4768,7 @@ int clif_skill_poseffect(struct block_list *src,int skill_id,int val,int x,int y
}
/*==========================================
- * 場所スキルエフェクト表示
+ * Tells all client's nearby 'unit' sight range that it spawned
*------------------------------------------*/
//FIXME: this is just an AREA version of clif_getareachar_skillunit()
void clif_skill_setunit(struct skill_unit *unit)
@@ -4765,7 +4806,7 @@ void clif_skill_setunit(struct skill_unit *unit)
}
/*==========================================
- * ワープ場所選択
+ * Used to display 'teleport' and 'warp portal' information on it's respective dialogs
*------------------------------------------*/
void clif_skill_warppoint(struct map_session_data* sd, short skill_num, short skill_lv, unsigned short map1, unsigned short map2, unsigned short map3, unsigned short map4)
{
@@ -4832,7 +4873,7 @@ void clif_skill_teleportmessage(struct map_session_data *sd, int type)
}
/*==========================================
- * モンスター情報
+ * Server tells client to display 'estimation' (Sense) information for monster (bl) 'dst'
*------------------------------------------*/
int clif_skill_estimation(struct map_session_data *sd,struct block_list *dst)
{
@@ -4868,14 +4909,15 @@ int clif_skill_estimation(struct map_session_data *sd,struct block_list *dst)
return 0;
}
/*==========================================
- * アイテム合成可能リスト
+ * Server tells client to display a window similar to Mangifier (item) one
+ * Server populates the window with avilable crafting options according to skill used to call this
*------------------------------------------*/
-int clif_skill_produce_mix_list(struct map_session_data *sd, int trigger)
+int clif_skill_produce_mix_list(struct map_session_data *sd, int skillid , int trigger)
{
int i,c,view,fd;
nullpo_ret(sd);
- if(sd->menuskill_id == AM_PHARMACY)
+ if(sd->menuskill_id == skillid)
return 0; //Avoid resending the menu twice or more times...
fd=sd->fd;
WFIFOHEAD(fd, MAX_SKILL_PRODUCE_DB * 8 + 8);
@@ -4895,7 +4937,7 @@ int clif_skill_produce_mix_list(struct map_session_data *sd, int trigger)
WFIFOW(fd, 2)=c*8+8;
WFIFOSET(fd,WFIFOW(fd,2));
if(c > 0) {
- sd->menuskill_id = AM_PHARMACY;
+ sd->menuskill_id = skillid;
sd->menuskill_val = trigger;
return 1;
}
@@ -4966,9 +5008,9 @@ int clif_status_load(struct block_list *bl,int type, int flag)
return 0;
}
/*==========================================
- * 状態異常アイコン/メッセージ表示
+ * Server tell's BL and nearby clients of his status change
*------------------------------------------*/
-int clif_status_change(struct block_list *bl,int type,int flag,unsigned int tick)
+int clif_status_change(struct block_list *bl,int type,int flag,unsigned int tick,int val1, int val2, int val3)
{
unsigned char buf[32];
@@ -4996,9 +5038,9 @@ int clif_status_change(struct block_list *bl,int type,int flag,unsigned int tick
if( battle_config.display_status_timers && tick>0 )
{
WBUFL(buf,9)=tick;
- WBUFL(buf,13)=0;
- WBUFL(buf,17)=0;
- WBUFL(buf,21)=0;
+ WBUFL(buf,13) = val1;
+ WBUFL(buf,17) = val2;
+ WBUFL(buf,21) = val3;
}
clif_send(buf,packet_len(WBUFW(buf,0)),bl,AREA);
return 0;
@@ -5031,7 +5073,6 @@ int clif_displaymessage(const int fd, const char* mes)
}
/*==========================================
- * 天の声を送信する
* Send broadcast message in yellow or blue (without font formatting).
* S 009A <len>.W <message>.?B
*------------------------------------------*/
@@ -5055,7 +5096,8 @@ int clif_broadcast(struct block_list* bl, const char* mes, int len, int type, en
}
/*==========================================
- * グローバルメッセージ
+ * Displays a message on a 'bl' to all it's nearby clients
+ * Used by npc_globalmessage
*------------------------------------------*/
void clif_GlobalMessage(struct block_list* bl, const char* message)
{
@@ -5128,7 +5170,8 @@ int clif_broadcast2(struct block_list* bl, const char* mes, int len, unsigned lo
return 0;
}
/*==========================================
- * HPSP回復エフェクトを送信する
+ * Server tells self client to heal self for 'val', is either SP_HP or SP_SP
+ * It displays these green and blue heal numbers that show up at your body and go up until they fade away
*------------------------------------------*/
int clif_heal(int fd,int type,int val)
{
@@ -5142,7 +5185,7 @@ int clif_heal(int fd,int type,int val)
}
/*==========================================
- * 復活する
+ * Server tells nearby clients of 'bl' that it ressurected (and plays ress effect)
*------------------------------------------*/
int clif_resurrection(struct block_list *bl,int type)
{
@@ -5190,7 +5233,8 @@ void clif_map_type(struct map_session_data* sd, enum map_type type)
}
/*==========================================
- * PVP実装?(仮)
+ * Server tells client on it's pvp rank and map status,
+ * (it controls the counter on the bottom right of the map existent in pvp rooms)
*------------------------------------------*/
int clif_pvpset(struct map_session_data *sd,int pvprank,int pvpnum,int type)
{
@@ -5239,7 +5283,8 @@ void clif_map_property_mapall(int map, enum map_property property)
}
/*==========================================
- * 精錬エフェクトを送信する
+ * Server tells client the status on refine of item index 'index' from refine 'val'
+ * Message displayed depends on 'fail' (broken(red) or success(blue))
*------------------------------------------*/
void clif_refine(int fd, int fail, int index, int val)
{
@@ -5308,7 +5353,8 @@ int clif_wis_end(int fd, int flag)
}
/*==========================================
- * キャラID名前引き結果を送信する
+ * Server tells client that char id 'charid' is to be assigned the name of 'name'
+ * This is used when client requests the server the name written in a item, e.g. crafted alche potions
*------------------------------------------*/
int clif_solved_charname(int fd, int charid, const char* name)
{
@@ -5321,7 +5367,7 @@ int clif_solved_charname(int fd, int charid, const char* name)
}
/*==========================================
- * カードの挿入可能リストを返す
+ * Server tells client to list all items that may be worn by card item of index 'idx'
*------------------------------------------*/
int clif_use_card(struct map_session_data *sd,int idx)
{
@@ -5371,7 +5417,7 @@ int clif_use_card(struct map_session_data *sd,int idx)
return 0;
}
/*==========================================
- * カードの挿入終了
+ * Server tells client his status on the previous clif_use_card (failed or OK)
*------------------------------------------*/
int clif_insert_card(struct map_session_data *sd,int idx_equip,int idx_card,int flag)
{
@@ -5390,7 +5436,7 @@ int clif_insert_card(struct map_session_data *sd,int idx_equip,int idx_card,int
}
/*==========================================
- * 鑑定可能アイテムリスト送信
+ * Server tells client it's list of unidentified items
*------------------------------------------*/
int clif_item_identify_list(struct map_session_data *sd)
{
@@ -5419,7 +5465,7 @@ int clif_item_identify_list(struct map_session_data *sd)
}
/*==========================================
- * 鑑定結果
+ * Server tells client his item of index 'idx' has been identified
*------------------------------------------*/
int clif_item_identified(struct map_session_data *sd,int idx,int flag)
{
@@ -5437,7 +5483,7 @@ int clif_item_identified(struct map_session_data *sd,int idx,int flag)
}
/*==========================================
- * 修理可能アイテムリスト送信
+ * Server tells client the list of broken items
*------------------------------------------*/
int clif_item_repair_list(struct map_session_data *sd,struct map_session_data *dstsd)
{
@@ -5537,7 +5583,9 @@ int clif_item_refine_list(struct map_session_data *sd)
}
/*==========================================
- * アイテムによる一時的なスキル効果
+ * Server tells client to display the 'green skill name' at the top of the screen + target cursor,
+ * for skill 'skillid' of 'skilllv' level
+ * Used for example when player uses a skill scroll (e.g. Fire Bolt Scroll)
*------------------------------------------*/
int clif_item_skill(struct map_session_data *sd,int skillid,int skilllv)
{
@@ -5561,7 +5609,7 @@ int clif_item_skill(struct map_session_data *sd,int skillid,int skilllv)
}
/*==========================================
- * カートにアイテム追加
+ * Server tells client it's status on trying to add item of index 'n' and amount 'amount' to it's cart
*------------------------------------------*/
int clif_cart_additem(struct map_session_data *sd,int n,int amount,int fail)
{
@@ -5611,7 +5659,7 @@ int clif_cart_additem(struct map_session_data *sd,int n,int amount,int fail)
}
/*==========================================
- * カートからアイテム削除
+ * Server tells client it's status on trying to remove item of index 'n' and amount 'amount' from it's cart to invent
*------------------------------------------*/
int clif_cart_delitem(struct map_session_data *sd,int n,int amount)
{
@@ -5996,10 +6044,11 @@ void clif_party_inviteack(struct map_session_data* sd, const char* nick, int res
/*==========================================
- * パーティ設定送信
- * flag & 0x001=exp変更ミス
- * 0x010=item変更ミス
- * 0x100=一人にのみ送信
+ * Server tells client (and it's party members) of a change in the party settings
+ * 'Flag' Options
+ * - 0x01 (exp)
+ * - 0x10 (item)
+ * - 0x100 (party member logged in / was added to party)
*------------------------------------------*/
int clif_party_option(struct party_data *p,struct map_session_data *sd,int flag)
{
@@ -6034,7 +6083,7 @@ int clif_party_option(struct party_data *p,struct map_session_data *sd,int flag)
return 0;
}
/*==========================================
- * パーティ脱退(脱退前に呼ぶこと)
+ * Server tells party members of party 'p' that 'sd' player left
*------------------------------------------*/
int clif_party_withdraw(struct party_data* p, struct map_session_data* sd, int account_id, const char* name, int flag)
{
@@ -6056,15 +6105,14 @@ int clif_party_withdraw(struct party_data* p, struct map_session_data* sd, int a
WBUFL(buf,2)=account_id;
memcpy(WBUFP(buf,6),name,NAME_LENGTH);
WBUFB(buf,30)=flag&0x0f;
-
if((flag&0xf0)==0)
clif_send(buf,packet_len(0x105),&sd->bl,PARTY);
- else
+ else
clif_send(buf,packet_len(0x105),&sd->bl,SELF);
return 0;
}
/*==========================================
- * パーティメッセージ送信
+ * Server deploys a message to all party members, called from party.c:party_recv_message()
*------------------------------------------*/
int clif_party_message(struct party_data* p, int account_id, const char* mes, int len)
{
@@ -6086,7 +6134,7 @@ int clif_party_message(struct party_data* p, int account_id, const char* mes, in
return 0;
}
/*==========================================
- * パーティ座標通知
+ * Server tells all party members of 'sd' player that 'sd' player location changed
*------------------------------------------*/
int clif_party_xy(struct map_session_data *sd)
{
@@ -6119,7 +6167,7 @@ int clif_party_xy_single(int fd, struct map_session_data *sd)
/*==========================================
- * パーティHP通知
+ * Server tells nearby party members of 'sd' that his hp bar has updated
*------------------------------------------*/
int clif_party_hp(struct map_session_data *sd)
{
@@ -6224,7 +6272,7 @@ int clif_hpmeter_sub(struct block_list *bl, va_list ap)
}
/*==========================================
- * GMへ場所とHP通知
+ * Server tells all nearby gms to 'sd' that 'sd' hp bar was updated
*------------------------------------------*/
int clif_hpmeter(struct map_session_data *sd)
{
@@ -6237,7 +6285,7 @@ int clif_hpmeter(struct map_session_data *sd)
}
/*==========================================
- * パーティ場所移動(未使用)
+ * (?) Server tells 'sd' party members that 'sd' state 'changed'
*------------------------------------------*/
void clif_party_move(struct party* p, struct map_session_data* sd, int online)
{
@@ -6258,7 +6306,8 @@ void clif_party_move(struct party* p, struct map_session_data* sd, int online)
clif_send(buf,packet_len(0x104),&sd->bl,PARTY);
}
/*==========================================
- * 攻撃するために移動が必要
+ * Server tells client to attack bl, if not in range of attack (rhw.range) it'll move to bl
+ * called from unit.c
*------------------------------------------*/
int clif_movetoattack(struct map_session_data *sd,struct block_list *bl)
{
@@ -6280,7 +6329,7 @@ int clif_movetoattack(struct map_session_data *sd,struct block_list *bl)
return 0;
}
/*==========================================
- * 製造エフェクト
+ * Server tells client to display produce effect (refine-like), success or failure depends on 'flag'
*------------------------------------------*/
int clif_produceeffect(struct map_session_data* sd,int flag,int nameid)
{
@@ -6331,7 +6380,7 @@ int clif_pet_roulette(struct map_session_data *sd,int data)
}
/*==========================================
- * pet卵リスト作成
+ * Server tells client to list it's eggs (used in hatching window to select a egg)
*------------------------------------------*/
int clif_sendegg(struct map_session_data *sd)
{
@@ -6461,7 +6510,7 @@ int clif_pet_food(struct map_session_data *sd,int foodid,int fail)
}
/*==========================================
- * オートスペル リスト送信
+ * Server tells client to display autospell (Sage Skill) skill selection list
*------------------------------------------*/
int clif_autospell(struct map_session_data *sd,int skilllv)
{
@@ -6549,7 +6598,7 @@ void clif_devotion(struct block_list *src, struct map_session_data *tsd)
}
/*==========================================
- * 氣球
+ * Server tells clients nearby 'sd' (and himself) to display 'sd->spiritball' number of spiritballs on 'sd'
*------------------------------------------*/
int clif_spiritball(struct map_session_data *sd)
{
@@ -6581,7 +6630,8 @@ int clif_combo_delay(struct block_list *bl,int wait)
return 0;
}
/*==========================================
- *白刃取り
+ * Server tells client to display blade stop animation 'link' from 'src' to 'dst_id' (account id of target)
+ * active toggles the state
*------------------------------------------*/
void clif_bladestop(struct block_list *src, int dst_id, int active)
{
@@ -6598,7 +6648,7 @@ void clif_bladestop(struct block_list *src, int dst_id, int active)
}
/*==========================================
- * MVPエフェクト
+ * Server tells clients nearby 'sd' (and itself) to display MvP killed effect on 'sd' player
*------------------------------------------*/
int clif_mvp_effect(struct map_session_data *sd)
{
@@ -6612,7 +6662,7 @@ int clif_mvp_effect(struct map_session_data *sd)
return 0;
}
/*==========================================
- * MVPアイテム所得
+ * Server tells client to display mvp drop prize info to player 'sd' for item id 'nameid'
*------------------------------------------*/
int clif_mvp_item(struct map_session_data *sd,int nameid)
{
@@ -6631,7 +6681,7 @@ int clif_mvp_item(struct map_session_data *sd,int nameid)
return 0;
}
/*==========================================
- * MVP経験値所得
+ * Server tells client to display mvp exp prize to player 'sd' for amount 'exp'
*------------------------------------------*/
int clif_mvp_exp(struct map_session_data *sd, unsigned int exp)
{
@@ -6693,7 +6743,7 @@ void clif_guild_belonginfo(struct map_session_data *sd, struct guild *g)
/*==========================================
- * ギルドメンバログイン通知
+ * Server tells all members of 'g' guild that member of index 'idx' is online or offline (flag 1:0)
*------------------------------------------*/
int clif_guild_memberlogin_notice(struct guild *g,int idx,int flag)
{
@@ -6755,7 +6805,7 @@ int clif_guild_send_onlineinfo(struct map_session_data *sd)
}
/*==========================================
- * ギルドマスター通知(14dへの応答)
+ * Tells 'sd' whether he is the guild master of his guild or not (relies on sd->state.gmaster_flag)
*------------------------------------------*/
int clif_guild_masterormember(struct map_session_data *sd)
{
@@ -6814,7 +6864,7 @@ int clif_guild_basicinfo(struct map_session_data *sd)
}
/*==========================================
- * ギルド同盟/敵対情報
+ * Server tells client 'sd' it's guild alliances
*------------------------------------------*/
int clif_guild_allianceinfo(struct map_session_data *sd)
{
@@ -6843,7 +6893,7 @@ int clif_guild_allianceinfo(struct map_session_data *sd)
}
/*==========================================
- * ギルドメンバーリスト
+ * Server tells client it's guild member list
*------------------------------------------*/
int clif_guild_memberlist(struct map_session_data *sd)
{
@@ -6873,7 +6923,7 @@ int clif_guild_memberlist(struct map_session_data *sd)
WFIFOL(fd,c*104+22)=(int)cap_value(m->exp,0,INT32_MAX);
WFIFOL(fd,c*104+26)=m->online;
WFIFOL(fd,c*104+30)=m->position;
- memset(WFIFOP(fd,c*104+34),0,50); // メモ?
+ memset(WFIFOP(fd,c*104+34),0,50); //[Ind] - This is displayed in the 'note' column but being you can't edit it it's sent empty.
memcpy(WFIFOP(fd,c*104+84),m->name,NAME_LENGTH);
c++;
}
@@ -6882,7 +6932,7 @@ int clif_guild_memberlist(struct map_session_data *sd)
return 0;
}
/*==========================================
- * ギルド役職名リスト
+ * Server tell client it's guild position list
*------------------------------------------*/
int clif_guild_positionnamelist(struct map_session_data *sd)
{
@@ -6905,7 +6955,7 @@ int clif_guild_positionnamelist(struct map_session_data *sd)
return 0;
}
/*==========================================
- * ギルド役職情報リスト
+ * Server tell client about it's guild position permissions and tax
*------------------------------------------*/
int clif_guild_positioninfolist(struct map_session_data *sd)
{
@@ -6931,7 +6981,7 @@ int clif_guild_positioninfolist(struct map_session_data *sd)
return 0;
}
/*==========================================
- * ギルド役職変更通知
+ * Server tells client about position 'idx' information, being it changed
*------------------------------------------*/
int clif_guild_positionchanged(struct guild *g,int idx)
{
@@ -6952,7 +7002,7 @@ int clif_guild_positionchanged(struct guild *g,int idx)
return 0;
}
/*==========================================
- * ギルドメンバ変更通知
+ * Server tells client about a specific guild member index that changed
*------------------------------------------*/
int clif_guild_memberpositionchanged(struct guild *g,int idx)
{
@@ -6971,7 +7021,7 @@ int clif_guild_memberpositionchanged(struct guild *g,int idx)
return 0;
}
/*==========================================
- * ギルドエンブレム送信
+ * Server tells client about this new cool emblem a specific guild got
*------------------------------------------*/
int clif_guild_emblem(struct map_session_data *sd,struct guild *g)
{
@@ -7076,7 +7126,7 @@ int clif_guild_notice(struct map_session_data* sd, struct guild* g)
}
/*==========================================
- * ギルドメンバ勧誘
+ * Server tells client 'sd' that guild 'g' wants to invite him
*------------------------------------------*/
int clif_guild_invite(struct map_session_data *sd,struct guild *g)
{
@@ -7116,7 +7166,7 @@ int clif_guild_inviteack(struct map_session_data *sd,int flag)
}
/*==========================================
- * ギルドメンバ脱退通知
+ * Server tells guild members of 'sd' that he left his guild for a reason
*------------------------------------------*/
int clif_guild_leave(struct map_session_data *sd,const char *name,const char *mes)
{
@@ -7132,7 +7182,7 @@ int clif_guild_leave(struct map_session_data *sd,const char *name,const char *me
}
/*==========================================
- * ギルドメンバ追放通知
+ * Server tells guild members of 'sd' that 'name' of account id 'account_id' was expelled for reason 'mes'
*------------------------------------------*/
void clif_guild_expulsion(struct map_session_data* sd, const char* name, const char* mes, int account_id)
{
@@ -7155,7 +7205,7 @@ void clif_guild_expulsion(struct map_session_data* sd, const char* name, const c
}
/*==========================================
- * ギルド追放メンバリスト
+ * Server tells client on sd's guild expulsion records
*------------------------------------------*/
void clif_guild_expulsionlist(struct map_session_data* sd)
{
@@ -7225,7 +7275,7 @@ void clif_guild_message(struct guild *g,int account_id,const char *mes,int len)
/*==========================================
- * ギルドスキル割り振り通知
+ * Server tells client 'sd' that his guild skill 'skill_num' gone to level 'lv'
*------------------------------------------*/
int clif_guild_skillup(struct map_session_data *sd,int skill_num,int lv)
{
@@ -7245,7 +7295,7 @@ int clif_guild_skillup(struct map_session_data *sd,int skill_num,int lv)
return 0;
}
/*==========================================
- * ギルド同盟要請
+ * Server tells client 'sd' that 'account_id' from guild name 'name' wants to invite 'sd's guild for alliance
*------------------------------------------*/
int clif_guild_reqalliance(struct map_session_data *sd,int account_id,const char *name)
{
@@ -7284,7 +7334,7 @@ int clif_guild_allianceack(struct map_session_data *sd,int flag)
return 0;
}
/*==========================================
- * ギルド関係解消通知
+ * Server tells client 'sd' that guild_id is either in or out of it's alliance list (depend on flag)
*------------------------------------------*/
int clif_guild_delalliance(struct map_session_data *sd,int guild_id,int flag)
{
@@ -7337,7 +7387,7 @@ int clif_guild_oppositionack(struct map_session_data *sd,int flag)
}*/
/*==========================================
- * ギルド解散通知
+ * Server tells client 'sd' that guild broke because of 'flag' reason
*------------------------------------------*/
int clif_guild_broken(struct map_session_data *sd,int flag)
{
@@ -7354,7 +7404,7 @@ int clif_guild_broken(struct map_session_data *sd,int flag)
}
/*==========================================
- * エモーション
+ * Server tells all nearby clients of 'bl' to display emoticon number 'type'
*------------------------------------------*/
void clif_emotion(struct block_list *bl,int type)
{
@@ -7369,7 +7419,7 @@ void clif_emotion(struct block_list *bl,int type)
}
/*==========================================
- * トーキーボックス
+ * Server tells all clients nearby 'bl' that he stepped in a talkie box (and displays the message)
*------------------------------------------*/
void clif_talkiebox(struct block_list* bl, const char* talkie)
{
@@ -7383,7 +7433,7 @@ void clif_talkiebox(struct block_list* bl, const char* talkie)
}
/*==========================================
- * 結婚エフェクト
+ * Server tells bl and nearby clients to display marriage effect
*------------------------------------------*/
void clif_wedding_effect(struct block_list *bl)
{
@@ -7396,7 +7446,7 @@ void clif_wedding_effect(struct block_list *bl)
clif_send(buf, packet_len(0x1ea), bl, AREA);
}
/*==========================================
- * ?なたに逢いたい使用時名前叫び
+ * Server tells client 'sd' to create a warp to call his partner (wedding skill)
*------------------------------------------*/
void clif_callpartner(struct map_session_data *sd)
@@ -7562,41 +7612,41 @@ void clif_GM_silence(struct map_session_data* sd, struct map_session_data* tsd,
}
/*==========================================
- * Wis拒否許可応答
+ * ? Unknown functionality : not called anywhere
*------------------------------------------*/
-int clif_wisexin(struct map_session_data *sd,int type,int flag)
-{
- int fd;
-
- nullpo_ret(sd);
-
- fd=sd->fd;
- WFIFOHEAD(fd,packet_len(0xd1));
- WFIFOW(fd,0)=0xd1;
- WFIFOB(fd,2)=type;
- WFIFOB(fd,3)=flag;
- WFIFOSET(fd,packet_len(0xd1));
-
- return 0;
-}
+//int clif_wisexin(struct map_session_data *sd,int type,int flag)
+//{
+// int fd;
+//
+// nullpo_ret(sd);
+//
+// fd=sd->fd;
+// WFIFOHEAD(fd,packet_len(0xd1));
+// WFIFOW(fd,0)=0xd1;
+// WFIFOB(fd,2)=type;
+// WFIFOB(fd,3)=flag;
+// WFIFOSET(fd,packet_len(0xd1));
+//
+// return 0;
+//}
/*==========================================
- * Wis全拒否許可応答
+ * ? Unknown functionality : not called anywhere
*------------------------------------------*/
-int clif_wisall(struct map_session_data *sd,int type,int flag)
-{
- int fd;
-
- nullpo_ret(sd);
-
- fd=sd->fd;
- WFIFOHEAD(fd,packet_len(0xd2));
- WFIFOW(fd,0)=0xd2;
- WFIFOB(fd,2)=type;
- WFIFOB(fd,3)=flag;
- WFIFOSET(fd,packet_len(0xd2));
-
- return 0;
-}
+//int clif_wisall(struct map_session_data *sd,int type,int flag)
+//{
+// int fd;
+//
+// nullpo_ret(sd);
+//
+// fd=sd->fd;
+// WFIFOHEAD(fd,packet_len(0xd2));
+// WFIFOW(fd,0)=0xd2;
+// WFIFOB(fd,2)=type;
+// WFIFOB(fd,3)=flag;
+// WFIFOSET(fd,packet_len(0xd2));
+//
+// return 0;
+//}
/*==========================================
* Play a BGM! [Rikter/Yommy]
@@ -7615,7 +7665,8 @@ void clif_playBGM(struct map_session_data* sd, const char* name)
}
/*==========================================
- * サウンドエフェクト
+ * Server tells 'bl' to play a .wav music file in client's /wav/ folder named 'name'
+ * functionality of 'type' is unclear. it's normally sent as '0'
*------------------------------------------*/
void clif_soundeffect(struct map_session_data* sd, struct block_list* bl, const char* name, int type)
{
@@ -8459,7 +8510,7 @@ static int clif_guess_PacketVer(int fd, int get_previous, int *error)
// ------------
// clif_parse_*
// ------------
-// パケット読み取って色々操作
+// Parses incoming (player) connection
/*==========================================
*
*------------------------------------------*/
@@ -8548,8 +8599,9 @@ void clif_parse_WantToConnection(int fd, TBL_PC* sd)
}
/*==========================================
- * 007d クライアント側マップ読み込み完了
- * map侵入時に必要なデータを全て送りつける
+ * 007d : Server/Client tells that he is able to proceed
+ * This is run by both server (from pc.c) and client (on map load/refresh
+ * (teleport/warping in same map also triggers this)
*------------------------------------------*/
void clif_parse_LoadEndAck(int fd,struct map_session_data *sd)
{
@@ -9020,9 +9072,11 @@ void clif_parse_GlobalMessage(int fd, struct map_session_data* sd)
const char* text = (char*)RFIFOP(fd,4);
int textlen = RFIFOW(fd,2) - 4;
- char *name, *message;
+ char *name, *message, *fakename = NULL;
int namelen, messagelen;
+ bool is_fake;
+
// validate packet and retrieve name and message
if( !clif_process_message(sd, 0, &name, &namelen, &message, &messagelen) )
return;
@@ -9039,21 +9093,35 @@ void clif_parse_GlobalMessage(int fd, struct map_session_data* sd)
return;
sd->cantalk_tick = gettick() + battle_config.min_chat_delay;
}
-
+ /**
+ * Fake Name Design by FatalEror (bug report #9)
+ **/
+ if( ( is_fake = ( sd->fakename[0] ) ) ) {
+ fakename = (char*) malloc(strlen(sd->fakename)+messagelen+3);
+ strcpy(fakename, sd->fakename);
+ strcat(fakename, " : ");
+ strcat(fakename, message);
+ textlen = strlen(fakename) + 1;
+ }
// send message to others (using the send buffer for temp. storage)
WFIFOHEAD(fd, 8 + textlen);
WFIFOW(fd,0) = 0x8d;
WFIFOW(fd,2) = 8 + textlen;
WFIFOL(fd,4) = sd->bl.id;
- safestrncpy((char*)WFIFOP(fd,8), text, textlen);
+ safestrncpy((char*)WFIFOP(fd,8), is_fake ? fakename : text, textlen);
//FIXME: chat has range of 9 only
clif_send(WFIFOP(fd,0), WFIFOW(fd,2), &sd->bl, sd->chatID ? CHAT_WOS : AREA_CHAT_WOC);
// send back message to the speaker
- memcpy(WFIFOP(fd,0), RFIFOP(fd,0), RFIFOW(fd,2));
- WFIFOW(fd,0) = 0x8e;
+ if( is_fake ) {
+ WFIFOW(fd,0) = 0x8e;
+ WFIFOW(fd,2) = textlen + 4;
+ safestrncpy((char*)WFIFOP(fd,4), fakename, textlen);
+ } else {
+ memcpy(WFIFOP(fd,0), RFIFOP(fd,0), RFIFOW(fd,2));
+ WFIFOW(fd,0) = 0x8e;
+ }
WFIFOSET(fd, WFIFOW(fd,2));
-
#ifdef PCRE_SUPPORT
// trigger listening npcs
map_foreachinrange(npc_chat_sub, &sd->bl, AREA_SIZE, BL_NPC, text, textlen, &sd->bl);
@@ -9837,7 +9905,7 @@ static void clif_noask_sub(struct map_session_data *src, struct map_session_data
}
/*==========================================
- * 取引要請を相手に送る
+ * Client tells server to send a trade request to char id RFIFOL(fd,2)
*------------------------------------------*/
void clif_parse_TradeRequest(int fd,struct map_session_data *sd)
{
@@ -9864,7 +9932,7 @@ void clif_parse_TradeRequest(int fd,struct map_session_data *sd)
}
/*==========================================
- * 取引要請
+ * Client tells server he replied to a trade request sent to him
*------------------------------------------*/
void clif_parse_TradeAck(int fd,struct map_session_data *sd)
{
@@ -9872,7 +9940,7 @@ void clif_parse_TradeAck(int fd,struct map_session_data *sd)
}
/*==========================================
- * アイテム追加
+ * Client tells server to add RFIFOL(fd,4) quantity of item index RFIFOW(fd,2)
*------------------------------------------*/
void clif_parse_TradeAddItem(int fd,struct map_session_data *sd)
{
@@ -9886,7 +9954,7 @@ void clif_parse_TradeAddItem(int fd,struct map_session_data *sd)
}
/*==========================================
- * アイテム追加完了(ok押し)
+ * Client tells server player he is done adding items to his trade window
*------------------------------------------*/
void clif_parse_TradeOk(int fd,struct map_session_data *sd)
{
@@ -9894,7 +9962,7 @@ void clif_parse_TradeOk(int fd,struct map_session_data *sd)
}
/*==========================================
- * 取引キャンセル
+ * Client tells server player cancelled the trade
*------------------------------------------*/
void clif_parse_TradeCancel(int fd,struct map_session_data *sd)
{
@@ -9902,7 +9970,7 @@ void clif_parse_TradeCancel(int fd,struct map_session_data *sd)
}
/*==========================================
- * 取引許諾(trade押し)
+ * Client tells server player 'locked' the trade screen (can't add/remove items)
*------------------------------------------*/
void clif_parse_TradeCommit(int fd,struct map_session_data *sd)
{
@@ -9918,7 +9986,7 @@ void clif_parse_StopAttack(int fd,struct map_session_data *sd)
}
/*==========================================
- * カートへアイテムを移す
+ * Client tells server player dragged (RFIFOL(fd,4))x of item idx RIFOFW(fd,2)-2 to cart
*------------------------------------------*/
void clif_parse_PutItemToCart(int fd,struct map_session_data *sd)
{
@@ -9929,7 +9997,7 @@ void clif_parse_PutItemToCart(int fd,struct map_session_data *sd)
pc_putitemtocart(sd,RFIFOW(fd,2)-2,RFIFOL(fd,4));
}
/*==========================================
- * カートからアイテムを出す
+ * Client tells server to take y (RFIFOL(fd,4)) amount of item (idx:RFIFOW(fd,2)-2) from cart and add to inventory
*------------------------------------------*/
void clif_parse_GetItemFromCart(int fd,struct map_session_data *sd)
{
@@ -9939,16 +10007,18 @@ void clif_parse_GetItemFromCart(int fd,struct map_session_data *sd)
}
/*==========================================
- * 付属品(鷹,ペコ,カート)をはずす
+ * Client tells server the user hit the 'OFF' button in the equip window (appears when mounting, with falcon, etc)
*------------------------------------------*/
void clif_parse_RemoveOption(int fd,struct map_session_data *sd)
{
- //Can only remove Cart/Riding/Falcon.
- pc_setoption(sd,sd->sc.option&~(OPTION_CART|OPTION_RIDING|OPTION_FALCON));
+ /**
+ * Attempts to remove these options when this function is called (will remove all available)
+ **/
+ pc_setoption(sd,sd->sc.option&~(OPTION_CART|OPTION_RIDING|OPTION_FALCON|OPTION_DRAGON|OPTION_MADOGEAR));
}
/*==========================================
- * チェンジカート
+ * Client tells server the user selected cart type 'type', comes from cart selection screen (Change Cart Skill)
*------------------------------------------*/
void clif_parse_ChangeCart(int fd,struct map_session_data *sd)
{
@@ -9968,7 +10038,7 @@ void clif_parse_ChangeCart(int fd,struct map_session_data *sd)
}
/*==========================================
- * ステータスアップ
+ * Client tells Server to process a /str, /vit, etc(others)
*------------------------------------------*/
void clif_parse_StatusUp(int fd,struct map_session_data *sd)
{
@@ -9976,7 +10046,7 @@ void clif_parse_StatusUp(int fd,struct map_session_data *sd)
}
/*==========================================
- * スキルレベルアップ
+ * Client tells server to level up skill (RFIFOW(fd,2)) by 1
*------------------------------------------*/
void clif_parse_SkillUp(int fd,struct map_session_data *sd)
{
@@ -10056,7 +10126,7 @@ static void clif_parse_UseSkillToPos_mercenary(struct mercenary_data *md, struct
}
/*==========================================
- * スキル使用(ID指定)
+ * Client tells server he'd like to use skill of id 'skillnum' and level 'skilllv' on 'target_id'
*------------------------------------------*/
void clif_parse_UseSkillToId(int fd, struct map_session_data *sd)
{
@@ -10163,7 +10233,7 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd)
}
/*==========================================
- * スキル使用(場所指定)
+ * Client tells server he'd like to use AoE skill id 'skillnum' of level 'skilllv' on 'x','y' location
*------------------------------------------*/
void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, short skilllv, short skillnum, short x, short y, int skillmoreinfo)
{
@@ -10273,7 +10343,7 @@ void clif_parse_UseSkillToPosMoreInfo(int fd, struct map_session_data *sd)
);
}
/*==========================================
- * スキル使用(map指定)
+ * (?) I *think* this one is for skills cast on self, not entirely sure
*------------------------------------------*/
void clif_parse_UseSkillMap(int fd, struct map_session_data* sd)
{
@@ -10294,7 +10364,7 @@ void clif_parse_UseSkillMap(int fd, struct map_session_data* sd)
skill_castend_map(sd,skill_num,map_name);
}
/*==========================================
- * メモ要求
+ * Client tells server he did '/memo'
*------------------------------------------*/
void clif_parse_RequestMemo(int fd,struct map_session_data *sd)
{
@@ -10302,13 +10372,12 @@ void clif_parse_RequestMemo(int fd,struct map_session_data *sd)
pc_memo(sd,-1);
}
/*==========================================
- * アイテム合成
+ * Client tells server he selected something from a crafting window (e.g. pharmacy)
*------------------------------------------*/
void clif_parse_ProduceMix(int fd,struct map_session_data *sd)
{
- if (sd->menuskill_id != AM_PHARMACY)
+ if( sd->menuskill_id != -1 && sd->menuskill_id != AM_PHARMACY && sd->menuskill_id != RK_RUNEMASTERY )
return;
-
if (pc_istrading(sd)) {
//Make it fail to avoid shop exploits where you sell something different than you see.
clif_skill_fail(sd,sd->ud.skillid,0,0);
@@ -10341,7 +10410,7 @@ void clif_parse_Cooking(int fd,struct map_session_data *sd)
sd->menuskill_val = sd->menuskill_id = 0;
}
/*==========================================
- * 武器修理
+ * Client tells server he selected something in his 'repair item list'
*------------------------------------------*/
void clif_parse_RepairItem(int fd, struct map_session_data *sd)
{
@@ -10446,7 +10515,7 @@ void clif_parse_NpcCloseClicked(int fd,struct map_session_data *sd)
}
/*==========================================
- * アイテム鑑定
+ * Client tells server he selected something in his 'magnifier item list'
*------------------------------------------*/
void clif_parse_ItemIdentify(int fd,struct map_session_data *sd)
{
@@ -10463,23 +10532,35 @@ void clif_parse_ItemIdentify(int fd,struct map_session_data *sd)
sd->menuskill_val = sd->menuskill_id = 0;
}
/*==========================================
- * 矢作成
+ * Client tells server he selected something in his 'arrow crafting list'
*------------------------------------------*/
void clif_parse_SelectArrow(int fd,struct map_session_data *sd)
{
- if (sd->menuskill_id != AC_MAKINGARROW)
- return;
if (pc_istrading(sd)) {
//Make it fail to avoid shop exploits where you sell something different than you see.
clif_skill_fail(sd,sd->ud.skillid,0,0);
sd->menuskill_val = sd->menuskill_id = 0;
return;
}
- skill_arrow_create(sd,RFIFOW(fd,2));
+ switch( sd->menuskill_id ) {
+ case AC_MAKINGARROW:
+ skill_arrow_create(sd,RFIFOW(fd,2));
+ break;
+ case WL_READING_SB:
+ skill_spellbook(sd,RFIFOW(fd,2));
+ break;
+ case GC_POISONINGWEAPON:
+ skill_poisoningweapon(sd,RFIFOW(fd,2));
+ break;
+ case NC_MAGICDECOY:
+ skill_magicdecoy(sd,RFIFOW(fd,2));
+ break;
+ }
+
sd->menuskill_val = sd->menuskill_id = 0;
}
/*==========================================
- * オートスペル受信
+ * Client tells server he selected something in his 'autospell skill list'
*------------------------------------------*/
void clif_parse_AutoSpell(int fd,struct map_session_data *sd)
{
@@ -10489,7 +10570,7 @@ void clif_parse_AutoSpell(int fd,struct map_session_data *sd)
sd->menuskill_val = sd->menuskill_id = 0;
}
/*==========================================
- * カード使用
+ * Client tells server he clicked on a card item, requests the can-add-to list
*------------------------------------------*/
void clif_parse_UseCard(int fd,struct map_session_data *sd)
{
@@ -10498,7 +10579,7 @@ void clif_parse_UseCard(int fd,struct map_session_data *sd)
clif_use_card(sd,RFIFOW(fd,2)-2);
}
/*==========================================
- * カード挿入装備選択
+ * Client tells server he selected something in his 'carding list' (the one that lists all items you got that can receive that card)
*------------------------------------------*/
void clif_parse_InsertCard(int fd,struct map_session_data *sd)
{
@@ -10508,7 +10589,7 @@ void clif_parse_InsertCard(int fd,struct map_session_data *sd)
}
/*==========================================
- * 0193 キャラID名前引き
+ * 0193 : Client asks server for nick reference to a specific char id
*------------------------------------------*/
void clif_parse_SolveCharName(int fd, struct map_session_data *sd)
{
@@ -10567,7 +10648,7 @@ void clif_parse_LocalBroadcast(int fd, struct map_session_data* sd)
}
/*==========================================
- * カプラ倉庫へ入れる
+ * Client tells server to move (item_amount) quantity of item idx (item_index) from inventory to storage
*------------------------------------------*/
void clif_parse_MoveToKafra(int fd, struct map_session_data *sd)
{
@@ -10589,7 +10670,7 @@ void clif_parse_MoveToKafra(int fd, struct map_session_data *sd)
}
/*==========================================
- * カプラ倉庫から出す
+ * Client tells server to move (item_amount) quantity of item idx (item_index) from storage to inventory
*------------------------------------------*/
void clif_parse_MoveFromKafra(int fd,struct map_session_data *sd)
{
@@ -10606,7 +10687,7 @@ void clif_parse_MoveFromKafra(int fd,struct map_session_data *sd)
}
/*==========================================
- * カプラ倉庫へカートから入れる
+ * Client tells server to move RFIFOL(fd,4) quantity of item idx RFIFOW(fd,2) from cart to storage
*------------------------------------------*/
void clif_parse_MoveToKafraFromCart(int fd, struct map_session_data *sd)
{
@@ -10623,7 +10704,7 @@ void clif_parse_MoveToKafraFromCart(int fd, struct map_session_data *sd)
}
/*==========================================
- * カプラ倉庫から出す
+ * Client tells server to move RFIFOL(fd,4) quantity of item idx RFIFOW(fd,2) from storage to cart
*------------------------------------------*/
void clif_parse_MoveFromKafraToCart(int fd, struct map_session_data *sd)
{
@@ -10640,7 +10721,7 @@ void clif_parse_MoveFromKafraToCart(int fd, struct map_session_data *sd)
}
/*==========================================
- * カプラ倉庫を閉じる
+ * Client tells server to close the kafra
*------------------------------------------*/
void clif_parse_CloseKafra(int fd, struct map_session_data *sd)
{
@@ -10771,7 +10852,7 @@ void clif_parse_ReplyPartyInvite2(int fd,struct map_session_data *sd)
}
/*==========================================
- * パーティ脱退要求
+ * Client tells server to remove itself from it's party
*------------------------------------------*/
void clif_parse_LeaveParty(int fd, struct map_session_data *sd)
{
@@ -10784,7 +10865,7 @@ void clif_parse_LeaveParty(int fd, struct map_session_data *sd)
}
/*==========================================
- * パーティ除名要求
+ * Client tells server to remove player account id RFIFOL(fd,2) with char name RFIFOP(fd,6) from his party
*------------------------------------------*/
void clif_parse_RemovePartyMember(int fd, struct map_session_data *sd)
{
@@ -10797,7 +10878,11 @@ void clif_parse_RemovePartyMember(int fd, struct map_session_data *sd)
}
/*==========================================
- * パーティ設定変更要求
+ * Client tells server to change it's party configuration
+ * - clients before 20090603
+ * -- It only may toggle exp sharing
+ * - 20090603 or newer
+ * -- It may toggle exp (RFIFOW(fd,2) and item sharing options (RFIFOB(fd,6) and RFIFOB(fd,7))
*------------------------------------------*/
void clif_parse_PartyChangeOption(int fd, struct map_session_data *sd)
{
@@ -11251,7 +11336,7 @@ void clif_parse_GuildChangeNotice(int fd, struct map_session_data* sd)
}
/*==========================================
- * ギルド勧誘
+ * Client tells server to invite account id RFIFOL(fd,2) to his guild
*------------------------------------------*/
void clif_parse_GuildInvite(int fd,struct map_session_data *sd)
{
@@ -11275,7 +11360,8 @@ void clif_parse_GuildInvite(int fd,struct map_session_data *sd)
}
/*==========================================
- * ギルド勧誘返信
+ * Client tells server his reply on the request from guild ID RFIFOL(fd,2),
+ * - based on RFIFOB(fd,6) which is either 1 (accept) or 0 (reject)
*------------------------------------------*/
void clif_parse_GuildReplyInvite(int fd,struct map_session_data *sd)
{
@@ -11283,7 +11369,7 @@ void clif_parse_GuildReplyInvite(int fd,struct map_session_data *sd)
}
/*==========================================
- * ギルド脱退
+ * Client tells server he wants to leave his current guild
*------------------------------------------*/
void clif_parse_GuildLeave(int fd,struct map_session_data *sd)
{
@@ -11351,7 +11437,7 @@ void clif_parse_GuildMessage(int fd, struct map_session_data* sd)
}
/*==========================================
- * ギルド同盟要求
+ * Client tells server he'd like to send a alliance request to account id RFIFOL(fd,2)
*------------------------------------------*/
void clif_parse_GuildRequestAlliance(int fd, struct map_session_data *sd)
{
@@ -11378,7 +11464,8 @@ void clif_parse_GuildRequestAlliance(int fd, struct map_session_data *sd)
}
/*==========================================
- * ギルド同盟要求返信
+ * Client tells server his response to the alliance request from,
+ * Guild ID RFIFOL(fd,2) based on RFIFOL(fd,6) which is 1 (accepted) or 0 (rejected)
*------------------------------------------*/
void clif_parse_GuildReplyAlliance(int fd, struct map_session_data *sd)
{
@@ -11386,7 +11473,8 @@ void clif_parse_GuildReplyAlliance(int fd, struct map_session_data *sd)
}
/*==========================================
- * ギルド関係解消
+ * Client tells server he'd like to delete alliance from guild ID RFIFOL(fd,2),
+ * RFIFOL(fd,6) returns a 1 or 0 flag but apparently it is no longer used
*------------------------------------------*/
void clif_parse_GuildDelAlliance(int fd, struct map_session_data *sd)
{
@@ -11402,7 +11490,7 @@ void clif_parse_GuildDelAlliance(int fd, struct map_session_data *sd)
}
/*==========================================
- * ギルド敵対
+ * Client tells server he'd like his guild to be set antagonist of account id RFIFOL(fd,2)'s guild
*------------------------------------------*/
void clif_parse_GuildOpposition(int fd, struct map_session_data *sd)
{
@@ -11429,7 +11517,7 @@ void clif_parse_GuildOpposition(int fd, struct map_session_data *sd)
}
/*==========================================
- * ギルド解散
+ * Client tells server he'd like to break (delete) his own guild
*------------------------------------------*/
void clif_parse_GuildBreak(int fd, struct map_session_data *sd)
{
@@ -11476,7 +11564,7 @@ void clif_parse_ChangePetName(int fd, struct map_session_data *sd)
}
/*==========================================
- * /kill <???>
+ * /kill <account_id>
* (or right click menu for GM "(name) force to quit")
* S 00cc <id>.L
*------------------------------------------*/
@@ -11997,7 +12085,7 @@ void clif_parse_PMIgnoreAll(int fd, struct map_session_data *sd)
}
/*==========================================
- * Wis拒否リスト
+ * Client tells server he'd like the server to list him his ignore list
*------------------------------------------*/
void clif_parse_PMIgnoreList(int fd,struct map_session_data *sd)
{
@@ -12015,7 +12103,7 @@ void clif_parse_PMIgnoreList(int fd,struct map_session_data *sd)
}
/*==========================================
- * スパノビの/doridoriによるSPR2倍
+ * Client tells server he did a /doridori
*------------------------------------------*/
void clif_parse_NoviceDoriDori(int fd, struct map_session_data *sd)
{
@@ -13214,7 +13302,6 @@ void clif_parse_Auction_setitem(int fd, struct map_session_data *sd)
clif_Auction_setitem(fd, idx + 2, false);
}
-
/// Result from an auction action (ZC_AUCTION_RESULT)
/// 0250 <result>.B
/// result:
@@ -14329,7 +14416,7 @@ void clif_displayexp(struct map_session_data *sd, unsigned int exp, char type, b
/// 0: Displays 'value' for 5 seconds.
/// 1: Incremental counter (1 tick/second), negated 'value' specifies start value (e.g. using -10 lets the counter start at 10).
/// 2: Decremental counter (1 tick/second), negated 'value' specifies start value (does not stop when reaching 0, but overflows).
-/// 3: Decremental counter (2 ticks/second), 'value' specifies start value (stops when reaching 0, displays at most 2 digits).
+/// 3: Decremental counter (1 tick/second), 'value' specifies start value (stops when reaching 0, displays at most 2 digits).
/// value:
/// Except for type 3 it is interpreted as seconds for displaying as DD:HH:MM:SS, HH:MM:SS, MM:SS or SS (leftmost '00' is not displayed).
void clif_showdigit(struct map_session_data* sd, unsigned char type, int value)
@@ -14886,6 +14973,183 @@ void clif_parse_debug(int fd,struct map_session_data *sd)
ShowDump(RFIFOP(fd,0), packet_len);
}
+/**
+ * Rune Knight
+ **/
+void clif_millenniumshield(struct map_session_data *sd, short shields ) {
+#if PACKETVER >= 20081217
+ unsigned char buf[10];
+
+ WBUFW(buf,0) = 0x440;
+ WBUFL(buf,2) = sd->bl.id;
+ WBUFW(buf,6) = shields;
+ WBUFW(buf,8) = 0;
+ clif_send(buf,packet_len(0x440),&sd->bl,AREA);
+#endif
+}
+/**
+ * Warlock
+ **/
+/*==========================================
+ * Spellbook list [LimitLine/3CeAM]
+ *------------------------------------------*/
+int clif_spellbook_list(struct map_session_data *sd)
+{
+ int i, c;
+ int fd;
+
+ nullpo_ret(sd);
+
+ fd = sd->fd;
+ WFIFOHEAD(fd, 8 * 8 + 8);
+ WFIFOW(fd,0) = 0x1ad;
+
+ for( i = 0, c = 0; i < MAX_INVENTORY; i ++ )
+ {
+ if( itemdb_is_spellbook(sd->status.inventory[i].nameid) )
+ {
+ WFIFOW(fd, c * 2 + 4) = sd->status.inventory[i].nameid;
+ c ++;
+ }
+ }
+
+ if( c > 0 )
+ {
+ WFIFOW(fd,2) = c * 2 + 4;
+ WFIFOSET(fd, WFIFOW(fd, 2));
+ sd->menuskill_id = WL_READING_SB;
+ sd->menuskill_val = c;
+ }
+ else
+ status_change_end(&sd->bl,SC_STOP,-1);
+
+ return 1;
+}
+/**
+ * Mechanic
+ **/
+/*==========================================
+ * Magic Decoy Material List
+ *------------------------------------------*/
+int clif_magicdecoy_list(struct map_session_data *sd, int skill_lv, short x, short y) {
+ int i, c;
+ int fd;
+
+ nullpo_ret(sd);
+
+ fd = sd->fd;
+ WFIFOHEAD(fd, 8 * 8 + 8);
+ WFIFOW(fd,0) = 0x1ad; // This is the official packet. [pakpil]
+
+ for( i = 0, c = 0; i < MAX_INVENTORY; i ++ ) {
+ if( itemdb_is_element(sd->status.inventory[i].nameid) ) {
+ WFIFOW(fd, c * 2 + 4) = sd->status.inventory[i].nameid;
+ c ++;
+ }
+ }
+ if( c > 0 ) {
+ sd->menuskill_id = NC_MAGICDECOY;
+ sd->menuskill_val = skill_lv;
+ sd->sc.comet_x = x;
+ sd->sc.comet_y = y;
+ WFIFOW(fd,2) = c * 2 + 4;
+ WFIFOSET(fd, WFIFOW(fd, 2));
+ } else {
+ clif_skill_fail(sd,NC_MAGICDECOY,0,0);
+ return 0;
+ }
+
+ return 1;
+}
+/**
+ * Guilotine Cross
+ **/
+/*==========================================
+ * Guillotine Cross Poisons List
+ *------------------------------------------*/
+int clif_poison_list(struct map_session_data *sd, int skill_lv) {
+ int i, c;
+ int fd;
+
+ nullpo_ret(sd);
+
+ fd = sd->fd;
+ WFIFOHEAD(fd, 8 * 8 + 8);
+ WFIFOW(fd,0) = 0x1ad; // This is the official packet. [pakpil]
+
+ for( i = 0, c = 0; i < MAX_INVENTORY; i ++ ) {
+ if( itemdb_is_poison(sd->status.inventory[i].nameid) ) {
+ WFIFOW(fd, c * 2 + 4) = sd->status.inventory[i].nameid;
+ c ++;
+ }
+ }
+ if( c > 0 ) {
+ sd->menuskill_id = GC_POISONINGWEAPON;
+ sd->menuskill_val = skill_lv;
+ WFIFOW(fd,2) = c * 2 + 4;
+ WFIFOSET(fd, WFIFOW(fd, 2));
+ } else {
+ clif_skill_fail(sd,GC_POISONINGWEAPON,0x2b,0);
+ return 0;
+ }
+
+ return 1;
+}
+/**
+ * Sends a new status without a tick (currently used by the new mounts)
+ **/
+int clif_status_load_notick(struct block_list *bl,int type,int flag,int val1, int val2, int val3) {
+ unsigned char buf[32];
+
+ nullpo_ret(bl);
+
+ WBUFW(buf,0)=0x043f;
+ WBUFW(buf,2)=type;
+ WBUFL(buf,4)=bl->id;
+ WBUFB(buf,8)=flag;
+ WBUFL(buf,9) = 0;
+ WBUFL(buf,13) = val1;
+ WBUFL(buf,17) = val2;
+ WBUFL(buf,21) = val3;
+
+ clif_send(buf,packet_len(WBUFW(buf,0)),bl,AREA);
+ return 0;
+}
+//Notifies FD of ID's type
+int clif_status_load_single(int fd, int id,int type,int flag,int val1, int val2, int val3) {
+ WFIFOHEAD(fd, packet_len(0x043f));
+ WFIFOW(fd,0)=0x043f;
+ WFIFOW(fd,2)=type;
+ WFIFOL(fd,4)=id;
+ WFIFOB(fd,8)=flag;
+ WFIFOL(fd,9) = 0;
+ WFIFOL(fd,13) = val1;
+ WFIFOL(fd,17) = val2;
+ WFIFOL(fd,21) = val3;
+ WFIFOSET(fd, packet_len(0x043f));
+ return 0;
+}
+// msgstringtable.txt
+// 0x291 <line>.W
+void clif_msgtable(int fd, int line) {
+ WFIFOHEAD(fd, packet_len(0x291));
+ WFIFOW(fd, 0) = 0x291;
+ WFIFOW(fd, 2) = line;
+ WFIFOSET(fd, packet_len(0x291));
+}
+
+// msgstringtable.txt
+// 0x7e2 <line>.W <value>.L
+void clif_msgtable_num(int fd, int line, int num) {
+#if PACKETVER >= 20090805
+ WFIFOHEAD(fd, packet_len(0x7e2));
+ WFIFOW(fd, 0) = 0x7e2;
+ WFIFOW(fd, 2) = line;
+ WFIFOL(fd, 4) = num;
+ WFIFOSET(fd, packet_len(0x7e2));
+#endif
+}
+
/*==========================================
* Main client packet processing function
*------------------------------------------*/
@@ -15055,7 +15319,7 @@ int clif_parse(int fd)
}
/*==========================================
- * パケットデータベース読み込み
+ * Reads packet_db.txt and setups its array reference
*------------------------------------------*/
static int packetdb_readdb(void)
{
diff --git a/src/map/clif.h b/src/map/clif.h
index 783c8f4a1..8b6271075 100644
--- a/src/map/clif.h
+++ b/src/map/clif.h
@@ -343,7 +343,7 @@ int clif_skill_estimation(struct map_session_data *sd,struct block_list *dst);
void clif_skill_warppoint(struct map_session_data* sd, short skill_num, short skill_lv, unsigned short map1, unsigned short map2, unsigned short map3, unsigned short map4);
void clif_skill_memomessage(struct map_session_data* sd, int type);
void clif_skill_teleportmessage(struct map_session_data* sd, int type);
-int clif_skill_produce_mix_list(struct map_session_data *sd, int trigger);
+int clif_skill_produce_mix_list(struct map_session_data *sd, int skillid, int trigger);
void clif_cooking_list(struct map_session_data *sd, int trigger);
int clif_produceeffect(struct map_session_data* sd,int flag,int nameid);
@@ -361,7 +361,7 @@ void clif_bladestop(struct block_list* src, int dst_id, int active);
void clif_changemapcell(int fd, int m, int x, int y, int type, enum send_target target);
int clif_status_load(struct block_list *bl,int type, int flag);
-int clif_status_change(struct block_list *bl,int type,int flag,unsigned int tick);
+int clif_status_change(struct block_list *bl,int type,int flag,unsigned int tick,int val1, int val2, int val3);
int clif_wis_message(int fd, const char* nick, const char* mes, int mes_len);
int clif_wis_end(int fd,int flag);
@@ -629,5 +629,29 @@ void clif_search_store_info_ack(struct map_session_data* sd);
void clif_search_store_info_failed(struct map_session_data* sd, unsigned char reason);
void clif_open_search_store_info(struct map_session_data* sd);
void clif_search_store_info_click_ack(struct map_session_data* sd, short x, short y);
-
+/**
+ * 3CeAM
+ **/
+void clif_msgtable(int fd, int line);
+void clif_msgtable_num(int fd, int line, int num);
+/**
+ * Rune Knight
+ **/
+void clif_millenniumshield(struct map_session_data *sd, short shields );
+/**
+ * Warlock
+ **/
+int clif_spellbook_list(struct map_session_data *sd);
+/**
+ * Mechanic
+ **/
+int clif_magicdecoy_list(struct map_session_data *sd, int skill_lv, short x, short y);
+/**
+ * Guilotine Cross
+ **/
+int clif_poison_list(struct map_session_data *sd, int skill_lv);
+/**
+ * [RRInd] for the new mounts
+ **/
+int clif_status_load_notick(struct block_list *bl,int type,int flag,int val1, int val2, int val3);
#endif /* _CLIF_H_ */
diff --git a/src/map/itemdb.c b/src/map/itemdb.c
index d8a8bb2cc..00d4176c5 100644
--- a/src/map/itemdb.c
+++ b/src/map/itemdb.c
@@ -706,7 +706,35 @@ static int itemdb_gendercheck(struct item_data *id)
return (battle_config.ignore_items_gender) ? 2 : id->sex;
}
-
+/**
+ * [RRInd]
+ * For backwards compatibility, in Renewal mode, MATK from weapons comes from the atk slot
+ * We use a ':' delimiter which, if not found, assumes the weapon does not provide any matk.
+ **/
+void itemdb_rr_split_atoi(char *str, int *atk, int *matk) {
+ int i, val[2];
+
+ for (i=0; i<2; i++) {
+ if (!str) break;
+ val[i] = atoi(str);
+ str = strchr(str,':');
+ if (str)
+ *str++=0;
+ }
+ if( i == 0 ) {
+ *atk = *matk = 0;
+ return;//no data found
+ }
+ if( i == 1 ) {//Single Value, we assume it's the ATK
+ *atk = val[0];
+ *matk = 0;
+ return;
+ }
+ //We assume we have 2 values.
+ *atk = val[0];
+ *matk = val[1];
+ return;
+}
/*==========================================
* processes one itemdb entry
*------------------------------------------*/
@@ -736,7 +764,7 @@ static bool itemdb_parse_dbrow(char** str, const char* source, int line, int scr
id->type = atoi(str[3]);
- if( id->type < 0 || id->type == IT_UNKNOWN || id->type == IT_UNKNOWN2 || ( id->type > IT_DELAYCONSUME && id->type < IT_CASH ) || id->type >= IT_MAX )
+ if( id->type < 0 || id->type == IT_UNKNOWN || id->type == IT_UNKNOWN2 || ( id->type > IT_THROWWEAPON && id->type < IT_CASH ) || id->type >= IT_MAX )
{// catch invalid item types
ShowWarning("itemdb_parse_dbrow: Invalid item type %d for item %d. IT_ETC will be used.\n", id->type, nameid);
id->type = IT_ETC;
@@ -773,7 +801,11 @@ static bool itemdb_parse_dbrow(char** str, const char* source, int line, int scr
id->value_buy, id->value_sell, nameid, id->jname);
id->weight = atoi(str[6]);
+#if RRMODE
+ itemdb_rr_split_atoi(str[7],&id->atk,&id->matk);
+#else
id->atk = atoi(str[7]);
+#endif
id->def = atoi(str[8]);
id->range = atoi(str[9]);
id->slot = atoi(str[10]);
@@ -835,7 +867,14 @@ static bool itemdb_parse_dbrow(char** str, const char* source, int line, int scr
*------------------------------------------*/
static int itemdb_readdb(void)
{
- const char* filename[] = { "item_db.txt", "item_db2.txt" };
+ /**
+ * ro-resources inheritance: item_db -> item_db_re -> item_db2 (user customs)
+ **/
+#if RRMODE
+ const char* filename[] = { "item_db.txt","item_db_re.txt","item_db2.txt" };
+#else
+ const char* filename[] = { "item_db.txt","item_db2.txt" };
+#endif
int fi;
for( fi = 0; fi < ARRAYLENGTH(filename); ++fi )
@@ -947,7 +986,11 @@ static int itemdb_readdb(void)
*======================================*/
static int itemdb_read_sqldb(void)
{
+#if RRMODE
+ const char* item_db_name[] = { item_db_db, item_db_re_db, item_db2_db };
+#else
const char* item_db_name[] = { item_db_db, item_db2_db };
+#endif
int fi;
for( fi = 0; fi < ARRAYLENGTH(item_db_name); ++fi )
diff --git a/src/map/itemdb.h b/src/map/itemdb.h
index 5b54acd67..801b81be8 100644
--- a/src/map/itemdb.h
+++ b/src/map/itemdb.h
@@ -5,6 +5,7 @@
#define _ITEMDB_H_
#include "../common/mmo.h" // ITEM_NAME_LENGTH
+#include "map.h" //RRMODE
#define MAX_RANDITEM 11000
@@ -13,6 +14,11 @@
#define MAX_SEARCH 5 //Designed for search functions, species max number of matches to display.
+/**
+ * Arch Bishop
+ **/
+#define ITEMID_ANCILLA 12333
+
#define ITEMID_YELLOW_GEMSTONE 715
#define ITEMID_RED_GEMSTONE 716
#define ITEMID_BLUE_GEMSTONE 717
@@ -50,6 +56,9 @@ struct item_data {
int equip;
int weight;
int atk;
+#if RRMODE
+ int matk;//[RRInd] -- used in RE for matk
+#endif
int def;
int range;
int slot;
@@ -61,7 +70,7 @@ struct item_data {
//Lupus: I rearranged order of these fields due to compatibility with ITEMINFO script command
// some script commands should be revised as well...
unsigned int class_base[3]; //Specifies if the base can wear this item (split in 3 indexes per type: 1-1, 2-1, 2-2)
- unsigned class_upper : 3; //Specifies if the upper-type can equip it (bitfield, 1: normal, 2: upper, 3: baby)
+ unsigned class_upper : 4; //Specifies if the upper-type can equip it (bitfield, 1: normal, 2: upper, 3: baby,4:third)
struct {
unsigned short chance;
int id;
@@ -143,4 +152,35 @@ void itemdb_reload(void);
void do_final_itemdb(void);
int do_init_itemdb(void);
+/**
+ * Rune Knight
+ **/
+enum {
+ ITEMID_NAUTHIZ = 12725,
+ ITEMID_RAIDO,
+ ITEMID_BERKANA,
+ ITEMID_ISA,
+ ITEMID_OTHILA,
+ ITEMID_URUZ,
+ ITEMID_THURISAZ,
+ ITEMID_WYRD,
+ ITEMID_HAGALAZ,
+} rune_list;
+#define itemdb_is_rune(n) (n >= ITEMID_NAUTHIZ && n <= ITEMID_HAGALAZ)
+/**
+ * Warlock
+ **/
+#define itemdb_is_spellbook(n) (n >= 6188 && n <= 6205)
+/**
+ * Ranger
+ **/
+#define ITEMID_TRAP_ALLOY 7940
+/**
+ * Mechanic
+ **/
+#define itemdb_is_element(n) (n >= 990 && n <= 993)
+/**
+ * Guilotine Cross
+ **/
+#define itemdb_is_poison(n) (n >= 12717 && n <= 12724)
#endif /* _ITEMDB_H_ */
diff --git a/src/map/map.c b/src/map/map.c
index 39077de6c..9155a11f3 100644
--- a/src/map/map.c
+++ b/src/map/map.c
@@ -68,6 +68,7 @@ Sql* mmysql_handle;
int db_use_sqldbs = 0;
char item_db_db[32] = "item_db";
char item_db2_db[32] = "item_db2";
+char item_db_re_db[32] = "item_db_re";
char mob_db_db[32] = "mob_db";
char mob_db2_db[32] = "mob_db2";
@@ -3205,6 +3206,9 @@ int map_config_read(char *cfgName)
if (strcmpi(w1, "import") == 0)
map_config_read(w2);
else
+ if (strcmpi(w1, "console_msg_log") == 0)
+ console_msg_log = atoi(w2);//[Ind]
+ else
ShowWarning("Unknown setting '%s' in file %s\n", w1, cfgName);
}
@@ -3526,41 +3530,39 @@ void do_abort(void)
/*======================================================
* Map-Server Version Screen [MC Cameri]
*------------------------------------------------------*/
-void map_helpscreen(int flag)
-{
- puts("Usage: map-server [options]");
- puts("Options:");
- puts(CL_WHITE" Commands\t\t\tDescription"CL_RESET);
- puts("-----------------------------------------------------------------------------");
- puts(" --help, --h, --?, /? Displays this help screen");
- puts(" --map-config <file> Load map-server configuration from <file>");
- puts(" --battle-config <file> Load battle configuration from <file>");
- puts(" --atcommand-config <file> Load atcommand configuration from <file>");
- puts(" --script-config <file> Load script configuration from <file>");
- puts(" --msg-config <file> Load message configuration from <file>");
- puts(" --grf-path-file <file> Load grf path file configuration from <file>");
- puts(" --sql-config <file> Load inter-server configuration from <file>");
- puts(" (SQL Only)");
- puts(" --log-config <file> Load logging configuration from <file>");
- puts(" (SQL Only)");
- puts(" --version, --v, -v, /v Displays the server's version");
- puts("\n");
- if (flag) exit(EXIT_FAILURE);
+static void map_helpscreen(bool do_exit)
+{
+ ShowInfo("Usage: %s [options]\n", SERVER_NAME);
+ ShowInfo("\n");
+ ShowInfo("Options:\n");
+ ShowInfo(" -?, -h [--help]\t\tDisplays this help screen.\n");
+ ShowInfo(" -v [--version]\t\tDisplays the server's version.\n");
+ ShowInfo(" --run-once\t\t\tCloses server after loading (testing).\n");
+ ShowInfo(" --map-config <file>\t\tAlternative map-server configuration.\n");
+ ShowInfo(" --battle-config <file>\tAlternative battle configuration.\n");
+ ShowInfo(" --atcommand-config <file>\tAlternative atcommand configuration.\n");
+ ShowInfo(" --script-config <file>\tAlternative script configuration.\n");
+ ShowInfo(" --msg-config <file>\t\tAlternative message configuration.\n");
+ ShowInfo(" --grf-path <file>\t\tAlternative GRF path configuration.\n");
+ ShowInfo(" --inter-config <file>\t\tAlternative inter-server configuration.\n");
+ ShowInfo(" --log-config <file>\t\tAlternative logging configuration.\n");
+ if( do_exit )
+ exit(EXIT_SUCCESS);
}
/*======================================================
* Map-Server Version Screen [MC Cameri]
*------------------------------------------------------*/
-void map_versionscreen(int flag)
+static void map_versionscreen(bool do_exit)
{
- ShowInfo(CL_WHITE "eAthena version %d.%02d.%02d, Athena Mod version %d" CL_RESET"\n",
- ATHENA_MAJOR_VERSION, ATHENA_MINOR_VERSION, ATHENA_REVISION,
- ATHENA_MOD_VERSION);
- ShowInfo(CL_GREEN "Website/Forum:" CL_RESET "\thttp://eathena.deltaanime.net/\n");
- ShowInfo(CL_GREEN "IRC Channel:" CL_RESET "\tirc://irc.deltaanime.net/#athena\n");
- ShowInfo("\nOpen " CL_WHITE "readme.html" CL_RESET " for more information.");
- if (ATHENA_RELEASE_FLAG) ShowNotice("This version is not for release.\n");
- if (flag) exit(EXIT_FAILURE);
+ ShowInfo(CL_WHITE"eAthena version %d.%02d.%02d, Athena Mod version %d" CL_RESET"\n", ATHENA_MAJOR_VERSION, ATHENA_MINOR_VERSION, ATHENA_REVISION, ATHENA_MOD_VERSION);
+ ShowInfo(CL_GREEN"Website/Forum:"CL_RESET"\thttp://eathena.ws/\n");
+ ShowInfo(CL_GREEN"IRC Channel:"CL_RESET"\tirc://irc.deltaanime.net/#athena\n");
+ ShowInfo("Open "CL_WHITE"readme.html"CL_RESET" for more information.\n");
+ if(ATHENA_RELEASE_FLAG)
+ ShowNotice("This version is not for release.\n");
+ if( do_exit )
+ exit(EXIT_SUCCESS);
}
/*======================================================
@@ -3591,6 +3593,16 @@ void do_shutdown(void)
}
}
+static bool map_arg_next_value(const char* option, int i, int argc)
+{
+ if( i >= argc-1 )
+ {
+ ShowWarning("Missing value for option '%s'.\n", option);
+ return false;
+ }
+
+ return true;
+}
int do_init(int argc, char *argv[])
{
@@ -3611,31 +3623,67 @@ int do_init(int argc, char *argv[])
srand(gettick());
- for (i = 1; i < argc ; i++) {
- if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "--h") == 0 || strcmp(argv[i], "--?") == 0 || strcmp(argv[i], "/?") == 0)
- map_helpscreen(1);
- else if (strcmp(argv[i], "--version") == 0 || strcmp(argv[i], "--v") == 0 || strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "/v") == 0)
- map_versionscreen(1);
- else if (strcmp(argv[i], "--map_config") == 0 || strcmp(argv[i], "--map-config") == 0)
- MAP_CONF_NAME=argv[i+1];
- else if (strcmp(argv[i],"--battle_config") == 0 || strcmp(argv[i],"--battle-config") == 0)
- BATTLE_CONF_FILENAME = argv[i+1];
- else if (strcmp(argv[i],"--atcommand_config") == 0 || strcmp(argv[i],"--atcommand-config") == 0)
- ATCOMMAND_CONF_FILENAME = argv[i+1];
- else if (strcmp(argv[i],"--script_config") == 0 || strcmp(argv[i],"--script-config") == 0)
- SCRIPT_CONF_NAME = argv[i+1];
- else if (strcmp(argv[i],"--msg_config") == 0 || strcmp(argv[i],"--msg-config") == 0)
- MSG_CONF_NAME = argv[i+1];
- else if (strcmp(argv[i],"--grf_path_file") == 0 || strcmp(argv[i],"--grf-path-file") == 0)
- GRF_PATH_FILENAME = argv[i+1];
-#ifndef TXT_ONLY
- else if (strcmp(argv[i],"--inter_config") == 0 || strcmp(argv[i],"--inter-config") == 0)
- INTER_CONF_NAME = argv[i+1];
-#endif
- else if (strcmp(argv[i],"--log_config") == 0 || strcmp(argv[i],"--log-config") == 0)
- LOG_CONF_NAME = argv[i+1];
- else if (strcmp(argv[i],"--run_once") == 0) // close the map-server as soon as its done.. for testing [Celest]
- runflag = 0;
+ for( i = 1; i < argc ; i++ )
+ {
+ const char* arg = argv[i];
+
+ if( arg[0] != '-' && ( arg[0] != '/' || arg[1] == '-' ) )
+ {// -, -- and /
+ ShowError("Unknown option '%s'.\n", argv[i]);
+ exit(EXIT_FAILURE);
+ }
+ else if( (++arg)[0] == '-' )
+ {// long option
+ arg++;
+
+ if( strcmp(arg, "help") == 0 )
+ map_helpscreen(true);
+ else if( strcmp(arg, "version") == 0 )
+ map_versionscreen(true);
+ 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 ) {
+ if( map_arg_next_value(arg, i, argc) )
+ BATTLE_CONF_FILENAME = argv[++i];
+ } 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 ) {
+ if( map_arg_next_value(arg, i, argc) )
+ SCRIPT_CONF_NAME = argv[++i];
+ } 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 ) {
+ if( map_arg_next_value(arg, i, argc) )
+ GRF_PATH_FILENAME = argv[++i];
+ } 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 ) {
+ 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]
+ runflag = CORE_ST_STOP;
+ else {
+ ShowError("Unknown option '%s'.\n", argv[i]);
+ exit(EXIT_FAILURE);
+ }
+ }
+ else switch( arg[0] )
+ {// short option
+ case '?':
+ case 'h':
+ map_helpscreen(true);
+ break;
+ case 'v':
+ map_versionscreen(true);
+ break;
+ default:
+ ShowError("Unknown option '%s'.\n", argv[i]);
+ exit(EXIT_FAILURE);
+ }
}
map_config_read(MAP_CONF_NAME);
diff --git a/src/map/map.h b/src/map/map.h
index 8e4507599..18f5f3928 100644
--- a/src/map/map.h
+++ b/src/map/map.h
@@ -10,6 +10,11 @@
#include "../common/mapindex.h"
#include "../common/db.h"
+/**
+ * [ro-resources.net]
+ **/
+#include "./RRConfig/Core.h"
+
#include <stdarg.h>
struct npc_data;
@@ -46,7 +51,7 @@ enum E_MAPSERVER_ST
#define NATURAL_HEAL_INTERVAL 500
#define MIN_FLOORITEM 2
#define MAX_FLOORITEM START_ACCOUNT_NUM
-#define MAX_LEVEL 99
+#define MAX_LEVEL 150
#define MAX_DROP_PER_MAP 48
#define MAX_IGNORE_LIST 20 // official is 14
#define MAX_VENDING 12
@@ -68,10 +73,12 @@ enum E_MAPSERVER_ST
#define JOBL_UPPER 0x1000 //4096
#define JOBL_BABY 0x2000 //8192
+#define JOBL_THIRD 0x4000 //16384
//for filtering and quick checking.
#define MAPID_UPPERMASK 0x0fff
#define MAPID_BASEMASK 0x00ff
+#define MAPID_THIRDMASK (JOBL_THIRD|MAPID_UPPERMASK)
//First Jobs
//Note the oddity of the novice:
//Super Novices are considered the 2-1 version of the novice! Novices are considered a first class type, too...
@@ -154,6 +161,31 @@ enum {
MAPID_BABY_ALCHEMIST,
MAPID_BABY_ROGUE,
MAPID_BABY_SOUL_LINKER,
+ MAPID_RUNE_KNIGHT = JOBL_THIRD|JOBL_2_1|0x1,
+ MAPID_WARLOCK,
+ MAPID_RANGER,
+ MAPID_ARCH_BISHOP,
+ MAPID_MECHANIC,
+ MAPID_GUILLOTINE_CROSS,
+ MAPID_ROYAL_GUARD = JOBL_THIRD|JOBL_2_2|0x1,
+ MAPID_SORCERER,
+ MAPID_MINSTRELWANDERER,
+ MAPID_SURA,
+ MAPID_GENETIC,
+ MAPID_SHADOW_CHASER,
+ MAPID_RUNE_KNIGHT_T = JOBL_THIRD|JOBL_UPPER|JOBL_2_1|0x1,
+ MAPID_WARLOCK_T,
+ MAPID_RANGER_T,
+ MAPID_ARCH_BISHOP_T,
+ MAPID_MECHANIC_T,
+ MAPID_GUILLOTINE_CROSS_T,
+ MAPID_ROYAL_GUARD_T = JOBL_THIRD|JOBL_UPPER|JOBL_2_2|0x1,
+ MAPID_SORCERER_T,
+ MAPID_MINSTRELWANDERER_T,
+ MAPID_SURA_T,
+ MAPID_GENETIC_T,
+ MAPID_SHADOW_CHASER_T,
+
};
//Max size for inputs to Graffiti, Talkie Box and Vending text prompts
@@ -476,7 +508,10 @@ struct map_data {
unsigned fireworks : 1;
unsigned sakura : 1; // [Valaris]
unsigned leaves : 1; // [Valaris]
- unsigned rain : 1; // [Valaris]
+ /**
+ * No longer available, keeping here just in case it's back someday. [Ind]
+ **/
+ //unsigned rain : 1; // [Valaris]
unsigned nogo : 1; // [Valaris]
unsigned nobaseexp : 1; // [Lorky] added by Lupus
unsigned nojobexp : 1; // [Lorky]
@@ -643,7 +678,6 @@ int map_random_dir(struct block_list *bl, short *x, short *y); // [Skotlex]
int cleanup_sub(struct block_list *bl, va_list ap);
-void map_helpscreen(int flag); // [Valaris]
int map_delmap(char* mapname);
void map_flags_init(void);
@@ -667,8 +701,6 @@ extern char *SCRIPT_CONF_NAME;
extern char *MSG_CONF_NAME;
extern char *GRF_PATH_FILENAME;
-extern char *map_server_dns;
-
//Useful typedefs from jA [Skotlex]
typedef struct map_session_data TBL_PC;
typedef struct npc_data TBL_NPC;
@@ -697,6 +729,7 @@ extern Sql* logmysql_handle;
extern char item_db_db[32];
extern char item_db2_db[32];
+extern char item_db_re_db[32];
extern char mob_db_db[32];
extern char mob_db2_db[32];
diff --git a/src/map/mob.c b/src/map/mob.c
index 5272b17e8..8181fb5e7 100644
--- a/src/map/mob.c
+++ b/src/map/mob.c
@@ -2163,8 +2163,12 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
merc_hom_gainexp(tmpsd[i]->hd, base_exp);
if(base_exp || job_exp)
{
- if( md->dmglog[i].flag != MDLF_PET || battle_config.pet_attack_exp_to_master )
+ if( md->dmglog[i].flag != MDLF_PET || battle_config.pet_attack_exp_to_master ) {
+#if RRMODE
+ party_renewal_exp_mod(&base_exp,&job_exp,tmpsd[i]->status.base_level,md->level);
+#endif
pc_gainexp(tmpsd[i], &md->bl, base_exp, job_exp, false);
+ }
}
if(zeny) // zeny from mobs [Valaris]
pc_getzeny(tmpsd[i], zeny);
@@ -2185,6 +2189,11 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
struct item_drop_list *dlist = ers_alloc(item_drop_list_ers, struct item_drop_list);
struct item_drop *ditem;
int drop_rate;
+#if RRMODE
+ int drop_modifier = mvp_sd ? party_renewal_drop_mod(mvp_sd->status.base_level - md->level) :
+ second_sd ? party_renewal_drop_mod(second_sd->status.base_level - md->level) :
+ third_sd ? party_renewal_drop_mod(third_sd->status.base_level - md->level) : 100;
+#endif
dlist->m = md->bl.m;
dlist->x = md->bl.x;
dlist->y = md->bl.y;
@@ -2226,7 +2235,10 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
// Increase drop rate if user has SC_ITEMBOOST
if (sd && sd->sc.data[SC_ITEMBOOST]) // now rig the drop rate to never be over 90% unless it is originally >90%.
drop_rate = max(drop_rate,cap_value((int)(0.5+drop_rate*(sd->sc.data[SC_ITEMBOOST]->val1)/100.),0,9000));
-
+#if RRMODE
+ if( drop_modifier != 100 )
+ drop_rate = drop_rate * drop_modifier / 100;
+#endif
// attempt to drop the item
if (rand() % 10000 >= drop_rate)
continue;
@@ -2437,8 +2449,11 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
delete_timer(md->deletetimer,mob_timer_delete);
md->deletetimer = INVALID_TIMER;
}
-
- mob_deleteslave(md);
+ /**
+ * Only loops if necessary (e.g. a poring would never need to loop)
+ **/
+ if( md->can_summon )
+ mob_deleteslave(md);
map_freeblock_unlock();
@@ -2700,6 +2715,10 @@ int mob_summonslave(struct mob_data *md2,int *value,int amount,int skill_id)
if(mobdb_checkid(value[0]) == 0)
return 0;
+ /**
+ * Flags this monster is able to summon; saves a worth amount of memory upon deletion
+ **/
+ md2->can_summon = 1;
while(count < 5 && mobdb_checkid(value[count])) count++;
if(count < 1) return 0;
diff --git a/src/map/mob.h b/src/map/mob.h
index 9e86b8d63..2c6d882c9 100644
--- a/src/map/mob.h
+++ b/src/map/mob.h
@@ -161,6 +161,11 @@ struct mob_data {
short skillidx;
unsigned int skilldelay[MAX_MOBSKILL];
char npc_event[EVENT_NAME_LENGTH];
+ /**
+ * Did this monster summon something?
+ * Used to flag summon deletions, saves a worth amount of memory
+ **/
+ bool can_summon : 1;
};
diff --git a/src/map/npc.c b/src/map/npc.c
index dae395876..1762bc73b 100644
--- a/src/map/npc.c
+++ b/src/map/npc.c
@@ -199,7 +199,33 @@ struct npc_data* npc_name2id(const char* name)
{
return (struct npc_data *) strdb_get(npcname_db, name);
}
-
+/**
+ * For the Secure NPC Timeout option (check RRConfig/Secure.h) [RR]
+ **/
+#if SECURE_NPCTIMEOUT
+/**
+ * Timer to check for idle time and timeout the dialog if necessary
+ **/
+int npc_rr_secure_timeout_timer(int tid, unsigned int tick, int id, intptr_t data) {
+ struct map_session_data* sd = NULL;
+ if( (sd = map_id2sd(id)) == NULL || !sd->npc_id )
+ return 0;//Not logged in anymore OR no longer attached to a npc
+
+ if( DIFF_TICK(tick,sd->npc_idle_tick) > (SECURE_NPCTIMEOUT*1000) ) {
+ /**
+ * If we still have the NPC script attached, tell it to stop.
+ **/
+ if( sd->st )
+ sd->st->state = END;
+ /**
+ * This guy's been idle for longer than allowed, close him.
+ **/
+ clif_scriptclose(sd,sd->npc_id);
+ } else //Create a new instance of ourselves to continue
+ sd->npc_idle_timer = add_timer(gettick() + (SECURE_NPCTIMEOUT_INTERVAL*1000),npc_rr_secure_timeout_timer,sd->bl.id,0);
+ return 0;
+}
+#endif
/*==========================================
* イベントキューのイベント処理
*------------------------------------------*/
@@ -1114,6 +1140,15 @@ int npc_scriptcont(struct map_session_data* sd, int id)
return 1;
}
}
+ /**
+ * For the Secure NPC Timeout option (check RRConfig/Secure.h) [RR]
+ **/
+#if SECURE_NPCTIMEOUT
+ /**
+ * Update the last NPC iteration
+ **/
+ sd->npc_idle_tick = gettick();
+#endif
run_script_main(sd->st);
return 0;
@@ -3058,8 +3093,11 @@ static const char* npc_parse_mapflag(char* w1, char* w2, char* w3, char* w4, con
map[m].flag.sakura=state;
else if (!strcmpi(w3,"leaves"))
map[m].flag.leaves=state;
- else if (!strcmpi(w3,"rain"))
- map[m].flag.rain=state;
+ /**
+ * No longer available, keeping here just in case it's back someday. [Ind]
+ **/
+ //else if (!strcmpi(w3,"rain"))
+ // map[m].flag.rain=state;
else if (!strcmpi(w3,"nightenabled"))
map[m].flag.nightenabled=state;
else if (!strcmpi(w3,"nogo"))
diff --git a/src/map/npc.h b/src/map/npc.h
index d40fb63b4..8f8d7eca9 100644
--- a/src/map/npc.h
+++ b/src/map/npc.h
@@ -157,4 +157,11 @@ int npc_cashshop_buy(struct map_session_data *sd, int nameid, int amount, int po
extern struct npc_data* fake_nd;
+/**
+ * For the Secure NPC Timeout option (check RRConfig/Secure.h) [RR]
+ **/
+#if SECURE_NPCTIMEOUT
+int npc_rr_secure_timeout_timer(int tid, unsigned int tick, int id, intptr_t data);
+#endif
+
#endif /* _NPC_H_ */
diff --git a/src/map/party.c b/src/map/party.c
index 9649505b4..f47f8e5c9 100644
--- a/src/map/party.c
+++ b/src/map/party.c
@@ -566,7 +566,7 @@ int party_member_withdraw(int party_id, int account_id, int char_id)
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 )
{
- clif_party_withdraw(p,sd,account_id,p->party.member[i].name,0x00);
+ 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]));
p->party.count--;
@@ -912,13 +912,64 @@ int party_send_xy_clear(struct party_data *p)
}
return 0;
}
-
+#if RRMODE
+/**
+ * Renewal Drop Earning Modifier
+ **/
+int party_renewal_drop_mod(int diff) {
+ if( diff >= -10 && diff <= 5 )
+ return 100;//no change.
+ if( diff > 0 ) {
+ if( diff > 5 && diff < 10 )
+ return 90;
+ if( diff > 9 && diff < 15 )
+ return 75;
+ if( diff > 14 && diff < 30 )
+ return 60;
+ } else {
+ if( diff <= -10 && diff <= -14 )
+ return 75;//75%
+ }
+ //other chases: 50%
+ return 50;
+}
+/**
+ * Renewal Experience Earning Mode
+ **/
+void party_renewal_exp_mod(unsigned int *base_exp, unsigned int *job_exp, int lvl, int moblvl) {
+ int diff = lvl - moblvl, boost = 0;
+ //-2 ~ +5: 100%
+ if( diff >= -2 && diff <= 5 )
+ return;//we don't change anything, it's 100% boost
+ //-3 ~ -10: +5% boost for each
+ if( diff >= -10 && diff <= -3 )
+ boost = 100 + (( -diff * 5 ) - 15 );
+ // 40% boost if difference is <= -10
+ else if ( diff <= -10 )
+ boost = 40;
+ else {
+ boost = ( diff > 5 && diff < 11 ) ? 95 :
+ ( diff > 10 && diff < 16 ) ? 90 :
+ ( diff > 15 && diff < 21 ) ? 85 :
+ ( diff > 20 && diff < 26 ) ? 60 :
+ ( diff > 25 && diff < 31 ) ? 35 :
+ 10;
+ }
+ if( *base_exp )
+ *base_exp = (unsigned int)cap_value(*base_exp * boost / 100, 1, UINT_MAX);
+ if( *job_exp )
+ *job_exp = (unsigned int)cap_value(*job_exp * boost / 100, 1, UINT_MAX);
+ return;
+}
+#endif
// exp share and added zeny share [Valaris]
int party_exp_share(struct party_data* p, struct block_list* src, unsigned int base_exp, unsigned int job_exp, int zeny)
{
struct map_session_data* sd[MAX_PARTY];
unsigned int i, c;
-
+#if RRMODE
+ int src_lvl = status_get_lv(src);
+#endif
nullpo_ret(p);
// count the number of players eligible for exp sharing
@@ -945,8 +996,10 @@ int party_exp_share(struct party_data* p, struct block_list* src, unsigned int b
zeny = (unsigned int) cap_value(zeny * bonus/100, INT_MIN, INT_MAX);
}
- for (i = 0; i < c; i++)
- {
+ for (i = 0; i < c; i++) {
+#if RRMODE
+ party_renewal_exp_mod(&base_exp,&job_exp,sd[i]->status.base_level,src_lvl);
+#endif
pc_gainexp(sd[i], src, base_exp, job_exp, false);
if (zeny) // zeny from mobs [Valaris]
pc_getzeny(sd[i],zeny);
diff --git a/src/map/party.h b/src/map/party.h
index 9fde5a6a4..4918d9a3a 100644
--- a/src/map/party.h
+++ b/src/map/party.h
@@ -92,4 +92,9 @@ void party_booking_update(struct map_session_data *sd, short* job);
void party_booking_search(struct map_session_data *sd, short level, short mapid, short job, unsigned long lastindex, short resultcount);
bool party_booking_delete(struct map_session_data *sd);
+#if RRMODE
+void party_renewal_exp_mod(unsigned int *base_exp, unsigned int *job_exp, int lvl, int moblvl);
+int party_renewal_drop_mod(int diff);
+#endif
+
#endif /* _PARTY_H_ */
diff --git a/src/map/pc.c b/src/map/pc.c
index b93334f35..6a6c24398 100644
--- a/src/map/pc.c
+++ b/src/map/pc.c
@@ -395,7 +395,7 @@ int pc_makesavestatus(struct map_session_data *sd)
//Only copy the Cart/Peco/Falcon options, the rest are handled via
//status change load/saving. [Skotlex]
- sd->status.option = sd->sc.option&(OPTION_CART|OPTION_FALCON|OPTION_RIDING);
+ sd->status.option = sd->sc.option&(OPTION_CART|OPTION_FALCON|OPTION_RIDING|OPTION_DRAGON|OPTION_WUGRIDER|OPTION_WUG|OPTION_MADOGEAR|OPTION_MOUNTING);
if (sd->sc.data[SC_JAILED])
{ //When Jailed, do not move last point.
@@ -765,10 +765,14 @@ int pc_isequip(struct map_session_data *sd,int n)
//Not equipable by class. [Skotlex]
if (!(1<<(sd->class_&MAPID_BASEMASK)&item->class_base[(sd->class_&JOBL_2_1)?1:((sd->class_&JOBL_2_2)?2:0)]))
return 0;
-
- //Not equipable by upper class. [Skotlex]
- if(!(1<<((sd->class_&JOBL_UPPER)?1:((sd->class_&JOBL_BABY)?2:0))&item->class_upper))
+ //Not usable by upper class. [Inkfish]
+ while( 1 ) {
+ if( item->class_upper&1 && !(sd->class_&(JOBL_UPPER|JOBL_THIRD|JOBL_BABY)) ) break;
+ if( item->class_upper&2 && sd->class_&(JOBL_UPPER|JOBL_THIRD) ) break;
+ if( item->class_upper&4 && sd->class_&JOBL_BABY ) break;
+ if( item->class_upper&8 && sd->class_&JOBL_THIRD ) break;
return 0;
+ }
return 1;
}
@@ -825,7 +829,17 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim
sd->invincible_timer = INVALID_TIMER;
sd->npc_timer_id = INVALID_TIMER;
sd->pvp_timer = INVALID_TIMER;
-
+ /**
+ * For the Secure NPC Timeout option (check RRConfig/Secure.h) [RR]
+ **/
+#if SECURE_NPCTIMEOUT
+ /**
+ * Initialize to defaults/expected
+ **/
+ sd->npc_idle_timer = INVALID_TIMER;
+ sd->npc_idle_tick = tick;
+#endif
+
sd->canuseitem_tick = tick;
sd->canusecashfood_tick = tick;
sd->canequip_tick = tick;
@@ -915,7 +929,7 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim
if (battle_config.display_version == 1){
char buf[256];
- sprintf(buf, "eAthena SVN version: %s", get_svn_revision());
+ sprintf(buf, "SVN version: %s", get_svn_revision());
clif_displaymessage(sd->fd, buf);
}
@@ -3379,7 +3393,15 @@ int pc_additem(struct map_session_data *sd,struct item *item_data,int amount)
w = data->weight*amount;
if(sd->weight + w > sd->max_weight)
return 2;
-
+ if( itemdb_is_rune(item_data->nameid) ) {
+ int rune = pc_search_inventory(sd,item_data->nameid);
+ if( ( rune >= 0 && sd->status.inventory[rune].amount + amount > MAX_RUNE ) ||
+ ( rune == -1 && amount > MAX_RUNE )
+ ) {
+ clif_msgtable(sd->fd,0x61b);
+ return 1;
+ }
+ }
i = MAX_INVENTORY;
if( itemdb_isstackable2(data) && item_data->expire_time == 0 )
@@ -3662,6 +3684,17 @@ int pc_isUseitem(struct map_session_data *sd,int n)
if( nameid >= 12153 && nameid <= 12182 && sd->md != NULL )
return 0; // Mercenary Scrolls
+ /**
+ * Only Rune Knights may use runes
+ **/
+ if( itemdb_is_rune(nameid) && (sd->class_&MAPID_THIRDMASK) != MAPID_RUNE_KNIGHT )
+ return 0;
+ /**
+ * Only GCross may use poisons
+ **/
+ 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
@@ -3685,13 +3718,14 @@ int pc_isUseitem(struct map_session_data *sd,int n)
(item->class_base[sd->class_&JOBL_2_1?1:(sd->class_&JOBL_2_2?2:0)])
))
return 0;
-
- //Not usable by upper class. [Skotlex]
- if(!(
- (1<<(sd->class_&JOBL_UPPER?1:(sd->class_&JOBL_BABY?2:0))) &
- item->class_upper
- ))
+ //Not usable by upper class. [Inkfish]
+ while( 1 ) {
+ if( item->class_upper&1 && !(sd->class_&(JOBL_UPPER|JOBL_THIRD|JOBL_BABY)) ) break;
+ if( item->class_upper&2 && sd->class_&(JOBL_UPPER|JOBL_THIRD) ) break;
+ if( item->class_upper&4 && sd->class_&JOBL_BABY ) break;
+ if( item->class_upper&8 && sd->class_&JOBL_THIRD ) break;
return 0;
+ }
//Dead Branch & Bloody Branch & Porings Box
if((log_config.branch > 0) && (nameid == 604 || nameid == 12103 || nameid == 12109))
@@ -4534,6 +4568,36 @@ int pc_jobid2mapid(unsigned short b_class)
case JOB_BABY_MONK: return MAPID_BABY_MONK;
case JOB_BABY_ALCHEMIST: return MAPID_BABY_ALCHEMIST;
case JOB_BABY_ROGUE: return MAPID_BABY_ROGUE;
+ //3.1 non-trans
+ case JOB_RUNE_KNIGHT: return MAPID_RUNE_KNIGHT;
+ case JOB_WARLOCK: return MAPID_WARLOCK;
+ case JOB_RANGER: return MAPID_RANGER;
+ case JOB_ARCH_BISHOP: return MAPID_ARCH_BISHOP;
+ case JOB_MECHANIC: return MAPID_MECHANIC;
+ case JOB_GUILLOTINE_CROSS: return MAPID_GUILLOTINE_CROSS;
+ //3.1 trans
+ case JOB_RUNE_KNIGHT_T: return MAPID_RUNE_KNIGHT_T;
+ case JOB_WARLOCK_T: return MAPID_WARLOCK_T;
+ case JOB_RANGER_T: return MAPID_RANGER_T;
+ case JOB_ARCH_BISHOP_T: return MAPID_ARCH_BISHOP_T;
+ case JOB_MECHANIC_T: return MAPID_MECHANIC_T;
+ case JOB_GUILLOTINE_CROSS_T:return MAPID_GUILLOTINE_CROSS_T;
+ //3.2 non-trans
+ case JOB_ROYAL_GUARD: return MAPID_ROYAL_GUARD;
+ case JOB_SORCERER: return MAPID_SORCERER;
+ case JOB_MINSTREL: return MAPID_MINSTRELWANDERER;
+ case JOB_WANDERER: return MAPID_MINSTRELWANDERER;
+ case JOB_SURA: return MAPID_SURA;
+ case JOB_GENETIC: return MAPID_GENETIC;
+ case JOB_SHADOW_CHASER: return MAPID_SHADOW_CHASER;
+ //3.2 trans
+ case JOB_ROYAL_GUARD_T: return MAPID_ROYAL_GUARD_T;
+ case JOB_SORCERER_T: return MAPID_SORCERER_T;
+ case JOB_MINSTREL_T: return MAPID_MINSTRELWANDERER_T;
+ case JOB_WANDERER_T: return MAPID_MINSTRELWANDERER_T;
+ case JOB_SURA_T: return MAPID_SURA_T;
+ case JOB_GENETIC_T: return MAPID_GENETIC_T;
+ case JOB_SHADOW_CHASER_T: return MAPID_SHADOW_CHASER_T;
default:
return -1;
}
@@ -4620,6 +4684,34 @@ int pc_mapid2jobid(unsigned short class_, int sex)
case MAPID_BABY_MONK: return JOB_BABY_MONK;
case MAPID_BABY_ALCHEMIST: return JOB_BABY_ALCHEMIST;
case MAPID_BABY_ROGUE: return JOB_BABY_ROGUE;
+ //3.1 non-trans
+ case MAPID_RUNE_KNIGHT: return JOB_RUNE_KNIGHT;
+ case MAPID_WARLOCK: return JOB_WARLOCK;
+ case MAPID_RANGER: return JOB_RANGER;
+ case MAPID_ARCH_BISHOP: return JOB_ARCH_BISHOP;
+ case MAPID_MECHANIC: return JOB_MECHANIC;
+ case MAPID_GUILLOTINE_CROSS:return JOB_GUILLOTINE_CROSS;
+ //3.1 trans
+ case MAPID_RUNE_KNIGHT_T: return JOB_RUNE_KNIGHT_T;
+ case MAPID_WARLOCK_T: return JOB_WARLOCK_T;
+ case MAPID_RANGER_T: return JOB_RANGER_T;
+ case MAPID_ARCH_BISHOP_T: return JOB_ARCH_BISHOP_T;
+ case MAPID_MECHANIC_T: return JOB_MECHANIC_T;
+ case MAPID_GUILLOTINE_CROSS_T:return JOB_GUILLOTINE_CROSS_T;
+ //3.2 non-trans
+ case MAPID_ROYAL_GUARD: return JOB_ROYAL_GUARD;
+ case MAPID_SORCERER: return JOB_SORCERER;
+ case MAPID_MINSTRELWANDERER:return sex?JOB_MINSTREL:JOB_WANDERER;
+ case MAPID_SURA: return JOB_SURA;
+ case MAPID_GENETIC: return JOB_GENETIC;
+ case MAPID_SHADOW_CHASER: return JOB_SHADOW_CHASER;
+ //3.2 trans
+ case MAPID_ROYAL_GUARD_T: return JOB_ROYAL_GUARD_T;
+ case MAPID_SORCERER_T: return JOB_SORCERER_T;
+ case MAPID_MINSTRELWANDERER_T:return sex?JOB_MINSTREL_T:JOB_WANDERER_T;
+ case MAPID_SURA_T: return JOB_SURA_T;
+ case MAPID_GENETIC_T: return JOB_GENETIC_T;
+ case MAPID_SHADOW_CHASER_T: return JOB_SHADOW_CHASER_T;
default:
return -1;
}
@@ -4898,7 +4990,7 @@ int pc_checkjoblevelup(struct map_session_data *sd)
status_calc_pc(sd,0);
clif_misceffect(&sd->bl,1);
if (pc_checkskill(sd, SG_DEVIL) && !pc_nextjobexp(sd))
- clif_status_change(&sd->bl,SI_DEVIL, 1, 0); //Permanent blind effect from SG_DEVIL.
+ clif_status_change(&sd->bl,SI_DEVIL, 1, 0, 0, 0, 1); //Permanent blind effect from SG_DEVIL.
npc_script_event(sd, NPCE_JOBLVUP);
return 1;
@@ -5131,7 +5223,11 @@ int pc_need_status_point(struct map_session_data* sd, int type, int val)
swap(low, high);
for ( ; low < high; low++ )
+#if RRMODE //Renewal Stat Cost Formula
+ sp += (low < 100) ? (2 + (low - 1) / 10) : (16 + 4 * ((low - 100) / 5));
+#else
sp += ( 1 + (low + 9) / 10 );
+#endif
return sp;
}
@@ -5480,7 +5576,16 @@ int pc_resetskill(struct map_session_data* sd, int flag)
i &= ~OPTION_CART;
if( i&OPTION_FALCON && pc_checkskill(sd, HT_FALCON) )
i &= ~OPTION_FALCON;
-
+ if( i&OPTION_DRAGON && pc_checkskill(sd, RK_DRAGONTRAINING) )
+ i &= ~OPTION_DRAGON;
+ if( i&OPTION_WUG && pc_checkskill(sd, RA_WUGMASTERY) )
+ i &= ~OPTION_WUG;
+ if( i&OPTION_WUGRIDER && pc_checkskill(sd, RA_WUGRIDER) )
+ i &= ~OPTION_WUGRIDER;
+ if( i&OPTION_MADOGEAR && ( sd->class_&MAPID_THIRDMASK ) == MAPID_MECHANIC )
+ i &= ~OPTION_MADOGEAR;
+ if( i&OPTION_MOUNTING )
+ i &= ~OPTION_MOUNTING;
if( i != sd->sc.option )
pc_setoption(sd, i);
@@ -6400,7 +6505,14 @@ int pc_jobchange(struct map_session_data *sd,int job, int upper)
i&=~OPTION_CART;
if(i&OPTION_FALCON && !pc_checkskill(sd, HT_FALCON))
i&=~OPTION_FALCON;
-
+ if( i&OPTION_DRAGON && !pc_checkskill(sd,RK_DRAGONTRAINING) )
+ i&=~OPTION_DRAGON;
+ if( i&OPTION_WUGRIDER && !pc_checkskill(sd,RA_WUGMASTERY) )
+ i&=~OPTION_WUGRIDER;
+ if( i&OPTION_WUG && !pc_checkskill(sd,RA_WUGMASTERY) )
+ i&=~OPTION_WUG;
+ if( i&OPTION_MADOGEAR ) //You do not need a skill for this.
+ i&=~OPTION_MADOGEAR;
if(i != sd->sc.option)
pc_setoption(sd, i);
@@ -6528,15 +6640,15 @@ int pc_setoption(struct map_session_data *sd,int type)
sd->sc.option=type;
clif_changeoption(&sd->bl);
- if (type&OPTION_RIDING && !(p_type&OPTION_RIDING) && (sd->class_&MAPID_BASEMASK) == MAPID_SWORDMAN)
- { //We are going to mount. [Skotlex]
+ if( (type&OPTION_RIDING && !(p_type&OPTION_RIDING)) || (type&OPTION_DRAGON && !(p_type&OPTION_DRAGON) && pc_checkskill(sd,RK_DRAGONTRAINING) > 0) )
+ { // Mounting
clif_status_load(&sd->bl,SI_RIDING,1);
- status_calc_pc(sd,0); //Mounting/Umounting affects walk and attack speeds.
+ status_calc_pc(sd,0);
}
- else if (!(type&OPTION_RIDING) && p_type&OPTION_RIDING && (sd->class_&MAPID_BASEMASK) == MAPID_SWORDMAN)
- { //We are going to dismount.
+ else if( (!(type&OPTION_RIDING) && p_type&OPTION_RIDING) || (!(type&OPTION_DRAGON) && p_type&OPTION_DRAGON && pc_checkskill(sd,RK_DRAGONTRAINING) > 0) )
+ { // Dismount
clif_status_load(&sd->bl,SI_RIDING,0);
- status_calc_pc(sd,0); //Mounting/Umounting affects walk and attack speeds.
+ status_calc_pc(sd,0);
}
if(type&OPTION_CART && !(p_type&OPTION_CART))
@@ -6553,11 +6665,49 @@ int pc_setoption(struct map_session_data *sd,int type)
status_calc_pc(sd,0); //Remove speed penalty.
}
+ if (type&OPTION_MOUNTING && !(p_type&OPTION_MOUNTING)) {
+ clif_status_load_notick(&sd->bl,SI_ALL_RIDING,2,1,0,0);
+ status_calc_pc(sd,0);
+ } else if (!(type&OPTION_MOUNTING) && p_type&OPTION_MOUNTING) {
+ clif_status_load_notick(&sd->bl,SI_ALL_RIDING,0,0,0,0);
+ status_calc_pc(sd,0);
+ }
+
+
if (type&OPTION_FALCON && !(p_type&OPTION_FALCON)) //Falcon ON
clif_status_load(&sd->bl,SI_FALCON,1);
else if (!(type&OPTION_FALCON) && p_type&OPTION_FALCON) //Falcon OFF
clif_status_load(&sd->bl,SI_FALCON,0);
+ if( (sd->class_&MAPID_THIRDMASK) == MAPID_RANGER ) {
+ if( type&OPTION_WUGRIDER && !(p_type&OPTION_WUGRIDER) ) { // Mounting
+ clif_status_load(&sd->bl,SI_WUGRIDER,1);
+ status_calc_pc(sd,0);
+ } else if( !(type&OPTION_WUGRIDER) && p_type&OPTION_WUGRIDER ) { // Dismount
+ clif_status_load(&sd->bl,SI_WUGRIDER,0);
+ status_calc_pc(sd,0);
+ }
+ }
+ if( (sd->class_&MAPID_THIRDMASK) == MAPID_MECHANIC ) {
+ if( type&OPTION_MADOGEAR && !(p_type&OPTION_MADOGEAR) ) {
+ status_calc_pc(sd, 0);
+ status_change_end(&sd->bl,SC_MAXIMIZEPOWER,-1);
+ status_change_end(&sd->bl,SC_OVERTHRUST,-1);
+ status_change_end(&sd->bl,SC_WEAPONPERFECTION,-1);
+ status_change_end(&sd->bl,SC_ADRENALINE,-1);
+ status_change_end(&sd->bl,SC_CARTBOOST,-1);
+ status_change_end(&sd->bl,SC_MELTDOWN,-1);
+ status_change_end(&sd->bl,SC_MAXOVERTHRUST,-1);
+ } else if( !(type&OPTION_MADOGEAR) && p_type&OPTION_MADOGEAR ) {
+ status_calc_pc(sd, 0);
+ status_change_end(&sd->bl,SC_SHAPESHIFT,-1);
+ status_change_end(&sd->bl,SC_HOVERING,-1);
+ status_change_end(&sd->bl,SC_ACCELERATION,-1);
+ status_change_end(&sd->bl,SC_OVERHEAT_LIMITPOINT,-1);
+ status_change_end(&sd->bl,SC_OVERHEAT,-1);
+ }
+ }
+
if (type&OPTION_FLYING && !(p_type&OPTION_FLYING))
new_look = JOB_STAR_GLADIATOR2;
else if (!(type&OPTION_FLYING) && p_type&OPTION_FLYING)
@@ -6644,7 +6794,7 @@ int pc_setriding(TBL_PC* sd, int flag)
if( pc_checkskill(sd,KN_RIDING) > 0 ) // ライディングスキル所持
pc_setoption(sd, sd->sc.option|OPTION_RIDING);
} else if( pc_isriding(sd) ){
- pc_setoption(sd, sd->sc.option&~OPTION_RIDING);
+ pc_setoption(sd, sd->sc.option&~OPTION_RIDING);
}
return 0;
@@ -7801,6 +7951,30 @@ void pc_setstand(struct map_session_data *sd){
sd->state.dead_sit = sd->vd.dead_sit = 0;
}
+/**
+ * Mechanic (MADO GEAR)
+ **/
+void pc_overheat(struct map_session_data *sd, int val) {
+ int heat = val, skill,
+ limit[] = { 10, 20, 28, 46, 66 };
+
+ if( !(sd->sc.option&OPTION_MADOGEAR) || sd->sc.data[SC_OVERHEAT] )
+ return; // already burning
+
+ skill = cap_value(pc_checkskill(sd,NC_MAINFRAME),0,4);
+ if( sd->sc.data[SC_OVERHEAT_LIMITPOINT] ) {
+ heat += sd->sc.data[SC_OVERHEAT_LIMITPOINT]->val1;
+ status_change_end(&sd->bl,SC_OVERHEAT_LIMITPOINT,-1);
+ }
+
+ heat = max(0,heat); // Avoid negative HEAT
+ if( heat >= limit[skill] )
+ sc_start(&sd->bl,SC_OVERHEAT,100,0,1000);
+ else
+ sc_start(&sd->bl,SC_OVERHEAT_LIMITPOINT,100,heat,30000);
+
+ return;
+}
int pc_split_str(char *str,char **val,int num)
{
int i;
@@ -8060,7 +8234,11 @@ int pc_readdb(void)
// スキルツリ?
memset(statp,0,sizeof(statp));
i=1;
+#if RRMODE
+ sprintf(line, "%s/statpoint_renewal.txt", db_path);
+#else
sprintf(line, "%s/statpoint.txt", db_path);
+#endif
fp=fopen(line,"r");
if(fp == NULL){
ShowWarning("Can't read '"CL_WHITE"%s"CL_RESET"'... Generating DB.\n",line);
@@ -8079,7 +8257,11 @@ int pc_readdb(void)
i++;
}
fclose(fp);
+ #if RRMODE
+ ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n","statpoint_renewal.txt");
+ #else
ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n","statpoint.txt");
+ #endif
}
// generate the remaining parts of the db if necessary
k = battle_config.use_statpoint_table; //save setting
diff --git a/src/map/pc.h b/src/map/pc.h
index 4d1e929a0..51588c842 100644
--- a/src/map/pc.h
+++ b/src/map/pc.h
@@ -21,6 +21,9 @@
#define MAX_PC_SKILL_REQUIRE 5
#define MAX_PC_FEELHATE 3
+//For Warlock
+#define MAX_SPELLBOOK 10
+
struct weapon_data {
int atkmods[3];
// all the variables except atkmods get zero'ed in each call of status_calc_pc
@@ -405,6 +408,13 @@ struct map_session_data {
bool changed; // if true, should sync with charserver on next mailbox request
} mail;
+ // Reading SpellBook
+ struct {
+ unsigned short skillid;
+ unsigned char level;
+ unsigned char points;
+ } rsb[MAX_SPELLBOOK];
+
//Quest log system [Kevin] [Inkfish]
int num_quests;
int avail_quests;
@@ -420,13 +430,33 @@ struct map_session_data {
unsigned int bg_id;
unsigned short user_font;
+ /**
+ * For the Secure NPC Timeout option (check RRConfig/Secure.h) [RR]
+ **/
+#if SECURE_NPCTIMEOUT
+ /**
+ * ID of the timer
+ * @info
+ * - value is -1 (INVALID_TIMER constant) when not being used
+ * - timer is cancelled upon closure of the current npc's instance
+ **/
+ int npc_idle_timer;
+ /**
+ * Tick on the last recorded NPC iteration (next/menu/whatever)
+ * @info
+ * - It is updated on every NPC iteration as mentioned above
+ **/
+ unsigned int npc_idle_tick;
+#endif
+
// temporary debugging of bug #3504
const char* delunit_prevfile;
int delunit_prevline;
};
//Update this max as necessary. 55 is the value needed for Super Baby currently
-#define MAX_SKILL_TREE 55
+//Raised to 75 due to 3rds
+#define MAX_SKILL_TREE 75
//Total number of classes (for data storage)
#define CLASS_COUNT (JOB_MAX - JOB_NOVICE_HIGH + JOB_MAX_BASIC)
@@ -538,7 +568,12 @@ enum equip_index {
#define pc_isinvisible(sd) ( (sd)->sc.option&OPTION_INVISIBLE )
#define pc_is50overweight(sd) ( (sd)->weight*100 >= (sd)->max_weight*battle_config.natural_heal_weight_rate )
#define pc_is90overweight(sd) ( (sd)->weight*10 >= (sd)->max_weight*9 )
-#define pc_maxparameter(sd) ( (sd)->class_&JOBL_BABY ? battle_config.max_baby_parameter : battle_config.max_parameter )
+#define pc_maxparameter(sd) ( (sd)->class_&JOBL_THIRD ? battle_config.max_third_parameter : (sd)->class_&JOBL_BABY ? battle_config.max_baby_parameter : battle_config.max_parameter )
+/**
+ * Ranger
+ **/
+#define pc_iswug(sd) ( (sd)->sc.option&OPTION_WUG )
+#define pc_isridingwug(sd) ( (sd)->sc.option&OPTION_WUGRIDER )
#define pc_stop_walking(sd, type) unit_stop_walking(&(sd)->bl, type)
#define pc_stop_attack(sd) unit_stop_attack(&(sd)->bl)
@@ -550,7 +585,8 @@ enum equip_index {
#define pcdb_checkid(class_) \
( \
( (class_) >= JOB_NOVICE && (class_) < JOB_MAX_BASIC ) \
-|| ( (class_) >= JOB_NOVICE_HIGH && (class_) < JOB_MAX ) \
+|| ( (class_) >= JOB_NOVICE_HIGH && (class_) <= JOB_SOUL_LINKER ) \
+|| ( (class_) >= JOB_RUNE_KNIGHT && (class_) < JOB_MAX ) \
)
int pc_class2idx(int class_);
@@ -785,5 +821,8 @@ void pc_inventory_rental_add(struct map_session_data *sd, int seconds);
int pc_read_motd(void); // [Valaris]
int pc_disguise(struct map_session_data *sd, int class_);
-
+/**
+ * Mechanic (Mado Gear)
+ **/
+void pc_overheat(struct map_session_data *sd, int val);
#endif /* _PC_H_ */
diff --git a/src/map/script.c b/src/map/script.c
index 151535c2f..452212a7d 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -325,7 +325,10 @@ enum {
MF_FOG,
MF_SAKURA,
MF_LEAVES,
- MF_RAIN, //20
+ /**
+ * No longer available, keeping here just in case it's back someday. [Ind]
+ **/
+ //MF_RAIN, //20
// 21 free
MF_NOGO = 22,
MF_CLOUDS,
@@ -3365,7 +3368,18 @@ static void script_detach_state(struct script_state* st, bool dequeue_event)
{
sd->st = st->bk_st;
sd->npc_id = st->bk_npcid;
-
+ /**
+ * For the Secure NPC Timeout option (check RRConfig/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)
{
//Remove tag for removal.
@@ -3407,6 +3421,14 @@ static void script_attach_state(struct script_state* st)
}
sd->st = st;
sd->npc_id = st->oid;
+/**
+ * For the Secure NPC Timeout option (check RRConfig/Secure.h) [RR]
+ **/
+#if SECURE_NPCTIMEOUT
+ if( sd->npc_idle_timer == INVALID_TIMER )
+ sd->npc_idle_timer = add_timer(gettick() + (SECURE_NPCTIMEOUT_INTERVAL*1000),npc_rr_secure_timeout_timer,sd->bl.id,0);
+ sd->npc_idle_tick = gettick();
+#endif
}
}
@@ -7549,7 +7571,7 @@ BUILDIN_FUNC(checkriding)
if( sd == NULL )
return 0;// no player attached, report source
- if( pc_isriding(sd) )
+ if( pc_isriding(sd) || sd->sc.option&OPTION_MOUNTING )
script_pushint(st, 1);
else
script_pushint(st, 0);
@@ -7771,7 +7793,7 @@ BUILDIN_FUNC(produce)
return 0;
trigger=script_getnum(st,2);
- clif_skill_produce_mix_list(sd, trigger);
+ clif_skill_produce_mix_list(sd, -1, trigger);
return 0;
}
/*==========================================
@@ -9146,7 +9168,7 @@ BUILDIN_FUNC(roclass)
}
/*==========================================
- *携帯卵孵化機使用
+ * Tells client to open a hatching window, used for pet incubator
*------------------------------------------*/
BUILDIN_FUNC(birthpet)
{
@@ -9616,7 +9638,10 @@ BUILDIN_FUNC(getmapflag)
case MF_FIREWORKS: script_pushint(st,map[m].flag.fireworks); break;
case MF_SAKURA: script_pushint(st,map[m].flag.sakura); break;
case MF_LEAVES: script_pushint(st,map[m].flag.leaves); break;
- case MF_RAIN: script_pushint(st,map[m].flag.rain); break;
+ /**
+ * No longer available, keeping here just in case it's back someday. [Ind]
+ **/
+ //case MF_RAIN: script_pushint(st,map[m].flag.rain); break;
case MF_NIGHTENABLED: script_pushint(st,map[m].flag.nightenabled); break;
case MF_NOGO: script_pushint(st,map[m].flag.nogo); break;
case MF_NOBASEEXP: script_pushint(st,map[m].flag.nobaseexp); break;
@@ -9686,7 +9711,10 @@ BUILDIN_FUNC(setmapflag)
case MF_FIREWORKS: map[m].flag.fireworks=1; break;
case MF_SAKURA: map[m].flag.sakura=1; break;
case MF_LEAVES: map[m].flag.leaves=1; break;
- case MF_RAIN: map[m].flag.rain=1; break;
+ /**
+ * No longer available, keeping here just in case it's back someday. [Ind]
+ **/
+ //case MF_RAIN: map[m].flag.rain=1; break;
case MF_NIGHTENABLED: map[m].flag.nightenabled=1; break;
case MF_NOGO: map[m].flag.nogo=1; break;
case MF_NOBASEEXP: map[m].flag.nobaseexp=1; break;
@@ -9753,7 +9781,10 @@ BUILDIN_FUNC(removemapflag)
case MF_FIREWORKS: map[m].flag.fireworks=0; break;
case MF_SAKURA: map[m].flag.sakura=0; break;
case MF_LEAVES: map[m].flag.leaves=0; break;
- case MF_RAIN: map[m].flag.rain=0; break;
+ /**
+ * No longer available, keeping here just in case it's back someday. [Ind]
+ **/
+ //case MF_RAIN: map[m].flag.rain=0; break;
case MF_NIGHTENABLED: map[m].flag.nightenabled=0; break;
case MF_NOGO: map[m].flag.nogo=0; break;
case MF_NOBASEEXP: map[m].flag.nobaseexp=0; break;
@@ -14951,8 +14982,133 @@ BUILDIN_FUNC(searchstores)
searchstore_open(sd, uses, effect);
return 0;
}
+/// Displays a number as large digital clock.
+/// showdigit <value>[,<type>];
+BUILDIN_FUNC(showdigit)
+{
+ unsigned int type = 0;
+ int value;
+ struct map_session_data* sd;
+
+ if( ( sd = script_rid2sd(st) ) == NULL )
+ {
+ return 0;
+ }
+
+ value = script_getnum(st,2);
+
+ if( script_hasdata(st,3) )
+ {
+ type = script_getnum(st,3);
+ if( type > 3 )
+ {
+ ShowError("buildin_showdigit: Invalid type %u.\n", type);
+ return 1;
+ }
+ }
+ clif_showdigit(sd, (unsigned char)type, value);
+ return 0;
+}
+/**
+ * Rune Knight
+ **/
+BUILDIN_FUNC(makerune) {
+ TBL_PC* sd;
+ if( (sd = script_rid2sd(st)) == NULL )
+ return 0;
+ clif_skill_produce_mix_list(sd,RK_RUNEMASTERY,24);
+ sd->itemid = script_getnum(st,2);
+ return 0;
+}
+/**
+ * checkdragon() returns 1 if mounting a dragon or 0 otherwise.
+ **/
+BUILDIN_FUNC(checkdragon) {
+ TBL_PC* sd;
+ if( (sd = script_rid2sd(st)) == NULL )
+ return 0;
+ if( sd->sc.option&OPTION_DRAGON )
+ script_pushint(st,1);
+ else
+ script_pushint(st,0);
+ return 0;
+}
+/**
+ * setdragon({optional Color}) returns 1 on success or 0 otherwise
+ * - Toggles the dragon on a RK if he can mount;
+ * @param Color - when not provided uses the green dragon;
+ * - 1 : Green Dragon
+ * - 2 : Brown Dragon
+ * - 3 : Gray Dragon
+ * - 4 : Blue Dragon
+ * - 5 : Red Dragon
+ **/
+BUILDIN_FUNC(setdragon) {
+ TBL_PC* sd;
+ int color = script_hasdata(st,2) ? script_getnum(st,2) : 0;
+ unsigned int option = OPTION_DRAGON1;
+ if( (sd = script_rid2sd(st)) == NULL )
+ return 0;
+ if( !pc_checkskill(sd,RK_DRAGONTRAINING) || (sd->class_&MAPID_THIRDMASK) != MAPID_RUNE_KNIGHT )
+ script_pushint(st,0);//Doesn't have the skill or it's not a Rune Knight
+ else if ( sd->sc.option&OPTION_DRAGON ) {//Is mounted; release
+ pc_setoption(sd, sd->sc.option&~OPTION_DRAGON);
+ script_pushint(st,1);
+ } else {//Not mounted; Mount now.
+ if( color ) {
+ option = ( color == 1 ? OPTION_DRAGON1 :
+ color == 2 ? OPTION_DRAGON2 :
+ color == 3 ? OPTION_DRAGON3 :
+ color == 4 ? OPTION_DRAGON4 :
+ color == 5 ? OPTION_DRAGON5 : 0);
+ if( !option ) {
+ ShowWarning("script_setdragon: Unknown Color %d used; changing to green (1)\n",color);
+ option = OPTION_DRAGON1;
+ }
+ }
+ pc_setoption(sd, sd->sc.option|option);
+ script_pushint(st,1);
+ }
+ return 0;
+}
+
+/**
+ * ismounting() returns 1 if mounting a new mount or 0 otherwise
+ **/
+BUILDIN_FUNC(ismounting) {
+ TBL_PC* sd;
+ if( (sd = script_rid2sd(st)) == NULL )
+ return 0;
+ if( sd->sc.option&OPTION_MOUNTING )
+ script_pushint(st,1);
+ else
+ script_pushint(st,0);
+ return 0;
+}
+
+/**
+ * setmounting() returns 1 on success or 0 otherwise
+ * - Toggles new mounts on a player when he can mount
+ * - Will fail if the player is mounting a non-new mount, e.g. dragon, peco, wug, etc.
+ * - Will unmount the player is he is already mounting
+ **/
+BUILDIN_FUNC(setmounting) {
+ TBL_PC* sd;
+ if( (sd = script_rid2sd(st)) == NULL )
+ return 0;
+ if( sd->sc.option&(OPTION_WUGRIDER|OPTION_RIDING|OPTION_DRAGON|OPTION_MADOGEAR) )
+ script_pushint(st,0);//can't mount with one of these
+ else {
+ if( sd->sc.option&OPTION_MOUNTING )
+ pc_setoption(sd, sd->sc.option&~OPTION_MOUNTING);//release mount
+ else
+ pc_setoption(sd, sd->sc.option|OPTION_MOUNTING);//mount
+ script_pushint(st,1);//in both cases, return 1.
+ }
+ return 0;
+}
// declarations that were supposed to be exported from npc_chat.c
#ifdef PCRE_SUPPORT
BUILDIN_FUNC(defpattern);
@@ -15317,6 +15473,7 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(pushpc,"ii"),
BUILDIN_DEF(buyingstore,"i"),
BUILDIN_DEF(searchstores,"ii"),
+ BUILDIN_DEF(showdigit,"i?"),
// WoE SE
BUILDIN_DEF(agitstart2,""),
BUILDIN_DEF(agitend2,""),
@@ -15348,7 +15505,14 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(instance_npcname,"s?"),
BUILDIN_DEF(has_instance,"s?"),
BUILDIN_DEF(instance_warpall,"sii?"),
-
+ /**
+ * 3rd-related
+ **/
+ BUILDIN_DEF(makerune,"i"),
+ BUILDIN_DEF(checkdragon,""),//[Ind]
+ BUILDIN_DEF(setdragon,"?"),//[Ind]
+ BUILDIN_DEF(ismounting,""),//[Ind]
+ BUILDIN_DEF(setmounting,""),//[Ind]
//Quest Log System [Inkfish]
BUILDIN_DEF(setquest, "i"),
BUILDIN_DEF(erasequest, "i"),
diff --git a/src/map/skill.c b/src/map/skill.c
index 28bb9e389..41c3580ae 100644
--- a/src/map/skill.c
+++ b/src/map/skill.c
@@ -59,11 +59,23 @@ struct s_skill_db skill_db[MAX_SKILL_DB];
struct s_skill_produce_db skill_produce_db[MAX_SKILL_PRODUCE_DB];
struct s_skill_arrow_db skill_arrow_db[MAX_SKILL_ARROW_DB];
struct s_skill_abra_db skill_abra_db[MAX_SKILL_ABRA_DB];
+//Warlock
+struct s_skill_spellbook_db {
+ int nameid;
+ int skillid;
+ int points;
+};
+
+struct s_skill_spellbook_db skill_spellbook_db[MAX_SKILL_SPELLBOOK_DB];
+//Guillotine Cross
+struct s_skill_magicmushroom_db skill_magicmushroom_db[MAX_SKILL_MAGICMUSHROOM_DB];
struct s_skill_unit_layout skill_unit_layout[MAX_SKILL_UNIT_LAYOUT];
int firewall_unit_pos;
int icewall_unit_pos;
-
+int earthstrain_unit_pos;
+//early declaration
+int skill_stasis_check(struct block_list *bl, int src_id, int skillid);
//Since only mob-casted splash skills can hit ice-walls
static inline int splash_target(struct block_list* bl)
{
@@ -170,6 +182,7 @@ int skill_get_unit_target( int id ) { skill_get (skill_db[id].unit_target&
int skill_get_unit_bl_target( int id ) { skill_get (skill_db[id].unit_target&BL_ALL, id, 1); }
int skill_get_unit_flag( int id ) { skill_get (skill_db[id].unit_flag, id, 1); }
int skill_get_unit_layout_type( int id ,int lv ){ skill_get (skill_db[id].unit_layout_type[lv-1], id, lv); }
+int skill_get_cooldown( int id ,int lv ) { skill_get (skill_db[id].cooldown[lv-1], id, lv); }
int skill_tree_get_max(int id, int b_class)
{
@@ -241,6 +254,12 @@ int skill_get_range2 (struct block_list *bl, int id, int lv)
case MA_CHARGEARROW:
case SN_FALCONASSAULT:
case HT_POWER:
+ /**
+ * Ranger
+ **/
+ case RA_ARROWSTORM:
+ case RA_AIMEDBOLT:
+ case RA_WUGBITE:
if( bl->type == BL_PC )
range += pc_checkskill((TBL_PC*)bl, AC_VULTURE);
else
@@ -261,6 +280,36 @@ int skill_get_range2 (struct block_list *bl, int id, int lv)
if (bl->type == BL_PC)
range = skill_get_range(NJ_SHADOWJUMP,pc_checkskill((TBL_PC*)bl,NJ_SHADOWJUMP));
break;
+ /**
+ * Warlock
+ **/
+ case WL_WHITEIMPRISON:
+ case WL_SOULEXPANSION:
+ case WL_FROSTMISTY:
+ case WL_MARSHOFABYSS:
+ case WL_SIENNAEXECRATE:
+ case WL_DRAINLIFE:
+ case WL_CRIMSONROCK:
+ case WL_HELLINFERNO:
+ case WL_COMET:
+ case WL_CHAINLIGHTNING:
+ case WL_TETRAVORTEX:
+ case WL_RELEASE:
+ if( bl->type == BL_PC )
+ range += pc_checkskill((TBL_PC*)bl, WL_RADIUS);
+ break;
+ /**
+ * Ranger Bonus
+ **/
+ case HT_LANDMINE:
+ case HT_FREEZINGTRAP:
+ case HT_BLASTMINE:
+ case HT_CLAYMORETRAP:
+ case RA_CLUSTERBOMB:
+ case RA_FIRINGTRAP:
+ case RA_ICEBOUNDTRAP:
+ if( bl->type == BL_PC )
+ range += (1 + pc_checkskill((TBL_PC*)bl, RA_RESEARCHTRAP))/2;
}
if( !range && bl->type != BL_PC )
@@ -291,14 +340,25 @@ int skill_calc_heal(struct block_list *src, struct block_list *target, int skill
default:
if (skill_lv >= battle_config.max_heal_lv)
return battle_config.max_heal;
-
- hp = ( status_get_lv(src)+status_get_int(src) )/8 *(4+ skill_lv*8);
+ #if RRMODE
+ /**
+ * Renewal Heal Formula (from Doddler)
+ * TODO: whats that( 1+ %Modifier / 100 ) ? currently using 'x1' (100/100) until found out
+ * - Min = ( [ ( BaseLvl + INT ) / 5 ] * 30 ) * (1+( %Modifier / 100)) * (HealLvl * 0.1) + StatusMATK + EquipMATK - [(WeaponMATK * WeaponLvl) / 10]
+ * - Max = ( [ ( BaseLvl + INT ) / 5 ] * 30 ) * (1+( %Modifier / 100)) * (HealLvl * 0.1) + StatusMATK + EquipMATK + [(WeaponMATK * WeaponLvl) / 10]
+ **/
+ hp = ( ( ( ( status_get_lv(src) + status_get_int(src) ) / 5 ) * 30 ) * ( skill_lv / 10 ) + status_get_matk_min(src) + status_get_matk_max(src) - ( ( status_get_matk_max(src) * status_get_wlv(src) ) / 10 ) ) + rand()%( ( ( ( status_get_lv(src) + status_get_int(src) ) / 5 ) * 30 ) * ( skill_lv / 10 ) + status_get_matk_min(src) + status_get_matk_max(src) + ( ( status_get_matk_max(src) * status_get_wlv(src) ) / 10 ) );
+ #else
+ hp = ( status_get_lv(src) + status_get_int(src) ) / 8 * (4 + ( skill_id == AB_HIGHNESSHEAL ? ( sd ? pc_checkskill(sd,AL_HEAL) : 10 ) : skill_lv ) * 8);
+ #endif
if( sd && ((skill = pc_checkskill(sd, HP_MEDITATIO)) > 0) )
hp += hp * skill * 2 / 100;
else if( src->type == BL_HOM && (skill = merc_hom_checkskill(((TBL_HOM*)src), HLIF_BRAIN)) > 0 )
hp += hp * skill * 2 / 100;
break;
}
+ if( skill_id == AB_HIGHNESSHEAL )
+ hp = (hp * (20 + 3 * (skill_lv - 1))) / 10;
if( ( (target && target->type == BL_MER) || !heal ) && skill_id != NPC_EVILLAND )
hp >>= 1;
@@ -378,6 +438,9 @@ int skillnotok (int skillid, struct map_session_data *sd)
if(map[m].flag.restricted && map[m].zone && skill_get_nocast (skillid) & (8*map[m].zone))
return 1;
+ if( sd->sc.option&OPTION_MOUNTING )
+ return 1;//You can't use skills while in the new mounts (The client doesn't let you, this is to make cheat-safe)
+
switch (skillid) {
case AL_WARP:
if(map[m].flag.nowarp) {
@@ -410,6 +473,12 @@ int skillnotok (int skillid, struct map_session_data *sd)
return 1;
}
break;
+ case GC_DARKILLUSION:
+ if( map_flag_gvg(m) ) {
+ clif_skill_fail(sd,skillid,0,0);
+ return 1;
+ }
+ break;
case GD_EMERGENCYCALL:
if (
!(battle_config.emergency_call&((agit_flag || agit2_flag)?2:1)) ||
@@ -420,6 +489,23 @@ int skillnotok (int skillid, struct map_session_data *sd)
return 1;
}
break;
+ case BS_GREED:
+ case WS_CARTBOOST:
+ case BS_HAMMERFALL:
+ case BS_ADRENALINE:
+ case MC_CARTREVOLUTION:
+ case MC_MAMMONITE:
+ case WS_MELTDOWN:
+ case MG_SIGHT:
+ case TF_HIDING:
+ /**
+ * These skills cannot be used while in mado gear (credits to Xantara)
+ **/
+ if(sd->sc.option&OPTION_MADOGEAR) {
+ clif_skill_fail(sd,skillid,0,0);
+ return 1;
+ }
+ break;
}
return (map[m].flag.noskill);
}
@@ -471,6 +557,8 @@ struct s_skill_unit_layout* skill_get_unit_layout (int skillid, int skilllv, str
return &skill_unit_layout [firewall_unit_pos + dir];
else if (skillid == WZ_ICEWALL)
return &skill_unit_layout [icewall_unit_pos + dir];
+ else if( skillid == WL_EARTHSTRAIN ) //Warlock
+ return &skill_unit_layout [earthstrain_unit_pos + dir];
ShowError("skill_get_unit_layout: unknown unit layout for skill %d (level %d)\n", skillid, skilllv);
return &skill_unit_layout[0]; // default 1x1 layout
@@ -587,6 +675,9 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, int
rate=(sd->status.job_level+9)/10;
skill_castend_damage_id(src,bl,HT_BLITZBEAT,(skill<rate)?skill:rate,tick,SD_LEVEL);
}
+ // Automatic trigger of Warg Strike [Jobbie]
+ if( pc_iswug(sd) && (sd->status.weapon == W_BOW || sd->status.weapon == W_FIST) && (skill=pc_checkskill(sd,RA_WUGSTRIKE)) > 0 && rand()%1000 <= sstatus->luk*10/3+1 )
+ skill_castend_damage_id(src,bl,RA_WUGSTRIKE,skill,tick,0);
// Gank
if(dstmd && sd->status.weapon != W_BOW &&
(skill=pc_checkskill(sd,RG_SNATCHER)) > 0 &&
@@ -683,7 +774,14 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, int
case WZ_METEOR:
sc_start(bl,SC_STUN,3*skilllv,skilllv,skill_get_time2(skillid,skilllv));
break;
-
+#if FIREIVY_ON
+ //case WZ_FIREIVY:
+ // Testing for Fire Ivy
+ //sc_start(bl,SC_STUN,3*skilllv,skilllv,skill_get_time2(skillid,skilllv));
+ //sc_start(bl,SC_STUN,(5*skilllv+35),skilllv,skill_get_time2(skillid,skilllv));
+ //sc_start(bl,SC_BURNING,(8*skilllv+35),skilllv,skill_get_time2(skillid,skilllv));
+ //break;
+#endif
case WZ_VERMILION:
sc_start(bl,SC_BLIND,4*skilllv,skilllv,skill_get_time2(skillid,skilllv));
break;
@@ -929,6 +1027,104 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, int
case NPC_CRITICALWOUND:
sc_start(bl,SC_CRITICALWOUND,100,skilllv,skill_get_time2(skillid,skilllv));
break;
+ /**
+ * Rune Knight
+ **/
+ case RK_HUNDREDSPEAR:
+ if( !sd || pc_checkskill(sd,KN_SPEARBOOMERANG) == 0 )
+ break; // Spear Boomerang auto cast chance only works if you have mastered Spear Boomerang.
+ rate = 10 + 3 * skilllv;
+ if( rand()%100 < rate )
+ skill_castend_damage_id(src,bl,KN_SPEARBOOMERANG,1,tick,0);
+ break;
+ case RK_WINDCUTTER:
+ sc_start(bl,SC_FEAR,3+2*skilllv,skilllv,skill_get_time(skillid,skilllv));
+ break;
+ case RK_DRAGONBREATH:
+ sc_start4(bl,SC_BURNING,5+5*skilllv,skilllv,1000,src->id,0,skill_get_time(skillid,skilllv));
+ break;
+ /**
+ * Arch Bishop
+ **/
+ case AB_ADORAMUS:
+ if( tsc && !tsc->data[SC_DECREASEAGI] ) //Prevent duplicate agi-down effect.
+ sc_start(bl, SC_ADORAMUS, 100, skilllv, skill_get_time(skillid, skilllv));
+ break;
+ /**
+ * Warlock
+ **/
+ case WL_CRIMSONROCK:
+ sc_start(bl, SC_STUN, 40, skilllv, skill_get_time(skillid, skilllv));
+ break;
+ case WL_COMET:
+ sc_start4(bl,SC_BURNING,100,skilllv,1000,src->id,0,skill_get_time(skillid,skilllv));
+ break;
+ case WL_EARTHSTRAIN:
+ {
+ int rate = 0, i;
+ const int pos[5] = { EQP_WEAPON, EQP_HELM, EQP_SHIELD, EQP_ARMOR, EQP_ACC };
+ rate = 6 * skilllv + sstatus->dex / 10 + (sd? sd->status.job_level / 4 : 0) - tstatus->dex /5;// The tstatus->dex / 5 part is unofficial, but players gotta have some kind of way to have resistance. [Rytech]
+ //rate -= rate * tstatus->dex / 200; // Disabled until official resistance is found.
+
+ for( i = 0; i < skilllv; i++ )
+ skill_strip_equip(bl,pos[i],rate,skilllv,skill_get_time2(skillid,skilllv));
+ }
+ break;
+ case WL_JACKFROST:
+ sc_start(bl,SC_FREEZE,100,skilllv,skill_get_time(skillid,skilllv));
+ break;
+ /**
+ * Ranger
+ **/
+ case RA_WUGBITE:
+ sc_start(bl, SC_BITE, 70, skilllv, skill_get_time(skillid, skilllv) + (sd ? pc_checkskill(sd,RA_TOOTHOFWUG) * 1000 : 0)); // Need official chance.
+ break;
+ case RA_SENSITIVEKEEN:
+ if( rand()%100 < 8 * skilllv )
+ skill_castend_damage_id(src, bl, RA_WUGBITE, sd ? pc_checkskill(sd, RA_WUGBITE):skilllv, tick, SD_ANIMATION);
+ break;
+ case RA_MAGENTATRAP:
+ case RA_COBALTTRAP:
+ case RA_MAIZETRAP:
+ case RA_VERDURETRAP:
+ if( dstmd && !(dstmd->status.mode&MD_BOSS) )
+ sc_start2(bl,SC_ELEMENTALCHANGE,100,skilllv,skill_get_ele(skillid,skilllv),skill_get_time2(skillid,skilllv));
+ break;
+ case RA_FIRINGTRAP:
+ case RA_ICEBOUNDTRAP:
+ sc_start(bl, (skillid == RA_FIRINGTRAP) ? SC_BURNING:SC_FREEZING, 40 + 10 * skilllv, skilllv, skill_get_time2(skillid, skilllv));
+ break;
+ /**
+ * Mechanic
+ **/
+ case NC_PILEBUNKER:
+ if( rand()%100 < 5 + 15*skilllv )
+ { //Deactivatable Statuses: Kyrie Eleison, Auto Guard, Steel Body, Assumptio, and Millennium Shield
+ status_change_end(bl, SC_KYRIE, -1);
+ status_change_end(bl, SC_AUTOGUARD, -1);
+ status_change_end(bl, SC_STEELBODY, -1);
+ status_change_end(bl, SC_ASSUMPTIO, -1);
+ status_change_end(bl, SC_MILLENNIUMSHIELD, -1);
+ }
+ break;
+ case NC_FLAMELAUNCHER:
+ sc_start4(bl, SC_BURNING, 50 + 10 * skilllv, skilllv, 1000, src->id, 0, skill_get_time2(skillid, skilllv));
+ break;
+ case NC_COLDSLOWER:
+ sc_start(bl, SC_FREEZE, 10 * skilllv, skilllv, skill_get_time(skillid, skilllv));
+ sc_start(bl, SC_FREEZING, 20 + 10 * skilllv, skilllv, skill_get_time2(skillid, skilllv));
+ break;
+ case NC_POWERSWING:
+ sc_start(bl, SC_STUN, 5*skilllv, skilllv, skill_get_time(skillid, skilllv));
+ if( rand()%100 < 5*skilllv )
+ skill_castend_damage_id(src, bl, NC_AXEBOOMERANG, pc_checkskill(sd, NC_AXEBOOMERANG), tick, 1);
+ break;
+ /**
+ * Guilotine Cross
+ **/
+ case GC_WEAPONCRUSH:
+ skill_castend_nodamage_id(src,bl,skillid,skilllv,tick,BCT_ENEMY);
+ break;
}
if (md && battle_config.summons_trigger_autospells && md->master_id && md->special_state.ai)
@@ -1039,7 +1235,7 @@ int skill_additional_effect (struct block_list* src, struct block_list *bl, int
if (DIFF_TICK(ud->canact_tick, tick + rate) < 0){
ud->canact_tick = tick+rate;
if ( battle_config.display_status_timers && sd )
- clif_status_change(src, SI_ACTIONDELAY, 1, rate);
+ clif_status_change(src, SI_ACTIONDELAY, 1, rate, 0, 0, 0);
}
}
}
@@ -1315,7 +1511,7 @@ int skill_counter_additional_effect (struct block_list* src, struct block_list *
if (DIFF_TICK(ud->canact_tick, tick + rate) < 0){
ud->canact_tick = tick+rate;
if ( battle_config.display_status_timers && dstsd )
- clif_status_change(bl, SI_ACTIONDELAY, 1, rate);
+ clif_status_change(bl, SI_ACTIONDELAY, 1, rate, 0, 0, 0);
}
}
}
@@ -1450,7 +1646,7 @@ int skill_strip_equip(struct block_list *bl, unsigned short where, int rate, int
return 0;
sc = status_get_sc(bl);
- if (!sc)
+ if (!sc || sc->option&OPTION_MADOGEAR ) //Mado Gear cannot be divested [Ind]
return 0;
for (i = 0; i < ARRAYLENGTH(pos); i++) {
@@ -1465,8 +1661,8 @@ int skill_strip_equip(struct block_list *bl, unsigned short where, int rate, int
}
return where?1:0;
}
-
-
+//Early declaration
+static int skill_area_temp[8];
/*=========================================================================
Used to knock back players, monsters, traps, etc
- 'count' is the number of squares to knock back
@@ -1655,8 +1851,14 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds
sc->data[SC_SPIRIT]->val4 = dsrc->id;
}
}
+ /**
+ * Official Magic Reflection Behavior : damage reflected depends on gears caster wears, not target
+ **/
+ #if RR_MAGIC_REFLECTION
+ if( dmg.dmg_lv != ATK_MISS )//Wiz SL cancelled and consumed fragment
+ dmg = battle_calc_attack(BF_MAGIC,bl,bl,skillid,skilllv,flag&0xFFF);
+ #endif
}
-
if(sc && sc->data[SC_MAGICROD] && src == dsrc) {
int sp = skill_get_sp(skillid,skilllv);
dmg.damage = dmg.damage2 = 0;
@@ -1678,7 +1880,7 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds
if( damage > 0 && dmg.flag&BF_WEAPON && src != bl && ( src == dsrc || ( dsrc->type == BL_SKILL && ( skillid == SG_SUN_WARM || skillid == SG_MOON_WARM || skillid == SG_STAR_WARM ) ) )
&& skillid != WS_CARTTERMINATION )
- rdamage = battle_calc_return_damage(bl, damage, dmg.flag);
+ rdamage = battle_calc_return_damage(bl,src, &damage, dmg.flag);
//Skill hit type
type=(skillid==0)?5:skill_get_hit(skillid);
@@ -1804,7 +2006,31 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds
else // the central target doesn't display an animation
dmg.dmotion = clif_skill_damage(dsrc,bl,tick, dmg.amotion, dmg.dmotion, damage, dmg.div_, skillid, -2, 5); // needs -2(!) as skill level
break;
-
+ /**
+ * Warlock
+ **/
+ case WL_HELLINFERNO:
+ dmg.dmotion = clif_skill_damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,1,skillid,-2,6);
+ break;
+ case WL_SOULEXPANSION:
+ case WL_COMET:
+ dmg.dmotion = clif_skill_damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,dmg.div_,skillid,skilllv,8);
+ break;
+ case WL_CHAINLIGHTNING_ATK:
+ dmg.dmotion = clif_skill_damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,1,WL_CHAINLIGHTNING,-2,6);
+ break;
+ case WL_TETRAVORTEX_FIRE:
+ case WL_TETRAVORTEX_WATER:
+ case WL_TETRAVORTEX_WIND:
+ case WL_TETRAVORTEX_GROUND:
+ dmg.dmotion = clif_skill_damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,1,WL_TETRAVORTEX_FIRE,-2,type);
+ break;
+ /**
+ * Arch Bishop
+ **/
+ case AB_DUPLELIGHT_MELEE:
+ case AB_DUPLELIGHT_MAGIC:
+ dmg.amotion = 300;
default:
if( flag&SD_ANIMATION && dmg.div_ < 2 ) //Disabling skill animation doesn't works on multi-hit.
type = 5;
@@ -1819,8 +2045,22 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds
&& (!sc || !sc->data[SC_PRESERVE])
&& damage < tsd->battle_status.hp)
{ //Updated to not be able to copy skills if the blow will kill you. [Skotlex]
- if ((tsd->status.skill[skillid].id == 0 || tsd->status.skill[skillid].flag == SKILL_FLAG_PLAGIARIZED) &&
- can_copy(tsd,skillid,bl)) // Split all the check into their own function [Aru]
+ int copy_skill = skillid;
+ /**
+ * Copy Referal: dummy skills should point to their source upon copying
+ **/
+ switch( skillid ) {
+ case AB_DUPLELIGHT_MELEE:
+ case AB_DUPLELIGHT_MAGIC:
+ copy_skill = AB_DUPLELIGHT;
+ break;
+ case WL_CHAINLIGHTNING_ATK:
+ copy_skill = WL_CHAINLIGHTNING;
+ break;
+ }
+
+ if ((tsd->status.skill[copy_skill].id == 0 || tsd->status.skill[copy_skill].flag == SKILL_FLAG_PLAGIARIZED) &&
+ can_copy(tsd,copy_skill,bl)) // Split all the check into their own function [Aru]
{
int lv = skilllv;
if (tsd->cloneskill_id && tsd->status.skill[tsd->cloneskill_id].flag == SKILL_FLAG_PLAGIARIZED){
@@ -1833,11 +2073,11 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds
if ((type = pc_checkskill(tsd,RG_PLAGIARISM)) < lv)
lv = type;
- tsd->cloneskill_id = skillid;
- pc_setglobalreg(tsd, "CLONE_SKILL", skillid);
+ tsd->cloneskill_id = copy_skill;
+ pc_setglobalreg(tsd, "CLONE_SKILL", copy_skill);
pc_setglobalreg(tsd, "CLONE_SKILL_LV", lv);
- tsd->status.skill[skillid].id = skillid;
+ tsd->status.skill[skillid].id = copy_skill;
tsd->status.skill[skillid].lv = lv;
tsd->status.skill[skillid].flag = SKILL_FLAG_PLAGIARIZED;
clif_addskill(tsd,skillid);
@@ -1871,6 +2111,12 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds
if( damage > 0 ) //Counter status effects [Skotlex]
skill_counter_additional_effect(src,bl,skillid,skilllv,dmg.flag,tick);
}
+ // Hell Inferno burning status only starts if Fire part hits.
+ if( skillid == WL_HELLINFERNO && dmg.damage > 0 )
+ sc_start4(bl,SC_BURNING,55+5*skilllv,skilllv,1000,src->id,0,skill_get_time(skillid,skilllv));
+ // Apply knock back chance in SC_TRIANGLESHOT skill.
+ else if( skillid == SC_TRIANGLESHOT && rand()%100 > (1 + skilllv) )
+ dmg.blewcount = 0;
//Only knockback if it's still alive, otherwise a "ghost" is left behind. [Skotlex]
//Reflected spells do not bounce back (bl == dsrc since it only happens for direct skills)
@@ -1882,6 +2128,8 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds
case MG_FIREWALL: direction = unit_getdir(bl); break; // backwards
case WZ_STORMGUST: direction = rand()%8; break; // randomly
case PR_SANCTUARY: direction = unit_getdir(bl); break; // backwards
+ case WL_CRIMSONROCK: direction = map_calc_dir(bl,skill_area_temp[4],skill_area_temp[5]); break;
+
}
skill_blown(dsrc,bl,dmg.blewcount,direction,0);
}
@@ -1937,6 +2185,19 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds
battle_drain(tsd, src, rdamage, rdamage, sstatus->race, is_boss(src));
skill_additional_effect(bl, src, CR_REFLECTSHIELD, 1, BF_WEAPON|BF_SHORT|BF_NORMAL,ATK_DEF,tick);
}
+ if( damage > 0 ) {
+ if( skillid == RK_CRUSHSTRIKE ) // Your weapon will not be broken if you miss.
+ skill_break_equip(src,EQP_WEAPON,10000,BCT_SELF);
+
+ if( skillid == GC_VENOMPRESSURE ) {
+ struct status_change *ssc = status_get_sc(src);
+ if( ssc && ssc->data[SC_POISONINGWEAPON] && rand()%100 < 70 + 5*skilllv ) {
+ sc_start(bl,ssc->data[SC_POISONINGWEAPON]->val2,100,ssc->data[SC_POISONINGWEAPON]->val1,skill_get_time2(GC_POISONINGWEAPON,ssc->data[SC_POISONINGWEAPON]->val1));
+ status_change_end(src,SC_POISONINGWEAPON,-1);
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ }
+ }
+ }
if (!(flag&2) &&
(
@@ -1963,7 +2224,6 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds
* ffff=自由に使用可能
* 0 =予約?B0に固定
*------------------------------------------*/
-static int skill_area_temp[8];
typedef int (*SkillFunc)(struct block_list *, struct block_list *, int, int, unsigned int, int);
int skill_area_sub (struct block_list *bl, va_list ap)
{
@@ -2034,6 +2294,17 @@ static int skill_check_unit_range_sub (struct block_list *bl, va_list ap)
case HT_CLAYMORETRAP:
case HT_TALKIEBOX:
case HP_BASILICA:
+ /**
+ * Ranger
+ **/
+ case RA_ELECTRICSHOCKER:
+ case RA_CLUSTERBOMB:
+ case RA_MAGENTATRAP:
+ case RA_COBALTTRAP:
+ case RA_MAIZETRAP:
+ case RA_VERDURETRAP:
+ case RA_FIRINGTRAP:
+ case RA_ICEBOUNDTRAP:
//Non stackable on themselves and traps (including venom dust which does not has the trap inf2 set)
if (skillid != g_skillid && !(skill_get_inf2(g_skillid)&INF2_TRAP) && g_skillid != AS_VENOMDUST)
return 0;
@@ -2346,6 +2617,61 @@ static int skill_timerskill(int tid, unsigned int tick, int id, intptr_t data)
}
}
break;
+ /**
+ * Warlock
+ **/
+ case WL_CHAINLIGHTNING_ATK:
+ {
+ struct block_list *nbl = NULL; // Next Target of Chain
+ skill_attack(BF_MAGIC,src,src,target,skl->skill_id,skl->skill_lv,tick,skl->flag); // Hit a Lightning on the current Target
+ if( skl->type > 1 )
+ { // Remaining Chains Hit
+ nbl = battle_getenemyarea(src,target->x,target->y,2,BL_CHAR|BL_SKILL,target->id); // Search for a new Target around current one...
+ if( nbl == NULL && skl->x > 1 )
+ {
+ nbl = target;
+ skl->x--;
+ }
+ else skl->x = 3;
+ }
+
+ if( nbl )
+ skill_addtimerskill(src,tick+status_get_adelay(src),nbl->id,skl->x,0,WL_CHAINLIGHTNING_ATK,skl->skill_lv,skl->type-1,skl->flag);
+ }
+ break;
+ case WL_TETRAVORTEX_FIRE:
+ case WL_TETRAVORTEX_WATER:
+ case WL_TETRAVORTEX_WIND:
+ case WL_TETRAVORTEX_GROUND:
+ skill_attack(BF_MAGIC,src,src,target,skl->skill_id,skl->skill_lv,tick,skl->flag);
+ if( skl->type >= 3 )
+ { // Final Hit
+ status_change_end(src,SC_MAGICPOWER,-1); // Removes Magic Power
+ if( !status_isdead(target) )
+ { // Final Status Effect
+ int effects[4] = { SC_BURNING, SC_FREEZING, SC_BLEEDING, SC_STUN },
+ applyeffects[4] = { 0, 0, 0, 0 },
+ i, j = 0, k = 0;
+ for( i = 1; i <= 8; i = i + i )
+ {
+ if( skl->x&i )
+ {
+ applyeffects[j] = effects[k];
+ j++;
+ }
+ k++;
+ }
+ if( j )
+ {
+ i = applyeffects[rand()%j];
+ status_change_start(target, i, 10000, skl->skill_lv,
+ (i == SC_BURNING ? 1000 : 0),
+ (i == SC_BURNING ? src->id : 0),
+ 0, skill_get_time(WL_TETRAVORTEX,skl->skill_lv), 0);
+ }
+ }
+ }
+ break;
default:
skill_attack(skl->type,src,src,target,skl->skill_id,skl->skill_lv,tick,skl->flag);
break;
@@ -2368,7 +2694,13 @@ static int skill_timerskill(int tid, unsigned int tick, int id, intptr_t data)
else if( path_search_long(NULL, src->m, src->x, src->y, skl->x, skl->y, CELL_CHKWALL) )
skill_unitsetting(src,skl->skill_id,skl->skill_lv,skl->x,skl->y,skl->flag);
break;
+ case WL_EARTHSTRAIN:
+ skill_unitsetting(src,skl->skill_id,skl->skill_lv,skl->x,skl->y,(skl->type<<16)|skl->flag);
+ break;
+
}
+ if( skl->skill_id >= WL_TETRAVORTEX_FIRE && skl->skill_id <= WL_TETRAVORTEX_GROUND )
+ status_change_end(src,SC_MAGICPOWER,-1);
}
} while (0);
//Free skl now that it is no longer needed.
@@ -2569,6 +2901,43 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int
case NPC_BLEEDING:
case NPC_CRITICALWOUND:
case NPC_HELLPOWER:
+ /**
+ * Rune Knight
+ **/
+ case RK_SONICWAVE:
+ case RK_HUNDREDSPEAR:
+ case RK_WINDCUTTER:
+ /**
+ * Arch Bishop
+ **/
+ case AB_DUPLELIGHT_MELEE:
+ /**
+ * Ranger
+ **/
+ case RA_AIMEDBOLT:
+ /**
+ * Mechanic
+ **/
+ case NC_AXEBOOMERANG:
+ case NC_POWERSWING:
+ /**
+ * Guilotinne Cross
+ **/
+ case GC_CROSSIMPACT:
+ case GC_VENOMPRESSURE:
+
+ skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
+ break;
+
+ /**
+ * Mechanic (MADO GEAR)
+ **/
+ case NC_BOOSTKNUCKLE:
+ case NC_PILEBUNKER:
+ case NC_VULCANARM:
+ case NC_COLDSLOWER:
+ case NC_ARMSCANNON:
+ if (sd) pc_overheat(sd,1);
skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
break;
@@ -2637,6 +3006,8 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int
}
break;
+ case NC_FLAMELAUNCHER:
+ if (sd) pc_overheat(sd,1);
case SN_SHARPSHOOTING:
case MA_SHARPSHOOTING:
case NJ_KAMAITACHI:
@@ -2766,6 +3137,35 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int
case NPC_PULSESTRIKE:
case NPC_HELLJUDGEMENT:
case NPC_VAMPIRE_GIFT:
+ /**
+ * Rune Knight
+ **/
+ case RK_IGNITIONBREAK:
+ /**
+ * Arch Bishop
+ **/
+ case AB_JUDEX:
+ /**
+ * Warlock
+ **/
+ case WL_SOULEXPANSION:
+ case WL_CRIMSONROCK:
+ case WL_COMET:
+ /**
+ * Ranger
+ **/
+ case RA_ARROWSTORM:
+ case RA_WUGDASH:
+ /**
+ * Mechanic
+ **/
+ case NC_SELFDESTRUCTION:
+ case NC_AXETORNADO:
+ /**
+ * Guilotine Cross
+ **/
+ case GC_ROLLINGCUTTER:
+ case GC_COUNTERSLASH:
if( flag&1 )
{ //Recursive invocation
// skill_area_temp[0] holds number of targets in area
@@ -2792,7 +3192,10 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int
skill_area_temp[0] = 0;
skill_area_temp[1] = bl->id;
skill_area_temp[2] = 0;
-
+ if( skillid == WL_CRIMSONROCK ) {
+ skill_area_temp[4] = bl->x;
+ skill_area_temp[5] = bl->y;
+ }
// if skill damage should be split among targets, count them
//SD_LEVEL -> Forced splash damage for Auto Blitz-Beat -> count targets
//special case: Venom Splasher uses a different range for searching than for splashing
@@ -2800,7 +3203,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int
skill_area_temp[0] = map_foreachinrange(skill_area_sub, bl, (skillid == AS_SPLASHER)?1:skill_get_splash(skillid, skilllv), BL_CHAR, src, skillid, skilllv, tick, BCT_ENEMY, skill_area_sub_count);
// recursive invocation of skill_castend_damage_id() with flag|1
- map_foreachinrange(skill_area_sub, bl, skill_get_splash(skillid, skilllv), splash_target(src), src, skillid, skilllv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill_castend_damage_id);
+ map_foreachinrange(skill_area_sub, bl, skill_get_splash(skillid, skilllv), (skillid == WL_CRIMSONROCK)?BL_CHAR|BL_SKILL:splash_target(src), src, skillid, skilllv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill_castend_damage_id);
//FIXME: Isn't EarthQuake a ground skill after all?
if( skillid == NPC_EARTHQUAKE )
@@ -2920,6 +3323,20 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int
case NJ_KOUENKA:
case NJ_HYOUSENSOU:
case NJ_HUUJIN:
+#if FIREIVY_ON
+ case WZ_FIREIVY:
+#endif
+ /**
+ * Arch Bishop
+ **/
+ case AB_ADORAMUS:
+ case AB_RENOVATIO:
+ case AB_HIGHNESSHEAL:
+ case AB_DUPLELIGHT_MAGIC:
+ /**
+ * Warlock
+ **/
+ case WL_HELLINFERNO:
skill_attack(BF_MAGIC,src,src,bl,skillid,skilllv,tick,flag);
break;
@@ -3006,6 +3423,10 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int
case NPC_SMOKING:
case GS_FLING:
case NJ_ZENYNAGE:
+ /**
+ * Rune Knight
+ **/
+ case RK_DRAGONBREATH:
skill_attack(BF_MISC,src,src,bl,skillid,skilllv,tick,flag);
break;
@@ -3062,6 +3483,330 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int
status_change_end(src, SC_HIDING, INVALID_TIMER);
skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
break;
+ /**
+ * Rune Knight
+ **/
+ case RK_PHANTOMTHRUST:
+ unit_setdir(src,map_calc_dir(src, bl->x, bl->y));
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+
+ skill_blown(src,bl,distance_bl(src,bl)-1,unit_getdir(src),0);
+ if( battle_check_target(src,bl,BCT_ENEMY) )
+ skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
+ break;
+
+ case RK_STORMBLAST:
+ case RK_CRUSHSTRIKE:
+ if( sd ) {
+ if( pc_checkskill(sd,RK_RUNEMASTERY) >= ( skillid == RK_CRUSHSTRIKE ? 7 : 3 ) )
+ skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
+ else
+ clif_skill_fail(sd,skillid,0,0);
+ } else //non-sd support
+ skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
+ break;
+ /**
+ * Guilotinne Cross
+ **/
+ case GC_DARKILLUSION:
+ {
+ short x, y;
+ short dir = map_calc_dir(src,bl->x,bl->y);
+
+ if( dir > 4 ) x = -1;
+ else if( dir > 0 && dir < 4 ) x = 1;
+ else x = 0;
+ if( dir < 3 || dir > 5 ) y = -1;
+ else if( dir > 3 && dir < 5 ) y = 1;
+ else y = 0;
+
+ if( unit_movepos(src, bl->x+x, bl->y+y, 1, 1) )
+ {
+ clif_slide(src,bl->x+x,bl->y+y);
+ clif_fixpos(src); // the official server send these two packts.
+ skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
+ if( rand()%100 < 4 * skilllv )
+ skill_castend_damage_id(src,bl,GC_CROSSIMPACT,skilllv,tick,flag);
+ }
+
+ }
+ break;
+
+ case GC_WEAPONCRUSH:
+ if( sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == GC_WEAPONBLOCKING )
+ skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
+ else if( sd )
+ clif_skill_fail(sd,skillid,0x1f,0);
+ break;
+
+ case GC_CROSSRIPPERSLASHER:
+ if( sd && !(sc && sc->data[SC_ROLLINGCUTTER]) )
+ clif_skill_fail(sd,skillid,0x17,0);
+ else
+ {
+ skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
+ status_change_end(src,SC_ROLLINGCUTTER,-1);
+ }
+ break;
+
+ case GC_PHANTOMMENACE:
+ if( flag&1 )
+ { // Only Hits Invisible Targets
+ struct status_change *tsc = status_get_sc(bl);
+ if(tsc && (tsc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) || tsc->data[SC__INVISIBILITY]) )
+ skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
+ }
+ break;
+ /**
+ * Warlock
+ **/
+ case WL_CHAINLIGHTNING:
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ skill_addtimerskill(src,tick + 150,bl->id,3,0,WL_CHAINLIGHTNING_ATK,skilllv,4+skilllv,flag);
+ break;
+ case WL_DRAINLIFE:
+ {
+ int heal = skill_attack(skill_get_type(skillid), src, src, bl, skillid, skilllv, tick, flag);
+ int rate = 70 + 4 * skilllv + ( sd ? sd->status.job_level : 50 ) / 5;
+
+ heal = 8 * skilllv;
+ if( status_get_lv(src) > 100 ) heal = heal * status_get_lv(src) / 100; // Base level bonus.
+
+ if( bl->type == BL_SKILL )
+ heal = 0; // Don't absorb heal from Ice Walls or other skill units.
+
+ if( heal && rand()%100 < rate )
+ {
+ status_heal(src, heal, 0, 0);
+ clif_skill_nodamage(NULL, src, AL_HEAL, heal, 1);
+ }
+ }
+ break;
+
+ case WL_TETRAVORTEX:
+ if( sd )
+ {
+ int spheres[5] = { 0, 0, 0, 0, 0 },
+ positions[5] = {-1,-1,-1,-1,-1 },
+ i, j = 0, k, subskill = 0;
+
+ for( i = SC_SPHERE_1; i <= SC_SPHERE_5; i++ )
+ if( sc && sc->data[i] )
+ {
+ spheres[j] = i;
+ positions[j] = sc->data[i]->val2;
+ j++; //
+ }
+
+ if( j < 4 )
+ { // Need 4 spheres minimum
+ clif_skill_fail(sd,skillid,0,0);
+ break;
+ }
+
+ // Sphere Sort, this time from new to old
+ for( i = 0; i <= j - 2; i++ )
+ for( k = i + 1; k <= j - 1; k++ )
+ if( positions[i] < positions[k] )
+ {
+ swap(positions[i],positions[k]);
+ swap(spheres[i],spheres[k]);
+ }
+
+ k = 0;
+ for( i = 0; i < 4; i++ )
+ {
+ switch( sc->data[spheres[i]]->val1 )
+ {
+ case WLS_FIRE: subskill = WL_TETRAVORTEX_FIRE; k |= 1; break;
+ case WLS_WIND: subskill = WL_TETRAVORTEX_WIND; k |= 4; break;
+ case WLS_WATER: subskill = WL_TETRAVORTEX_WATER; k |= 2; break;
+ case WLS_STONE: subskill = WL_TETRAVORTEX_GROUND; k |= 8; break;
+ }
+
+ skill_addtimerskill(src,tick+status_get_adelay(src)*i,bl->id,k,0,subskill,skilllv,i,flag);
+ status_change_end(src, spheres[i], INVALID_TIMER);
+ }
+ }
+ break;
+
+ case WL_RELEASE:
+ if( sd )
+ {
+ int i;
+ // Priority is to release SpellBook
+ ARR_FIND(0,MAX_SPELLBOOK,i,sd->rsb[i].skillid != 0);
+ if( i < MAX_SPELLBOOK )
+ { // SpellBook
+ int rsb_skillid, rsb_skilllv;
+
+ if( skilllv > 1 )
+ {
+ ARR_FIND(0,MAX_SPELLBOOK,i,sd->rsb[i].skillid == 0);
+ i--; // At skilllvl 2, Release uses the last learned skill in spellbook
+ }
+
+ rsb_skillid = sd->rsb[i].skillid;
+ rsb_skilllv = sd->rsb[i].level;
+
+ if( skilllv > 1 )
+ sd->rsb[i].skillid = 0; // Last position - only remove it from list
+ else
+ memmove(&sd->rsb[0],&sd->rsb[1],sizeof(sd->rsb) - sizeof(sd->rsb[0]));
+
+ if( sd->rsb[0].skillid == 0 )
+ status_change_end(src, SC_READING_SB, INVALID_TIMER);
+
+ status_change_end(src, SC_MAGICPOWER, INVALID_TIMER);
+
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ if( !skill_check_condition_castbegin(sd,rsb_skillid,rsb_skilllv) )
+ break;
+
+ switch( skill_get_casttype(rsb_skillid) )
+ {
+ case CAST_GROUND:
+ skill_castend_pos2(src,bl->x,bl->y,rsb_skillid,rsb_skilllv,tick,0);
+ break;
+ case CAST_NODAMAGE:
+ skill_castend_nodamage_id(src,bl,rsb_skillid,rsb_skilllv,tick,0);
+ break;
+ case CAST_DAMAGE:
+ skill_castend_damage_id(src,bl,rsb_skillid,rsb_skilllv,tick,0);
+ break;
+ }
+
+ sd->ud.canact_tick = tick + skill_delayfix(src, rsb_skillid, rsb_skilllv);
+ clif_status_change(src, SI_ACTIONDELAY, 1, skill_delayfix(src, rsb_skillid, rsb_skilllv), 0, 0, 0);
+ }
+ else
+ { // Summon Balls
+ int j = 0, k, skele;
+ int spheres[5] = { 0, 0, 0, 0, 0 },
+ positions[5] = {-1,-1,-1,-1,-1 };
+
+ for( i = SC_SPHERE_1; i <= SC_SPHERE_5; i++ )
+ if( sc && sc->data[i] )
+ {
+ spheres[j] = i;
+ positions[j] = sc->data[i]->val2;
+ sc->data[i]->val2--; // Prepares for next position
+ j++;
+ }
+
+ if( j == 0 )
+ { // No Spheres
+ clif_skill_fail(sd,skillid,0,0);
+ break;
+ }
+
+ // Sphere Sort
+ for( i = 0; i <= j - 2; i++ )
+ for( k = i + 1; k <= j - 1; k++ )
+ if( positions[i] > positions[k] )
+ {
+ swap(positions[i],positions[k]);
+ swap(spheres[i],spheres[k]);
+ }
+
+ status_change_end(src, SC_MAGICPOWER, INVALID_TIMER);
+
+ if( skilllv == 1 ) j = 1; // Limit only to one ball
+ for( i = 0; i < j; i++ )
+ {
+ skele = WL_RELEASE - 5 + sc->data[spheres[i]]->val1 - WLS_FIRE; // Convert Ball Element into Skill ATK for balls
+ // WL_SUMMON_ATK_FIRE, WL_SUMMON_ATK_WIND, WL_SUMMON_ATK_WATER, WL_SUMMON_ATK_GROUND
+ skill_addtimerskill(src,tick+status_get_adelay(src)*i,bl->id,0,0,skele,sc->data[spheres[i]]->val3,BF_MAGIC,flag|SD_LEVEL);
+ status_change_end(src, spheres[i], INVALID_TIMER); // Eliminate ball
+ }
+ clif_skill_nodamage(src,bl,skillid,0,1);
+ }
+ }
+ break;
+ case WL_FROSTMISTY:
+ {
+ struct status_change *tsc = status_get_sc(bl);
+ if( tsc && (tsc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) || tsc->data[SC__INVISIBILITY]) )
+ break; // Doesn't hit/cause Freezing to invisible enemy
+ // Causes Freezing status through walls.
+ sc_start(bl,status_skill2sc(skillid),20+12*skilllv+(sd ? sd->status.job_level : 50)/5,skilllv,skill_get_time(skillid,skilllv));
+ // Doesn't deal damage through non-shootable walls.
+ if( path_search(NULL,src->m,src->x,src->y,bl->x,bl->y,1,CELL_CHKWALL) )
+ skill_attack(BF_MAGIC,src,src,bl,skillid,skilllv,tick,flag);
+ }
+ break;
+
+ case WL_JACKFROST: {
+ struct status_change *tsc = status_get_sc(bl);
+ if( tsc && (tsc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) || tsc->data[SC__INVISIBILITY]) )
+ break; // Do not hit invisible enemy
+ skill_attack(skill_get_type(skillid), src, src, bl, skillid, skilllv, tick, flag);
+ }
+ break;
+ /**
+ * Ranger
+ **/
+ case RA_WUGSTRIKE:
+ case RA_WUGBITE:
+ if( path_search(NULL,src->m,src->x,src->y,bl->x,bl->y,1,CELL_CHKNOREACH) ) {
+ if( skillid == RA_WUGSTRIKE ) {
+ if( sd && pc_isridingwug(sd) && !map_flag_gvg(src->m) && !map[src->m].flag.battleground && unit_movepos(src,bl->x,bl->y,1,1) )
+ clif_slide(src, bl->x, bl->y);
+ }
+ skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
+ }
+ break;
+
+ case RA_SENSITIVEKEEN:
+ if( bl->type != BL_SKILL ) { // Only Hits Invisible Targets
+ struct status_change * tsc = status_get_sc(bl);
+ if(tsc && (tsc->option&(OPTION_HIDE|OPTION_CLOAK) || tsc->data[SC__INVISIBILITY]) )
+ skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
+ }
+ else
+ {
+ struct skill_unit *su = BL_CAST(BL_SKILL,bl);
+ struct skill_unit_group* sg;
+
+ if( su && (sg=su->group) && skill_get_inf2(sg->skill_id)&INF2_TRAP && sg->src_id != src->id &&
+ battle_check_target(src, map_id2bl(sg->src_id), BCT_ENEMY) > 0 )
+ {
+ if( sd && !(sg->unit_id == UNT_USED_TRAPS || (sg->unit_id == UNT_ANKLESNARE && sg->val2 != 0 )) )
+ {
+ struct item item_tmp;
+ memset(&item_tmp,0,sizeof(item_tmp));
+ item_tmp.nameid = ( sg->unit_id >= UNT_MAGENTATRAP && sg->unit_id <= UNT_CLUSTERBOMB )?ITEMID_TRAP_ALLOY:ITEMID_TRAP;
+ item_tmp.identify = 1;
+ if( item_tmp.nameid )
+ map_addflooritem(&item_tmp,1,sd->bl.m,sd->bl.x,sd->bl.y,0,0,0,0);
+ }
+ skill_delunit(su);
+ }
+ }
+ break;
+ /**
+ * Mechanic
+ **/
+ case NC_INFRAREDSCAN:
+ if( flag&1 )
+ { //TODO: Need a confirmation if the other type of hidden status is included to be scanned. [Jobbie]
+ if( rand()%100 < 50 )
+ sc_start(bl, SC_INFRAREDSCAN, 10000, skilllv, skill_get_time(skillid, skilllv));
+ status_change_end(bl, SC_HIDING, -1);
+ status_change_end(bl, SC_CLOAKING, -1);
+ status_change_end(bl, SC_CLOAKINGEXCEED, -1); // Need confirm it.
+ }
+ else
+ {
+ map_foreachinrange(skill_area_sub, bl, skill_get_splash(skillid, skilllv), splash_target(src), src, skillid, skilllv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill_castend_damage_id);
+ clif_skill_damage(src,src,tick, status_get_amotion(src), 0, -30000, 1, skillid, skilllv, 6);
+ if( sd ) pc_overheat(sd,1);
+ }
+ break;
+
+ case NC_MAGNETICFIELD:
+ sc_start2(bl,SC_MAGNETICFIELD,100,skilllv,src->id,skill_get_time(skillid,skilllv));
+ break;
case 0:
if(sd) {
if (flag & 3){
@@ -3153,6 +3898,11 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
case AL_HEAL:
case ALL_RESURRECTION:
case PR_ASPERSIO:
+ /**
+ * Arch Bishop
+ **/
+ case AB_RENOVATIO:
+ case AB_HIGHNESSHEAL:
//Apparently only player casted skills can be offensive like this.
if (sd && battle_check_undead(tstatus->race,tstatus->def_ele)) {
if (battle_check_target(src, bl, BCT_ENEMY) < 1) {
@@ -3186,11 +3936,17 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
{
case HLIF_HEAL: //[orn]
case AL_HEAL:
+ /**
+ * Arch Bishop
+ **/
+ case AB_HIGHNESSHEAL:
{
int heal = skill_calc_heal(src, bl, skillid, skilllv, true);
int heal_get_jobexp;
- if( status_isimmune(bl) || (dstmd && (dstmd->class_ == MOBID_EMPERIUM || mob_is_battleground(dstmd))) )
+ if( status_isimmune(bl) ||
+ (dstmd && (dstmd->class_ == MOBID_EMPERIUM || mob_is_battleground(dstmd))) ||
+ (skillid == AL_HEAL && dstsd && dstsd->sc.option&OPTION_MADOGEAR) )//Mado is immune to AL_HEAL
heal=0;
if( sd && dstsd && sd->status.partner_id == dstsd->status.char_id && (sd->class_&MAPID_UPPERMASK) == MAPID_SUPER_NOVICE && sd->status.sex == 0 )
@@ -3599,7 +4355,10 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
sc_start4(src,SC_WATK_ELEMENT,100,3,20,0,0,skill_get_time2(skillid, skilllv));
if (sd) skill_blockpc_start (sd, skillid, skill_get_time(skillid, skilllv));
break;
-
+ case ASC_EDP:
+ clif_skill_nodamage(src,bl,skillid,skilllv,
+ sc_start(bl,type,100,skilllv,skill_get_time(skillid,skilllv) + ( sd ? 3000 * pc_checkskill(sd,GC_RESEARCHNEWPOISON) : 0 )));
+ break;
case AL_INCAGI:
case AL_BLESSING:
case MER_INCAGI:
@@ -3640,7 +4399,6 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
case HW_MAGICPOWER:
case PF_MEMORIZE:
case PA_SACRIFICE:
- case ASC_EDP:
case PF_DOUBLECASTING:
case SG_SUN_COMFORT:
case SG_MOON_COMFORT:
@@ -3657,6 +4415,32 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
case ST_PRESERVE:
case NPC_INVINCIBLE:
case NPC_INVINCIBLEOFF:
+ /**
+ * Rune Knight
+ **/
+ case RK_DEATHBOUND:
+ /**
+ * Arch Bishop
+ **/
+ case AB_RENOVATIO:
+ case AB_EXPIATIO:
+ case AB_DUPLELIGHT:
+ case AB_SECRAMENT:
+ /**
+ * Mechanic
+ **/
+ case NC_ACCELERATION:
+ case NC_HOVERING:
+ case NC_SHAPESHIFT:
+ /**
+ * Warlock
+ **/
+ case WL_RECOGNIZEDSPELL:
+ /**
+ * Guillotine Cross
+ **/
+ case GC_VENOMIMPRESS:
+
clif_skill_nodamage(src,bl,skillid,skilllv,
sc_start(bl,type,100,skilllv,skill_get_time(skillid,skilllv)));
break;
@@ -3914,14 +4698,14 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
case AM_PHARMACY:
if(sd) {
- clif_skill_produce_mix_list(sd,22);
+ clif_skill_produce_mix_list(sd,skillid,22);
clif_skill_nodamage(src,bl,skillid,skilllv,1);
}
break;
case SA_CREATECON:
if(sd) {
- clif_skill_produce_mix_list(sd,23);
+ clif_skill_produce_mix_list(sd,skillid,23);
clif_skill_nodamage(src,bl,skillid,skilllv,1);
}
break;
@@ -3942,12 +4726,32 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
case ASC_METEORASSAULT:
case GS_SPREADATTACK:
+ /**
+ * Rune Knight
+ **/
+ case RK_STORMBLAST:
+ /**
+ * Mechanic
+ **/
+ case NC_AXETORNADO:
+ /**
+ * Guilotine Cross
+ **/
+ case GC_COUNTERSLASH:
skill_area_temp[1] = 0;
clif_skill_nodamage(src,bl,skillid,skilllv,1);
- map_foreachinrange(skill_area_sub, bl, skill_get_splash(skillid, skilllv), splash_target(src),
+ i = map_foreachinrange(skill_area_sub, bl, skill_get_splash(skillid, skilllv), splash_target(src),
src, skillid, skilllv, tick, flag|BCT_ENEMY|SD_SPLASH|1, skill_castend_damage_id);
+ if( !i && skillid == NC_AXETORNADO )
+ clif_skill_damage(src,src,tick, status_get_amotion(src), 0, -30000, 1, skillid, skilllv, 6);
break;
+ case NC_EMERGENCYCOOL:
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ status_change_end(src,SC_OVERHEAT_LIMITPOINT,-1);
+ status_change_end(src,SC_OVERHEAT,-1);
+ break;
+ case NC_INFRAREDSCAN:
case NPC_EARTHQUAKE:
case NPC_VAMPIRE_GIFT:
case NPC_HELLJUDGEMENT:
@@ -4091,6 +4895,11 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
clif_skill_nodamage(src,bl,skillid,-1,status_change_end(bl, type, INVALID_TIMER)); //Hide skill-scream animation.
map_freeblock_unlock();
return 0;
+ } else if( tsc && tsc->option&OPTION_MADOGEAR ) {
+ //Mado Gear cannot hide
+ if( sd ) clif_skill_fail(sd,skillid,0,0);
+ map_freeblock_unlock();
+ return 0;
}
clif_skill_nodamage(src,bl,skillid,-1,sc_start(bl,type,100,skilllv,skill_get_time(skillid,skilllv)));
break;
@@ -4106,6 +4915,11 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
clif_walkok(sd); // So aegis has to resend the walk ok.
break;
case AS_CLOAKING:
+ case RA_CAMOUFLAGE:
+ /**
+ * Guilotine Cross
+ **/
+ case GC_CLOAKINGEXCEED:
if (tsce)
{
i = status_change_end(bl, type, INVALID_TIMER);
@@ -4425,6 +5239,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
case RG_STRIPARMOR:
case RG_STRIPHELM:
case ST_FULLSTRIP:
+ case GC_WEAPONCRUSH:
{
unsigned short location = 0;
int d = 0;
@@ -4443,6 +5258,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
switch (skillid) {
case RG_STRIPWEAPON:
+ case GC_WEAPONCRUSH:
location = EQP_WEAPON;
break;
case RG_STRIPSHIELD:
@@ -4460,14 +5276,14 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
}
//Special message when trying to use strip on FCP [Jobbie]
- if( sd && skillid == ST_FULLSTRIP && tsc && tsc->data[SC_CP_WEAPON] && tsc->data[SC_CP_HELM] && tsc->data[SC_CP_ARMOR] && tsc->data[SC_CP_SHIELD] )
+ if( sd && skillid == ST_FULLSTRIP && tsc && tsc->data[SC_CP_WEAPON] && tsc->data[SC_CP_HELM] && tsc->data[SC_CP_ARMOR] && tsc->data[SC_CP_SHIELD])
{
clif_gospel_info(sd, 0x28);
break;
}
//Attempts to strip at rate i and duration d
- if( (i = skill_strip_equip(bl, location, i, skilllv, d)) || skillid != ST_FULLSTRIP )
+ if( (i = skill_strip_equip(bl, location, i, skilllv, d)) || (skillid != ST_FULLSTRIP && skillid != GC_WEAPONCRUSH ) )
clif_skill_nodamage(src,bl,skillid,skilllv,i);
//Nothing stripped.
@@ -4631,7 +5447,8 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
clif_skill_nodamage(src,bl,skillid,skilllv,1);
if((dstsd && (dstsd->class_&MAPID_UPPERMASK) == MAPID_SOUL_LINKER)
|| (tsc && tsc->data[SC_SPIRIT] && tsc->data[SC_SPIRIT]->val2 == SL_ROGUE) //Rogue's spirit defends againt dispel.
- || rand()%100 >= 50+10*skilllv)
+ || rand()%100 >= 50+10*skilllv
+ || ( tsc && tsc->option&OPTION_MADOGEAR ) )//Mado Gear is immune to dispell according to bug report 49 [Ind]
{
if (sd)
clif_skill_fail(sd,skillid,0,0);
@@ -5654,6 +6471,610 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
clif_skill_nodamage(src, bl, skillid, skilllv, buyingstore_setup(sd, MAX_BUYINGSTORE_SLOTS));
}
break;
+ case RK_ENCHANTBLADE:
+ clif_skill_nodamage(src,bl,skillid,skilllv,// formula not confirmed
+ sc_start2(bl,type,100,skilllv,100+20*skilllv/*+sstatus->int_/2+status_get_lv(bl)/10*/,skill_get_time(skillid,skilllv)));
+ break;
+ case RK_DRAGONHOWLING:
+ if( flag&1)
+ sc_start(bl,type,50 + 6 * skilllv,skilllv,skill_get_time(skillid,skilllv));
+ else
+ {
+ skill_area_temp[2] = 0;
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ map_foreachinrange(skill_area_sub, src,
+ skill_get_splash(skillid,skilllv),BL_CHAR,
+ src,skillid,skilllv,tick,flag|BCT_ENEMY|SD_PREAMBLE|1,
+ skill_castend_nodamage_id);
+ }
+ break;
+ case RK_IGNITIONBREAK:
+ //case LG_EARTHDRIVE:
+ clif_skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skillid, skilllv, 6);
+ //if( skillid == LG_EARTHDRIVE )
+ //{
+ // int dummy = 1;
+ // i = skill_get_splash(skillid,skilllv);
+ // map_foreachinarea(skill_cell_overlap, src->m, src->x-i, src->y-i, src->x+i, src->y+i, BL_SKILL, LG_EARTHDRIVE, &dummy, src);
+ //}
+ map_foreachinrange(skill_area_sub, bl,skill_get_splash(skillid,skilllv),BL_CHAR,
+ src,skillid,skilllv,tick,flag|BCT_ENEMY|1,skill_castend_damage_id);
+ break;
+ case RK_STONEHARDSKIN:
+ if( sd && pc_checkskill(sd,RK_RUNEMASTERY) >= 4 )
+ {
+ int heal = sstatus->hp / 4; // 25% HP
+ if( status_charge(bl,heal,0) )
+ clif_skill_nodamage(src,bl,skillid,skilllv,sc_start2(bl,type,100,skilllv,heal,skill_get_time(skillid,skilllv)));
+ else
+ clif_skill_fail(sd,skillid,0,0);
+ }
+ break;
+ case RK_REFRESH:
+ if( sd && pc_checkskill(sd,RK_RUNEMASTERY) >= 8 )
+ {
+ int heal = status_get_max_hp(bl) * 25 / 100;
+ clif_skill_nodamage(src,bl,skillid,skilllv,
+ sc_start(bl,type,100,skilllv,skill_get_time(skillid,skilllv)));
+ status_heal(bl,heal,0,1);
+ status_change_clear_buffs(bl,2);
+ }
+ break;
+
+ case RK_MILLENNIUMSHIELD:
+ if( sd && pc_checkskill(sd,RK_RUNEMASTERY) >= 9 )
+ {
+ short shields = (rand()%100<50) ? 4 : ((rand()%100<80) ? 3 : 2);
+ sc_start4(bl,type,100,skilllv,shields,1000,0,skill_get_time(skillid,skilllv));
+ clif_millenniumshield(sd,shields);
+ clif_skill_nodamage(src,bl,skillid,1,1);
+ }
+ break;
+
+ case RK_GIANTGROWTH:
+ case RK_VITALITYACTIVATION:
+ case RK_ABUNDANCE:
+ if( sd )
+ {
+ int lv = 1; // RK_GIANTGROWTH
+ if( skillid == RK_VITALITYACTIVATION )
+ lv = 2;
+ else if( skillid == RK_ABUNDANCE )
+ lv = 6;
+ if( pc_checkskill(sd,RK_RUNEMASTERY) >= lv )
+ clif_skill_nodamage(src,bl,skillid,skilllv,sc_start(bl,type,100,skilllv,skill_get_time(skillid,skilllv)));
+ }
+ break;
+
+ case RK_FIGHTINGSPIRIT:
+ if( flag&1 ) {
+ if( src == bl )
+ sc_start2(bl,type,100,skill_area_temp[5],10*(sd?pc_checkskill(sd,RK_RUNEMASTERY):10),skill_get_time(skillid,skilllv));
+ else
+ sc_start(bl,type,100,skill_area_temp[5]/4,skill_get_time(skillid,skilllv));
+ } else if( sd && pc_checkskill(sd,RK_RUNEMASTERY) >= 5 ) {
+ if( sd->status.party_id ) {
+ i = party_foreachsamemap(skill_area_sub,sd,skill_get_splash(skillid,skilllv),src,skillid,skilllv,tick,BCT_PARTY,skill_area_sub_count);
+ skill_area_temp[5] = 7 * i; // ATK
+ party_foreachsamemap(skill_area_sub,sd,skill_get_splash(skillid,skilllv),src,skillid,skilllv,tick,flag|BCT_PARTY|1,skill_castend_nodamage_id);
+ } else
+ sc_start2(bl,type,100,7,5,skill_get_time(skillid,skilllv));
+ }
+ clif_skill_nodamage(src,bl,skillid,1,1);
+ break;
+ /**
+ * Guilotine Cross
+ **/
+ case GC_ROLLINGCUTTER:
+ {
+ short count = 1;
+ skill_area_temp[2] = 0;
+ map_foreachinrange(skill_area_sub,src,skill_get_splash(skillid,skilllv),BL_CHAR,src,skillid,skilllv,tick,flag|BCT_ENEMY|SD_PREAMBLE|SD_SPLASH|1,skill_castend_damage_id);
+ if( tsc && tsc->data[SC_ROLLINGCUTTER] )
+ { // Every time the skill is casted the status change is reseted adding a counter.
+ count += (short)tsc->data[SC_ROLLINGCUTTER]->val1;
+ if( count > 10 )
+ count = 10; // Max coounter
+ status_change_end(bl, SC_ROLLINGCUTTER, INVALID_TIMER);
+ }
+ sc_start(bl,SC_ROLLINGCUTTER,100,count,skill_get_time(skillid,skilllv));
+ clif_skill_nodamage(src,src,skillid,skilllv,1);
+ }
+ break;
+
+ case GC_WEAPONBLOCKING:
+ if( tsc && tsc->data[SC_WEAPONBLOCKING] )
+ status_change_end(bl, SC_WEAPONBLOCKING, INVALID_TIMER);
+ else
+ sc_start(bl,SC_WEAPONBLOCKING,100,skilllv,skill_get_time(skillid,skilllv));
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ break;
+
+ case GC_CREATENEWPOISON:
+ if( sd )
+ {
+ clif_skill_produce_mix_list(sd,skillid,25);
+ clif_skill_nodamage(src, bl, skillid, skilllv, 1);
+ }
+ break;
+
+ case GC_POISONINGWEAPON:
+ if( sd ) {
+ clif_poison_list(sd,skilllv);
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ }
+ break;
+
+ case GC_ANTIDOTE:
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ if( tsc )
+ {
+ status_change_end(bl, SC_PARALYSE, INVALID_TIMER);
+ status_change_end(bl, SC_PYREXIA, INVALID_TIMER);
+ status_change_end(bl, SC_DEATHHURT, INVALID_TIMER);
+ status_change_end(bl, SC_LEECHESEND, INVALID_TIMER);
+ status_change_end(bl, SC_VENOMBLEED, INVALID_TIMER);
+ status_change_end(bl, SC_MAGICMUSHROOM, INVALID_TIMER);
+ status_change_end(bl, SC_TOXIN, INVALID_TIMER);
+ status_change_end(bl, SC_OBLIVIONCURSE, INVALID_TIMER);
+ }
+ break;
+
+ case GC_PHANTOMMENACE:
+ clif_skill_damage(src,bl,tick, status_get_amotion(src), 0, -30000, 1, skillid, skilllv, 6);
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ map_foreachinrange(skill_area_sub,src,skill_get_splash(skillid,skilllv),BL_CHAR,
+ src,skillid,skilllv,tick,flag|BCT_ENEMY|1,skill_castend_damage_id);
+ break;
+
+ case GC_HALLUCINATIONWALK:
+ {
+ int heal = status_get_max_hp(bl) / 10;
+ if( status_get_hp(bl) < heal ) { // if you haven't enough HP skill fails.
+ if( sd ) clif_skill_fail(sd,skillid,0x02,0);
+ break;
+ }
+ if( !status_charge(bl,heal,0) )
+ {
+ if( sd ) clif_skill_fail(sd,skillid,0x02,0);
+ break;
+ }
+ clif_skill_nodamage(src,bl,skillid,skilllv,sc_start(bl,type,100,skilllv,skill_get_time(skillid,skilllv)));
+ }
+ break;
+ /**
+ * Arch Bishop
+ **/
+ case AB_ANCILLA:
+ if( sd ) {
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ skill_produce_mix(sd, skillid, ITEMID_ANCILLA, 0, 0, 0, 1);
+ }
+ break;
+
+ case AB_CLEMENTIA:
+ case AB_CANTO:
+ {
+ int bless_lv = pc_checkskill(sd,AL_BLESSING);
+ int agi_lv = pc_checkskill(sd,AL_INCAGI);
+ if( sd == NULL || sd->status.party_id == 0 || flag&1 )
+ clif_skill_nodamage(bl, bl, skillid, skilllv, sc_start(bl,type,100,
+ (skillid == AB_CLEMENTIA)? bless_lv : (skillid == AB_CANTO)? agi_lv : skilllv, skill_get_time(skillid,skilllv)));
+ else if( sd )
+ party_foreachsamemap(skill_area_sub, sd, skill_get_splash(skillid, skilllv), src, skillid, skilllv, tick, flag|BCT_PARTY|1, skill_castend_nodamage_id);
+ }
+ break;
+
+ case AB_PRAEFATIO:
+ if( sd == NULL || sd->status.party_id == 0 || flag&1 )
+ clif_skill_nodamage(bl, bl, skillid, skilllv, sc_start4(bl, type, 100, skilllv, 0, 0, 1, skill_get_time(skillid, skilllv)));
+ else if( sd )
+ party_foreachsamemap(skill_area_sub, sd, skill_get_splash(skillid, skilllv), src, skillid, skilllv, tick, flag|BCT_PARTY|1, skill_castend_nodamage_id);
+ break;
+
+ case AB_CHEAL:
+ if( sd == NULL || sd->status.party_id == 0 || flag&1 )
+ {
+ if( sd && tstatus && !battle_check_undead(tstatus->race, tstatus->def_ele) )
+ {
+ i = skill_calc_heal(src, bl, AL_HEAL, pc_checkskill(sd, AL_HEAL), true);
+ status_heal(bl, i, 0, 1);
+ clif_skill_nodamage(bl, bl, skillid, i, 1);
+ }
+ }
+ else if( sd )
+ party_foreachsamemap(skill_area_sub, sd, skill_get_splash(skillid, skilllv), src, skillid, skilllv, tick, flag|BCT_PARTY|1, skill_castend_nodamage_id);
+ break;
+
+ case AB_ORATIO:
+ if( flag&1 )
+ sc_start(bl, type, 40 + 5 * skilllv, skilllv, skill_get_time(skillid, skilllv));
+ else
+ {
+ map_foreachinrange(skill_area_sub, src, skill_get_splash(skillid, skilllv), BL_CHAR,
+ src, skillid, skilllv, tick, flag|BCT_ENEMY|1, skill_castend_nodamage_id);
+ clif_skill_nodamage(src, bl, skillid, skilllv, 1);
+ }
+ break;
+
+ case AB_LAUDAAGNUS:
+ if( flag&1 || sd == NULL )
+ {
+ if( (tsc && (tsc->data[SC_FREEZE] || tsc->data[SC_STONE] ||
+ tsc->data[SC_BLIND]))&& (rand()%100 < 30+5*skilllv) )
+ {
+ status_change_end(bl, SC_FREEZE, -1);
+ status_change_end(bl, SC_STONE, -1);
+ status_change_end(bl, SC_BLIND, -1);
+ }
+ // Success rate only applies to the curing effect and not stat bonus.
+ clif_skill_nodamage(bl, bl, skillid, skilllv,
+ sc_start(bl, type, 100, skilllv, skill_get_time(skillid, skilllv)));
+ }
+ else if( sd )
+ party_foreachsamemap(skill_area_sub, sd, skill_get_splash(skillid, skilllv),
+ src, skillid, skilllv, tick, flag|BCT_PARTY|1, skill_castend_nodamage_id);
+ break;
+
+ case AB_LAUDARAMUS:
+ if( flag&1 || sd == NULL )
+ {
+ if( (tsc && (tsc->data[SC_SLEEP] || tsc->data[SC_STUN] ||
+ tsc->data[SC_SILENCE]))&& (rand()%100 < 30+5*skilllv) )
+ {
+ status_change_end(bl, SC_SLEEP, -1);
+ status_change_end(bl, SC_STUN, -1);
+ status_change_end(bl, SC_SILENCE, -1);
+ }
+ clif_skill_nodamage(bl, bl, skillid, skilllv,
+ sc_start(bl, type, 100, skilllv, skill_get_time(skillid, skilllv)));
+ //Success rate only applies to the curing effect and not stat bonus.
+ }
+ else if( sd )
+ party_foreachsamemap(skill_area_sub, sd, skill_get_splash(skillid, skilllv),
+ src, skillid, skilllv, tick, flag|BCT_PARTY|1, skill_castend_nodamage_id);
+ break;
+
+ case AB_CLEARANCE:
+ if( flag&1 || (i = skill_get_splash(skillid, skilllv)) < 1 )
+ { //As of the behavior in official server Clearance is just a super version of Dispell skill. [Jobbie]
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ if((dstsd && (dstsd->class_&MAPID_UPPERMASK) == MAPID_SOUL_LINKER) || rand()%100 >= 30 + 10 * skilllv)
+ {
+ if (sd)
+ clif_skill_fail(sd,skillid,0,0);
+ break;
+ }
+ if(status_isimmune(bl) || !tsc || !tsc->count)
+ break;
+ for(i=0;i<SC_MAX;i++)
+ {
+ if (!tsc->data[i])
+ continue;
+ switch (i) {
+ case SC_WEIGHT50: case SC_WEIGHT90: case SC_HALLUCINATION:
+ case SC_STRIPWEAPON: case SC_STRIPSHIELD: case SC_STRIPARMOR:
+ case SC_STRIPHELM: case SC_CP_WEAPON: case SC_CP_SHIELD:
+ case SC_CP_ARMOR: case SC_CP_HELM: case SC_COMBO:
+ case SC_STRFOOD: case SC_AGIFOOD: case SC_VITFOOD:
+ case SC_INTFOOD: case SC_DEXFOOD: case SC_LUKFOOD:
+ case SC_HITFOOD: case SC_FLEEFOOD: case SC_BATKFOOD:
+ case SC_WATKFOOD: case SC_MATKFOOD: case SC_DANCING:
+ case SC_GUILDAURA: case SC_SPIRIT: case SC_AUTOBERSERK:
+ case SC_CARTBOOST: case SC_MELTDOWN: case SC_SAFETYWALL:
+ case SC_SMA: case SC_SPEEDUP0: case SC_NOCHAT:
+ case SC_ANKLE: case SC_SPIDERWEB: case SC_JAILED:
+ case SC_ITEMBOOST: case SC_EXPBOOST: case SC_LIFEINSURANCE:
+ case SC_BOSSMAPINFO: case SC_PNEUMA: case SC_AUTOSPELL:
+ case SC_INCHITRATE: case SC_INCATKRATE: case SC_NEN:
+ case SC_READYSTORM: case SC_READYDOWN: case SC_READYTURN:
+ case SC_READYCOUNTER:case SC_DODGE: case SC_WARM:
+ case SC_SPEEDUP1: case SC_AUTOTRADE: case SC_CRITICALWOUND:
+ case SC_JEXPBOOST: case SC_INVINCIBLE: case SC_INVINCIBLEOFF:
+ case SC_HELLPOWER: case SC_MANU_ATK: case SC_MANU_DEF:
+ case SC_SPL_ATK: case SC_SPL_DEF: case SC_MANU_MATK:
+ case SC_SPL_MATK: case SC_RICHMANKIM: case SC_ETERNALCHAOS:
+ case SC_DRUMBATTLE: case SC_NIBELUNGEN: case SC_ROKISWEIL:
+ case SC_INTOABYSS: case SC_SIEGFRIED: case SC_WHISTLE:
+ case SC_ASSNCROS: case SC_POEMBRAGI: case SC_APPLEIDUN:
+ case SC_HUMMING: case SC_DONTFORGETME: case SC_FORTUNE:
+ case SC_SERVICE4U: case SC_FOOD_STR_CASH: case SC_FOOD_AGI_CASH:
+ case SC_FOOD_VIT_CASH: case SC_FOOD_DEX_CASH: case SC_FOOD_INT_CASH:
+ case SC_FOOD_LUK_CASH: /* case SC_ELECTRICSHOCKER: case SC_BITE:
+ case SC__STRIPACCESSORY: case SC__ENERVATION: case SC__GROOMY:
+ case SC__IGNORANCE: case SC__LAZINESS: case SC__UNLUCKY:
+ case SC__WEAKNESS: case SC_SAVAGE_STEAK: case SC_COCKTAIL_WARG_BLOOD:
+ case SC_MAGNETICFIELD:case SC_MINOR_BBQ: case SC_SIROMA_ICE_TEA:
+ case SC_DROCERA_HERB_STEAMED: case SC_PUTTI_TAILS_NOODLES:
+ case SC_NEUTRALBARRIER_MASTER: case SC_NEUTRALBARRIER:
+ case SC_STEALTHFIELD_MASTER: case SC_STEALTHFIELD: */
+ continue;
+ case SC_ASSUMPTIO:
+ if( bl->type == BL_MOB )
+ continue;
+ break;
+ }
+ if(i==SC_BERSERK /*|| i==SC_SATURDAYNIGHTFEVER*/) tsc->data[i]->val2=0; //Mark a dispelled berserk to avoid setting hp to 100 by setting hp penalty to 0.
+ status_change_end(bl,(sc_type)i,-1);
+ }
+ break;
+ }
+ map_foreachinrange(skill_area_sub, bl, i, BL_CHAR, src, skillid, skilllv, tick, flag|1, skill_castend_damage_id);
+ break;
+
+ case AB_SILENTIUM:
+ // Should the level of Lex Divina be equivalent to the level of Silentium or should the highest level learned be used? [LimitLine]
+ map_foreachinrange(skill_area_sub, src, skill_get_splash(skillid, skilllv), BL_CHAR,
+ src, PR_LEXDIVINA, skilllv, tick, flag|BCT_ENEMY|1, skill_castend_nodamage_id);
+ clif_skill_nodamage(src, bl, skillid, skilllv, 1);
+ break;
+ /**
+ * Warlock
+ **/
+ case WL_STASIS:
+ if( flag&1 )
+ sc_start2(bl,type,100,skilllv,src->id,skill_get_time(skillid,skilllv));
+ else
+ {
+ map_foreachinrange(skill_area_sub,src,skill_get_splash(skillid, skilllv),BL_CHAR,src,skillid,skilllv,tick,(map_flag_vs(src->m)?BCT_ALL:BCT_ENEMY|BCT_SELF)|flag|1,skill_castend_nodamage_id);
+ clif_skill_nodamage(src, bl, skillid, skilllv, 1);
+ }
+ break;
+
+ case WL_WHITEIMPRISON:
+ if( !(tsc && tsc->data[type]) && (src == bl || battle_check_target(src, bl, BCT_ENEMY)) )
+ {
+ int rate = 50 + 3 * skilllv + ( sd? sd->status.job_level : 50 ) / 4;
+ i = sc_start2(bl,type,rate,skilllv,src->id,(src == bl)?skill_get_time2(skillid,skilllv):skill_get_time(skillid, skilllv));
+ clif_skill_nodamage(src,bl,skillid,skilllv,i);
+ if( sd && i )
+ skill_blockpc_start(sd,skillid,4000); // Reuse Delay only activated on success
+ }
+ else if( sd )
+ clif_skill_fail(sd,skillid,0,0);
+ break;
+
+ case WL_FROSTMISTY:
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ map_foreachinrange(skill_area_sub,bl,skill_get_splash(skillid,skilllv),BL_CHAR|BL_SKILL,src,skillid,skilllv,tick,flag|BCT_ENEMY,skill_castend_damage_id);
+ break;
+
+ case WL_JACKFROST:
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ map_foreachinshootrange(skill_area_sub,bl,skill_get_splash(skillid,skilllv),BL_CHAR|BL_SKILL,src,skillid,skilllv,tick,flag|BCT_ENEMY|1,skill_castend_damage_id);
+ break;
+
+ case WL_MARSHOFABYSS:
+ // Should marsh of abyss still apply half reduction to players after the 28/10 patch? [LimitLine]
+ clif_skill_nodamage(src, bl, skillid, skilllv,
+ sc_start4(bl, type, 100, skilllv, status_get_int(src), sd ? sd->status.job_level : 50, 0,
+ skill_get_time(skillid, skilllv)));
+ break;
+
+ case WL_SIENNAEXECRATE:
+ if( status_isimmune(bl) || !tsc )
+ break;
+
+ if( flag&1 )
+ {
+ if( bl->id == skill_area_temp[1] )
+ break; // Already work on this target
+
+ if( tsc && tsc->data[SC_STONE] )
+ status_change_end(bl,SC_STONE,-1);
+ else
+ status_change_start(bl,SC_STONE,10000,skilllv,0,0,1000,(8+2*skilllv)*1000,2);
+ }
+ else
+ {
+ int rate = 40 + 8 * skilllv + ( sd? sd->status.job_level : 50 ) / 4;
+ // IroWiki says Rate should be reduced by target stats, but currently unknown
+ if( rand()%100 < rate )
+ { // Success on First Target
+ rate = 0;
+ if( !tsc->data[SC_STONE] )
+ rate = status_change_start(bl,SC_STONE,10000,skilllv,0,0,1000,(8+2*skilllv)*1000,2);
+ else
+ {
+ rate = 1;
+ status_change_end(bl,SC_STONE,-1);
+ }
+
+ if( rate )
+ {
+ skill_area_temp[1] = bl->id;
+ map_foreachinrange(skill_area_sub,bl,skill_get_splash(skillid,skilllv),BL_CHAR,src,skillid,skilllv,tick,flag|BCT_ENEMY|1,skill_castend_nodamage_id);
+ }
+ // Doesn't send failure packet if it fails on defense.
+ }
+ else if( sd ) // Failure on Rate
+ clif_skill_fail(sd,skillid,0,0);
+ }
+ break;
+
+ case WL_SUMMONFB:
+ case WL_SUMMONBL:
+ case WL_SUMMONWB:
+ case WL_SUMMONSTONE:
+ {
+ short element = 0, sctype = 0, pos = -1;
+ struct status_change *sc = status_get_sc(src);
+ if( !sc ) break;
+
+ for( i = SC_SPHERE_1; i <= SC_SPHERE_5; i++ )
+ {
+ if( !sctype && !sc->data[i] )
+ sctype = i; // Take the free SC
+ if( sc->data[i] )
+ pos = max(sc->data[i]->val2,pos);
+ }
+
+ if( !sctype )
+ {
+ if( sd ) // No free slots to put SC
+ clif_skill_fail(sd,skillid,0x13,0);
+ break;
+ }
+
+ pos++; // Used in val2 for SC. Indicates the order of this ball
+ switch( skillid )
+ { // Set val1. The SC element for this ball
+ case WL_SUMMONFB: element = WLS_FIRE; break;
+ case WL_SUMMONBL: element = WLS_WIND; break;
+ case WL_SUMMONWB: element = WLS_WATER; break;
+ case WL_SUMMONSTONE: element = WLS_STONE; break;
+ }
+
+ sc_start4(src,sctype,100,element,pos,skilllv,0,skill_get_time(skillid,skilllv));
+ clif_skill_nodamage(src,bl,skillid,0,0);
+ }
+ break;
+
+ case WL_READING_SB:
+ if( sd )
+ {
+ int i, preserved = 0, max_preserve = 4 * pc_checkskill(sd,WL_FREEZE_SP) + sstatus->int_ / 10 + sd->status.base_level / 10;
+ ARR_FIND(0, MAX_SPELLBOOK, i, sd->rsb[i].skillid == 0); // Search for a Free Slot
+ if( i == MAX_SPELLBOOK )
+ {
+ clif_skill_fail(sd,skillid,0x04,0);
+ break;
+ }
+ for( i = 0; i < MAX_SPELLBOOK && sd->rsb[i].skillid; i++ )
+ preserved += sd->rsb[i].points;
+
+ if( preserved >= max_preserve )
+ {
+ clif_skill_fail(sd,skillid,0x04,0);
+ break;
+ }
+
+ sc_start(bl,SC_STOP,100,skilllv,-1); //Can't move while selecting a spellbook.
+ clif_spellbook_list(sd);
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ }
+ break;
+ /**
+ * Ranger
+ **/
+ case RA_FEARBREEZE:
+ clif_skill_damage(src, src, tick, status_get_amotion(src), 0, -30000, 1, skillid, skilllv, 6);
+ clif_skill_nodamage(src, bl, skillid, skilllv, sc_start(bl, type, 100, skilllv, skill_get_time(skillid, skilllv)));
+ break;
+
+ case RA_WUGMASTERY:
+ if( sd )
+ {
+ if( pc_isridingwug(sd) )
+ clif_skill_fail(sd,skillid,0,0);
+ else if( !pc_iswug(sd) )
+ pc_setoption(sd,sd->sc.option|OPTION_WUG);
+ else
+ pc_setoption(sd,sd->sc.option&~OPTION_WUG);
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ }
+ break;
+
+ case RA_WUGRIDER:
+ if( sd ) {
+ if( !pc_isridingwug(sd) && pc_iswug(sd) ) {
+ pc_setoption(sd,sd->sc.option&~OPTION_WUG);
+ pc_setoption(sd,sd->sc.option|OPTION_WUGRIDER);
+ } else if( pc_isridingwug(sd) ) {
+ pc_setoption(sd,sd->sc.option&~OPTION_WUGRIDER);
+ pc_setoption(sd,sd->sc.option|OPTION_WUG);
+ } else if( sd ) {
+ clif_skill_fail(sd,skillid,0,0);
+ }
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ }
+ break;
+
+ case RA_WUGDASH:
+ if( tsce ) {
+ clif_skill_nodamage(src,bl,skillid,skilllv,status_change_end(bl, type, -1));
+ map_freeblock_unlock();
+ return 0;
+ }
+ if( sd && pc_isridingwug(sd) ) {
+ clif_skill_nodamage(src,bl,skillid,skilllv,sc_start4(bl,type,100,skilllv,unit_getdir(bl),0,0,1));
+ clif_walkok(sd);
+ }
+ break;
+
+ case RA_SENSITIVEKEEN:
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ clif_skill_damage(src,src,tick, status_get_amotion(src), 0, -30000, 1, skillid, skilllv, 6);
+ map_foreachinrange(skill_area_sub,src,skill_get_splash(skillid,skilllv),BL_CHAR|BL_SKILL,src,skillid,skilllv,tick,flag|BCT_ENEMY,skill_castend_damage_id);
+ break;
+ /**
+ * Mechanic
+ **/
+ case NC_F_SIDESLIDE:
+ case NC_B_SIDESLIDE:
+ {
+ int dir = (skillid == NC_F_SIDESLIDE) ? (unit_getdir(src)+4)%8 : unit_getdir(src);
+ skill_blown(src,bl,skill_get_blewcount(skillid,skilllv),dir,0x1);
+ clif_slide(src,src->x,src->y);
+ clif_fixpos(src); //Aegis sent this packet
+ clif_skill_nodamage(src,bl,skillid,skilllv,1);
+ }
+ break;
+
+ case NC_SELFDESTRUCTION:
+ if( sd ) {
+ if( sd->sc.option&OPTION_MADOGEAR )
+ pc_setoption(sd, sd->sc.option&~OPTION_MADOGEAR);
+ clif_skill_nodamage(src, bl, skillid, skilllv, 1);
+ skill_castend_damage_id(src, src, skillid, skilllv, tick, flag);
+ }
+ break;
+
+ case NC_ANALYZE:
+ clif_skill_damage(src, bl, tick, status_get_amotion(src), 0, -30000, 1, skillid, skilllv, 6);
+ clif_skill_nodamage(src, bl, skillid, skilllv,
+ sc_start(bl,type, 30 + 12 * skilllv,skilllv,skill_get_time(skillid,skilllv)));
+ if( sd ) pc_overheat(sd,1);
+ break;
+
+ case NC_MAGNETICFIELD:
+ if( (i = sc_start2(bl,type,100,skilllv,src->id,skill_get_time(skillid,skilllv))) )
+ {
+ map_foreachinrange(skill_area_sub,src,skill_get_splash(skillid,skilllv),splash_target(src),src,skillid,skilllv,tick,flag|BCT_ENEMY|SD_SPLASH|1,skill_castend_damage_id);;
+ clif_skill_damage(src,src,tick,status_get_amotion(src),0,-30000,1,skillid,skilllv,6);
+ pc_overheat(sd,1);
+ }
+ clif_skill_nodamage(src,src,skillid,skilllv,i);
+ break;
+
+ case NC_REPAIR:
+ if( sd )
+ {
+ int heal;
+ if( dstsd && (dstsd->sc.option&OPTION_MADOGEAR) )
+ {
+ heal = dstsd->status.max_hp * (3+3*skilllv) / 100;
+ status_heal(bl,heal,0,2);
+ } else {
+ heal = sd->status.max_hp * (3+3*skilllv) / 100;
+ status_heal(src,heal,0,2);
+ }
+
+ clif_skill_damage(src, src, tick, status_get_amotion(src), 0, -30000, 1, skillid, skilllv, 6);
+ clif_skill_nodamage(src, bl, skillid, skilllv, heal);
+ }
+ break;
+
+ case NC_DISJOINT:
+ {
+ if( bl->type != BL_MOB ) break;
+ md = map_id2md(bl->id);
+ if( md && md->class_ >= 2042 && md->class_ <= 2046 )
+ status_kill(bl);
+ clif_skill_nodamage(src, bl, skillid, skilllv, 1);
+ }
+ break;
+
default:
ShowWarning("skill_castend_nodamage_id: Unknown skill used:%d\n",skillid);
clif_skill_nodamage(src,bl,skillid,skilllv,1);
@@ -5858,13 +7279,15 @@ int skill_castend_id(int tid, unsigned int tick, int id, intptr_t data)
if (ud->state.running && ud->skillid == TK_JUMPKICK)
flag = 1;
- if (ud->walktimer != INVALID_TIMER && ud->skillid != TK_RUN)
+ if (ud->walktimer != INVALID_TIMER && ud->skillid != TK_RUN && ud->skillid != RA_WUGDASH)
unit_stop_walking(src,1);
if( !sd || sd->skillitem != ud->skillid || skill_get_delay(ud->skillid,ud->skilllv) )
ud->canact_tick = tick + skill_delayfix(src, ud->skillid, ud->skilllv); //Tests show wings don't overwrite the delay but skill scrolls do. [Inkfish]
+ if( sd && skill_get_cooldown(ud->skillid,ud->skilllv) > 0 )
+ skill_blockpc_start(sd, ud->skillid, skill_get_cooldown(ud->skillid, ud->skilllv));
if( battle_config.display_status_timers && sd )
- clif_status_change(src, SI_ACTIONDELAY, 1, skill_delayfix(src, ud->skillid, ud->skilllv));
+ clif_status_change(src, SI_ACTIONDELAY, 1, skill_delayfix(src, ud->skillid, ud->skilllv), 0, 0, 0);
if( sd )
{
switch( ud->skillid )
@@ -5900,7 +7323,7 @@ int skill_castend_id(int tid, unsigned int tick, int id, intptr_t data)
sc = status_get_sc(src);
if(sc && sc->count) {
if(sc->data[SC_MAGICPOWER] &&
- ud->skillid != HW_MAGICPOWER && ud->skillid != WZ_WATERBALL)
+ ud->skillid != HW_MAGICPOWER && ud->skillid != WZ_WATERBALL && ud->skillid != WL_TETRAVORTEX)
status_change_end(src, SC_MAGICPOWER, INVALID_TIMER);
if(sc->data[SC_SPIRIT] &&
sc->data[SC_SPIRIT]->val2 == SL_WIZARD &&
@@ -6077,7 +7500,7 @@ int skill_castend_pos(int tid, unsigned int tick, int id, intptr_t data)
if( !sd || sd->skillitem != ud->skillid || skill_get_delay(ud->skillid,ud->skilllv) )
ud->canact_tick = tick + skill_delayfix(src, ud->skillid, ud->skilllv);
if( battle_config.display_status_timers && sd )
- clif_status_change(src, SI_ACTIONDELAY, 1, skill_delayfix(src, ud->skillid, ud->skilllv));
+ clif_status_change(src, SI_ACTIONDELAY, 1, skill_delayfix(src, ud->skillid, ud->skilllv), 0, 0, 0);
// if( sd )
// {
// switch( ud->skillid )
@@ -6209,6 +7632,9 @@ int skill_castend_pos2(struct block_list* src, int x, int y, int skillid, int sk
case MG_SAFETYWALL:
case MG_FIREWALL:
case MG_THUNDERSTORM:
+#if FIREIVY_ON
+ case WZ_FIREIVY:
+#endif
case AL_PNEUMA:
case WZ_ICEWALL:
case WZ_FIREPILLAR:
@@ -6271,6 +7697,17 @@ int skill_castend_pos2(struct block_list* src, int x, int y, int skillid, int sk
case NJ_RAIGEKISAI:
case NJ_KAMAITACHI:
case NPC_EVILLAND:
+ /**
+ * Ranger
+ **/
+ case RA_ELECTRICSHOCKER:
+ case RA_CLUSTERBOMB:
+ case RA_MAGENTATRAP:
+ case RA_COBALTTRAP:
+ case RA_MAIZETRAP:
+ case RA_VERDURETRAP:
+ case RA_FIRINGTRAP:
+ case RA_ICEBOUNDTRAP:
flag|=1;//Set flag to 1 to prevent deleting ammo (it will be deleted on group-delete).
case GS_GROUNDDRIFT: //Ammo should be deleted right away.
skill_unitsetting(src,skillid,skilllv,x,y,0);
@@ -6518,6 +7955,118 @@ int skill_castend_pos2(struct block_list* src, int x, int y, int skillid, int sk
}
}
break;
+ /**
+ * Mechanic
+ **/
+ case NC_COLDSLOWER:
+ case NC_ARMSCANNON:
+ /**
+ * Rune Knight
+ **/
+ case RK_DRAGONBREATH:
+ case RK_WINDCUTTER:
+ i = skill_get_splash(skillid,skilllv);
+ map_foreachinarea(skill_area_sub,src->m,x-i,y-i,x+i,y+i,BL_CHAR,
+ src,skillid,skilllv,tick,flag|BCT_ENEMY|1,skill_castend_damage_id);
+ break;
+ /**
+ * Guilotine Cross
+ **/
+ case GC_POISONSMOKE:
+ if( !(sc && sc->data[SC_POISONINGWEAPON]) ) {
+ if( sd )
+ clif_skill_fail(sd,skillid,0x20,0);
+ return 0;
+ }
+ clif_skill_damage(src,src,tick,status_get_amotion(src),0,-30000,1,skillid,skilllv,6);
+ skill_unitsetting(src, skillid, skilllv, x, y, flag);
+ status_change_end(src,SC_POISONINGWEAPON,-1);
+ break;
+ /**
+ * Arch Bishop
+ **/
+ case AB_EPICLESIS:
+ if( (sg = skill_unitsetting(src, skillid, skilllv, x, y, 0)) ) {
+ i = sg->unit->range;
+ map_foreachinarea(skill_area_sub, src->m, x - i, y - i, x + i, y + i, BL_CHAR, src, ALL_RESURRECTION, 1, tick, flag|BCT_NOENEMY|1,skill_castend_nodamage_id);
+ }
+ break;
+ /**
+ * Warlock
+ **/
+ case WL_COMET:
+ if( sc ) {
+ sc->comet_x = x;
+ sc->comet_y = y;
+ }
+ i = skill_get_splash(skillid,skilllv);
+ map_foreachinarea(skill_area_sub,src->m,x-i,y-i,x+i,y+i,BL_CHAR,src,skillid,skilllv,tick,flag|BCT_ENEMY|1,skill_castend_damage_id);
+ break;
+
+ case WL_EARTHSTRAIN:
+ {
+ int i, wave = skilllv + 4, dir = map_calc_dir(src,x,y);
+ int sx = x, sy = y;
+
+ if( sc && sc->data[SC_MAGICPOWER] )
+ flag = flag|2; //Store the magic power flag
+
+ for( i = 0; i < wave; i++ )
+ {
+ switch( dir )
+ {
+ case 0: case 1: case 7: sy = src->y + i; break;
+ case 3: case 4: case 5: sy = src->y - i; break;
+ case 2: sx = src->x - i; break;
+ case 6: sx = src->x + i; break;
+ }
+ skill_addtimerskill(src,gettick() + (200 * i),0,sx,sy,skillid,skilllv,dir,flag&2); // Temp code until animation is replaced. [Rytech]
+ //skill_addtimerskill(src,gettick() + (150 * i),0,sx,sy,skillid,skilllv,dir,flag&2); // Official steping timer, but disabled due to too much noise.
+ }
+ }
+ break;
+ /**
+ * Ranger
+ **/
+ case RA_DETONATOR:
+ i = skill_get_splash(skillid, skilllv);
+ map_foreachinarea(skill_detonator, src->m, x-i, y-i, x+i, y+i, BL_SKILL, src);
+ clif_skill_damage(src, src, tick, status_get_amotion(src), 0, -30000, 1, skillid, skilllv, 6);
+ break;
+ /**
+ * Mechanic
+ **/
+ case NC_NEUTRALBARRIER:
+ case NC_STEALTHFIELD:
+ skill_clear_unitgroup(src); // To remove previous skills - cannot used combined
+ if( (sg = skill_unitsetting(src,skillid,skilllv,src->x,src->y,0)) != NULL )
+ {
+ sc_start2(src,skillid == NC_NEUTRALBARRIER ? SC_NEUTRALBARRIER_MASTER : SC_STEALTHFIELD_MASTER,100,skilllv,sg->group_id,skill_get_time(skillid,skilllv));
+ if( sd ) pc_overheat(sd,1);
+ }
+ break;
+
+ case NC_SILVERSNIPER:
+ {
+ int class_ = 2042;
+ struct mob_data *md;
+
+ md = mob_once_spawn_sub(src, src->m, x, y, status_get_name(src), class_, "");
+ if( md )
+ {
+ md->master_id = src->id;
+ md->special_state.ai = 3;
+ if( md->deletetimer != INVALID_TIMER )
+ delete_timer(md->deletetimer, mob_timer_delete);
+ md->deletetimer = add_timer (gettick() + skill_get_time(skillid, skilllv), mob_timer_delete, md->bl.id, 0);
+ mob_spawn( md );
+ }
+ }
+ break;
+
+ case NC_MAGICDECOY:
+ if( sd ) clif_magicdecoy_list(sd,skilllv,x,y);
+ break;
default:
ShowWarning("skill_castend_pos2: Unknown skill used:%d\n",skillid);
@@ -6566,7 +8115,12 @@ int skill_castend_map (struct map_session_data *sd, short skill_num, const char
sd->sc.data[SC_DANCING] ||
sd->sc.data[SC_BERSERK] ||
sd->sc.data[SC_BASILICA] ||
- sd->sc.data[SC_MARIONETTE]
+ sd->sc.data[SC_MARIONETTE] ||
+ /**
+ * Warlock
+ **/
+ sd->sc.data[SC_WHITEIMPRISON] ||
+ (sd->sc.data[SC_STASIS] && skill_stasis_check(&sd->bl, sd->sc.data[SC_STASIS]->val2, skill_num))
)) {
skill_failed(sd);
return 0;
@@ -6855,6 +8409,17 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, short skilli
case HT_FREEZINGTRAP:
case MA_FREEZINGTRAP:
case HT_BLASTMINE:
+ /**
+ * Ranger
+ **/
+ case RA_ELECTRICSHOCKER:
+ case RA_CLUSTERBOMB:
+ case RA_MAGENTATRAP:
+ case RA_COBALTTRAP:
+ case RA_MAIZETRAP:
+ case RA_VERDURETRAP:
+ case RA_FIRINGTRAP:
+ case RA_ICEBOUNDTRAP:
if( map_flag_gvg(src->m) || map[src->m].flag.battleground )
limit *= 4; // longer trap times in WOE [celest]
if( battle_config.vs_traps_bctall && map_flag_vs(src->m) && (src->type&battle_config.vs_traps_bctall) )
@@ -7004,6 +8569,17 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, short skilli
break;
}
+ /**
+ * Guilotine Cross
+ **/
+ case GC_POISONSMOKE:
+ if( !(sc && sc->data[SC_POISONINGWEAPON]) )
+ return NULL;
+ val1 = sc->data[SC_POISONINGWEAPON]->val1; // Level of Poison, to determine poisoning time
+ val2 = sc->data[SC_POISONINGWEAPON]->val2; // Type of Poison
+ limit = 4000 + 2000 * skilllv;
+ break;
+
}
nullpo_retr(NULL, group=skill_initunitgroup(src,layout->count,skillid,skilllv,skill_get_unit_id(skillid,flag&1)+subunt, limit, interval));
@@ -7078,6 +8654,17 @@ struct skill_unit_group* skill_unitsetting (struct block_list *src, short skilli
case HT_TALKIEBOX:
case HT_SKIDTRAP:
case MA_SKIDTRAP:
+ /**
+ * Ranger
+ **/
+ case RA_ELECTRICSHOCKER:
+ case RA_CLUSTERBOMB:
+ case RA_MAGENTATRAP:
+ case RA_COBALTTRAP:
+ case RA_MAIZETRAP:
+ case RA_VERDURETRAP:
+ case RA_FIRINGTRAP:
+ case RA_ICEBOUNDTRAP:
val1 = 3500;
break;
case GS_DESPERADO:
@@ -7157,8 +8744,8 @@ static int skill_unit_onplace (struct skill_unit *src, struct block_list *bl, un
sc = status_get_sc(bl);
- if (sc && sc->option&OPTION_HIDE && sg->skill_id != WZ_HEAVENDRIVE)
- return 0; //Hidden characters are immune to AoE skills except Heaven's Drive. [Skotlex]
+ if (sc && sc->option&OPTION_HIDE && sg->skill_id != WZ_HEAVENDRIVE && sg->skill_id != WL_EARTHSTRAIN )
+ return 0; //Hidden characters are immune to AoE skills except to these. [Skotlex]
type = status_skill2sc(sg->skill_id);
sce = (sc && type != -1)?sc->data[type]:NULL;
@@ -7541,6 +9128,16 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns
case UNT_FLASHER:
case UNT_FREEZINGTRAP:
case UNT_FIREPILLAR_ACTIVE:
+ /**
+ * Ranger
+ **/
+ case UNT_CLUSTERBOMB:
+ case UNT_MAGENTATRAP:
+ case UNT_COBALTTRAP:
+ case UNT_MAIZETRAP:
+ case UNT_VERDURETRAP:
+ case UNT_FIRINGTRAP:
+ case UNT_ICEBOUNDTRAP:
map_foreachinrange(skill_trap_splash,&src->bl, skill_get_splash(sg->skill_id, sg->skill_lv), sg->bl_flag, &src->bl,tick);
if (sg->unit_id != UNT_FIREPILLAR_ACTIVE)
clif_changetraplook(&src->bl, sg->unit_id==UNT_LANDMINE?UNT_FIREPILLAR_ACTIVE:UNT_USED_TRAPS);
@@ -7707,6 +9304,10 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns
break;
case UNT_GRAVITATION:
+ case UNT_EARTHSTRAIN:
+ case UNT_FIREWALK:
+ case UNT_ELECTRICWALK:
+ case UNT_PSYCHIC_WAVE:
skill_attack(skill_get_type(sg->skill_id),ss,&src->bl,bl,sg->skill_id,sg->skill_lv,tick,0);
break;
@@ -7722,6 +9323,71 @@ int skill_unit_onplace_timer (struct skill_unit *src, struct block_list *bl, uns
//clif_changetraplook(&src->bl, UNT_FIREPILLAR_ACTIVE);
sg->limit=DIFF_TICK(tick,sg->tick)+1500;
break;
+ /**
+ * 3rd stuff
+ **/
+ case UNT_POISONSMOKE:
+ if( battle_check_target(ss,bl,BCT_ENEMY) > 0 && !(tsc && tsc->data[sg->val2]) && rand()%100 < 20 )
+ sc_start(bl,sg->val2,100,sg->val1,skill_get_time2(GC_POISONINGWEAPON,sg->val1));
+ break;
+
+ case UNT_EPICLESIS:
+ if( bl->type == BL_PC && !battle_check_undead(tstatus->race, tstatus->def_ele) && tstatus->race != RC_DEMON )
+ {
+ int hp, sp;
+ switch( sg->skill_lv )
+ {
+ case 1: case 2: hp = 3; sp = 2; break;
+ case 3: case 4: hp = 4; sp = 3; break;
+ case 5: default: hp = 5; sp = 4; break;
+ }
+ hp = tstatus->max_hp * hp / 100;
+ sp = tstatus->max_sp * sp / 100;
+ status_heal(bl, hp, sp, 0);
+ if( tstatus->hp < tstatus->max_hp )
+ clif_skill_nodamage(&src->bl, bl, AL_HEAL, hp, 1);
+ if( tstatus->sp < tstatus->max_sp )
+ clif_skill_nodamage(&src->bl, bl, MG_SRECOVERY, sp, 1);
+ sc_start(bl, type, 100, sg->skill_lv, sg->interval + 100);
+ sg->val2++;
+ // Reveal hidden players every 5 seconds.
+ if( sg->val2 >= 5 )
+ {
+ sg->val2 = 0;
+ // TODO: check if other hidden status can be removed.
+ status_change_end(bl,SC_HIDING,-1);
+ status_change_end(bl,SC_CLOAKING,-1);
+ }
+ }
+ /* Enable this if kRO fix the current skill. Currently no damage on undead and demon monster. [Jobbie]
+ else if( battle_check_target(ss, bl, BCT_ENEMY) > 0 && battle_check_undead(tstatus->race, tstatus->def_ele) )
+ skill_castend_damage_id(&src->bl, bl, sg->skill_id, sg->skill_lv, 0, 0);*/
+ break;
+
+ case UNT_STEALTHFIELD:
+ if( bl->id == sg->src_id )
+ break; // Dont work on Self (video shows that)
+ case UNT_NEUTRALBARRIER:
+ sc_start(bl,type,100,sg->skill_lv,sg->interval + 100);
+ break;
+
+ case UNT_DIMENSIONDOOR:
+ if( tsd && !map[bl->m].flag.noteleport )
+ pc_randomwarp(tsd,3);
+ else if( bl->type == BL_MOB && battle_config.mob_warp&8 )
+ unit_warp(bl,-1,-1,-1,3);
+ break;
+
+ case UNT_REVERBERATION:
+ clif_changetraplook(&src->bl,UNT_USED_TRAPS);
+ map_foreachinrange(skill_trap_splash,&src->bl, skill_get_splash(sg->skill_id, sg->skill_lv), sg->bl_flag, &src->bl,tick);
+ sg->limit = DIFF_TICK(tick,sg->tick) + 1500;
+ break;
+
+ case UNT_SEVERE_RAINSTORM:
+ if( battle_check_target(&src->bl, bl, BCT_ENEMY) )
+ skill_attack(BF_WEAPON,ss,&src->bl,bl,WM_SEVERE_RAINSTORM_MELEE,sg->skill_lv,tick,0);
+ break;
}
if (sg->state.magic_power && sc && !sc->data[SC_MAGICPOWER])
@@ -7759,6 +9425,7 @@ int skill_unit_onout (struct skill_unit *src, struct block_list *bl, unsigned in
switch(sg->unit_id){
case UNT_SAFETYWALL:
case UNT_PNEUMA:
+ case UNT_EPICLESIS://Arch Bishop
if (sce)
status_change_end(bl, type, INVALID_TIMER);
break;
@@ -7767,7 +9434,6 @@ int skill_unit_onout (struct skill_unit *src, struct block_list *bl, unsigned in
if( sce && sce->val4 == src->bl.id )
status_change_end(bl, type, INVALID_TIMER);
break;
-
case UNT_HERMODE: //Clear Hermode if the owner moved.
if (sce && sce->val3 == BCT_SELF && sce->val4 == sg->group_id)
status_change_end(bl, type, INVALID_TIMER);
@@ -8003,6 +9669,19 @@ static int skill_check_condition_char_sub (struct block_list *bl, va_list ap)
p_sd[(*c)++]=tsd->bl.id;
return 1;
}
+ case AB_ADORAMUS:
+ { // Adoramus does not consume Blue Gemstone when there is at least 1 Priest class next to the caster
+ if( (tsd->class_&MAPID_UPPERMASK) == MAPID_PRIEST )
+ p_sd[(*c)++] = tsd->bl.id;
+ return 1;
+ }
+ case WL_COMET:
+ { // Comet does not consume Red Gemstones when there is at least 1 Warlock class next to the caster
+ if( tsd->status.class_ == 4055 || tsd->status.class_ == 4061 )
+ p_sd[(*c)++] = tsd->bl.id;
+ return 1;
+ }
+
default: //Warning: Assuming Ensemble Dance/Songs for code speed. [Skotlex]
{
int skilllv;
@@ -8052,6 +9731,13 @@ int skill_check_pc_partner (struct map_session_data *sd, short skill_id, short*
status_charge(&tsd->bl, 0, 10);
}
return c;
+ case AB_ADORAMUS:
+ if( c > 0 && (tsd = map_id2sd(p_sd[0])) != NULL )
+ {
+ i = 2 * (*skill_lv);
+ status_charge(&tsd->bl, 0, i);
+ }
+ break;
default: //Warning: Assuming Ensemble skills here (for speed)
if (c > 0 && sd->sc.data[SC_DANCING] && (tsd = map_id2sd(p_sd[0])) != NULL)
{
@@ -8484,6 +10170,97 @@ int skill_check_condition_castbegin(struct map_session_data* sd, short skill, sh
return 0;
}
break;
+ /**
+ * Arch Bishop
+ **/
+ case AB_ANCILLA:
+ {
+ int count = 0;
+ for( i = 0; i < MAX_INVENTORY; i ++ )
+ if( sd->status.inventory[i].nameid == ITEMID_ANCILLA )
+ count += sd->status.inventory[i].amount;
+ if( count >= 3 ) {
+ clif_skill_fail(sd, skill, 0x0c, 0);
+ return 0;
+ }
+ }
+ break;
+ /**
+ * Keeping as a note:
+ * Bug Report #17 provides a link to a sep-2011 changelog that shows this requirement was removed
+ **/
+ //case AB_LAUDAAGNUS:
+ //case AB_LAUDARAMUS:
+ // if( !sd->status.party_id ) {
+ // clif_skill_fail(sd,skill,0,0);
+ // return 0;
+ // }
+ // break;
+
+ case AB_ADORAMUS:
+ /**
+ * Warlock
+ **/
+ case WL_COMET:
+ if( skill_check_pc_partner(sd,skill,&lv,1,0) <= 0 && ((i = pc_search_inventory(sd,require.itemid[0])) < 0 || sd->status.inventory[i].amount < require.amount[0]) )
+ {
+ //clif_skill_fail(sd,skill,0x47,require.amount[0],require.itemid[0]);
+ clif_skill_fail(sd,skill,0,0);
+ return 0;
+ }
+ break;
+ case WL_SUMMONFB:
+ case WL_SUMMONBL:
+ case WL_SUMMONWB:
+ case WL_SUMMONSTONE:
+ if( sc )
+ {
+ ARR_FIND(SC_SPHERE_1,SC_SPHERE_5+1,i,!sc->data[i]);
+ if( i == SC_SPHERE_5+1 )
+ { // No more free slots
+ clif_skill_fail(sd,skill,0x13,0);
+ return 0;
+ }
+ }
+ break;
+ /**
+ * Guilotine Cross
+ **/
+ case GC_HALLUCINATIONWALK:
+ if( sc && (sc->data[SC_HALLUCINATIONWALK] || sc->data[SC_HALLUCINATIONWALK_POSTDELAY]) ) {
+ clif_skill_fail(sd,skill,0x0,0);
+ return 0;
+ }
+ break;
+ case GC_COUNTERSLASH:
+ case GC_WEAPONCRUSH:
+ if( !(sc && sc->data[SC_COMBO] && sc->data[SC_COMBO]->val1 == GC_WEAPONBLOCKING) ) {
+ clif_skill_fail(sd, skill, 0x1f, 0);
+ return 0;
+ }
+ break;
+ case GC_CROSSRIPPERSLASHER:
+ if( !(sc && sc->data[SC_ROLLINGCUTTER]) ) {
+ clif_skill_fail(sd, skill, 0x17, 0);
+ return 0;
+ }
+ break;
+ case GC_POISONSMOKE:
+ case GC_VENOMPRESSURE:
+ if( !(sc && sc->data[SC_POISONINGWEAPON]) ) {
+ clif_skill_fail(sd, skill, 0x20, 0);
+ return 0;
+ }
+ break;
+ /**
+ * Ranger
+ **/
+ case RA_SENSITIVEKEEN:
+ if(!pc_iswug(sd)) {
+ clif_skill_fail(sd,skill,0x17,0);
+ return 0;
+ }
+ break;
}
switch(require.state) {
@@ -8568,6 +10345,51 @@ int skill_check_condition_castbegin(struct map_session_data* sd, short skill, sh
break;
clif_skill_fail(sd,skill,0,0);
return 0;
+ /**
+ * Rune Knight
+ **/
+ case ST_RIDINGDRAGON:
+ if( !(sd->sc.option&OPTION_DRAGON)) {
+ clif_skill_fail(sd,skill,0,0);
+ return 0;
+ }
+ break;
+ /**
+ * Wug
+ **/
+ case ST_WUG:
+ if( !(sd->sc.option&OPTION_WUG) ) {
+ clif_skill_fail(sd,skill,0,0);
+ return 0;
+ }
+ break;
+ /**
+ * Riding Wug
+ **/
+ case ST_RIDINGWUG:
+ if( !(sd->sc.option&OPTION_WUGRIDER) ){
+ clif_skill_fail(sd,skill,0,0);
+ return 0;
+ }
+ break;
+ /**
+ * Mechanic
+ **/
+ case ST_MADO:
+ if( !(sd->sc.option&OPTION_MADOGEAR) ) {
+ clif_skill_fail(sd,skill,0,0);
+ return 0;
+ }
+ break;
+ /**
+ * Sorcerer
+ **/
+ //case ST_ELEMENTALSPIRIT:
+ // if(!sd->ed) {
+ // clif_skill_fail(sd,skill,0x4f,0,0);
+ // return 0;
+ // }
+ // break;
}
if(require.mhp > 0 && get_percentage(status->hp, status->max_hp) > require.mhp) {
@@ -8648,6 +10470,10 @@ int skill_check_condition_castend(struct map_session_data* sd, short skill, shor
case PR_BENEDICTIO:
skill_check_pc_partner(sd, skill, &lv, 1, 1);
break;
+ case AB_ADORAMUS:
+ //if( skill_check_pc_partner(sd,skill,&lv, 1, 2) )
+ // sd->state.no_gemstone = 1; // Mark this skill as it don't consume ammo because partners gives SP
+ break;
case AM_CANNIBALIZE:
case AM_SPHEREMINE:
{
@@ -8667,6 +10493,32 @@ int skill_check_condition_castend(struct map_session_data* sd, short skill, shor
}
break;
}
+ case NC_SILVERSNIPER:
+ case NC_MAGICDECOY:
+ {
+ int c = 0, j;
+ int maxcount = skill_get_maxcount(skill,lv);
+ int mob_class = 2042;
+ if( skill == NC_MAGICDECOY )
+ mob_class = 2043;
+
+ if( battle_config.land_skill_limit && maxcount > 0 && ( battle_config.land_skill_limit&BL_PC ) )
+ {
+ if( skill == NC_MAGICDECOY )
+ {
+ for( j = mob_class; j <= 2046; j++ )
+ i = map_foreachinmap(skill_check_condition_mob_master_sub, sd->bl.m, BL_MOB, sd->bl.id, j, skill, &c);
+ }
+ else
+ i = map_foreachinmap(skill_check_condition_mob_master_sub, sd->bl.m, BL_MOB, sd->bl.id, mob_class, skill, &c);
+ if( c >= maxcount )
+ {
+ clif_skill_fail(sd , skill, 0, 0);
+ return 0;
+ }
+ }
+ }
+ break;
}
status = &sd->battle_status;
@@ -8854,6 +10706,10 @@ struct skill_condition skill_get_requirement(struct map_session_data* sd, short
if (sd->status.hom_id) //Don't delete items when hom is already out.
continue;
break;
+ case NC_SHAPESHIFT:
+ if( i < 4 )
+ continue;
+ break;
case WZ_FIREPILLAR: // celest
if (lv <= 5) // no gems required at level 1-5
continue;
@@ -8957,12 +10813,12 @@ int skill_castfix (struct block_list *bl, int skill_id, int skill_lv)
sd = BL_CAST(BL_PC, bl);
// calculate base cast time (reduced by dex)
- if( !(skill_get_castnodex(skill_id, skill_lv)&1) )
- {
- int scale = battle_config.castrate_dex_scale - status_get_dex(bl);
+ if( !(skill_get_castnodex(skill_id, skill_lv)&1) ) {
+ int scale = CONST_CASTRATE_SCALE - CONST_CASTRATE_CALC;
if( scale > 0 ) // not instant cast
- time = time * scale / battle_config.castrate_dex_scale;
- else return 0; // instant cast
+ time = time * scale / CONST_CASTRATE_SCALE;
+ else
+ return 0; // instant cast
}
// calculate cast time reduced by item/card bonuses
@@ -8980,11 +10836,9 @@ int skill_castfix (struct block_list *bl, int skill_id, int skill_lv)
}
}
}
-
// config cast time multiplier
if (battle_config.cast_rate != 100)
time = time * battle_config.cast_rate / 100;
-
// return final cast time
return (time > 0) ? time : 0;
}
@@ -8992,10 +10846,16 @@ int skill_castfix (struct block_list *bl, int skill_id, int skill_lv)
/*==========================================
* Does cast-time reductions based on sc data.
*------------------------------------------*/
-int skill_castfix_sc (struct block_list *bl, int time)
+int skill_castfix_sc (struct block_list *bl, int time, int skill_id, int skill_lv)
{
struct status_change *sc = status_get_sc(bl);
-
+#if RECASTING
+ int fixed = skill_get_cast(skill_id, skill_lv);
+ if( fixed > 1 )
+ fixed = fixed * 20 / 100;
+ else
+ fixed = 0;
+#endif
if (sc && sc->count) {
if (sc->data[SC_SLOWCAST])
time += time * sc->data[SC_SLOWCAST]->val2 / 100;
@@ -9010,8 +10870,24 @@ int skill_castfix_sc (struct block_list *bl, int time)
}
if (sc->data[SC_POEMBRAGI])
time -= time * sc->data[SC_POEMBRAGI]->val2 / 100;
- }
+#if RECASTING
+ /**
+ * AB Sacrament reduces fixed cast time by (10 x Level)% (up to 50%)
+ **/
+ if( sc->data[SC_SECRAMENT] )
+ fixed -= fixed * sc->data[SC_SECRAMENT]->val2 / 100;
+#endif
+ }
+#if RECASTING
+ /**
+ * WL_RADIUS decreases 10/15/20% fixed cast time from warlock skills
+ **/
+ if( bl->type == BL_PC && skill_id >= WL_WHITEIMPRISON && skill_id <= WL_FREEZE_SP && ( skill_lv = pc_checkskill((TBL_PC*)bl, WL_RADIUS) ) )
+ fixed -= fixed * (5+(skill_lv*5)) / 100;
+ return (time > 0 || fixed > 0) ? cap_value( time , fixed , INT_MAX ) : 0;
+#else
return (time > 0) ? time : 0;
+#endif
}
/*==========================================
@@ -9572,8 +11448,8 @@ int skill_frostjoke_scream (struct block_list *bl, va_list ap)
return 0;
if (bl->type == BL_PC) {
struct map_session_data *sd = (struct map_session_data *)bl;
- if (sd && sd->sc.option&OPTION_INVISIBLE)
- return 0;
+ if ( sd && sd->sc.option&(OPTION_INVISIBLE|OPTION_MADOGEAR) )
+ return 0;//Frost Joke / Scream cannot target invisible or MADO Gear characters [Ind]
}
//It has been reported that Scream/Joke works the same regardless of woe-setting. [Skotlex]
if(battle_check_target(src,bl,BCT_ENEMY) > 0)
@@ -9731,6 +11607,48 @@ int skill_greed (struct block_list *bl, va_list ap)
return 0;
}
+//For Ranger's Detonator [Jobbie/3CeAM]
+int skill_detonator(struct block_list *bl, va_list ap)
+{
+ struct skill_unit *unit=NULL;
+ struct block_list *src;
+ int unit_id;
+
+ nullpo_ret(bl);
+ nullpo_ret(ap);
+ src = va_arg(ap,struct block_list *);
+
+ if( bl->type != BL_SKILL || (unit = (struct skill_unit *)bl) == NULL || !unit->group )
+ return 0;
+ if( unit->group->src_id != src->id )
+ return 0;
+
+ unit_id = unit->group->unit_id;
+ switch( unit_id )
+ { //List of Hunter and Ranger Traps that can be detonate.
+ case UNT_BLASTMINE:
+ case UNT_SANDMAN:
+ case UNT_CLAYMORETRAP:
+ case UNT_TALKIEBOX:
+ case UNT_CLUSTERBOMB:
+ case UNT_FIRINGTRAP:
+ case UNT_ICEBOUNDTRAP:
+ if( unit_id == UNT_TALKIEBOX )
+ {
+ clif_talkiebox(bl,unit->group->valstr);
+ unit->group->val2 = -1;
+ }
+ else
+ map_foreachinrange(skill_trap_splash,bl,skill_get_splash(unit->group->skill_id,unit->group->skill_lv),unit->group->bl_flag,bl,unit->group->tick);
+
+ clif_changetraplook(bl,unit_id == UNT_FIRINGTRAP ? UNT_DUMMYSKILL : UNT_USED_TRAPS);
+ unit->group->unit_id = UNT_USED_TRAPS;
+ unit->range = -1;
+ unit->group->limit = DIFF_TICK(gettick(),unit->group->tick) + (unit_id == UNT_TALKIEBOX ? 5000 : 1500);
+ break;
+ }
+ return 0;
+}
/*==========================================
*
@@ -9897,6 +11815,15 @@ static int skill_trap_splash (struct block_list *bl, va_list ap)
if(skill_attack(BF_WEAPON,ss,src,bl,sg->skill_id,sg->skill_lv,tick,sg->val1))
skill_blown(src,bl,skill_get_blewcount(sg->skill_id,sg->skill_lv),-1,0);
break;
+ case UNT_ELECTRICSHOCKER:
+ clif_skill_damage(src,bl,tick,0,0,-30000,1,sg->skill_id,sg->skill_lv,5);
+ break;
+ case UNT_FIRINGTRAP:
+ case UNT_ICEBOUNDTRAP:
+ case UNT_CLUSTERBOMB:
+ if(skill_attack(BF_MISC,ss,bl,bl,sg->skill_id,sg->skill_lv,tick,sg->val1))
+ clif_skill_damage(bl,bl,tick,0,0,-30000,1,sg->skill_id,sg->skill_lv,5);
+ break;
default:
skill_attack(skill_get_type(sg->skill_id),ss,src,bl,sg->skill_id,sg->skill_lv,tick,0);
break;
@@ -9964,6 +11891,37 @@ bool skill_check_cloaking(struct block_list *bl, struct status_change_entry *sce
return wall;
}
+bool skill_check_camouflage(struct block_list *bl, struct status_change_entry *sce)
+{
+ static int dx[] = { 0, 1, 0, -1, -1, 1, 1, -1};
+ static int dy[] = {-1, 0, 1, 0, -1, -1, 1, 1};
+ bool wall = true;
+ int i;
+
+ if( bl->type == BL_PC )
+ { //Check for walls.
+ ARR_FIND( 0, 8, i, map_getcell(bl->m, bl->x+dx[i], bl->y+dy[i], CELL_CHKNOPASS) != 0 );
+ if( i == 8 )
+ wall = false;
+ }
+
+ if( sce )
+ {
+ if( !wall )
+ {
+ if( sce->val1 < 3 ) //End camouflage.
+ status_change_end(bl, SC_CAMOUFLAGE, -1);
+ else
+ if( sce->val3&1 )
+ { //Remove wall bonus
+ sce->val3&=~1;
+ status_calc_bl(bl,SCB_SPEED);
+ }
+ }
+ }
+
+ return wall;
+}
/*==========================================
*
@@ -10005,6 +11963,16 @@ struct skill_unit *skill_initunit (struct skill_unit_group *group, int idx, int
case HP_BASILICA:
skill_unitsetmapcell(unit,HP_BASILICA,group->skill_lv,CELL_BASILICA,true);
break;
+ /**
+ * Ranger
+ **/
+ case RA_ELECTRICSHOCKER:
+ {
+ struct block_list* target = map_id2bl(group->val2);
+ if( target )
+ status_change_end(target, SC_ELECTRICSHOCKER, -1);
+ }
+ break;
default:
if (group->state.song_dance&0x1) //Check for dissonance.
skill_dance_overlap(unit, 1);
@@ -10203,14 +12171,36 @@ int skill_delunitgroup_(struct skill_unit_group *group, const char* file, int li
}
}
- if (group->skill_id == SG_SUN_WARM ||
- group->skill_id == SG_MOON_WARM ||
- group->skill_id == SG_STAR_WARM) {
- struct status_change *sc = status_get_sc(src);
- if(sc && sc->data[SC_WARM]) {
- sc->data[SC_WARM]->val4 = 0;
- status_change_end(src, SC_WARM, INVALID_TIMER);
- }
+ switch( group->skill_id ) {
+ case SG_SUN_WARM:
+ case SG_MOON_WARM:
+ case SG_STAR_WARM:
+ {
+ struct status_change *sc = NULL;
+ if( (sc = status_get_sc(src)) != NULL && sc->data[SC_WARM] ) {
+ sc->data[SC_WARM]->val4 = 0;
+ status_change_end(src, SC_WARM, INVALID_TIMER);
+ }
+ }
+ break;
+ case NC_NEUTRALBARRIER:
+ {
+ struct status_change *sc = NULL;
+ if( (sc = status_get_sc(src)) != NULL && sc->data[SC_NEUTRALBARRIER_MASTER] ) {
+ sc->data[SC_NEUTRALBARRIER_MASTER]->val2 = 0;
+ status_change_end(src,SC_NEUTRALBARRIER_MASTER,-1);
+ }
+ }
+ break;
+ case NC_STEALTHFIELD:
+ {
+ struct status_change *sc = NULL;
+ if( (sc = status_get_sc(src)) != NULL && sc->data[SC_STEALTHFIELD_MASTER] ) {
+ sc->data[SC_STEALTHFIELD_MASTER]->val2 = 0;
+ status_change_end(src,SC_STEALTHFIELD_MASTER,-1);
+ }
+ }
+ break;
}
if (src->type==BL_PC && group->state.ammo_consume)
@@ -10379,6 +12369,14 @@ static int skill_unit_timer_sub (DBKey key, void* data, va_list ap)
case UNT_FREEZINGTRAP:
case UNT_CLAYMORETRAP:
case UNT_TALKIEBOX:
+ case UNT_CLUSTERBOMB:
+ case UNT_MAGENTATRAP:
+ case UNT_COBALTTRAP:
+ case UNT_MAIZETRAP:
+ case UNT_VERDURETRAP:
+ case UNT_FIRINGTRAP:
+ case UNT_ICEBOUNDTRAP:
+
{
struct block_list* src;
if( unit->val1 > 0 && (src = map_id2bl(group->src_id)) != NULL && src->type == BL_PC )
@@ -10445,6 +12443,11 @@ static int skill_unit_timer_sub (DBKey key, void* data, va_list ap)
case UNT_FREEZINGTRAP:
case UNT_TALKIEBOX:
case UNT_ANKLESNARE:
+ /**
+ * Ranger
+ **/
+ case UNT_ELECTRICSHOCKER:
+ case UNT_CLUSTERBOMB:
if( unit->val1 <= 0 ) {
if( group->unit_id == UNT_ANKLESNARE && group->val2 > 0 )
skill_delunit(unit);
@@ -10817,6 +12820,9 @@ int skill_produce_mix (struct map_session_data *sd, int skill_id, int nameid, in
if (!skill_id) //A skill can be specified for some override cases.
skill_id = skill_produce_db[idx].req_skill;
+ if( skill_id == GC_RESEARCHNEWPOISON )
+ skill_id = GC_CREATENEWPOISON;
+
slot[0]=slot1;
slot[1]=slot2;
slot[2]=slot3;
@@ -10838,13 +12844,35 @@ int skill_produce_mix (struct map_session_data *sd, int skill_id, int nameid, in
ele=ele_table[slot[i]-994];
}
}
+ if( skill_id == RK_RUNEMASTERY ) {
+ int temp_qty, skill_lv = pc_checkskill(sd,skill_id);
+ if( skill_lv == 10 ) temp_qty = 1 + rand()%3;
+ else if( skill_lv > 5 ) temp_qty = 1 + rand()%2;
+ else temp_qty = 1;
+ for( i = 0; i < MAX_INVENTORY; i++ ) {
+ if( sd->status.inventory[i].nameid == nameid ) {
+ if( sd->status.inventory[i].amount >= MAX_RUNE ) {
+ clif_msgtable(sd->fd,0x61b);
+ return 0;
+ } else {
+ /**
+ * the amount fits, say we got temp_qty 4 and 19 runes, we trim temp_qty to 1.
+ **/
+ if( temp_qty + sd->status.inventory[i].amount >= MAX_RUNE )
+ temp_qty = MAX_RUNE - sd->status.inventory[i].amount;
+ }
+ break;
+ }
+ }
+ qty = temp_qty;
+ }
for(i=0;i<MAX_PRODUCE_RESOURCE;i++){
int j,id,x;
if( (id=skill_produce_db[idx].mat_id[i]) <= 0 )
continue;
num++;
- x=qty*skill_produce_db[idx].mat_amount[i];
+ x=( skill_id == RK_RUNEMASTERY ? 1 : qty)*skill_produce_db[idx].mat_amount[i];
do{
int y=0;
j = pc_search_inventory(sd,id);
@@ -10889,6 +12917,10 @@ int skill_produce_mix (struct map_session_data *sd, int skill_id, int nameid, in
make_per = (2000 + 40*status->dex + 20*status->luk);
break;
case AL_HOLYWATER:
+ /**
+ * Arch Bishop
+ **/
+ case AB_ANCILLA:
make_per = 100000; //100% success
break;
case AM_PHARMACY: // Potion Preparation - reviewed with the help of various Ragnainfo sources [DracoRPG]
@@ -10939,6 +12971,19 @@ int skill_produce_mix (struct map_session_data *sd, int skill_id, int nameid, in
case SA_CREATECON: // Elemental Converter Creation
make_per = 100000; // should be 100% success rate
break;
+ /**
+ * Rune Knight
+ **/
+ case RK_RUNEMASTERY:
+ make_per = 5 * (sd->itemid + pc_checkskill(sd,skill_id)) * 100;
+ break;
+ /**
+ * Guilotine Cross
+ **/
+ case GC_CREATENEWPOISON:
+ make_per = 3000 + 500 * pc_checkskill(sd,GC_RESEARCHNEWPOISON);
+ qty = 1+rand()%pc_checkskill(sd,GC_RESEARCHNEWPOISON);
+ break;
default:
if (sd->menuskill_id == AM_PHARMACY &&
sd->menuskill_val > 10 && sd->menuskill_val <= 20)
@@ -11008,6 +13053,10 @@ int skill_produce_mix (struct map_session_data *sd, int skill_id, int nameid, in
flag = battle_config.produce_item_name_input&0x2;
break;
case AL_HOLYWATER:
+ /**
+ * Arch Bishop
+ **/
+ case AB_ANCILLA:
flag = battle_config.produce_item_name_input&0x8;
break;
case ASC_CDP:
@@ -11086,6 +13135,11 @@ int skill_produce_mix (struct map_session_data *sd, int skill_id, int nameid, in
clif_produceeffect(sd,0,nameid);
clif_misceffect(&sd->bl,3);
break;
+ case RK_RUNEMASTERY:
+ case GC_CREATENEWPOISON:
+ clif_produceeffect(sd,2,nameid);
+ clif_misceffect(&sd->bl,5);
+ break;
default: //Those that don't require a skill?
if( skill_produce_db[idx].itemlv > 10 && skill_produce_db[idx].itemlv <= 20)
{ //Cooking items.
@@ -11130,6 +13184,11 @@ int skill_produce_mix (struct map_session_data *sd, int skill_id, int nameid, in
clif_produceeffect(sd,1,nameid);
clif_misceffect(&sd->bl,2);
break;
+ case RK_RUNEMASTERY:
+ case GC_CREATENEWPOISON:
+ clif_produceeffect(sd,3,nameid);
+ clif_misceffect(&sd->bl,6);
+ break;
default:
if( skill_produce_db[idx].itemlv > 10 && skill_produce_db[idx].itemlv <= 20 )
{ //Cooking items.
@@ -11183,6 +13242,125 @@ int skill_arrow_create (struct map_session_data *sd, int nameid)
return 0;
}
+int skill_poisoningweapon( struct map_session_data *sd, int nameid) {
+ sc_type type;
+ int t_lv = 0, chance, i;
+ nullpo_ret(sd);
+ if( nameid <= 0 || (i = pc_search_inventory(sd,nameid)) < 0 || pc_delitem(sd,i,1,0,0) ) {
+ clif_skill_fail(sd,GC_POISONINGWEAPON,0,0);
+ return 0;
+ }
+ switch( nameid )
+ { // t_lv used to take duration from skill_get_time2
+ case PO_PARALYSE: type = SC_PARALYSE; t_lv = 1; break;
+ case PO_PYREXIA: type = SC_PYREXIA; t_lv = 2; break;
+ case PO_DEATHHURT: type = SC_DEATHHURT; t_lv = 3; break;
+ case PO_LEECHESEND: type = SC_LEECHESEND; t_lv = 4; break;
+ case PO_VENOMBLEED: type = SC_VENOMBLEED; t_lv = 6; break;
+ case PO_TOXIN: type = SC_TOXIN; t_lv = 7; break;
+ case PO_MAGICMUSHROOM: type = SC_MAGICMUSHROOM; t_lv = 8; break;
+ case PO_OBLIVIONCURSE: type = SC_OBLIVIONCURSE; t_lv = 9; break;
+ default:
+ clif_skill_fail(sd,GC_POISONINGWEAPON,0,0);
+ return 0;
+ }
+
+ chance = 2 + 2 * sd->menuskill_val; // 2 + 2 * skill_lv
+ sc_start4(&sd->bl,SC_POISONINGWEAPON,100,t_lv,type,chance,0,skill_get_time(GC_POISONINGWEAPON,sd->menuskill_val));
+
+ return 0;
+}
+int skill_magicdecoy(struct map_session_data *sd, int nameid) {
+ int x, y, i, class_, skill;
+ struct mob_data *md;
+ nullpo_ret(sd);
+ skill = sd->menuskill_val;
+
+ if( nameid <= 0 || !itemdb_is_element(nameid) || (i = pc_search_inventory(sd,nameid)) < 0 || !skill || pc_delitem(sd,i,1,0,0) )
+ {
+ clif_skill_fail(sd,NC_MAGICDECOY,0,0);
+ return 0;
+ }
+
+ // Spawn Position
+ pc_delitem(sd,i,1,0,0);
+ x = sd->sc.comet_x;
+ y = sd->sc.comet_y;
+ sd->sc.comet_x = sd->sc.comet_y = 0;
+ sd->menuskill_val = 0;
+
+ class_ = (nameid == 990 || nameid == 991) ? 2043 + nameid - 990 : (nameid == 992) ? 2046 : 2045;
+
+
+ md = mob_once_spawn_sub(&sd->bl, sd->bl.m, x, y, sd->status.name, class_, "");
+ if( md ) {
+ md->master_id = sd->bl.id;
+ md->special_state.ai = 3;
+ if( md->deletetimer != INVALID_TIMER )
+ delete_timer(md->deletetimer, mob_timer_delete);
+ md->deletetimer = add_timer (gettick() + skill_get_time(NC_MAGICDECOY,skill), mob_timer_delete, md->bl.id, 0);
+ mob_spawn(md);
+ md->status.matk_min = md->status.matk_max = 250 + (50 * skill);
+ }
+
+ return 0;
+}
+// Warlock Spellbooks. [LimitLine/3CeAM]
+int skill_spellbook (struct map_session_data *sd, int nameid) {
+ int i, j, points, skillid, preserved = 0, max_preserve;
+ nullpo_ret(sd);
+
+ if( sd->sc.data[SC_STOP] ) status_change_end(&sd->bl,SC_STOP,-1);
+ if( nameid <= 0 ) return 0;
+
+ if( pc_search_inventory(sd,nameid) < 0 )
+ { // User with no item on inventory
+ clif_skill_fail(sd,WL_READING_SB,0x04,0);
+ return 0;
+ }
+
+ ARR_FIND(0,MAX_SPELLBOOK,j,sd->rsb[j].skillid == 0); // Search for a free slot
+ if( j == MAX_SPELLBOOK )
+ { // No more free slots
+ clif_skill_fail(sd,WL_READING_SB,0x35,0);
+ return 0;
+ }
+
+ ARR_FIND(0,MAX_SKILL_SPELLBOOK_DB,i,skill_spellbook_db[i].nameid == nameid); // Search for information of this item
+ if( i == MAX_SKILL_SPELLBOOK_DB )
+ { // Fake nameid
+ clif_skill_fail(sd,WL_READING_SB,0x04,0);
+ return 0;
+ }
+
+ skillid = skill_spellbook_db[i].skillid;
+ points = skill_spellbook_db[i].points;
+
+ if( !pc_checkskill(sd,skillid) )
+ { // User don't know the skill
+ sc_start(&sd->bl,SC_SLEEP,100,1,skill_get_time(WL_READING_SB,pc_checkskill(sd,WL_READING_SB)));
+ clif_skill_fail(sd,WL_READING_SB,0x34,0);
+ return 0;
+ }
+
+ max_preserve = 4 * pc_checkskill(sd,WL_FREEZE_SP) + status_get_int(&sd->bl) / 10 + sd->status.base_level / 10;
+ for( i = 0; i < MAX_SPELLBOOK && sd->rsb[i].skillid; i++ )
+ preserved += sd->rsb[i].points;
+
+ if( preserved + points >= max_preserve )
+ { // No more free points
+ clif_skill_fail(sd,WL_READING_SB,0x04,0);
+ return 0;
+ }
+
+ sd->rsb[j].skillid = skillid;
+ sd->rsb[j].level = pc_checkskill(sd,skillid);
+ sd->rsb[j].points = points;
+ sc_start2(&sd->bl,SC_READING_SB,100,0,preserved+points,-1);
+
+ return 1;
+}
+
/*==========================================
*
@@ -11360,6 +13538,7 @@ void skill_init_unit_layout (void)
switch (i) {
case MG_FIREWALL:
case WZ_ICEWALL:
+ case WL_EARTHSTRAIN://Warlock
// these will be handled later
break;
case PR_SANCTUARY:
@@ -11566,6 +13745,90 @@ void skill_init_unit_layout (void)
}
pos++;
}
+ earthstrain_unit_pos = pos;
+ for( i = 0; i < 8; i++ )
+ { // For each Direction
+ skill_unit_layout[pos].count = 3; // Temp code being used as the official method makes too much noise in game. [Rytech]
+ //skill_unit_layout[pos].count = 15; // This line is here to replace the above one once gravity changes the animation.
+ switch( i )
+ {
+ case 0: case 1: case 3: case 4: case 5: case 7:
+ {
+ int dx[] = {-5, 0, 5};
+ int dy[] = { 0, 0, 0};
+ //int dx[] = {-7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7}; // Leave this here for future use.
+ //int dy[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ memcpy(skill_unit_layout[pos].dx,dx,sizeof(dx));
+ memcpy(skill_unit_layout[pos].dy,dy,sizeof(dy));
+ }
+ break;
+ case 2:
+ case 6:
+ {
+ int dx[] = { 0, 0, 0};
+ int dy[] = {-5, 0, 5};
+ //int dx[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // Leave this here for future use.
+ //int dy[] = {-7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7};
+ memcpy(skill_unit_layout[pos].dx,dx,sizeof(dx));
+ memcpy(skill_unit_layout[pos].dy,dy,sizeof(dy));
+ }
+ break;
+ }
+ pos++;
+ }
+
+}
+// Stasis skill usage check. [LimitLine/3CeAM]
+int skill_stasis_check(struct block_list *bl, int src_id, int skillid)
+{
+ int inf = 0;
+ if( !bl || skillid < 1 )
+ return 0; // Can do it
+ inf = skill_get_inf2(skillid);
+ if( inf == INF2_SONG_DANCE || /*skill_get_inf2(skillid) == INF2_CHORUS_SKILL ||*/ inf == INF2_SPIRIT_SKILL )
+ return 1; // Can't do it.
+
+ switch( skillid )
+ {
+ case NV_FIRSTAID: case TF_HIDING: case AS_CLOAKING: case WZ_SIGHTRASHER:
+ case RG_STRIPWEAPON: case RG_STRIPSHIELD: case RG_STRIPARMOR: case WZ_METEOR:
+ case RG_STRIPHELM: case SC_STRIPACCESSARY: case ST_FULLSTRIP: case WZ_SIGHTBLASTER:
+ case ST_CHASEWALK: case SC_ENERVATION: case SC_GROOMY: case WZ_ICEWALL:
+ case SC_IGNORANCE: case SC_LAZINESS: case SC_UNLUCKY: case WZ_STORMGUST:
+ case SC_WEAKNESS: case AL_RUWACH: case AL_PNEUMA: case WZ_JUPITEL:
+ case AL_HEAL: case AL_BLESSING: case AL_INCAGI: case WZ_VERMILION:
+ case AL_TELEPORT: case AL_WARP: case AL_HOLYWATER: case WZ_EARTHSPIKE:
+ case AL_HOLYLIGHT: case PR_IMPOSITIO: case PR_ASPERSIO: case WZ_HEAVENDRIVE:
+ case PR_SANCTUARY: case PR_STRECOVERY: case PR_MAGNIFICAT: case WZ_QUAGMIRE:
+ case ALL_RESURRECTION: case PR_LEXDIVINA: case PR_LEXAETERNA: case HW_GRAVITATION:
+ case PR_MAGNUS: case PR_TURNUNDEAD: case MG_SRECOVERY: case HW_MAGICPOWER:
+ case MG_SIGHT: case MG_NAPALMBEAT: case MG_SAFETYWALL: case HW_GANBANTEIN:
+ case MG_SOULSTRIKE: case MG_COLDBOLT: case MG_FROSTDIVER: case WL_DRAINLIFE:
+ case MG_STONECURSE: case MG_FIREBALL: case MG_FIREWALL: case WL_SOULEXPANSION:
+ case MG_FIREBOLT: case MG_LIGHTNINGBOLT: case MG_THUNDERSTORM: case MG_ENERGYCOAT:
+ case WL_WHITEIMPRISON: case WL_SUMMONFB: case WL_SUMMONBL: case WL_SUMMONWB:
+ case WL_SUMMONSTONE: case WL_SIENNAEXECRATE: case WL_RELEASE: case WL_EARTHSTRAIN:
+ case WL_RECOGNIZEDSPELL: case WL_READING_SB: case SA_MAGICROD: case SA_SPELLBREAKER:
+ case SA_DISPELL: case SA_FLAMELAUNCHER: case SA_FROSTWEAPON: case SA_LIGHTNINGLOADER:
+ case SA_SEISMICWEAPON: case SA_VOLCANO: case SA_DELUGE: case SA_VIOLENTGALE:
+ case SA_LANDPROTECTOR: case PF_HPCONVERSION: case PF_SOULCHANGE: case PF_SPIDERWEB:
+ case PF_FOGWALL: case TK_RUN: case TK_HIGHJUMP: case TK_SEVENWIND:
+ case SL_KAAHI: case SL_KAUPE: case SL_KAITE:
+#if FIREIVY_ON
+ case WZ_FIREIVY:
+#endif
+ // Skills that need to be confirmed.
+ case SO_FIREWALK: case SO_ELECTRICWALK: case SO_SPELLFIST: case SO_EARTHGRAVE:
+ case SO_DIAMONDDUST: case SO_POISON_BUSTER: case SO_PSYCHIC_WAVE: case SO_CLOUD_KILL:
+ case SO_STRIKING: case SO_WARMER: case SO_VACUUM_EXTREME: case SO_VARETYR_SPEAR:
+ case SO_ARRULLO:
+ return 1; // Can't do it.
+
+ default:
+ return 0; // Can do it.
+ }
+
+ return 0; // Can Cast anything else like Weapon Skills
}
/*==========================================
@@ -11596,7 +13859,10 @@ static bool skill_parse_row_skilldb(char* split[], int columns, int current)
i = skill_get_index(id);
if( !i ) // invalid skill id
return false;
-
+#if FIREIVY_ON == 0
+ if( i == WZ_FIREIVY ) //Disabled
+ return true;
+#endif
skill_split_atoi(split[1],skill_db[i].range);
skill_db[i].hit = atoi(split[2]);
skill_db[i].inf = atoi(split[3]);
@@ -11638,7 +13904,10 @@ static bool skill_parse_row_requiredb(char* split[], int columns, int current)
i = skill_get_index(i);
if( !i ) // invalid skill id
return false;
-
+#if FIREIVY_ON == 0
+ if( i == WZ_FIREIVY ) //Disabled
+ return true;
+#endif
skill_split_atoi(split[1],skill_db[i].hp);
skill_split_atoi(split[2],skill_db[i].mhp);
skill_split_atoi(split[3],skill_db[i].sp);
@@ -11696,6 +13965,17 @@ static bool skill_parse_row_requiredb(char* split[], int columns, int current)
else if( strcmpi(split[10],"recover_weight_rate")==0 ) skill_db[i].state = ST_RECOV_WEIGHT_RATE;
else if( strcmpi(split[10],"move_enable")==0 ) skill_db[i].state = ST_MOVE_ENABLE;
else if( strcmpi(split[10],"water")==0 ) skill_db[i].state = ST_WATER;
+ /**
+ * New States
+ **/
+ else if( strcmpi(split[10],"dragon")==0 ) skill_db[i].state = ST_RIDINGDRAGON;
+ else if( strcmpi(split[10],"warg")==0 ) skill_db[i].state = ST_WUG;
+ else if( strcmpi(split[10],"ridingwarg")==0 ) skill_db[i].state = ST_RIDINGWUG;
+ else if( strcmpi(split[10],"mado")==0 ) skill_db[i].state = ST_MADO;
+ else if( strcmpi(split[10],"elementalspirit")==0 ) skill_db[i].state = ST_ELEMENTALSPIRIT;
+ /**
+ * Unknown or no state
+ **/
else skill_db[i].state = ST_NONE;
skill_split_atoi(split[11],skill_db[i].spiritball);
@@ -11713,13 +13993,16 @@ static bool skill_parse_row_castdb(char* split[], int columns, int current)
i = skill_get_index(i);
if( !i ) // invalid skill id
return false;
-
+#if FIREIVY_ON == 0
+ if( i == WZ_FIREIVY ) //Disabled
+ return true;
+#endif
skill_split_atoi(split[1],skill_db[i].cast);
skill_split_atoi(split[2],skill_db[i].delay);
skill_split_atoi(split[3],skill_db[i].walkdelay);
skill_split_atoi(split[4],skill_db[i].upkeep_time);
skill_split_atoi(split[5],skill_db[i].upkeep_time2);
-
+ skill_split_atoi(split[6],skill_db[i].cooldown);
return true;
}
@@ -11729,7 +14012,10 @@ static bool skill_parse_row_castnodexdb(char* split[], int columns, int current)
i = skill_get_index(i);
if( !i ) // invalid skill id
return false;
-
+#if FIREIVY_ON == 0
+ if( i == WZ_FIREIVY ) //Disabled
+ return true;
+#endif
skill_split_atoi(split[1],skill_db[i].castnodex);
if( split[2] ) // optional column
skill_split_atoi(split[2],skill_db[i].delaynodex);
@@ -11743,7 +14029,10 @@ static bool skill_parse_row_nocastdb(char* split[], int columns, int current)
i = skill_get_index(i);
if( !i ) // invalid skill id
return false;
-
+#if FIREIVY_ON == 0
+ if( i == WZ_FIREIVY ) //Disabled
+ return true;
+#endif
skill_db[i].nocast |= atoi(split[1]);
return true;
@@ -11829,6 +14118,50 @@ static bool skill_parse_row_createarrowdb(char* split[], int columns, int curren
return true;
}
+static bool skill_parse_row_spellbookdb(char* split[], int columns, int current)
+{// SkillID,PreservePoints
+
+ int skillid = atoi(split[0]),
+ points = atoi(split[1]),
+ nameid = atoi(split[2]);
+
+ if( !skill_get_index(skillid) || !skill_get_max(skillid) )
+ ShowError("spellbook_db: Invalid skill ID %d\n", skillid);
+ if ( !skill_get_inf(skillid) )
+ ShowError("spellbook_db: Passive skills cannot be memorized (%d/%s)\n", skillid, skill_get_name(skillid));
+ if( points < 1 )
+ ShowError("spellbook_db: PreservePoints have to be 1 or above! (%d/%s)\n", skillid, skill_get_name(skillid));
+ else
+ {
+ skill_spellbook_db[current].skillid = skillid;
+ skill_spellbook_db[current].points = points;
+ skill_spellbook_db[current].nameid = nameid;
+
+ return true;
+ }
+
+ return false;
+}
+static bool skill_parse_row_magicmushroomdb(char* split[], int column, int current)
+{
+ int i = atoi(split[0]);
+
+ if( !skill_get_index(i) || !skill_get_max(i) )
+ {
+ ShowError("magicmushroom_db: Invalid skill ID %d\n", i);
+ return false;
+ }
+ if ( !skill_get_inf(i) )
+ {
+ ShowError("magicmushroom_db: Passive skills cannot be casted (%d/%s)\n", i, skill_get_name(i));
+ return false;
+ }
+
+ skill_magicmushroom_db[current].skillid = i;
+
+ return true;
+}
+
static bool skill_parse_row_abradb(char* split[], int columns, int current)
{// SkillID,DummyName,RequiredHocusPocusLevel,Rate
@@ -11843,7 +14176,10 @@ static bool skill_parse_row_abradb(char* split[], int columns, int current)
ShowError("abra_db: Passive skills cannot be casted (%d/%s)\n", i, skill_get_name(i));
return false;
}
-
+#if FIREIVY_ON == 0
+ if( i == WZ_FIREIVY ) //Disabled
+ return true;
+#endif
skill_abra_db[current].skillid = i;
skill_abra_db[current].req_lv = atoi(split[2]);
skill_abra_db[current].per = atoi(split[3]);
@@ -11859,13 +14195,14 @@ static void skill_readdb(void)
memset(skill_produce_db,0,sizeof(skill_produce_db));
memset(skill_arrow_db,0,sizeof(skill_arrow_db));
memset(skill_abra_db,0,sizeof(skill_abra_db));
-
+ memset(skill_spellbook_db,0,sizeof(skill_spellbook_db));
+ memset(skill_magicmushroom_db,0,sizeof(skill_magicmushroom_db));
// load skill databases
safestrncpy(skill_db[0].name, "UNKNOWN_SKILL", sizeof(skill_db[0].name));
safestrncpy(skill_db[0].desc, "Unknown Skill", sizeof(skill_db[0].desc));
sv_readdb(db_path, "skill_db.txt" , ',', 17, 17, MAX_SKILL_DB, skill_parse_row_skilldb);
sv_readdb(db_path, "skill_require_db.txt" , ',', 32, 32, MAX_SKILL_DB, skill_parse_row_requiredb);
- sv_readdb(db_path, "skill_cast_db.txt" , ',', 6, 6, MAX_SKILL_DB, skill_parse_row_castdb);
+ sv_readdb(db_path, "skill_cast_db.txt" , ',', 7, 7, MAX_SKILL_DB, skill_parse_row_castdb);
sv_readdb(db_path, "skill_castnodex_db.txt", ',', 2, 3, MAX_SKILL_DB, skill_parse_row_castnodexdb);
sv_readdb(db_path, "skill_nocast_db.txt" , ',', 2, 2, MAX_SKILL_DB, skill_parse_row_nocastdb);
sv_readdb(db_path, "skill_unit_db.txt" , ',', 8, 8, MAX_SKILL_DB, skill_parse_row_unitdb);
@@ -11873,6 +14210,11 @@ static void skill_readdb(void)
sv_readdb(db_path, "produce_db.txt" , ',', 4, 4+2*MAX_PRODUCE_RESOURCE, MAX_SKILL_PRODUCE_DB, skill_parse_row_producedb);
sv_readdb(db_path, "create_arrow_db.txt" , ',', 1+2, 1+2*MAX_ARROW_RESOURCE, MAX_SKILL_ARROW_DB, skill_parse_row_createarrowdb);
sv_readdb(db_path, "abra_db.txt" , ',', 4, 4, MAX_SKILL_ABRA_DB, skill_parse_row_abradb);
+ //Warlock
+ sv_readdb(db_path, "spellbook_db.txt" , ',', 3, 3, MAX_SKILL_SPELLBOOK_DB, skill_parse_row_spellbookdb);
+ //Guillotine Cross
+ sv_readdb(db_path, "magicmushroom_db.txt" , ',', 1, 1, MAX_SKILL_MAGICMUSHROOM_DB, skill_parse_row_magicmushroomdb);
+
}
void skill_reload (void)
diff --git a/src/map/skill.h b/src/map/skill.h
index 1ad6ea25a..97bd54252 100644
--- a/src/map/skill.h
+++ b/src/map/skill.h
@@ -13,7 +13,7 @@ struct skill_unit_group;
struct status_change_entry;
#define MAX_SKILL_DB MAX_SKILL
-#define MAX_SKILL_PRODUCE_DB 150
+#define MAX_SKILL_PRODUCE_DB 170
#define MAX_PRODUCE_RESOURCE 12
#define MAX_SKILL_ARROW_DB 150
#define MAX_ARROW_RESOURCE 5
@@ -91,7 +91,7 @@ struct s_skill_db {
int range[MAX_SKILL_LEVEL],hit,inf,element[MAX_SKILL_LEVEL],nk,splash[MAX_SKILL_LEVEL],max;
int num[MAX_SKILL_LEVEL];
int cast[MAX_SKILL_LEVEL],walkdelay[MAX_SKILL_LEVEL],delay[MAX_SKILL_LEVEL];
- int upkeep_time[MAX_SKILL_LEVEL],upkeep_time2[MAX_SKILL_LEVEL];
+ int upkeep_time[MAX_SKILL_LEVEL],upkeep_time2[MAX_SKILL_LEVEL],cooldown[MAX_SKILL_LEVEL];
int castcancel,cast_def_rate;
int inf2,maxcount[MAX_SKILL_LEVEL],skill_type;
int blewcount[MAX_SKILL_LEVEL];
@@ -290,7 +290,7 @@ int skill_clear_group(struct block_list *bl, int flag);
int skill_unit_ondamaged(struct skill_unit *src,struct block_list *bl,int damage,unsigned int tick);
int skill_castfix( struct block_list *bl, int skill_id, int skill_lv);
-int skill_castfix_sc( struct block_list *bl, int time);
+int skill_castfix_sc( struct block_list *bl, int time, int skill_id, int skill_lv);
int skill_delayfix( struct block_list *bl, int skill_id, int skill_lv);
// Skill conditions check and remove [Inkfish]
@@ -368,6 +368,14 @@ enum {
ST_RECOV_WEIGHT_RATE,
ST_MOVE_ENABLE,
ST_WATER,
+ /**
+ * 3rd States
+ **/
+ ST_RIDINGDRAGON,
+ ST_WUG,
+ ST_RIDINGWUG,
+ ST_MADO,
+ ST_ELEMENTALSPIRIT,
};
enum e_skill {
@@ -1310,7 +1318,7 @@ enum e_skill {
GN_S_PHARMACY,
GN_SLINGITEM_RANGEMELEEATK,
- AB_SECRAMENT,
+ AB_SECRAMENT=2515,
WM_SEVERE_RAINSTORM_MELEE,
SR_HOWLINGOFLION,
SR_RIDEINLIGHTNING,
@@ -1547,5 +1555,46 @@ enum {
UNT_MAX = 0x190
};
-
+/**
+ * Warlock
+ **/
+#define MAX_SKILL_SPELLBOOK_DB 17
+enum wl_spheres {
+ WLS_FIRE = 0x44,
+ WLS_WIND,
+ WLS_WATER,
+ WLS_STONE,
+};
+int skill_spellbook (struct map_session_data *sd, int nameid);
+/**
+ * Guilottine Cross
+ **/
+#define MAX_SKILL_MAGICMUSHROOM_DB 22
+struct s_skill_magicmushroom_db {
+ int skillid;
+};
+extern struct s_skill_magicmushroom_db skill_magicmushroom_db[MAX_SKILL_MAGICMUSHROOM_DB];
+/**
+ * Ranger
+ **/
+int skill_detonator(struct block_list *bl, va_list ap);
+bool skill_check_camouflage(struct block_list *bl, struct status_change_entry *sce);
+/**
+ * Mechanic
+ **/
+int skill_magicdecoy(struct map_session_data *sd, int nameid);
+/**
+ * Guiltoine Cross
+ **/
+int skill_poisoningweapon( struct map_session_data *sd, int nameid);
+enum gx_poison {
+ PO_PARALYSE = 12717,
+ PO_LEECHESEND,
+ PO_OBLIVIONCURSE,
+ PO_DEATHHURT,
+ PO_TOXIN,
+ PO_PYREXIA,
+ PO_MAGICMUSHROOM,
+ PO_VENOMBLEED
+};
#endif /* _SKILL_H_ */
diff --git a/src/map/status.c b/src/map/status.c
index 4df2c80d6..28506a4f6 100644
--- a/src/map/status.c
+++ b/src/map/status.c
@@ -56,7 +56,13 @@ static int refinebonus[MAX_REFINE_BONUS][3]; // 精錬ボーナステーブル(refine_db.t
int percentrefinery[5][MAX_REFINE+1]; // 精錬成功率(refine_db.txt)
static int atkmods[3][MAX_WEAPON_TYPE]; // 武器ATKサイズ修正(size_fix.txt)
static char job_bonus[CLASS_COUNT][MAX_LEVEL];
-
+#if RRMODE
+enum {
+ SHIELD_ASPD,
+ RE_JOB_DB_MAX,
+} RE_JOB_DB;
+static int re_job_db[CLASS_COUNT][RE_JOB_DB_MAX];//[RRInd]
+#endif
static struct eri *sc_data_ers; //For sc_data entries
static struct status_data dummy_status;
@@ -445,6 +451,162 @@ void initChangeTables(void)
set_sc( GD_LEADERSHIP , SC_GUILDAURA , SI_BLANK , SCB_STR|SCB_AGI|SCB_VIT|SCB_DEX );
set_sc( GD_BATTLEORDER , SC_BATTLEORDERS , SI_BLANK , SCB_STR|SCB_INT|SCB_DEX );
set_sc( GD_REGENERATION , SC_REGENERATION , SI_BLANK , SCB_REGEN );
+
+ /**
+ * Rune Knight
+ **/
+ set_sc( RK_ENCHANTBLADE , SC_ENCHANTBLADE , SI_ENCHANTBLADE , SCB_NONE );
+ set_sc( RK_DRAGONHOWLING , SC_FEAR , SI_BLANK , SCB_FLEE|SCB_HIT );
+ set_sc( RK_DEATHBOUND , SC_DEATHBOUND , SI_DEATHBOUND , SCB_NONE );
+ set_sc( RK_WINDCUTTER , SC_FEAR , SI_BLANK , SCB_FLEE|SCB_HIT );
+ add_sc( RK_DRAGONBREATH , SC_BURNING );
+ set_sc( RK_MILLENNIUMSHIELD , SC_MILLENNIUMSHIELD , SI_REUSE_MILLENNIUMSHIELD , SCB_NONE );
+ set_sc( RK_REFRESH , SC_REFRESH , SI_REFRESH , SCB_NONE );
+ set_sc( RK_GIANTGROWTH , SC_GIANTGROWTH , SI_GIANTGROWTH , SCB_STR );
+ set_sc( RK_STONEHARDSKIN , SC_STONEHARDSKIN , SI_STONEHARDSKIN , SCB_NONE );
+ set_sc( RK_VITALITYACTIVATION, SC_VITALITYACTIVATION, SI_VITALITYACTIVATION, SCB_REGEN );
+ set_sc( RK_FIGHTINGSPIRIT , SC_FIGHTINGSPIRIT , SI_FIGHTINGSPIRIT , SCB_WATK|SCB_ASPD );
+ set_sc( RK_ABUNDANCE , SC_ABUNDANCE , SI_ABUNDANCE , SCB_NONE );
+ /**
+ * GC Guillotine Cross
+ **/
+ set_sc( GC_VENOMIMPRESS , SC_VENOMIMPRESS , SI_VENOMIMPRESS , SCB_NONE );
+ set_sc( GC_POISONINGWEAPON , SC_POISONINGWEAPON , SI_POISONINGWEAPON , SCB_NONE );
+ set_sc( GC_WEAPONBLOCKING , SC_WEAPONBLOCKING , SI_WEAPONBLOCKING , SCB_NONE );
+ set_sc( GC_CLOAKINGEXCEED , SC_CLOAKINGEXCEED , SI_CLOAKINGEXCEED , SCB_SPEED );
+ set_sc( GC_HALLUCINATIONWALK , SC_HALLUCINATIONWALK, SI_HALLUCINATIONWALK, SCB_FLEE );
+ set_sc( GC_ROLLINGCUTTER , SC_ROLLINGCUTTER , SI_ROLLINGCUTTER , SCB_NONE );
+ /**
+ * Arch Bishop
+ **/
+ set_sc( AB_ADORAMUS , SC_ADORAMUS , SI_ADORAMUS , SCB_AGI|SCB_SPEED );
+ add_sc( AB_CLEMENTIA , SC_BLESSING );
+ add_sc( AB_CANTO , SC_INCREASEAGI );
+ set_sc( AB_EPICLESIS , SC_EPICLESIS , SI_EPICLESIS , SCB_MAXHP );
+ add_sc( AB_PRAEFATIO , SC_KYRIE );
+ set_sc( AB_ORATIO , SC_ORATIO , SI_ORATIO , SCB_NONE );
+ set_sc( AB_LAUDAAGNUS , SC_LAUDAAGNUS , SI_LAUDAAGNUS , SCB_VIT );
+ set_sc( AB_LAUDARAMUS , SC_LAUDARAMUS , SI_LAUDARAMUS , SCB_LUK );
+ set_sc( AB_RENOVATIO , SC_RENOVATIO , SI_RENOVATIO , SCB_REGEN );
+ set_sc( AB_EXPIATIO , SC_EXPIATIO , SI_EXPIATIO , SCB_ATK_ELE );
+ set_sc( AB_DUPLELIGHT , SC_DUPLELIGHT , SI_DUPLELIGHT , SCB_NONE );
+ set_sc( AB_SECRAMENT , SC_SECRAMENT , SI_SECRAMENT , SCB_NONE );
+ /**
+ * Warlock
+ **/
+ add_sc( WL_WHITEIMPRISON , SC_WHITEIMPRISON );
+ set_sc( WL_FROSTMISTY , SC_FREEZING , SI_FROSTMISTY , SCB_ASPD|SCB_SPEED|SCB_DEF|SCB_DEF2 );
+ set_sc( WL_MARSHOFABYSS , SC_MARSHOFABYSS , SI_MARSHOFABYSS , SCB_SPEED|SCB_FLEE|SCB_DEF|SCB_MDEF );
+ set_sc( WL_RECOGNIZEDSPELL , SC_RECOGNIZEDSPELL , SI_RECOGNIZEDSPELL , SCB_NONE );
+ set_sc( WL_STASIS , SC_STASIS , SI_STASIS , SCB_NONE );
+ /**
+ * Ranger
+ **/
+ set_sc( RA_FEARBREEZE , SC_FEARBREEZE , SI_FEARBREEZE , SCB_NONE );
+ set_sc( RA_ELECTRICSHOCKER , SC_ELECTRICSHOCKER , SI_ELECTRICSHOCKER , SCB_NONE );
+ set_sc( RA_WUGDASH , SC_WUGDASH , SI_WUGDASH , SCB_SPEED );
+ set_sc( RA_CAMOUFLAGE , SC_CAMOUFLAGE , SI_CAMOUFLAGE , SCB_CRI|SCB_SPEED );
+ add_sc( RA_MAGENTATRAP , SC_ELEMENTALCHANGE );
+ add_sc( RA_COBALTTRAP , SC_ELEMENTALCHANGE );
+ add_sc( RA_MAIZETRAP , SC_ELEMENTALCHANGE );
+ add_sc( RA_VERDURETRAP , SC_ELEMENTALCHANGE );
+ add_sc( RA_FIRINGTRAP , SC_BURNING );
+ set_sc( RA_ICEBOUNDTRAP , SC_FREEZING , SI_FROSTMISTY , SCB_NONE );
+ /**
+ * Mechanic
+ **/
+ set_sc( NC_ACCELERATION , SC_ACCELERATION , SI_ACCELERATION , SCB_SPEED );
+ set_sc( NC_HOVERING , SC_HOVERING , SI_HOVERING , SCB_SPEED );
+ set_sc( NC_SHAPESHIFT , SC_SHAPESHIFT , SI_SHAPESHIFT , SCB_DEF_ELE );
+ set_sc( NC_INFRAREDSCAN , SC_INFRAREDSCAN , SI_INFRAREDSCAN , SCB_FLEE );
+ set_sc( NC_ANALYZE , SC_ANALYZE , SI_ANALYZE , SCB_DEF|SCB_DEF2|SCB_MDEF|SCB_MDEF2 );
+ set_sc( NC_MAGNETICFIELD , SC_MAGNETICFIELD , SI_MAGNETICFIELD , SCB_NONE );
+ set_sc( NC_NEUTRALBARRIER , SC_NEUTRALBARRIER , SI_NEUTRALBARRIER , SCB_NONE );
+ set_sc( NC_STEALTHFIELD , SC_STEALTHFIELD , SI_STEALTHFIELD , SCB_NONE );
+ ///**
+ // * Shadow Chaser
+ // **/
+ //set_sc( SC_REPRODUCE , SC__REPRODUCE , SI_REPRODUCE , SCB_NONE );
+ //set_sc( SC_AUTOSHADOWSPELL , SC__AUTOSHADOWSPELL, SI_AUTOSHADOWSPELL , SCB_NONE );
+ //set_sc( SC_SHADOWFORM , SC__SHADOWFORM , SI_SHADOWFORM , SCB_NONE );
+ //set_sc( SC_BODYPAINT , SC__BODYPAINT , SI_BODYPAINTING , SCB_ASPD );
+ //set_sc( SC_INVISIBILITY , SC__INVISIBILITY , SI_INVISIBILITY , SCB_ASPD|SCB_CRI|SCB_ATK_ELE );
+ //set_sc( SC_DEADLYINFECT , SC__DEADLYINFECT , SI_DEADLYINFECT , SCB_NONE );
+ //set_sc( SC_ENERVATION , SC__ENERVATION , SI_ENERVATION , SCB_BATK );
+ //set_sc( SC_GROOMY , SC__GROOMY , SI_GROOMY , SCB_ASPD|SCB_HIT|SCB_SPEED );
+ //set_sc( SC_IGNORANCE , SC__IGNORANCE , SI_IGNORANCE , SCB_NONE );
+ //set_sc( SC_LAZINESS , SC__LAZINESS , SI_LAZINESS , SCB_FLEE );
+ //set_sc( SC_UNLUCKY , SC__UNLUCKY , SI_UNLUCKY , SCB_CRI|SCB_FLEE2 );
+ //set_sc( SC_WEAKNESS , SC__WEAKNESS , SI_WEAKNESS , SCB_FLEE2|SCB_MAXHP );
+ //set_sc( SC_STRIPACCESSARY , SC__STRIPACCESSORY , SI_STRIPACCESSORY , SCB_DEX|SCB_INT|SCB_LUK );
+ //set_sc( SC_MANHOLE , SC__MANHOLE , SI_MANHOLE , SCB_NONE );
+ //add_sc( SC_CHAOSPANIC , SC_CHAOS );
+ //set_sc( SC_BLOODYLUST , SC__BLOODYLUST , SI_BLOODYLUST , SCB_DEF|SCB_DEF2|SCB_BATK|SCB_WATK );
+ ///**
+ // * Royal Guard
+ // **/
+ //set_sc( LG_REFLECTDAMAGE , SC_REFLECTDAMAGE , SI_LG_REFLECTDAMAGE, SCB_NONE );
+ //set_sc( LG_FORCEOFVANGUARD , SC_FORCEOFVANGUARD , SI_FORCEOFVANGUARD , SCB_MAXHP|SCB_DEF );
+ //set_sc( LG_EXEEDBREAK , SC_EXEEDBREAK , SI_EXEEDBREAK , SCB_NONE );
+ //set_sc( LG_PRESTIGE , SC_PRESTIGE , SI_PRESTIGE , SCB_DEF2 );
+ //set_sc( LG_BANDING , SC_BANDING , SI_BANDING , SCB_DEF2|SCB_WATK );// Renewal: atk2 & def2
+ //set_sc( LG_PIETY , SC_BENEDICTIO , SI_BENEDICTIO , SCB_DEF_ELE );
+ //set_sc( LG_EARTHDRIVE , SC_EARTHDRIVE , SI_EARTHDRIVE , SCB_DEF|SCB_ASPD );
+ //set_sc( LG_INSPIRATION , SC_INSPIRATION , SI_INSPIRATION , SCB_MAXHP|SCB_WATK|SCB_HIT|SCB_VIT|SCB_AGI|SCB_STR|SCB_DEX|SCB_INT|SCB_LUK);
+ ///**
+ // * Sura
+ // **/
+ //add_sc( SR_DRAGONCOMBO , SC_STUN );
+ //add_sc( SR_EARTHSHAKER , SC_STUN );
+ //set_sc( SR_CRESCENTELBOW , SC_CRESCENTELBOW , SI_CRESCENTELBOW , SCB_NONE );
+ //set_sc( SR_CURSEDCIRCLE , SC_CURSEDCIRCLE_TARGET, SI_CURSEDCIRCLE_TARGET , SCB_NONE );
+ //set_sc( SR_LIGHTNINGWALK , SC_LIGHTNINGWALK , SI_LIGHTNINGWALK , SCB_NONE );
+ //set_sc( SR_RAISINGDRAGON , SC_RAISINGDRAGON , SI_RAISINGDRAGON , SCB_REGEN|SCB_MAXHP|SCB_MAXSP/*|SCB_ASPD*/ );
+ //set_sc( SR_GENTLETOUCH_ENERGYGAIN, SC_GT_ENERGYGAIN , SI_GENTLETOUCH_ENERGYGAIN, SCB_NONE );
+ //set_sc( SR_GENTLETOUCH_CHANGE , SC_GT_CHANGE , SI_GENTLETOUCH_CHANGE , SCB_BATK|SCB_ASPD|SCB_DEF|SCB_MDEF );
+ //set_sc( SR_GENTLETOUCH_REVITALIZE, SC_GT_REVITALIZE , SI_GENTLETOUCH_REVITALIZE, SCB_MAXHP|SCB_DEF2|SCB_REGEN|SCB_ASPD|SCB_SPEED );
+ ///**
+ // * Wanderer / Mistrel
+ // **/
+ //set_sc( WA_SWING_DANCE , SC_SWINGDANCE , SI_SWINGDANCE , SCB_SPEED|SCB_ASPD );
+ //set_sc( WA_SYMPHONY_OF_LOVER , SC_SYMPHONYOFLOVER , SI_SYMPHONYOFLOVERS , SCB_MDEF );
+ //set_sc( WA_MOONLIT_SERENADE , SC_MOONLITSERENADE , SI_MOONLITSERENADE , SCB_MATK );
+ //set_sc( MI_RUSH_WINDMILL , SC_RUSHWINDMILL , SI_RUSHWINDMILL , SCB_BATK );
+ //set_sc( MI_ECHOSONG , SC_ECHOSONG , SI_ECHOSONG , SCB_DEF2 );
+ //set_sc( MI_HARMONIZE , SC_HARMONIZE , SI_HARMONIZE , SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK );
+ //set_sc( WM_POEMOFNETHERWORLD , SC_STOP , SI_NETHERWORLD , SCB_NONE );
+ //set_sc( WM_VOICEOFSIREN , SC_VOICEOFSIREN , SI_VOICEOFSIREN , SCB_NONE );
+ //set_sc( WM_LULLABY_DEEPSLEEP , SC_DEEPSLEEP , SI_DEEPSLEEP , SCB_NONE );
+ //set_sc( WM_SIRCLEOFNATURE , SC_SIRCLEOFNATURE , SI_SIRCLEOFNATURE , SCB_NONE );
+ //set_sc( WM_GLOOMYDAY , SC_GLOOMYDAY , SI_GLOOMYDAY , SCB_FLEE|SCB_ASPD );
+ //set_sc( WM_SONG_OF_MANA , SC_SONGOFMANA , SI_SONGOFMANA , SCB_NONE );
+ //set_sc( WM_DANCE_WITH_WUG , SC_DANCEWITHWUG , SI_DANCEWITHWUG , SCB_ASPD );
+ //set_sc( WM_SATURDAY_NIGHT_FEVER , SC_SATURDAYNIGHTFEVER , SI_SATURDAYNIGHTFEVER , SCB_BATK|SCB_DEF|SCB_FLEE|SCB_REGEN );
+ //set_sc( WM_LERADS_DEW , SC_LERADSDEW , SI_LERADSDEW , SCB_MAXHP );
+ //set_sc( WM_MELODYOFSINK , SC_MELODYOFSINK , SI_MELODYOFSINK , SCB_BATK|SCB_MATK );
+ //set_sc( WM_BEYOND_OF_WARCRY , SC_BEYONDOFWARCRY , SI_WARCRYOFBEYOND , SCB_BATK|SCB_MATK );
+ //set_sc( WM_UNLIMITED_HUMMING_VOICE, SC_UNLIMITEDHUMMINGVOICE, SI_UNLIMITEDHUMMINGVOICE, SCB_NONE );
+ ///**
+ // * Sorcerer
+ // **/
+ //set_sc( SO_FIREWALK , SC_PROPERTYWALK , SI_PROPERTYWALK , SCB_NONE );
+ //set_sc( SO_ELECTRICWALK , SC_PROPERTYWALK , SI_PROPERTYWALK , SCB_NONE );
+ //set_sc( SO_SPELLFIST , SC_SPELLFIST , SI_SPELLFIST , SCB_NONE );
+ //set_sc( SO_CLOUD_KILL , SC_POISON , SI_CLOUDKILL , SCB_NONE );
+ //set_sc( SO_STRIKING , SC_STRIKING , SI_STRIKING , SCB_WATK|SCB_CRI );
+ //set_sc( SO_WARMER , SC_WARMER , SI_WARMER , SCB_NONE );
+ //set_sc( SO_VACUUM_EXTREME , SC_VACUUM_EXTREME , SI_VACUUM_EXTREME , SCB_NONE );
+ //set_sc( SO_ARRULLO , SC_DEEPSLEEP , SI_DEEPSLEEP , SCB_NONE );
+ ///**
+ // * Genetic
+ // **/
+ //set_sc( GN_CARTBOOST , SC_GN_CARTBOOST, SI_CARTSBOOST , SCB_SPEED );
+ //set_sc( GN_THORNS_TRAP , SC_THORNSTRAP , SI_THORNTRAP , SCB_NONE );
+ //set_sc( GN_BLOOD_SUCKER , SC_BLOODSUCKER , SI_BLOODSUCKER , SCB_NONE );
+ //set_sc( GN_WALLOFTHORN , SC_STOP , SI_BLANK , SCB_NONE );
+ //set_sc( GN_FIRE_EXPANSION_SMOKE_POWDER, SC_SMOKEPOWDER , SI_FIRE_EXPANSION_SMOKE_POWDER, SCB_NONE );
+ //set_sc( GN_FIRE_EXPANSION_TEAR_GAS , SC_TEARGAS , SI_FIRE_EXPANSION_TEAR_GAS , SCB_NONE );
+ //set_sc( GN_MANDRAGORA , SC_MANDRAGORA , SI_MANDRAGORA , SCB_INT );
// Storing the target job rather than simply SC_SPIRIT simplifies code later on.
SkillStatusChangeTable[SL_ALCHEMIST] = (sc_type)MAPID_ALCHEMIST,
@@ -516,6 +678,81 @@ void initChangeTables(void)
StatusIconChangeTable[SC_MERC_HPUP] = SI_MERC_HPUP;
StatusIconChangeTable[SC_MERC_SPUP] = SI_MERC_SPUP;
StatusIconChangeTable[SC_MERC_HITUP] = SI_MERC_HITUP;
+ // Warlock Spheres
+ StatusIconChangeTable[SC_SPHERE_1] = SI_SPHERE_1;
+ StatusIconChangeTable[SC_SPHERE_2] = SI_SPHERE_2;
+ StatusIconChangeTable[SC_SPHERE_3] = SI_SPHERE_3;
+ StatusIconChangeTable[SC_SPHERE_4] = SI_SPHERE_4;
+ StatusIconChangeTable[SC_SPHERE_5] = SI_SPHERE_5;
+
+ StatusIconChangeTable[SC_NEUTRALBARRIER_MASTER] = SI_NEUTRALBARRIER_MASTER;
+ StatusIconChangeTable[SC_STEALTHFIELD_MASTER] = SI_STEALTHFIELD_MASTER;
+ StatusIconChangeTable[SC_OVERHEAT] = SI_OVERHEAT;
+ StatusIconChangeTable[SC_OVERHEAT_LIMITPOINT] = SI_OVERHEAT_LIMITPOINT;
+
+ StatusIconChangeTable[SC_HALLUCINATIONWALK_POSTDELAY] = SI_HALLUCINATIONWALK_POSTDELAY;
+ StatusIconChangeTable[SC_TOXIN] = SI_TOXIN;
+ StatusIconChangeTable[SC_PARALYSE] = SI_PARALYSE;
+ StatusIconChangeTable[SC_VENOMBLEED] = SI_VENOMBLEED;
+ StatusIconChangeTable[SC_MAGICMUSHROOM] = SI_MAGICMUSHROOM;
+ StatusIconChangeTable[SC_DEATHHURT] = SI_DEATHHURT;
+ StatusIconChangeTable[SC_PYREXIA] = SI_PYREXIA;
+ StatusIconChangeTable[SC_OBLIVIONCURSE] = SI_OBLIVIONCURSE;
+ StatusIconChangeTable[SC_LEECHESEND] = SI_LEECHESEND;
+
+ StatusIconChangeTable[SC_SHIELDSPELL_DEF] = SI_SHIELDSPELL_DEF;
+ StatusIconChangeTable[SC_SHIELDSPELL_MDEF] = SI_SHIELDSPELL_MDEF;
+ StatusIconChangeTable[SC_SHIELDSPELL_REF] = SI_SHIELDSPELL_REF;
+ StatusIconChangeTable[SC_BANDING_DEFENCE] = SI_BANDING_DEFENCE;
+
+ StatusIconChangeTable[SC_GLOOMYDAY_SK] = SI_GLOOMYDAY;
+
+ StatusIconChangeTable[SC_CURSEDCIRCLE_ATKER] = SI_CURSEDCIRCLE_ATKER;
+
+ StatusIconChangeTable[SC_STOMACHACHE] = SI_STOMACHACHE;
+ StatusIconChangeTable[SC_MYSTERIOUS_POWDER] = SI_MYSTERIOUS_POWDER;
+ StatusIconChangeTable[SC_MELON_BOMB] = SI_MELON_BOMB;
+ StatusIconChangeTable[SC_BANANA_BOMB] = SI_BANANA_BOMB;
+ StatusIconChangeTable[SC_BANANA_BOMB_SITDOWN] = SI_BANANA_BOMB_SITDOWN_POSTDELAY;
+
+ //Genetics New Food Items Status Icons
+ StatusIconChangeTable[SC_SAVAGE_STEAK] = SI_SAVAGE_STEAK;
+ StatusIconChangeTable[SC_COCKTAIL_WARG_BLOOD] = SI_COCKTAIL_WARG_BLOOD;
+ StatusIconChangeTable[SC_MINOR_BBQ] = SI_MINOR_BBQ;
+ StatusIconChangeTable[SC_SIROMA_ICE_TEA] = SI_SIROMA_ICE_TEA;
+ StatusIconChangeTable[SC_DROCERA_HERB_STEAMED] = SI_DROCERA_HERB_STEAMED;
+ StatusIconChangeTable[SC_PUTTI_TAILS_NOODLES] = SI_PUTTI_TAILS_NOODLES;
+
+ StatusIconChangeTable[SC_BOOST500] |= SI_BOOST500;
+ StatusIconChangeTable[SC_FULL_SWING_K] |= SI_FULL_SWING_K;
+ StatusIconChangeTable[SC_MANA_PLUS] |= SI_MANA_PLUS;
+ StatusIconChangeTable[SC_MUSTLE_M] |= SI_MUSTLE_M;
+ StatusIconChangeTable[SC_LIFE_FORCE_F] |= SI_LIFE_FORCE_F;
+ StatusIconChangeTable[SC_EXTRACT_WHITE_POTION_Z] |= SI_EXTRACT_WHITE_POTION_Z;
+ StatusIconChangeTable[SC_VITATA_500] |= SI_VITATA_500;
+ StatusIconChangeTable[SC_EXTRACT_SALAMINE_JUICE] |= SI_EXTRACT_SALAMINE_JUICE;
+
+ // Elemental Spirit's 'side' status change icons.
+ StatusIconChangeTable[SC_CIRCLE_OF_FIRE] = SI_CIRCLE_OF_FIRE;
+ StatusIconChangeTable[SC_FIRE_CLOAK] = SI_FIRE_CLOAK;
+ StatusIconChangeTable[SC_WATER_SCREEN] = SI_WATER_SCREEN;
+ StatusIconChangeTable[SC_WATER_DROP] = SI_WATER_DROP;
+ StatusIconChangeTable[SC_WIND_STEP] = SI_WIND_STEP;
+ StatusIconChangeTable[SC_WIND_CURTAIN] = SI_WIND_CURTAIN;
+ StatusIconChangeTable[SC_SOLID_SKIN] = SI_SOLID_SKIN;
+ StatusIconChangeTable[SC_STONE_SHIELD] = SI_STONE_SHIELD;
+ StatusIconChangeTable[SC_PYROTECHNIC] = SI_PYROTECHNIC;
+ StatusIconChangeTable[SC_HEATER] = SI_HEATER;
+ StatusIconChangeTable[SC_TROPIC] = SI_TROPIC;
+ StatusIconChangeTable[SC_AQUAPLAY] = SI_AQUAPLAY;
+ StatusIconChangeTable[SC_COOLER] = SI_COOLER;
+ StatusIconChangeTable[SC_CHILLY_AIR] = SI_CHILLY_AIR;
+ StatusIconChangeTable[SC_GUST] = SI_GUST;
+ StatusIconChangeTable[SC_BLAST] = SI_BLAST;
+ StatusIconChangeTable[SC_WILD_STORM] = SI_WILD_STORM;
+ StatusIconChangeTable[SC_PETROLOGY] = SI_PETROLOGY;
+ StatusIconChangeTable[SC_CURSED_SOIL] = SI_CURSED_SOIL;
+ StatusIconChangeTable[SC_UPHEAVAL] = SI_UPHEAVAL;
//Other SC which are not necessarily associated to skills.
StatusChangeFlagTable[SC_ASPDPOTION0] = SCB_ASPD;
@@ -573,7 +810,12 @@ void initChangeTables(void)
StatusChangeFlagTable[SC_MERC_HPUP] |= SCB_MAXHP;
StatusChangeFlagTable[SC_MERC_SPUP] |= SCB_MAXSP;
StatusChangeFlagTable[SC_MERC_HITUP] |= SCB_HIT;
-
+#if RE_EDP
+ /**
+ * In RE EDP increases your atk and weapon atk
+ **/
+ StatusChangeFlagTable[SC_EDP] |= SCB_BATK|SCB_WATK;
+#endif
if( !battle_config.display_hallucination ) //Disable Hallucination.
StatusIconChangeTable[SC_HALLUCINATION] = SI_BLANK;
}
@@ -728,6 +970,7 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s
status_change_end(target, SC_HIDING, INVALID_TIMER);
status_change_end(target, SC_CLOAKING, INVALID_TIMER);
status_change_end(target, SC_CHASEWALK, INVALID_TIMER);
+ status_change_end(target, SC_CAMOUFLAGE, INVALID_TIMER);
if ((sce=sc->data[SC_ENDURE]) && !sce->val4) {
//Endure count is only reduced by non-players on non-gvg maps.
//val4 signals infinite endure. [Skotlex]
@@ -745,6 +988,8 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s
}
if(sc->data[SC_DANCING] && (unsigned int)hp > status->max_hp>>2)
status_change_end(target, SC_DANCING, INVALID_TIMER);
+ if(sc->data[SC_CLOAKINGEXCEED] && --(sc->data[SC_CLOAKINGEXCEED]->val2) <= 0)
+ status_change_end(target,SC_CLOAKINGEXCEED,-1);
}
unit_skillcastcancel(target, 2);
}
@@ -1176,6 +1421,8 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, int
}
if (sc->option&OPTION_CHASEWALK && skill_num != ST_CHASEWALK)
return 0;
+ if(sc->option&OPTION_MOUNTING)
+ return 0;//New mounts can't attack nor use skills in the client; this check makes it cheat-safe [Ind]
}
if (target == NULL || target == src) //No further checking needed.
return 1;
@@ -1210,6 +1457,8 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, int
if (tsc->option&hide_flag && !(status->mode&MD_BOSS) &&
(sd->special_state.perfect_hiding || !(status->mode&MD_DETECTOR)))
return 0;
+ if( tsc->data[SC_CAMOUFLAGE] && !(status->mode&(MD_BOSS|MD_DETECTOR)) && !skill_num )
+ return 0;
}
break;
case BL_ITEM: //Allow targetting of items to pick'em up (or in the case of mobs, to loot them).
@@ -1256,18 +1505,14 @@ int status_check_visibility(struct block_list *src, struct block_list *target)
switch (target->type)
{ //Check for chase-walk/hiding/cloaking opponents.
case BL_PC:
- if(tsc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) &&
- !(status->mode&MD_BOSS) &&
- (
- ((TBL_PC*)target)->special_state.perfect_hiding ||
- !(status->mode&MD_DETECTOR)
- ))
+ if( (tsc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) || tsc->data[SC_CAMOUFLAGE]) && !(status->mode&MD_BOSS) &&
+ ( ((TBL_PC*)target)->special_state.perfect_hiding || !(status->mode&MD_DETECTOR) ) )
return 0;
break;
default:
- if (tsc && tsc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) &&
- !(status->mode&(MD_BOSS|MD_DETECTOR)))
- return 0;
+ if( tsc && (tsc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) || tsc->data[SC_CAMOUFLAGE]) && !(status->mode&(MD_BOSS|MD_DETECTOR)) )
+ return 0;
+
}
return 1;
@@ -1288,7 +1533,24 @@ int status_base_amotion_pc(struct map_session_data* sd, struct status_data* stat
// raw delay adjustment from bAspd bonus
amotion+= sd->aspd_add;
-
+#if RRMODE
+ /**
+ * Bearing a shield decreases your ASPD by a fixed value depending on your class
+ **/
+ if( sd->status.shield )
+ amotion += re_job_db[pc_class2idx(sd->status.class_)][SHIELD_ASPD];
+ /**
+ * RE Absolute aspd modifiers
+ **/
+ if( sd->sc.count ) {
+ int i;
+ if ( sd->sc.data[i=SC_ASPDPOTION3] ||
+ sd->sc.data[i=SC_ASPDPOTION2] ||
+ sd->sc.data[i=SC_ASPDPOTION1] ||
+ sd->sc.data[i=SC_ASPDPOTION0] )
+ amotion -= sd->sc.data[i]->val1*10;
+ }
+#endif
return amotion;
}
@@ -1331,13 +1593,24 @@ static unsigned short status_base_atk(const struct block_list *bl, const struct
static inline unsigned short status_base_matk_max(const struct status_data* status)
{
- return status->int_+(status->int_/5)*(status->int_/5);
+ #if RRMODE
+ return status->matk_max;//In RE maximum MATK signs weapon matk, which we store in this var
+ #else //Original Max MATK Formula
+ return status->int_+(status->int_/5)*(status->int_/5);
+ #endif
}
-
+#if RRMODE
+static inline unsigned short status_base_matk_min(const struct status_data* status, int lvl)
+#else
static inline unsigned short status_base_matk_min(const struct status_data* status)
+#endif
{
- return status->int_+(status->int_/7)*(status->int_/7);
+ #if RRMODE //Renewal MATK Formula
+ return status->int_+(status->int_/2)+(status->dex/5)+(status->luk/3)+(lvl/4);
+ #else //Original Min MATK Formula
+ return status->int_+(status->int_/7)*(status->int_/7);
+ #endif
}
@@ -1350,14 +1623,31 @@ void status_calc_misc(struct block_list *bl, struct status_data *status, int lev
status->hit = status->flee =
status->def2 = status->mdef2 =
status->cri = status->flee2 = 0;
-
+#if RRMODE
+ status->matk_min = status_base_matk_min(status, level);
+#else
status->matk_min = status_base_matk_min(status);
+#endif
status->matk_max = status_base_matk_max(status);
+#if RRMODE //Renewal Formulas
+ status->hit += level + status->dex;//base level + ( every 1 dex = +1 hit )
+ status->hit += status->luk / 3;//every 3 luk = +1 hit
+ status->flee += level + status->agi;//base level + ( every 1 agi = +1 flee )
+ status->flee += status->luk/5;//every 5 luk = +1 flee
+ status->def2 += status->agi / 5;//every 5 agi = +1 def
+ status->def2 += status->vit / 2;//every 2 agi = +1 def
+ status->def2 += level / 2;//every 2 lvls = +1 def
+ status->mdef2 += status->int_ / 2;//every 2 int = +1 mdef
+ status->mdef2 += status->dex / 5;//every 5 dex = +1 mdef
+ status->mdef2 += level /4;//every 4 lvls = +1 mdef
+ //status->matk_min += level/4;//every 4 lvls = +1 matk
+#else //Old Formulas
status->hit += level + status->dex;
status->flee += level + status->agi;
status->def2 += status->vit;
status->mdef2 += status->int_ + (status->vit>>1);
+#endif
if( bl->type&battle_config.enable_critical )
status->cri += status->luk*3 + 10;
@@ -1374,6 +1664,10 @@ void status_calc_misc(struct block_list *bl, struct status_data *status, int lev
status->batk = cap_value(temp, 0, USHRT_MAX);
} else
status->batk = status_base_atk(bl, status);
+#if RRMODE //Renewal ATK Bonus Formula (after atk is calculated)
+ status->batk += status->luk / 3;//every 3 luk = +1ATK
+ status->batk += level / 4;//every 4 levels = +1 ATK
+#endif
if (status->cri)
switch (bl->type) {
case BL_MOB:
@@ -1684,6 +1978,18 @@ static unsigned int status_base_pc_maxsp(struct map_session_data* sd, struct sta
return val;
}
+#if RRMODE
+/**
+ * Renewal Absolute Bonus to be applied after all bonuses were applied (so % bonuses on say, skills, don't affect them)
+ **/
+void status_renewal_postcalc(struct status_data* status, int flag) {
+ if( flag&SCB_FLEE )
+ status->flee += 100;
+ if( flag&SCB_HIT )
+ status->hit += 175;
+ return;
+}
+#endif
//Calculates player data from scratch without counting SC adjustments.
//Should be invoked whenever players raise stats, learn passive skills or change equipment.
@@ -1909,7 +2215,6 @@ int status_calc_pc_(struct map_session_data* sd, bool first)
int r,wlv = sd->inventory_data[index]->wlv;
struct weapon_data *wd;
struct weapon_atk *wa;
-
if (wlv >= MAX_REFINE_BONUS)
wlv = MAX_REFINE_BONUS - 1;
if(i == EQI_HAND_L && sd->status.inventory[index].equip == EQP_HAND_L) {
@@ -1921,6 +2226,21 @@ int status_calc_pc_(struct map_session_data* sd, bool first)
}
wa->atk += sd->inventory_data[index]->atk;
wa->atk2 = (r=sd->status.inventory[index].refine)*refinebonus[wlv][0];
+ #if RRMODE
+ /**
+ * in RE matk_max is used as the weapon's matk.
+ * += is used so that two-wield weapons (in the case of, say, sinx) bonus stack.
+ **/
+ status->matk_max += sd->inventory_data[index]->matk;
+ /**
+ * Refine Bonus
+ **/
+ status->matk_max += sd->status.inventory[index].refine * refinebonus[wlv][0];
+ /**
+ * In RE weapon level is used in several areas, this way we save performance
+ **/
+ status->wlv = wlv;
+ #endif
if((r-=refinebonus[wlv][2])>0) //Overrefine bonus.
wd->overrefine = r*refinebonus[wlv][1];
@@ -2277,7 +2597,6 @@ int status_calc_pc_(struct map_session_data* sd, bool first)
status->flee += skill*(sd->class_&JOBL_2 && (sd->class_&MAPID_BASEMASK) == MAPID_THIEF? 4 : 3);
if((skill=pc_checkskill(sd,MO_DODGE))>0)
status->flee += (skill*3)>>1;
-
// ----- EQUIPMENT-DEF CALCULATION -----
// Apply relative modifiers from equipment
@@ -2429,7 +2748,6 @@ int status_calc_pc_(struct map_session_data* sd, bool first)
sd->subele[ELE_WIND] += sc->data[SC_ARMOR_RESIST]->val4;
}
}
-
status_cpy(&sd->battle_status, status);
// ----- CLIENT-SIDE REFRESH -----
@@ -2996,18 +3314,26 @@ void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag)
if(flag&SCB_MATK) {
//New matk
+ #if RRMODE
+ status->matk_min = status_base_matk_min(status,status_get_lv(bl));
+ #else
status->matk_min = status_base_matk_min(status);
+ #endif
status->matk_max = status_base_matk_max(status);
if( bl->type&BL_PC && sd->matk_rate != 100 )
{
//Bonuses from previous matk
+ #if RRMODE == 0 //Only changed in non-re [RRInd]
status->matk_max = status->matk_max * sd->matk_rate/100;
+ #endif
status->matk_min = status->matk_min * sd->matk_rate/100;
}
status->matk_min = status_calc_matk(bl, sc, status->matk_min);
- status->matk_max = status_calc_matk(bl, sc, status->matk_max);
+ #if RRMODE == 0 //Only changed in non-re [RRInd]
+ status->matk_max = status_calc_matk(bl, sc, status->matk_max);
+ #endif
if(sc->data[SC_MAGICPOWER]) { //Store current matk values
sc->mp_matk_min = status->matk_min;
@@ -3088,14 +3414,15 @@ void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag)
status->dmotion = status_calc_dmotion(bl, sc, b_status->dmotion);
}
}
-
+#if RRMODE
+ status_renewal_postcalc(status,flag);
+#endif
if(flag&(SCB_VIT|SCB_MAXHP|SCB_INT|SCB_MAXSP) && bl->type&BL_REGEN)
status_calc_regen(bl, status, status_get_regen_data(bl));
if(flag&SCB_REGEN && bl->type&BL_REGEN)
status_calc_regen_rate(bl, status_get_regen_data(bl), sc);
}
-
/// Recalculates parts of an object's base status and battle status according to the specified flags.
/// Also sends updates to the client wherever applicable.
/// @param flag bitfield of values from enum scb_flag
@@ -3265,6 +3592,11 @@ static unsigned short status_calc_str(struct block_list *bl, struct status_chang
str += ((sc->data[SC_MARIONETTE2]->val3)>>16)&0xFF;
if(sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_HIGH && str < 50)
str = 50;
+ /**
+ * RK Rune Skill
+ **/
+ if(sc->data[SC_GIANTGROWTH])
+ str += 30;
return (unsigned short)cap_value(str,0,USHRT_MAX);
}
@@ -3304,6 +3636,11 @@ static unsigned short status_calc_agi(struct block_list *bl, struct status_chang
agi += ((sc->data[SC_MARIONETTE2]->val3)>>8)&0xFF;
if(sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_HIGH && agi < 50)
agi = 50;
+ /**
+ * Arch Bishop
+ **/
+ if(sc->data[SC_ADORAMUS])
+ agi -= sc->data[SC_ADORAMUS]->val2;
return (unsigned short)cap_value(agi,0,USHRT_MAX);
}
@@ -3481,6 +3818,13 @@ static unsigned short status_calc_batk(struct block_list *bl, struct status_chan
batk += sc->data[SC_GATLINGFEVER]->val3;
if(sc->data[SC_MADNESSCANCEL])
batk += 100;
+#if RE_EDP
+ /**
+ * in RE EDP increases your base atk by atk x Skill Level.
+ **/
+ if( sc->data[SC_EDP] )
+ batk = batk * sc->data[SC_EDP]->val1;
+#endif
return (unsigned short)cap_value(batk,0,USHRT_MAX);
}
@@ -3525,6 +3869,13 @@ static unsigned short status_calc_watk(struct block_list *bl, struct status_chan
watk -= watk * sc->data[SC_STRIPWEAPON]->val2/100;
if(sc->data[SC_MERC_ATKUP])
watk += sc->data[SC_MERC_ATKUP]->val2;
+#if RE_EDP
+ /**
+ * in RE EDP increases your weapon atk by watk x Skill Level - 1
+ **/
+ if( sc->data[SC_EDP] && sc->data[SC_EDP]->val1 > 1 )
+ watk = watk * (sc->data[SC_EDP]->val1 - 1);
+#endif
return (unsigned short)cap_value(watk,0,USHRT_MAX);
}
@@ -3563,6 +3914,8 @@ static signed short status_calc_critical(struct block_list *bl, struct status_ch
critical += sc->data[SC_TRUESIGHT]->val2;
if(sc->data[SC_CLOAKING])
critical += critical;
+ if(sc->data[SC_CAMOUFLAGE])
+ critical += 100;
return (short)cap_value(critical,10,SHRT_MAX);
}
@@ -3593,6 +3946,8 @@ static signed short status_calc_hit(struct block_list *bl, struct status_change
hit += 20; // RockmanEXE; changed based on updated [Reddozen]
if(sc->data[SC_MERC_HITUP])
hit += sc->data[SC_MERC_HITUP]->val2;
+ if(sc->data[SC_FEAR])
+ hit -= hit * 20 / 100;
return (short)cap_value(hit,1,SHRT_MAX);
}
@@ -3640,6 +3995,29 @@ static signed short status_calc_flee(struct block_list *bl, struct status_change
flee += 10 + sc->data[SC_SPEED]->val1 * 10;
if(sc->data[SC_MERC_FLEEUP])
flee += sc->data[SC_MERC_FLEEUP]->val2;
+ if(sc->data[SC_FEAR])
+ flee -= flee * 20 / 100;
+ if(sc->data[SC_PARALYSE])
+ flee -= flee / 10; // 10% Flee reduction
+ if(sc->data[SC_INFRAREDSCAN])
+ flee -= flee * 30 / 100;
+ if( sc->data[SC__LAZINESS] )
+ flee -= flee * sc->data[SC__LAZINESS]->val3 / 100;
+ if( sc->data[SC_GLOOMYDAY] )
+ flee -= flee * sc->data[SC_GLOOMYDAY]->val2 / 100;
+ if( sc->data[SC_HALLUCINATIONWALK] )
+ flee += sc->data[SC_HALLUCINATIONWALK]->val2;
+ if( sc->data[SC_SATURDAYNIGHTFEVER] )
+ flee -= flee * (40 + 10 * sc->data[SC_SATURDAYNIGHTFEVER]->val1) / 100;
+ if( sc->data[SC_WATER_BARRIER] )
+ flee -= sc->data[SC_WATER_BARRIER]->val3;
+ if( sc->data[SC_WIND_STEP_OPTION] )
+ flee += flee * sc->data[SC_WIND_STEP_OPTION]->val2 / 100;
+ if( sc->data[SC_ZEPHYR] )
+ flee += flee * sc->data[SC_ZEPHYR]->val2 / 100;
+ if( sc->data[SC_MARSHOFABYSS] )
+ flee -= (9 * sc->data[SC_MARSHOFABYSS]->val3 / 10 + sc->data[SC_MARSHOFABYSS]->val2 / 10) * (bl->type == BL_MOB ? 2 : 1);
+
return (short)cap_value(flee,1,SHRT_MAX);
}
@@ -3696,6 +4074,26 @@ static signed char status_calc_def(struct block_list *bl, struct status_change *
def -= def * sc->data[SC_STRIPSHIELD]->val2/100;
if (sc->data[SC_FLING])
def -= def * (sc->data[SC_FLING]->val2)/100;
+ if( sc->data[SC_FREEZING] )
+ def -= def * 3 / 10;
+ if( sc->data[SC_MARSHOFABYSS] )
+ def -= def * ( 6 + 6 * sc->data[SC_MARSHOFABYSS]->val3/10 + (bl->type == BL_MOB ? 5 : 3) * sc->data[SC_MARSHOFABYSS]->val2/36 ) / 100;
+ if( sc->data[SC_ANALYZE] )
+ def -= def * ( 14 * sc->data[SC_ANALYZE]->val1 ) / 100;
+ if( sc->data[SC__BLOODYLUST] )
+ def -= def * 55 / 100;
+ if( sc->data[SC_FORCEOFVANGUARD] )
+ def += def * 2 * sc->data[SC_FORCEOFVANGUARD]->val1 / 100;
+ if(sc->data[SC_SATURDAYNIGHTFEVER])
+ def -= def * (10 + 10 * sc->data[SC_SATURDAYNIGHTFEVER]->val1) / 100;
+ if(sc->data[SC_EARTHDRIVE])
+ def -= def * 25 / 100;
+ if( sc->data[SC_GT_CHANGE] )
+ def -= def * sc->data[SC_GT_CHANGE]->val3 / 100;
+ if( sc->data[SC_ROCK_CRUSHER] )
+ def -= def * sc->data[SC_ROCK_CRUSHER]->val2 / 100;
+ if( sc->data[SC_POWER_OF_GAIA] )
+ def += def * sc->data[SC_POWER_OF_GAIA]->val2 / 100;
return (signed char)cap_value(def,CHAR_MIN,CHAR_MAX);
}
@@ -3728,6 +4126,20 @@ static signed short status_calc_def2(struct block_list *bl, struct status_change
+ def2 * ( sc->data[SC_JOINTBEAT]->val2&BREAK_WAIST ? 25 : 0 ) / 100;
if(sc->data[SC_FLING])
def2 -= def2 * (sc->data[SC_FLING]->val3)/100;
+ if( sc->data[SC_FREEZING] )
+ def2 -= def2 * 3 / 10;
+ if(sc->data[SC_ANALYZE])
+ def2 -= def2 * ( 14 * sc->data[SC_ANALYZE]->val1 ) / 100;
+ if( sc->data[SC_ECHOSONG] )
+ def2 += def2 * sc->data[SC_ECHOSONG]->val2/100;
+ if( sc->data[SC_PRESTIGE] )
+ def2 += def2 * sc->data[SC_PRESTIGE]->val1 / 100;
+ if( sc->data[SC_SHIELDSPELL_REF] && sc->data[SC_SHIELDSPELL_REF]->val1 == 1 )
+ def2 += sc->data[SC_SHIELDSPELL_REF]->val2;
+ if( sc->data[SC_BANDING] && sc->data[SC_BANDING]->val2 > 0 )
+ def2 += (5 + sc->data[SC_BANDING]->val1) * (sc->data[SC_BANDING]->val2);
+ if( sc->data[SC_GT_REVITALIZE] )
+ def2 += def2 * ( 50 + 10 * sc->data[SC_GT_REVITALIZE]->val1 ) / 100;
return (short)cap_value(def2,1,SHRT_MAX);
}
@@ -3755,6 +4167,16 @@ static signed char status_calc_mdef(struct block_list *bl, struct status_change
mdef += sc->data[SC_ENDURE]->val1;
if(sc->data[SC_CONCENTRATION])
mdef += 1; //Skill info says it adds a fixed 1 Mdef point.
+ if( sc->data[SC_MARSHOFABYSS] )
+ mdef -= mdef * ( 6 + 6 * sc->data[SC_MARSHOFABYSS]->val3/10 + (bl->type == BL_MOB ? 5 : 3) * sc->data[SC_MARSHOFABYSS]->val2/36 ) / 100;
+ if(sc->data[SC_ANALYZE])
+ mdef -= mdef * ( 14 * sc->data[SC_ANALYZE]->val1 ) / 100;
+ if(sc->data[SC_SYMPHONYOFLOVER])
+ mdef += mdef * sc->data[SC_SYMPHONYOFLOVER]->val2 / 100;
+ if(sc->data[SC_GT_CHANGE])
+ mdef -= mdef * sc->data[SC_GT_CHANGE]->val3 / 100;
+ if(sc->data[SC_WATER_BARRIER])
+ mdef += sc->data[SC_WATER_BARRIER]->val2;
return (signed char)cap_value(mdef,CHAR_MIN,CHAR_MAX);
}
@@ -3768,6 +4190,8 @@ static signed short status_calc_mdef2(struct block_list *bl, struct status_chang
return 0;
if(sc->data[SC_MINDBREAKER])
mdef2 -= mdef2 * sc->data[SC_MINDBREAKER]->val3/100;
+ if(sc->data[SC_ANALYZE])
+ mdef2 -= mdef2 * ( 14 * sc->data[SC_ANALYZE]->val1 ) / 100;
return (short)cap_value(mdef2,1,SHRT_MAX);
}
@@ -3794,9 +4218,17 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha
if( sc->data[SC_FUSION] )
val = 25;
- else
- if( sd && pc_isriding(sd) )
- val = 25;
+ else if( sd ) {
+ if( pc_isriding(sd) || sd->sc.option&(OPTION_DRAGON|OPTION_MOUNTING) )
+ val = 25;//Same bonus
+ else if( sd->sc.option&OPTION_WUGRIDER )
+ val = 15 + 5 * pc_checkskill(sd, RA_WUGRIDER);
+ else if( sd->sc.option&OPTION_MADOGEAR ) {
+ val = (- 10 * (5 - pc_checkskill(sd,NC_MADOLICENCE)));
+ if( sc->data[SC_ACCELERATION] )
+ val += 25;
+ }
+ }
speed_rate -= val;
}
@@ -3821,7 +4253,7 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha
if( sc->data[SC_DECREASEAGI] )
val = max( val, 25 );
- if( sc->data[SC_QUAGMIRE] )
+ if( sc->data[SC_QUAGMIRE] || sc->data[SC_HALLUCINATIONWALK_POSTDELAY])
val = max( val, 50 );
if( sc->data[SC_DONTFORGETME] )
val = max( val, sc->data[SC_DONTFORGETME]->val3 );
@@ -3845,6 +4277,24 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha
val = max( val, sc->data[SC_SUITON]->val3 );
if( sc->data[SC_SWOO] )
val = max( val, 300 );
+ if( sc->data[SC_FREEZING] )
+ val = max( val, 70 );
+ if( sc->data[SC_MARSHOFABYSS] )
+ val = max( val, 40 + 10 * sc->data[SC_MARSHOFABYSS]->val1 );
+ if( sc->data[SC_CAMOUFLAGE] && (sc->data[SC_CAMOUFLAGE]->val3&1) == 0 )
+ val = max( val, sc->data[SC_CAMOUFLAGE]->val1 < 3 ? 300 : 25 * (6 - sc->data[SC_CAMOUFLAGE]->val1) );
+ if( sc->data[SC__GROOMY] )
+ val = max( val, sc->data[SC__GROOMY]->val2);
+ if( sc->data[SC_STEALTHFIELD_MASTER] )
+ val = max( val, 30 );
+ if( sc->data[SC_BANDING_DEFENCE] )
+ val = max( val, sc->data[SC_BANDING_DEFENCE]->val1 );//+90% walking speed.
+ if( sc->data[SC_ROCK_CRUSHER_ATK] )
+ val = max( val, sc->data[SC_ROCK_CRUSHER_ATK]->val2 );
+ if( sc->data[SC_POWER_OF_GAIA] )
+ val = max( val, sc->data[SC_POWER_OF_GAIA]->val2 );
+ if( sc->data[SC_MELON_BOMB] )
+ val = max( val, sc->data[SC_MELON_BOMB]->val1 );
if( sd && sd->speed_rate + sd->speed_add_rate > 0 ) // permanent item-based speedup
val = max( val, sd->speed_rate + sd->speed_add_rate );
@@ -3912,7 +4362,12 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha
/// Note that the scale of aspd_rate is 1000 = 100%.
static short status_calc_aspd_rate(struct block_list *bl, struct status_change *sc, int aspd_rate)
{
+#if RRMODE == 0
+ /**
+ * this variable is not used unless in non-RE
+ **/
int i;
+#endif
if(!sc || !sc->count)
return cap_value(aspd_rate,0,SHRT_MAX);
@@ -3981,12 +4436,16 @@ static short status_calc_aspd_rate(struct block_list *bl, struct status_change *
else if(sc->data[SC_MADNESSCANCEL])
aspd_rate -= 200;
}
-
+#if RRMODE == 0
+ /**
+ * in RE they give a fixed boost -- we do so along SERVICE4U in status_base_amotion_pc
+ **/
if(sc->data[i=SC_ASPDPOTION3] ||
sc->data[i=SC_ASPDPOTION2] ||
sc->data[i=SC_ASPDPOTION1] ||
sc->data[i=SC_ASPDPOTION0])
aspd_rate -= sc->data[i]->val2;
+#endif
if(sc->data[SC_DONTFORGETME])
aspd_rate += 10 * sc->data[SC_DONTFORGETME]->val2;
if(sc->data[SC_LONGING])
@@ -4007,6 +4466,41 @@ static short status_calc_aspd_rate(struct block_list *bl, struct status_change *
if( sc->data[SC_JOINTBEAT]->val2&BREAK_KNEE )
aspd_rate += 100;
}
+ if( sc->data[SC_FREEZING] )
+ aspd_rate += 300;
+ if( sc->data[SC_HALLUCINATIONWALK_POSTDELAY] )
+ aspd_rate += 500;
+ if( sc->data[SC_FIGHTINGSPIRIT] && sc->data[SC_FIGHTINGSPIRIT]->val2 )
+ aspd_rate -= sc->data[SC_FIGHTINGSPIRIT]->val2;
+ if( sc->data[SC_PARALYSE] )
+ aspd_rate += 100;
+ if( sc->data[SC__BODYPAINT] )
+ aspd_rate += aspd_rate * (20 + 5 * sc->data[SC__BODYPAINT]->val1) / 100;
+ if( sc->data[SC__INVISIBILITY] )
+ aspd_rate += aspd_rate * sc->data[SC__INVISIBILITY]->val2 / 100;
+ if( sc->data[SC__GROOMY] )
+ aspd_rate += aspd_rate * sc->data[SC__GROOMY]->val2 / 100;
+ if( sc->data[SC_SWINGDANCE] )
+ aspd_rate -= aspd_rate * sc->data[SC_SWINGDANCE]->val2 / 100;
+ if( sc->data[SC_DANCEWITHWUG] )
+ aspd_rate -= aspd_rate * sc->data[SC_DANCEWITHWUG]->val3 / 100;
+ if( sc->data[SC_GLOOMYDAY] )
+ aspd_rate += aspd_rate * sc->data[SC_GLOOMYDAY]->val3 / 100;
+ if( sc->data[SC_EARTHDRIVE] )
+ aspd_rate += aspd_rate * 25 / 100;
+ /*As far I tested the skill there is no ASPD addition is applied. [Jobbie] */
+ //if( sc->data[SC_RAISINGDRAGON] )
+ // aspd_rate -= 100; //FIXME: Need official ASPD bonus of this status. [Jobbie]
+ if( sc->data[SC_GT_CHANGE] )
+ aspd_rate -= aspd_rate * (sc->data[SC_GT_CHANGE]->val2/200) / 100;
+ if( sc->data[SC_GT_REVITALIZE] )
+ aspd_rate -= aspd_rate * sc->data[SC_GT_REVITALIZE]->val2 / 100;
+ if( sc->data[SC_MELON_BOMB] )
+ aspd_rate += aspd_rate * sc->data[SC_MELON_BOMB]->val1 / 100;
+ if( sc->data[SC_BOOST500] )
+ aspd_rate -= aspd_rate * sc->data[SC_BOOST500]->val1/100;
+ if(sc->data[SC_EXTRACT_SALAMINE_JUICE])
+ aspd_rate -= aspd_rate * sc->data[SC_EXTRACT_SALAMINE_JUICE]->val1/100;
return (short)cap_value(aspd_rate,0,SHRT_MAX);
}
@@ -4020,7 +4514,7 @@ static unsigned short status_calc_dmotion(struct block_list *bl, struct status_c
return 0;
if( sc->data[SC_CONCENTRATION] )
return 0;
- if( sc->data[SC_RUN] )
+ if( sc->data[SC_RUN] || sc->data[SC_WUGDASH] )
return 0;
return (unsigned short)cap_value(dmotion,0,USHRT_MAX);
@@ -4045,6 +4539,12 @@ static unsigned int status_calc_maxhp(struct block_list *bl, struct status_chang
if(sc->data[SC_MERC_HPUP])
maxhp += maxhp * sc->data[SC_MERC_HPUP]->val2/100;
+ if(sc->data[SC_EPICLESIS])
+ maxhp += maxhp * 5 * sc->data[SC_EPICLESIS]->val1 / 100;
+ if(sc->data[SC_VENOMBLEED])
+ maxhp -= maxhp * 15 / 100;
+
+
return cap_value(maxhp,1,UINT_MAX);
}
@@ -4078,6 +4578,9 @@ static unsigned char status_calc_element(struct block_list *bl, struct status_ch
return ELE_UNDEAD;
if(sc->data[SC_ELEMENTALCHANGE])
return sc->data[SC_ELEMENTALCHANGE]->val2;
+ if(sc->data[SC_SHAPESHIFT])
+ return sc->data[SC_SHAPESHIFT]->val2;
+
return (unsigned char)cap_value(element,0,UCHAR_MAX);
}
@@ -4096,6 +4599,8 @@ static unsigned char status_calc_element_lv(struct block_list *bl, struct status
return 1;
if(sc->data[SC_ELEMENTALCHANGE])
return sc->data[SC_ELEMENTALCHANGE]->val1;
+ if(sc->data[SC_SHAPESHIFT])
+ return 1;
return (unsigned char)cap_value(lv,1,4);
}
@@ -4567,7 +5072,7 @@ void status_change_init(struct block_list *bl)
//the flag values are the same as in status_change_start.
int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int tick, int flag)
{
- int sc_def, tick_def = 0;
+ int sc_def = 0, tick_def = 0;
struct status_data* status;
struct status_change* sc;
struct map_session_data *sd;
@@ -4618,6 +5123,7 @@ int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int ti
sc_def = 3 +status->int_;
break;
case SC_DECREASEAGI:
+ case SC_ADORAMUS://Arch Bishop
if (sd) tick>>=1; //Half duration for players.
case SC_STONE:
case SC_FREEZE:
@@ -4647,6 +5153,40 @@ int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int ti
if (sd) //Duration greatly reduced for players.
tick /= 15;
//No defense against it (buff).
+ /**
+ * 3rd stuff
+ **/
+ case SC_WHITEIMPRISON:
+ rate -= (status_get_lv(bl) / 5 + status->vit / 4 + status->agi / 10)*100; // Lineal Reduction of Rate
+ //tick_def = (int)floor(log10(status_get_lv(bl)) * 10.);
+ break;
+ case SC_BURNING:
+ // From iROwiki : http://forums.irowiki.org/showpost.php?p=577240&postcount=583
+ tick -= 50*status->luk + 60*status->int_ + 170*status->vit;
+ tick = max(tick,10000); // Minimum Duration 10s.
+ break;
+ case SC_FREEZING:
+ tick -= 1000 * ((status->vit + status->dex) / 20);
+ tick = max(tick,10000); // Minimum Duration 10s.
+ break;
+ case SC_OBLIVIONCURSE:
+ sc_def = status->int_*4/5; //FIXME: info said this is the formula of status chance. Check again pls. [Jobbie]
+ break;
+ case SC_ELECTRICSHOCKER:
+ case SC_BITE:
+ {
+ if( bl->type == BL_MOB )
+ tick -= 1000 * (status->agi/10);
+ if( sd && type != SC_ELECTRICSHOCKER )
+ tick >>= 1;
+ }
+ break;
+ case SC_CRYSTALIZE:
+ tick -= (1000*(status->vit/10))+(status_get_lv(bl)/50);
+ break;
+ case SC_VACUUM_EXTREME:
+ tick -= 50*status->str;
+ break;
default:
//Effect that cannot be reduced? Likely a buff.
if (!(rand()%10000 < rate))
@@ -4749,7 +5289,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
struct status_change_entry* sce;
struct status_data *status;
struct view_data *vd;
- int opt_flag, calc_flag, undead_flag;
+ int opt_flag, calc_flag, undead_flag, val_flag = 0, tick_time = 0;
nullpo_ret(bl);
sc = status_get_sc(bl);
@@ -4787,16 +5327,27 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
//Check for inmunities / sc fails
switch (type)
{
- case SC_FREEZE:
case SC_STONE:
+ if(sc->data[SC_POWER_OF_GAIA])
+ return 0;
+ case SC_FREEZE:
//Undead are immune to Freeze/Stone
if (undead_flag && !(flag&1))
return 0;
case SC_SLEEP:
case SC_STUN:
+ case SC_FREEZING:
if (sc->opt1)
return 0; //Cannot override other opt1 status changes. [Skotlex]
+ if((type == SC_FREEZE || type == SC_FREEZING) && sc->data[SC_WARMER])
+ return 0; //Immune to Frozen and Freezing status if under Warmer status. [Jobbie]
+ break;
+
+ case SC_BURNING:
+ if(sc->opt1 || sc->data[SC_FREEZING])
+ return 0;
break;
+
case SC_SIGNUMCRUCIS:
//Only affects demons and undead element (but not players)
if((!undead_flag && status->race!=RC_DEMON) || bl->type == BL_PC)
@@ -4813,12 +5364,16 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
case SC_OVERTHRUST:
if (sc->data[SC_MAXOVERTHRUST])
return 0; //Overthrust can't take effect if under Max Overthrust. [Skotlex]
+ case SC_MAXOVERTHRUST:
+ if( sc->option&OPTION_MADOGEAR )
+ return 0;//Overthrust and Overthrust Max cannot be used on Mado Gear [Ind]
break;
case SC_ADRENALINE:
if(sd && !pc_check_weapontype(sd,skill_get_weapontype(BS_ADRENALINE)))
return 0;
if (sc->data[SC_QUAGMIRE] ||
- sc->data[SC_DECREASEAGI]
+ sc->data[SC_DECREASEAGI] ||
+ sc->option&OPTION_MADOGEAR //Adrenaline doesn't affect Mado Gear [Ind]
)
return 0;
break;
@@ -4830,6 +5385,9 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
)
return 0;
break;
+ case SC_MAGNIFICAT:
+ if( sc->option&OPTION_MADOGEAR ) //Mado is immune to magnificat
+ break;
case SC_ONEHAND:
case SC_MERC_QUICKEN:
case SC_TWOHANDQUICKEN:
@@ -4844,6 +5402,8 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
case SC_ASSNCROS:
if (sc->data[SC_QUAGMIRE])
return 0;
+ if(sc->option&OPTION_MADOGEAR)
+ return 0;//Mado is immune to increase agi, wind walk, cart boost, etc (others above) [Ind]
break;
case SC_CLOAKING:
//Avoid cloaking with no wall and low skill level. [Skotlex]
@@ -4995,6 +5555,10 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
if (sc->data[SC_LUKFOOD] && sc->data[SC_LUKFOOD]->val1 > val1)
return 0;
break;
+ case SC_CAMOUFLAGE:
+ if( sd && pc_checkskill(sd, RA_CAMOUFLAGE) < 3 && !skill_check_camouflage(bl,NULL) )
+ return 0;
+ break;
}
//Check for BOSS resistances
@@ -5003,8 +5567,6 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
return 0;
switch (type) {
case SC_BLESSING:
- if (!undead_flag && status->race!=RC_DEMON)
- break;
case SC_DECREASEAGI:
case SC_PROVOKE:
case SC_COMA:
@@ -5013,6 +5575,26 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
case SC_RICHMANKIM:
case SC_ROKISWEIL:
case SC_FOGWALL:
+ case SC_FREEZING:
+ case SC_BURNING: // Place here until we have info about its behavior on Boss-monsters. [pakpil]
+ case SC_MARSHOFABYSS:
+ case SC_ADORAMUS:
+
+ // Exploid prevention - kRO Fix
+ case SC_PYREXIA:
+ case SC_DEATHHURT:
+ case SC_TOXIN:
+ case SC_PARALYSE:
+ case SC_VENOMBLEED:
+ case SC_MAGICMUSHROOM:
+ case SC_OBLIVIONCURSE:
+ case SC_LEECHESEND:
+
+ // Ranger Effects
+ case SC_BITE:
+ case SC_ELECTRICSHOCKER:
+ case SC_MAGNETICFIELD:
+
return 0;
}
}
@@ -5048,6 +5630,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
status_change_end(bl, SC_TWOHANDQUICKEN, INVALID_TIMER);
status_change_end(bl, SC_ONEHAND, INVALID_TIMER);
status_change_end(bl, SC_MERC_QUICKEN, INVALID_TIMER);
+ status_change_end(bl, SC_ACCELERATION, INVALID_TIMER);
break;
case SC_ONEHAND:
//Removes the Aspd potion effect, as reported by Vicious. [Skotlex]
@@ -5286,6 +5869,8 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
case SC_EDP: // [Celest]
val2 = val1 + 2; //Chance to Poison enemies.
val3 = 50*(val1+1); //Damage increase (+50 +50*lv%)
+ if( sd )//[Ind] - iROwiki says each level increases its duration by 3 seconds
+ tick += pc_checkskill(sd,GC_RESEARCHNEWPOISON)*3000;
break;
case SC_POISONREACT:
val2=(val1+1)/2 + val1/10; // Number of counters [Skotlex]
@@ -5421,10 +6006,10 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
//val3 : Brings the skilllv (merged into val1 here)
//val4 : Partner
if (val1 == CG_MOONLIT)
- clif_status_change(bl,SI_MOONLIT,1,tick);
+ clif_status_change(bl,SI_MOONLIT,1,tick,0, 0, 0);
val1|= (val3<<16);
val3 = tick/1000; //Tick duration
- tick = 1000;
+ tick_time = 1000; // [GodLesZ] tick time
break;
case SC_LONGING:
val2 = 500-100*val1; //Aspd penalty.
@@ -5432,9 +6017,14 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
case SC_EXPLOSIONSPIRITS:
val2 = 75 + 25*val1; //Cri bonus
break;
+#if RRMODE == 0
+ /**
+ * Only in non-RE it's var is changed
+ **/
case SC_ASPDPOTION0:
case SC_ASPDPOTION1:
case SC_ASPDPOTION2:
+#endif
case SC_ASPDPOTION3:
val2 = 50*(2+type-SC_ASPDPOTION0);
break;
@@ -5455,6 +6045,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
clif_changelook(bl,LOOK_CLOTHES_COLOR,vd->cloth_color);
break;
case SC_NOCHAT:
+ // [GodLesZ] FIXME: is this correct? a hardcoded interval of 60sec? what about configuration ?_?
tick = 60000;
val1 = battle_config.manner_system; //Mute filters.
if (sd)
@@ -5486,7 +6077,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
case SC_POISON: /* 毒 */
val3 = tick/1000; //Damage iterations
if(val3 < 1) val3 = 1;
- tick = 1000;
+ tick_time = 1000; // [GodLesZ] tick time
//val4: HP damage
if (bl->type == BL_PC)
val4 = (type == SC_DPOISON) ? 3 + status->max_hp/50 : 3 + status->max_hp*3/200;
@@ -5500,7 +6091,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
case SC_BLEEDING:
val4 = tick/10000;
if (!val4) val4 = 1;
- tick = 10000;
+ tick_time = 10000; // [GodLesZ] tick time
break;
case SC_S_LIFEPOTION:
case SC_L_LIFEPOTION:
@@ -5511,7 +6102,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
if( val2 < 1 ) val2 = 1;
if( (val4 = tick/(val2 * 1000)) < 1 )
val4 = 1;
- tick = val2 * 1000; // val2 = Seconds between heals
+ tick_time = val2 * 1000; // [GodLesZ] tick time
break;
case SC_BOSSMAPINFO:
if( sd != NULL )
@@ -5525,12 +6116,12 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
val1 = boss_md->bl.id;
if( (val4 = tick/1000) < 1 )
val4 = 1;
- tick = 1000;
+ tick_time = 1000; // [GodLesZ] tick time
}
break;
case SC_HIDING:
val2 = tick/1000;
- tick = 1000;
+ tick_time = 1000; // [GodLesZ] tick time
val3 = 0; // unused, previously speed adjustment
val4 = val1+3; //Seconds before SP substraction happen.
break;
@@ -5560,7 +6151,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
case SC_SIGHTBLASTER:
val3 = skill_get_splash(val2, val1); //Val2 should bring the skill-id.
val2 = tick/250;
- tick = 10;
+ tick_time = 10; // [GodLesZ] tick time
break;
//Permanent effects.
@@ -5631,7 +6222,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
val2 = 12; //SP cost
val4 = 10000; //Decrease at 10secs intervals.
val3 = tick/val4;
- tick = val4;
+ tick_time = val4; // [GodLesZ] tick time
break;
case SC_PARRYING:
val2 = 20 + val1*3; //Block Chance
@@ -5654,13 +6245,13 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
if (!val4) val4 = skill_get_time2(status_sc2skill(type),val1);
if (!val4) val4 = 10000; //Val4 holds damage interval
val3 = tick/val4; //val3 holds skill duration
- tick = val4;
+ tick_time = val4; // [GodLesZ] tick time
break;
case SC_GOSPEL:
if(val4 == BCT_SELF) { // self effect
val2 = tick/10000;
- tick = 10000;
+ tick_time = 10000; // [GodLesZ] tick time
status_change_clear_buffs(bl,3); //Remove buffs/debuffs
}
break;
@@ -5926,7 +6517,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
case SC_SKA:
val2 = tick/1000;
val3 = rand()%100; //Def changes randomly every second...
- tick = 1000;
+ tick_time = 1000; // [GodLesZ] tick time
break;
case SC_JAILED:
//Val1 is duration in minutes. Use INT_MAX to specify 'unlimited' time.
@@ -6062,6 +6653,487 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
case SC_SPL_MATK:
val2 = 2; // Splendide group
break;
+ /**
+ * General
+ **/
+ case SC_FEAR:
+ val2 = 2;
+ val4 = tick / 1000;
+ tick_time = 1000; // [GodLesZ] tick time
+ break;
+ case SC_BURNING:
+ val4 = tick / 2000; // Total Ticks to Burn!!
+ tick_time = 2000; // [GodLesZ] tick time
+ break;
+ /**
+ * Rune Knight
+ **/
+ case SC_DEATHBOUND:
+ val2 = 500 + 100 * val1;
+ break;
+ case SC_FIGHTINGSPIRIT:
+ val_flag |= 1|2;
+ break;
+ case SC_ABUNDANCE:
+ val4 = tick / 10000;
+ tick_time = 10000; // [GodLesZ] tick time
+ break;
+ case SC_GIANTGROWTH:
+ val2 = 10; // Triple damage success rate.
+ break;
+ /**
+ * Arch Bishop
+ **/
+ case SC_RENOVATIO:
+ val4 = tick / 5000;
+ tick_time = 5000;
+ break;
+ case SC_SECRAMENT:
+ val2 = 10 * val1;
+ break;
+ case SC_VENOMIMPRESS:
+ val2 = 10 * val1;
+ val_flag |= 1|2;
+ break;
+ case SC_POISONINGWEAPON:
+ val_flag |= 1|2|4;
+ break;
+ case SC_WEAPONBLOCKING:
+ val2 = 10 + 2 * val1; // Chance
+ val4 = tick / 3000;
+ tick_time = 3000; // [GodLesZ] tick time
+ val_flag |= 1|2;
+ break;
+ case SC_TOXIN:
+ val4 = tick / 10000;
+ tick_time = 10000; // [GodLesZ] tick time
+ break;
+ case SC_MAGICMUSHROOM:
+ val4 = tick / 4000;
+ tick_time = 4000; // [GodLesZ] tick time
+ break;
+ case SC_PYREXIA:
+ val4 = tick / 3000;
+ tick_time = 4000; // [GodLesZ] tick time
+ break;
+ case SC_LEECHESEND:
+ val4 = tick / 1000;
+ tick_time = 1000; // [GodLesZ] tick time
+ break;
+ case SC_OBLIVIONCURSE:
+ val4 = tick / 3000;
+ tick_time = 3000; // [GodLesZ] tick time
+ break;
+ case SC_ROLLINGCUTTER:
+ val_flag |= 1;
+ break;
+ case SC_CLOAKINGEXCEED:
+ val2 = ( val1 + 1 ) / 2; // Hits
+ val3 = ( val1 - 1 ) * 10; // Walk speed
+ val_flag |= 1|2|4;
+ if (bl->type == BL_PC)
+ val4 |= battle_config.pc_cloak_check_type&7;
+ else
+ val4 |= battle_config.monster_cloak_check_type&7;
+ tick_time = 1000; // [GodLesZ] tick time
+ break;
+ case SC_HALLUCINATIONWALK:
+ val2 = 50 * val1; // Evasion rate of physical attacks. Flee
+ val3 = 10 * val1; // Evasion rate of magical attacks.
+ val_flag |= 1|2|4;
+ break;
+ case SC_WHITEIMPRISON:
+ status_change_end(bl, SC_BURNING, -1);
+ status_change_end(bl, SC_FREEZING, -1);
+ status_change_end(bl, SC_FREEZE, -1);
+ status_change_end(bl, SC_STONE, -1);
+ break;
+ case SC_FREEZING:
+ status_change_end(bl, SC_BURNING, -1);
+ break;
+ case SC_READING_SB:
+ // val2 = sp reduction per second
+ tick_time = 1000; // [GodLesZ] tick time
+ break;
+ case SC_SPHERE_1:
+ case SC_SPHERE_2:
+ case SC_SPHERE_3:
+ case SC_SPHERE_4:
+ case SC_SPHERE_5:
+ if( !sd )
+ return 0; // Should only work on players.
+ val4 = tick / 1000;
+ if( val4 < 1 )
+ val4 = 1;
+ tick_time = 1000; // [GodLesZ] tick time
+ val_flag |= 1;
+ break;
+ case SC_SHAPESHIFT:
+ switch( val1 )
+ {
+ case 1: val2 = ELE_FIRE; break;
+ case 2: val2 = ELE_EARTH; break;
+ case 3: val2 = ELE_WIND; break;
+ case 4: val2 = ELE_WATER; break;
+ }
+ break;
+ case SC_ELECTRICSHOCKER:
+ case SC_CRYSTALIZE:
+ val4 = tick / 1000;
+ if( val4 < 1 )
+ val4 = 1;
+ tick_time = 1000; // [GodLesZ] tick time
+ break;
+ case SC_CAMOUFLAGE:
+ //val3 |= battle_config.pc_camouflage_check_type&7;
+ tick_time = 1000; // [GodLesZ] tick time
+ break;
+ case SC_WUGDASH:
+ val4 = gettick(); //Store time at which you started running.
+ tick = -1;
+ break;
+ case SC__SHADOWFORM:
+ {
+ //struct map_session_data * s_sd = map_id2sd(val2);
+ //if( s_sd )
+ // s_sd->shadowform_id = bl->id;
+ val4 = tick / 1000;
+ val_flag |= 1|2|4;
+ tick_time = 1000; // [GodLesZ] tick time
+ }
+ break;
+ case SC__STRIPACCESSORY:
+ if (!sd)
+ val2 = 20;
+ break;
+ case SC__INVISIBILITY:
+ val2 = 50 - 10 * val1; // ASPD
+ val3 = 20 * val1; // CRITICAL
+ val4 = tick / 1000;
+ tick_time = 1000; // [GodLesZ] tick time
+ val_flag |= 1|2;
+ break;
+ case SC__ENERVATION:
+ val2 = 20 + 10 * val1; // ATK Reduction
+ val_flag |= 1|2;
+ if( sd ) pc_delspiritball(sd,sd->spiritball,0);
+ break;
+ case SC__GROOMY:
+ val2 = 20 + 10 * val1; //ASPD. Need to confirm if Movement Speed reduction is the same. [Jobbie]
+ val3 = 20 * val1; //HIT
+ val_flag |= 1|2|4;
+ if( sd )
+ { // Removes Animals
+ //if( pc_isriding(sd,OPTION_RIDING|OPTION_RIDING_DRAGON|OPTION_RIDING_WUG) ) pc_setriding(sd, 0);
+ //if( pc_iswarg(sd) ) pc_setoption(sd, sd->sc.option&~OPTION_WUG);
+ if( pc_isfalcon(sd) ) pc_setoption(sd, sd->sc.option&~OPTION_FALCON);
+ if( sd->status.pet_id > 0 ) pet_menu(sd, 3);
+ if( merc_is_hom_active(sd->hd) ) merc_hom_vaporize(sd,1);
+ if( sd->md ) merc_delete(sd->md,3);
+ }
+ break;
+ case SC__LAZINESS:
+ val2 = 10 + 10 * val1; // Cast reduction
+ val3 = 10 * val1; // Flee Reduction
+ val_flag |= 1|2|4;
+ break;
+ case SC__UNLUCKY:
+ val2 = 10 * val1; // Crit and Flee2 Reduction
+ val_flag |= 1|2|4;
+ break;
+ case SC__WEAKNESS:
+ val2 = 10 * val1;
+ val_flag |= 1|2;
+ skill_strip_equip(bl,EQP_WEAPON|EQP_SHIELD,100,val1,tick);
+ break;
+ case SC__BLOODYLUST:
+ val_flag |= 1|2;
+ break;
+ case SC_GN_CARTBOOST:
+ if( val1 < 3 )
+ val2 = 50;
+ else if( val1 < 5 )
+ val2 = 75;
+ else
+ val2 = 100;
+ break;
+ case SC_PROPERTYWALK:
+ val_flag |= 1|2;
+ val3 = 0;
+ break;
+ case SC_WARMER:
+ status_change_end(bl, SC_FREEZE, -1);
+ status_change_end(bl, SC_FREEZING, -1);
+ status_change_end(bl, SC_CRYSTALIZE, -1);
+ break;
+ case SC_STRIKING:
+ val4 = tick / 1000;
+ tick_time = 1000; // [GodLesZ] tick time
+ break;
+ case SC_BLOODSUCKER:
+ val4 = tick / 1000;
+ tick_time = 1000; // [GodLesZ] tick time
+ break;
+ case SC_SWINGDANCE:
+ val2 = 4 * val1; // Walk speed and aspd reduction.
+ break;
+ case SC_SYMPHONYOFLOVER:
+ case SC_RUSHWINDMILL:
+ case SC_ECHOSONG:
+ val2 = 6 * val1;
+ val2 += val3; //Adding 1% * Lesson Bonus
+ val2 += (int)(val4*2/10); //Adding 0.2% per JobLevel
+ break;
+ case SC_MOONLITSERENADE:
+ val2 = 10 * val1;
+ break;
+ case SC_HARMONIZE:
+ val2 = 3 + 2 * val1;
+ break;
+ case SC_VOICEOFSIREN:
+ val4 = tick / 2000;
+ tick_time = 2000; // [GodLesZ] tick time
+ break;
+ case SC_DEEPSLEEP:
+ val4 = tick / 2000;
+ tick_time = 2000; // [GodLesZ] tick time
+ break;
+ case SC_SIRCLEOFNATURE:
+ val2 = 1 + val1; //SP consume
+ val3 = 40 * val1; //HP recovery
+ val4 = tick / 1000;
+ tick_time = 1000; // [GodLesZ] tick time
+ break;
+ case SC_SONGOFMANA:
+ val3 = 10 + (2 * val2);
+ val4 = tick/3000;
+ tick_time = 3000; // [GodLesZ] tick time
+ break;
+ case SC_SATURDAYNIGHTFEVER:
+ if (!val4) val4 = skill_get_time2(status_sc2skill(type),val1);
+ if (!val4) val4 = 3000;
+ val3 = tick/val4;
+ tick_time = val4; // [GodLesZ] tick time
+ break;
+ case SC_GLOOMYDAY:
+ val2 = 3 + 2 * val1; // Flee reduction.
+ val3 = 3 * val1; // ASPD reduction.
+ break;
+ case SC_SITDOWN_FORCE:
+ case SC_BANANA_BOMB_SITDOWN:
+ if( sd && !pc_issit(sd) )
+ {
+ pc_setsit(sd);
+ skill_sit(sd,1);
+ clif_sitting(bl);
+ }
+ break;
+ case SC_DANCEWITHWUG:
+ val3 = (5 * val1) + (1 * val2); //Still need official value.
+ break;
+ case SC_LERADSDEW:
+ val3 = (5 * val1) + (1 * val2);
+ break;
+ case SC_MELODYOFSINK:
+ val3 = (5 * val1) + (1 * val2);
+ break;
+ case SC_BEYONDOFWARCRY:
+ val3 = (5 * val1) + (1 * val2);
+ break;
+ case SC_UNLIMITEDHUMMINGVOICE:
+ {
+ struct unit_data *ud = unit_bl2ud(bl);
+ if( ud == NULL ) return 0;
+ ud->state.skillcastcancel = 0;
+ val3 = 15 - (2 * val2);
+ }
+ break;
+ case SC_REFLECTDAMAGE:
+ val2 = 15 + 5 * val1;
+ val3 = (val1==5)?20:(val1+4)*2; // SP consumption
+ val4 = tick/10000;
+ tick_time = 10000; // [GodLesZ] tick time
+ break;
+ case SC_FORCEOFVANGUARD: // This is not the official way to handle it but I think we should use it. [pakpil]
+ val2 = 20 + 12 * (val1 - 1); // Chance
+ val3 = 5 + (2 * val1); // Max rage counters
+ tick_time = 6000; // [GodLesZ] tick time
+ val_flag |= 1|2|4;
+ break;
+ case SC_EXEEDBREAK:
+ val1 *= 150; // 150 * skill_lv
+ if( sd )
+ { // Chars.
+ struct item_data *id = sd->inventory_data[sd->equip_index[EQI_HAND_R]];
+ if( id ) val1 += (id->weight/10 * id->wlv * status_get_lv(bl) / 100); // (weapon_weight * weapon_level * base_lvl)/100
+ val1 += 15 * sd->status.job_level; // 15 * job_lvl
+ }
+ else // Mobs
+ val1 += (400 * status_get_lv(bl) / 100) + (15 * (status_get_lv(bl) / 2)); // About 1138% at mob_lvl 99. Is an aproximation to a standard weapon. [pakpil]
+ break;
+
+ case SC_PRESTIGE: // Bassed on suggested formula in iRO Wiki and some test, still need more test. [pakpil]
+ val2 = ((status->int_ + status->luk) / 6) + 5; // Chance to evade magic damage.
+ val1 *= 15; // Defence added
+ if( sd )
+ val1 += 10 * pc_checkskill(sd,CR_DEFENDER);
+ val_flag |= 1|2;
+ break;
+ case SC_BANDING:
+ tick_time = 5000; // [GodLesZ] tick time
+ val_flag |= 1;
+ break;
+ case SC_SHIELDSPELL_DEF:
+ case SC_SHIELDSPELL_MDEF:
+ case SC_SHIELDSPELL_REF:
+ val_flag |= 1|2;
+ break;
+ case SC_MAGNETICFIELD:
+ val3 = tick / 1000;
+ tick_time = 1000; // [GodLesZ] tick time
+ break;
+ case SC_INSPIRATION:
+ if( sd )
+ {
+ val2 = (40 * val1) + (3 * sd->status.job_level); // ATK bonus
+ val3 = (sd->status.job_level / 10) * 2 + 12; // All stat bonus
+ }
+ val4 = tick / 1000;
+ tick_time = 1000; // [GodLesZ] tick time
+ status_change_clear_buffs(bl,3); //Remove buffs/debuffs
+ break;
+ case SC_SPELLFIST:
+ case SC_CURSEDCIRCLE_ATKER:
+ val_flag |= 1|2|4;
+ break;
+ case SC_CRESCENTELBOW:
+ val2 = 94 + val1;
+ val_flag |= 1|2;
+ break;
+ case SC_LIGHTNINGWALK:
+ val1 = 88 + 2 * val1;
+ val_flag |= 1;
+ break;
+ case SC_RAISINGDRAGON:
+ val3 = tick / 5000;
+ tick_time = 5000; // [GodLesZ] tick time
+ break;
+ case SC_GT_CHANGE:
+ if( sd ) val2 = (13 * val1 / 2) * sd->status.agi; //Aspd - old formula.
+ val3 = 20 + 1 * val1; //Base Atk, Reduction to DEF & MDEF
+ break;
+ case SC_GT_REVITALIZE:
+ val2 = 5 * val1; //Custom value VIT, ASPD, SPEED bonus.
+ val3 = 60 + 40 * val1; //HP recovery
+ break;
+ case SC_PYROTECHNIC_OPTION:
+ val2 = 60; // Watk TODO: Renewal (Atk2)
+ val3 = 11; // % Increase damage.
+ val_flag |= 1|2|4;
+ break;
+ case SC_HEATER_OPTION:
+ val2 = 120; // Watk. TODO: Renewal (Atk2)
+ val3 = 33; // % Increase effects.
+ val4 = 3; // Change into fire element.
+ val_flag |= 1|2|4;
+ break;
+ case SC_TROPIC_OPTION:
+ val2 = 180; // Watk. TODO: Renewal (Atk2)
+ val3 = MG_FIREBOLT;
+ break;
+ case SC_AQUAPLAY_OPTION:
+ val2 = 40; // Matk. TODO: Renewal (Matk1)
+ val3 = 33; // % Increase effects.
+ val_flag |= 1|2|4;
+ break;
+ case SC_COOLER_OPTION:
+ val2 = 80; // % Freezing chance
+ val3 = 33; // % increased damage
+ val4 = 1; // Change into water elemet
+ val_flag |= 1|2|4;
+ break;
+ case SC_CHILLY_AIR_OPTION:
+ val2 = 120; // Matk. TODO: Renewal (Matk1)
+ val3 = MG_COLDBOLT;
+ val_flag |= 1|2;
+ break;
+ case SC_GUST_OPTION:
+ val2 = 33;
+ val_flag |= 1|2;
+ break;
+ case SC_WIND_STEP_OPTION:
+ val2 = 50; // % Increase speed and flee.
+ break;
+ case SC_BLAST_OPTION:
+ val2 = 33;
+ val3 = 4;
+ val_flag |= 1|2|4;
+ break;
+ case SC_WILD_STORM_OPTION:
+ val2 = MG_LIGHTNINGBOLT;
+ val_flag |= 1|2;
+ break;
+ case SC_PETROLOGY_OPTION:
+ val2 = 5;
+ val3 = 33;
+ val_flag |= 1|2|4;
+ break;
+ case SC_CURSED_SOIL_OPTION:
+ val2 = 10;
+ val3 = 33;
+ val4 = 2;
+ val_flag |= 1|2|4;
+ break;
+ case SC_UPHEAVAL_OPTION:
+ val2 = WZ_EARTHSPIKE;
+ val_flag |= 1|2;
+ break;
+ case SC_CIRCLE_OF_FIRE_OPTION:
+ val2 = 300;
+ val_flag |= 1|2;
+ break;
+ case SC_FIRE_CLOAK_OPTION:
+ case SC_WATER_DROP_OPTION:
+ case SC_WIND_CURTAIN_OPTION:
+ case SC_STONE_SHIELD_OPTION:
+ val2 = 20; // Elemental modifier. Not confirmed.
+ break;
+ case SC_CIRCLE_OF_FIRE:
+ case SC_FIRE_CLOAK:
+ case SC_WATER_DROP:
+ case SC_WATER_SCREEN:
+ case SC_WIND_CURTAIN:
+ case SC_WIND_STEP:
+ case SC_STONE_SHIELD:
+ case SC_SOLID_SKIN:
+ val2 = 10;
+ tick_time = 2000; // [GodLesZ] tick time
+ break;
+ case SC_WATER_BARRIER:
+ val2 = 40; // Increasement. Mdef1 ???
+ val3 = 20; // Reductions. Atk2, Flee1, Matk1 ????
+ val_flag |= 1|2|4;
+ break;
+ case SC_ZEPHYR:
+ val2 = 22; // Flee.
+ break;
+ case SC_TIDAL_WEAPON:
+ val2 = 20; // Increase Elemental's attack.
+ break;
+ case SC_ROCK_CRUSHER:
+ case SC_ROCK_CRUSHER_ATK:
+ case SC_POWER_OF_GAIA:
+ val2 = 33;
+ break;
+ case SC_MELON_BOMB:
+ case SC_BANANA_BOMB:
+ val1 = 15;
+ break;
+ case SC_STOMACHACHE:
+ val2 = 8; // SP consume.
+ val4 = tick / 10000;
+ tick_time = 10000; // [GodLesZ] tick time
+ break;
default:
if( calc_flag == SCB_NONE && StatusSkillChangeTable[type] == 0 && StatusIconChangeTable[type] == 0 )
@@ -6107,12 +7179,15 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
case SC_CLOSECONFINE2:
case SC_ANKLE:
case SC_SPIDERWEB:
+ case SC_ELECTRICSHOCKER:
unit_stop_walking(bl,1);
break;
case SC_HIDING:
case SC_CLOAKING:
+ case SC_CLOAKINGEXCEED:
case SC_CHASEWALK:
case SC_WEIGHT90:
+ case SC_CAMOUFLAGE:
unit_stop_attack(bl);
break;
case SC_SILENCE:
@@ -6130,6 +7205,8 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
case SC_FREEZE: sc->opt1 = OPT1_FREEZE; break;
case SC_STUN: sc->opt1 = OPT1_STUN; break;
case SC_SLEEP: sc->opt1 = OPT1_SLEEP; break;
+ case SC_BURNING: sc->opt1 = OPT1_BURNING; break; // Burning need this to be showed correctly. [pakpil]
+ case SC_WHITEIMPRISON: sc->opt1 = OPT1_IMPRISON; break;
//OPT2
case SC_POISON: sc->opt2 |= OPT2_POISON; break;
case SC_CURSE: sc->opt2 |= OPT2_CURSE; break;
@@ -6234,6 +7311,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
opt_flag = 2;
break;
case SC_CLOAKING:
+ case SC_CLOAKINGEXCEED:
sc->option |= OPTION_CLOAK;
opt_flag = 2;
break;
@@ -6280,10 +7358,15 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
calc_flag&=~SCB_DYE;
}
- if( vd && (pcdb_checkid(vd->class_) || bl->type == BL_MER ) ) //Only for players sprites, client crashes if they receive this for a mob o.O [Skotlex]
- clif_status_change(bl,StatusIconChangeTable[type],1,tick);
+ if( vd && (pcdb_checkid(vd->class_) || bl->type == BL_MER || bl->type == BL_MOB ) )
+ clif_status_change(bl,StatusIconChangeTable[type],1,tick,(val_flag&1)?val1:1,(val_flag&2)?val2:0,(val_flag&4)?val3:0);
else if( sd ) //Send packet to self otherwise (disguised player?)
clif_status_load(bl,StatusIconChangeTable[type],1);
+ /**
+ * used as temporary storage for scs with interval ticks, so that the actual duration is sent to the client first.
+ **/
+ if( tick_time )
+ tick = tick_time;
//Don't trust the previous sce assignment, in case the SC ended somewhere between there and here.
if((sce=sc->data[type]))
@@ -6337,6 +7420,16 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
case SC_MERC_SPUP:
status_percent_heal(bl, 0, 100); // Recover Full SP
break;
+ /**
+ * Ranger
+ **/
+ case SC_WUGDASH:
+ {
+ struct unit_data *ud = unit_bl2ud(bl);
+ if( ud )
+ ud->state.running = unit_wugdash(bl, sd);
+ }
+ break;
case SC_COMBO:
switch (sce->val1) {
case TK_STORMKICK:
@@ -6658,7 +7751,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const
}
if((sce->val1&0xFFFF) == CG_MOONLIT)
- clif_status_change(bl,SI_MOONLIT,0,0);
+ clif_status_change(bl,SI_MOONLIT,0,0,0,0,0);
status_change_end(bl, SC_LONGING, INVALID_TIMER);
}
@@ -6803,6 +7896,88 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const
status_change_end(tbl, SC_STOP, INVALID_TIMER);
}
break;
+ /**
+ * 3rd Stuff
+ **/
+ case SC_MILLENNIUMSHIELD:
+ clif_millenniumshield(sd,0);
+ break;
+ case SC_HALLUCINATIONWALK:
+ sc_start(bl,SC_HALLUCINATIONWALK_POSTDELAY,100,sce->val1,skill_get_time2(GC_HALLUCINATIONWALK,sce->val1));
+ break;
+ case SC_WHITEIMPRISON:
+ if( tid == -1 )
+ break; // Terminated by Damage
+ clif_damage(bl,bl,0,0,0,400*sce->val1,0,0,0);
+ status_zap(bl,400*sce->val1,0);
+ break;
+ case SC_WUGDASH:
+ {
+ struct unit_data *ud = unit_bl2ud(bl);
+ if (ud) {
+ ud->state.running = 0;
+ if (ud->walktimer != -1)
+ unit_stop_walking(bl,1);
+ }
+ }
+ break;
+ case SC_ADORAMUS:
+ status_change_end(bl, SC_BLIND, -1);
+ break;
+ /*
+ case SC__SHADOWFORM:
+ {
+ struct map_session_data *s_sd = map_id2sd(sce->val2);
+ if( !s_sd )
+ break;
+ s_sd->shadowform_id = 0;
+ }
+ break;
+ case SC_SITDOWN_FORCE:
+ if( sd && pc_issit(sd) )
+ {
+ pc_setstand(sd);
+ clif_standing(bl,true);
+ }
+ break;
+ case SC_NEUTRALBARRIER_MASTER:
+ case SC_STEALTHFIELD_MASTER:
+ if( sce->val2 )
+ {
+ struct skill_unit_group* group = skill_id2group(sce->val2);
+ sce->val2 = 0;
+ skill_delunitgroup(group);
+ }
+ break;
+ case SC_BANDING:
+ {
+ struct skill_unit_group *group;
+ if(sce->val4)
+ {
+ group = skill_id2group(sce->val4);
+ sce->val4 = 0;
+ skill_delunitgroup(group);
+ }
+ }
+ break;
+ case SC_CURSEDCIRCLE_ATKER:
+ if( sce->val3 )
+ map_foreachinrange(status_change_timer_sub, bl, skill_get_splash(SR_CURSEDCIRCLE, sce->val1),BL_CHAR, bl, sce, SC_CURSEDCIRCLE_TARGET, gettick());
+ break;
+ case SC_RAISINGDRAGON:
+ if( sd && sce->val2 && !pc_isdead(sd) )
+ {
+ int i;
+ i = min(sd->spiritball,5);
+ pc_delspiritball(sd, sd->spiritball, 0);
+ status_change_end(bl, SC_EXPLOSIONSPIRITS, -1);
+ while( i > 0 )
+ {
+ pc_addspiritball(sd, skill_get_time(MO_CALLSPIRITS, pc_checkskill(sd,MO_CALLSPIRITS)), 5);
+ --i;
+ }
+ }
+ break;*/
}
opt_flag = 1;
@@ -6832,6 +8007,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const
opt_flag|= 2|4; //Check for warp trigger + AoE trigger
break;
case SC_CLOAKING:
+ case SC_CLOAKINGEXCEED:
sc->option &= ~OPTION_CLOAK;
opt_flag|= 2;
break;
@@ -6962,7 +8138,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const
//On Aegis, when turning off a status change, first goes the sc packet, then the option packet.
if( vd && (pcdb_checkid(vd->class_) || bl->type == BL_MER ) )
- clif_status_change(bl,StatusIconChangeTable[type],0,0);
+ clif_status_change(bl,StatusIconChangeTable[type],0,0,0,0,0);
else if (sd)
clif_status_load(bl,StatusIconChangeTable[type],0);
@@ -7354,6 +8530,461 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data)
return 0;
}
break;
+ case SC_ABUNDANCE:
+ if(--(sce->val4) > 0)
+ {
+ if( !sc->data[SC_BERSERK] )
+ status_heal(bl,0,60,0);
+ sc_timer_next(10000+tick, status_change_timer, bl->id, data);
+ }
+ break;
+
+ case SC_PYREXIA:
+ if( --(sce->val4) >= 0 )
+ {
+ bool flag;
+ map_freeblock_lock();
+ clif_damage(bl,bl,tick,status_get_amotion(bl),0,100,0,0,0);
+ status_fix_damage(NULL,bl,100,0);
+ flag = !sc->data[type];
+ map_freeblock_unlock();
+ if( !flag )
+ {
+ if( sce->val4 == 10 )
+ sc_start(bl,SC_BLIND,100,sce->val1,30000); // Blind status for the final 30 seconds
+ sc_timer_next(3000+tick,status_change_timer,bl->id,data);
+ }
+ return 0;
+ }
+ break;
+
+ case SC_LEECHESEND:
+ if( --(sce->val4) >= 0 )
+ {
+ bool flag;
+ int damage = status->max_hp/100;
+ if( sd && (sd->status.class_ == JOB_GUILLOTINE_CROSS || sd->status.class_ == JOB_GUILLOTINE_CROSS_T ) )
+ damage += 3 * status->vit;
+ else
+ damage += 7 * status->vit;
+
+ unit_skillcastcancel(bl,2);
+
+ map_freeblock_lock();
+ status_zap(bl,damage,0);
+ flag = !sc->data[type];
+ map_freeblock_unlock();
+ if( !flag ) {
+ sc_timer_next(1000 + tick, status_change_timer, bl->id, data );
+ }
+ return 0;
+ }
+ break;
+
+ case SC_MAGICMUSHROOM:
+ if( --(sce->val4) >= 0 )
+ {
+ bool flag = 0;
+ int damage = status->max_hp * 3 / 100;
+ if( status->hp <= damage )
+ damage = status->hp - 1; // Cannot Kill
+
+ if( damage > 0 )
+ { // 3% Damage each 4 seconds
+ map_freeblock_lock();
+ status_zap(bl,damage,0);
+ flag = !sc->data[type]; // Killed? Should not
+ map_freeblock_unlock();
+ }
+
+ if( !flag )
+ { // Random Skill Cast
+ if( sd )
+ {
+ int mushroom_skillid = 0, i;
+ unit_stop_attack(bl);
+ unit_skillcastcancel(bl,1);
+ do
+ {
+ i = rand() % MAX_SKILL_MAGICMUSHROOM_DB;
+ mushroom_skillid = skill_magicmushroom_db[i].skillid;
+ }
+ while( mushroom_skillid == 0 );
+
+ switch( skill_get_casttype(mushroom_skillid) )
+ { // Magic Mushroom skills are buffs or area damage
+ case CAST_GROUND:
+ skill_castend_pos2(bl,bl->x,bl->y,mushroom_skillid,1,tick,0);
+ break;
+ case CAST_NODAMAGE:
+ skill_castend_nodamage_id(bl,bl,mushroom_skillid,1,tick,0);
+ break;
+ case CAST_DAMAGE:
+ skill_castend_damage_id(bl,bl,mushroom_skillid,1,tick,0);
+ break;
+ }
+ }
+
+ clif_emotion(bl,18);
+ sc_timer_next(4000+tick,status_change_timer,bl->id,data);
+ }
+ return 0;
+ }
+ break;
+
+ case SC_TOXIN:
+ if( --(sce->val4) >= 0 )
+ { //Damage is every 10 seconds including 3%sp drain.
+ bool flag;
+ map_freeblock_lock();
+ clif_damage(bl,bl,tick,status_get_amotion(bl),1,1,0,0,0);
+ status_damage(NULL,bl,1,status->max_sp*3/100,0,16);
+ flag = !sc->data[type];
+ map_freeblock_unlock();
+ if( !flag ) {
+ sc_timer_next(10000 + tick, status_change_timer, bl->id, data );
+ }
+ return 0;
+ }
+ break;
+
+ case SC_OBLIVIONCURSE:
+ if( --(sce->val4) >= 0 )
+ {
+ clif_emotion(bl,1);
+ sc_timer_next(3000 + tick, status_change_timer, bl->id, data );
+ return 0;
+ }
+ break;
+
+ case SC_WEAPONBLOCKING:
+ if( --(sce->val4) >= 0 )
+ {
+ if( !status_charge(bl,0,3) )
+ break;
+ sc_timer_next(3000+tick,status_change_timer,bl->id,data);
+ return 0;
+ }
+ break;
+
+ case SC_CLOAKINGEXCEED:
+ if(!status_charge(bl,0,10-sce->val1))
+ break;
+ sc_timer_next(1000 + tick, status_change_timer, bl->id, data);
+ return 0;
+
+ case SC_RENOVATIO:
+ if( --(sce->val4) >= 0 )
+ {
+ status_heal(bl, status->max_hp * 3 / 100, 0, 2);
+ sc_timer_next(5000 + tick, status_change_timer, bl->id, data);
+ return 0;
+ }
+ break;
+
+ case SC_BURNING:
+ if( --(sce->val4) >= 0 )
+ {
+ struct block_list *src = map_id2bl(sce->val3);
+ int flag, damage = 3 * status_get_max_hp(bl) / 100; // Non Elemental Damage
+ if( status )
+ damage += battle_attr_fix(NULL, bl, sce->val2, ELE_FIRE, status->def_ele, status->ele_lv);
+
+ map_freeblock_lock();
+ status_fix_damage(src,bl,damage,clif_damage(bl,bl,tick,0,0,damage,0,0,0));
+ flag = !sc->data[type];
+ map_freeblock_unlock();
+ if( !flag ) {// Target still lives. [LimitLine]
+ sc_timer_next(2000 + tick, status_change_timer, bl->id, data);
+ }
+ return 0;
+ }
+ break;
+
+ case SC_FEAR:
+ if( --(sce->val4) >= 0 )
+ {
+ if( sce->val2 > 0 )
+ sce->val2--;
+ sc_timer_next(1000 + tick, status_change_timer, bl->id, data);
+ return 0;
+ }
+ break;
+
+ case SC_SPHERE_1:
+ case SC_SPHERE_2:
+ case SC_SPHERE_3:
+ case SC_SPHERE_4:
+ case SC_SPHERE_5:
+ if( --(sce->val4) >= 0 )
+ {
+ if( !status_charge(bl, 0, 1) )
+ break;
+ sc_timer_next(1000 + tick, status_change_timer, bl->id, data);
+ return 0;
+ }
+ break;
+
+ case SC_READING_SB:
+ if( !status_charge(bl, 0, sce->val2) )
+ break;
+ sc_timer_next(1000 + tick, status_change_timer, bl->id, data);
+ return 0;
+
+ case SC_ELECTRICSHOCKER:
+ if( --(sce->val4) >= 0 )
+ {
+ status_charge(bl, 0, status->max_sp / 100 * sce->val1 );
+ sc_timer_next(1000 + tick, status_change_timer, bl->id, data);
+ return 0;
+ }
+ break;
+
+ case SC_CAMOUFLAGE:
+ if( !status_charge(bl,0,7 - sce->val1) )
+ break;
+ sc_timer_next(1000 + tick, status_change_timer, bl->id, data);
+ return 0;
+
+ case SC__REPRODUCE:
+ if(!status_charge(bl, 0, 1))
+ break;
+ sc_timer_next(1000+tick, status_change_timer, bl->id, data);
+ return 0;
+
+ case SC__SHADOWFORM:
+ if( --(sce->val4) >= 0 )
+ {
+ if( !status_charge(bl, 0, sce->val1 - (sce->val1 - 1)) )
+ break;
+ sc_timer_next(1000 + tick, status_change_timer, bl->id, data);
+ return 0;
+ }
+ break;
+
+ case SC__INVISIBILITY:
+ if( --(sce->val4) >= 0 )
+ {
+ if( !status_charge(bl, 0, (status->sp * 6 - sce->val1) / 100) )// 6% - skilllv.
+ break;
+ sc_timer_next(1000 + tick, status_change_timer, bl->id, data);
+ return 0;
+ }
+ break;
+
+ case SC_STRIKING:
+ if( --(sce->val4) >= 0 )
+ {
+ if( !status_charge(bl,0, sce->val1 ) )
+ break;
+ sc_timer_next(1000 + tick, status_change_timer, bl->id, data);
+ return 0;
+ }
+ break;
+
+ case SC_BLOODSUCKER:
+ if( --(sce->val4) >= 0 )
+ {
+ struct block_list *src = map_id2bl(sce->val2);
+ int damage;
+ bool flag;
+ if( !src || (src && (status_isdead(src) || src->m != bl->m || distance_bl(src, bl) >= 12)) )
+ break;
+ map_freeblock_lock();
+ damage = skill_attack(skill_get_type(GN_BLOOD_SUCKER), src, src, bl, GN_BLOOD_SUCKER, sce->val1, tick, 0);
+ flag = !sc->data[type];
+ map_freeblock_unlock();
+ status_heal(src, damage, 0, 0);
+ clif_skill_nodamage(src, bl, GN_BLOOD_SUCKER, 0, 1);
+ if (!flag) {
+ sc_timer_next(1000 + tick, status_change_timer, bl->id, data);
+ }
+ return 0;
+ }
+ break;
+
+ case SC_VOICEOFSIREN:
+ if( --(sce->val4) >= 0 )
+ {
+ clif_emotion(bl,3);
+ sc_timer_next(2000 + tick, status_change_timer, bl->id, data);
+ return 0;
+ }
+ break;
+
+ case SC_DEEPSLEEP:
+ if( --(sce->val4) >= 0 )
+ { // Recovers 1% HP/SP every 2 seconds.
+ status_heal(bl, status->max_hp / 100, status->max_sp / 100, 2);
+ sc_timer_next(2000 + tick, status_change_timer, bl->id, data);
+ return 0;
+ }
+ break;
+
+ case SC_SIRCLEOFNATURE:
+ if( --(sce->val4) >= 0 )
+ {
+ if( !status_charge(bl,0,sce->val2) )
+ break;
+ status_heal(bl, sce->val3, 0, 1);
+ sc_timer_next(1000 + tick, status_change_timer, bl->id, data);
+ return 0;
+ }
+ break;
+
+ case SC_SONGOFMANA:
+ if( --(sce->val4) >= 0 )
+ {
+ status_heal(bl,0,sce->val3,3);
+ sc_timer_next(3000 + tick, status_change_timer, bl->id, data);
+ return 0;
+ }
+ break;
+
+
+ case SC_SATURDAYNIGHTFEVER:
+ // 1% HP/SP drain every 3 seconds [Jobbie]
+ if( --(sce->val3) >= 0 )
+ {
+ int hp = status->hp / 100;
+ int sp = status->sp / 100;
+ if( !status_charge(bl, hp, sp) )
+ break;
+ sc_timer_next(sce->val4+tick, status_change_timer, bl->id, data);
+ return 0;
+ }
+ break;
+
+ case SC_CRYSTALIZE:
+ if( --(sce->val4) >= 0 )
+ { // Drains 2% of HP and 1% of SP every seconds.
+ status_charge(bl, status->max_hp * 2 / 100, status->max_sp / 100);
+ sc_timer_next(1000 + tick, status_change_timer, bl->id, data);
+ return 0;
+ }
+ break;
+
+ case SC_FORCEOFVANGUARD:
+ if( !status_charge(bl,0,20) )
+ break;
+ sc_timer_next(6000 + tick, status_change_timer, bl->id, data);
+ return 0;
+
+ case SC_BANDING:
+ if( status_charge(bl, 0, 7 - sce->val1) )
+ {
+ //if( sd ) pc_banding(sd, sce->val1);
+ sc_timer_next(5000 + tick, status_change_timer, bl->id, data);
+ return 0;
+ }
+ break;
+
+ case SC_REFLECTDAMAGE:
+ if( --(sce->val4) >= 0 ) {
+ if( !status_charge(bl,0,sce->val3) )
+ break;
+ sc_timer_next(10000 + tick, status_change_timer, bl->id, data);
+ return 0;
+ }
+ break;
+
+ case SC_OVERHEAT_LIMITPOINT:
+ if( --(sce->val1) > 0 ) { // Cooling
+ sc_timer_next(30000 + tick, status_change_timer, bl->id, data);
+ }
+ break;
+
+ case SC_OVERHEAT:
+ {
+ int flag, damage = status->max_hp / 100; // Suggestion 1% each second
+ if( damage >= status->hp ) damage = status->hp - 1; // Do not kill, just keep you with 1 hp minimum
+ map_freeblock_lock();
+ status_fix_damage(NULL,bl,damage,clif_damage(bl,bl,tick,0,0,damage,0,0,0));
+ flag = !sc->data[type];
+ map_freeblock_unlock();
+ if( !flag ) {
+ sc_timer_next(1000 + tick, status_change_timer, bl->id, data);
+ }
+ }
+ break;
+
+ case SC_MAGNETICFIELD:
+ {
+ if( --(sce->val3) <= 0 )
+ break; // Time out
+ if( sce->val2 == bl->id )
+ {
+ if( !status_charge(bl,0,14 + (3 * sce->val1)) )
+ break; // No more SP status should end, and in the next second will end for the other affected players
+ }
+ else
+ {
+ struct block_list *src = map_id2bl(sce->val2);
+ struct status_change *ssc;
+ if( !src || (ssc = status_get_sc(src)) == NULL || !ssc->data[SC_MAGNETICFIELD] )
+ break; // Source no more under Magnetic Field
+ }
+ sc_timer_next(1000 + tick, status_change_timer, bl->id, data);
+ }
+ break;
+
+ case SC_INSPIRATION:
+ if(--(sce->val4) >= 0)
+ {
+ int hp = status->max_hp * (7-sce->val1) / 100;
+ int sp = status->max_sp * (9-sce->val1) / 100;
+
+ if( !status_charge(bl,hp,sp) ) break;
+
+ sc_timer_next(1000+tick,status_change_timer,bl->id, data);
+ return 0;
+ }
+ break;
+
+ case SC_RAISINGDRAGON:
+ // 1% every 5 seconds [Jobbie]
+ if( --(sce->val3)>0 && status_charge(bl, sce->val2, 0) )
+ {
+ if( !sc->data[type] ) return 0;
+ sc_timer_next(5000 + tick, status_change_timer, bl->id, data);
+ return 0;
+ }
+ break;
+
+ case SC_CIRCLE_OF_FIRE:
+ case SC_FIRE_CLOAK:
+ case SC_WATER_DROP:
+ case SC_WATER_SCREEN:
+ case SC_WIND_CURTAIN:
+ case SC_WIND_STEP:
+ case SC_STONE_SHIELD:
+ case SC_SOLID_SKIN:
+ if( !status_charge(bl,0,sce->val2) )
+ {
+ struct block_list *s_bl = battle_get_master(bl);
+ if( s_bl )
+ status_change_end(s_bl,type+1,-1);
+ status_change_end(bl,type,-1);
+ break;
+ }
+ sc_timer_next(2000 + tick, status_change_timer, bl->id, data);
+ return 0;
+
+ case SC_STOMACHACHE:
+ if( --(sce->val4) > 0 )
+ {
+ status_charge(bl,0,sce->val2); // Reduce 8 every 10 seconds.
+ if( sd && !pc_issit(sd) ) // Force to sit every 10 seconds.
+ {
+ pc_stop_walking(sd,1|4);
+ pc_stop_attack(sd);
+ pc_setsit(sd);
+ clif_sitting(bl);
+ }
+ sc_timer_next(10000 + tick, status_change_timer, bl->id, data);
+ }
+ break;
+
}
// default for all non-handled control paths is to end the status
@@ -7384,11 +9015,15 @@ int status_change_timer_sub(struct block_list* bl, va_list ap)
case SC_CONCENTRATE:
status_change_end(bl, SC_HIDING, INVALID_TIMER);
status_change_end(bl, SC_CLOAKING, INVALID_TIMER);
+ status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER);
+ status_change_end(bl, SC_CAMOUFLAGE, INVALID_TIMER);
break;
case SC_RUWACH: /* ルアフ */
- if (tsc && (tsc->data[SC_HIDING] || tsc->data[SC_CLOAKING])) {
+ if (tsc && (tsc->data[SC_HIDING] || tsc->data[SC_CLOAKING] || tsc->data[SC_CAMOUFLAGE] || tsc->data[SC_CLOAKINGEXCEED])) {
status_change_end(bl, SC_HIDING, INVALID_TIMER);
status_change_end(bl, SC_CLOAKING, INVALID_TIMER);
+ status_change_end(bl, SC_CAMOUFLAGE, INVALID_TIMER);
+ status_change_end(bl, SC_CLOAKINGEXCEED, INVALID_TIMER);
if(battle_check_target( src, bl, BCT_ENEMY ) > 0)
skill_attack(BF_MAGIC,src,src,bl,AL_RUWACH,1,tick,0);
}
@@ -7716,6 +9351,25 @@ static int status_natural_heal_timer(int tid, unsigned int tick, int id, intptr_
* size_fix.txt - size adjustment table for weapons
* refine_db.txt - refining data table
*------------------------------------------*/
+#if RRMODE
+static bool status_readdb_job_re(char* fields[], int columns, int current) {
+ int idx, class_;
+ unsigned int i;
+
+ class_ = atoi(fields[0]);
+
+ if(!pcdb_checkid(class_)) {
+ ShowWarning("status_readdb_job_re: Invalid job class %d specified.\n", class_);
+ return false;
+ }
+ idx = pc_class2idx(class_);
+
+ for(i = 0; i < RE_JOB_DB_MAX; i++) {
+ re_job_db[idx][i] = atoi(fields[i+1]);
+ }
+ return true;
+}
+#endif
static bool status_readdb_job1(char* fields[], int columns, int current)
{// Job-specific values (weight, HP, SP, ASPD)
int idx, class_;
@@ -7801,7 +9455,9 @@ int status_readdb(void)
memset(hp_coefficient2, 0, sizeof(hp_coefficient2));
memset(sp_coefficient, 0, sizeof(sp_coefficient));
memset(aspd_base, 0, sizeof(aspd_base));
-
+#if RRMODE
+ memset(re_job_db, 0, sizeof(re_job_db));
+#endif
// job_db2.txt
memset(job_bonus,0,sizeof(job_bonus)); // Job-specific stats bonus
@@ -7828,6 +9484,10 @@ int status_readdb(void)
sv_readdb(db_path, "size_fix.txt", ',', MAX_WEAPON_TYPE, MAX_WEAPON_TYPE, ARRAYLENGTH(atkmods), &status_readdb_sizefix);
sv_readdb(db_path, "refine_db.txt", ',', 3+MAX_REFINE+1, 3+MAX_REFINE+1, ARRAYLENGTH(percentrefinery), &status_readdb_refine);
+#if RRMODE
+ sv_readdb(db_path, "re_job_db.txt", ',', 1+RE_JOB_DB_MAX, 1+RE_JOB_DB_MAX, -1, &status_readdb_job_re);
+#endif
+
return 0;
}
diff --git a/src/map/status.h b/src/map/status.h
index dcd532577..8572b1bbb 100644
--- a/src/map/status.h
+++ b/src/map/status.h
@@ -329,7 +329,248 @@ typedef enum sc_type {
SC_FOOD_VIT_CASH,
SC_FOOD_DEX_CASH,
SC_FOOD_INT_CASH,
- SC_FOOD_LUK_CASH,
+ SC_FOOD_LUK_CASH,//308
+ /**
+ * 3rd
+ **/
+ SC_FEAR,//309
+ SC_BURNING,//310
+ SC_FREEZING,//311
+ /**
+ * Rune Knight
+ **/
+ SC_ENCHANTBLADE,//312
+ SC_DEATHBOUND,//313
+ SC_MILLENNIUMSHIELD,
+ SC_CRUSHSTRIKE,//315
+ SC_REFRESH,
+ SC_REUSE_REFRESH,
+ SC_GIANTGROWTH,
+ SC_STONEHARDSKIN,
+ SC_VITALITYACTIVATION,//320
+ SC_STORMBLAST,
+ SC_FIGHTINGSPIRIT,
+ SC_ABUNDANCE,
+ /**
+ * Arch Bishop
+ **/
+ SC_ADORAMUS,
+ SC_EPICLESIS,//325
+ SC_ORATIO,
+ SC_LAUDAAGNUS,
+ SC_LAUDARAMUS,
+ SC_RENOVATIO,
+ SC_EXPIATIO,//330
+ SC_DUPLELIGHT,
+ SC_SECRAMENT,
+ /**
+ * Warlock
+ **/
+ SC_WHITEIMPRISON,
+ SC_MARSHOFABYSS,
+ SC_RECOGNIZEDSPELL,//335
+ SC_STASIS,
+ SC_SPHERE_1,
+ SC_SPHERE_2,
+ SC_SPHERE_3,
+ SC_SPHERE_4,//340
+ SC_SPHERE_5,
+ SC_READING_SB,
+ SC_FREEZINGSPELL,
+ /**
+ * Ranger
+ **/
+ SC_FEARBREEZE,
+ SC_ELECTRICSHOCKER,//345
+ SC_WUGDASH,
+ SC_BITE,
+ SC_CAMOUFLAGE,
+ /**
+ * Mechanic
+ **/
+ SC_ACCELERATION,
+ SC_HOVERING,//350
+ SC_SHAPESHIFT,
+ SC_INFRAREDSCAN,
+ SC_ANALYZE,
+ SC_MAGNETICFIELD,
+ SC_NEUTRALBARRIER,//355
+ SC_NEUTRALBARRIER_MASTER,
+ SC_STEALTHFIELD,
+ SC_STEALTHFIELD_MASTER,
+ SC_OVERHEAT,
+ SC_OVERHEAT_LIMITPOINT,//360
+ /**
+ * Guillotine Cross
+ **/
+ SC_VENOMIMPRESS,
+ SC_POISONINGWEAPON,
+ SC_WEAPONBLOCKING,
+ SC_CLOAKINGEXCEED,
+ SC_HALLUCINATIONWALK,//365
+ SC_HALLUCINATIONWALK_POSTDELAY,
+ SC_ROLLINGCUTTER,
+ SC_TOXIN,
+ SC_PARALYSE,
+ SC_VENOMBLEED,//370
+ SC_MAGICMUSHROOM,
+ SC_DEATHHURT,
+ SC_PYREXIA,
+ SC_OBLIVIONCURSE,
+ SC_LEECHESEND,//375
+ /**
+ * Royal Guard
+ **/
+ SC_REFLECTDAMAGE,
+ SC_FORCEOFVANGUARD,
+ SC_SHIELDSPELL_DEF,
+ SC_SHIELDSPELL_MDEF,
+ SC_SHIELDSPELL_REF,//380
+ SC_EXEEDBREAK,
+ SC_PRESTIGE,
+ SC_BANDING,
+ SC_BANDING_DEFENCE,
+ SC_EARTHDRIVE,//385
+ SC_INSPIRATION,
+ /**
+ * Sorcerer
+ **/
+ SC_SPELLFIST,
+ SC_CRYSTALIZE,
+ SC_STRIKING,
+ SC_WARMER,//390
+ SC_VACUUM_EXTREME,
+ SC_PROPERTYWALK,
+ /**
+ * Minstrel / Wanderer
+ **/
+ SC_SWINGDANCE,
+ SC_SYMPHONYOFLOVER,
+ SC_MOONLITSERENADE,//395
+ SC_RUSHWINDMILL,
+ SC_ECHOSONG,
+ SC_HARMONIZE,
+ SC_VOICEOFSIREN,
+ SC_DEEPSLEEP,//400
+ SC_SIRCLEOFNATURE,
+ SC_GLOOMYDAY,
+ SC_GLOOMYDAY_SK,
+ SC_SONGOFMANA,
+ SC_DANCEWITHWUG,//405
+ SC_SATURDAYNIGHTFEVER,
+ SC_LERADSDEW,
+ SC_MELODYOFSINK,
+ SC_BEYONDOFWARCRY,
+ SC_UNLIMITEDHUMMINGVOICE,//410
+ SC_SITDOWN_FORCE,
+ /**
+ * Sura
+ **/
+ SC_CRESCENTELBOW,
+ SC_CURSEDCIRCLE_ATKER,
+ SC_CURSEDCIRCLE_TARGET,
+ SC_LIGHTNINGWALK,//415
+ SC_RAISINGDRAGON,
+ SC_GT_ENERGYGAIN,
+ SC_GT_CHANGE,
+ SC_GT_REVITALIZE,
+ /**
+ * Genetic
+ **/
+ SC_GN_CARTBOOST,//420
+ SC_THORNSTRAP,
+ SC_BLOODSUCKER,
+ SC_SMOKEPOWDER,
+ SC_TEARGAS,
+ SC_MANDRAGORA,//425
+ SC_STOMACHACHE,
+ SC_MYSTERIOUS_POWDER,
+ SC_MELON_BOMB,
+ SC_BANANA_BOMB,
+ SC_BANANA_BOMB_SITDOWN,//430
+ SC_SAVAGE_STEAK,
+ SC_COCKTAIL_WARG_BLOOD,
+ SC_MINOR_BBQ,
+ SC_SIROMA_ICE_TEA,
+ SC_DROCERA_HERB_STEAMED,//435
+ SC_PUTTI_TAILS_NOODLES,
+ SC_BOOST500,
+ SC_FULL_SWING_K,
+ SC_MANA_PLUS,
+ SC_MUSTLE_M,//440
+ SC_LIFE_FORCE_F,
+ SC_EXTRACT_WHITE_POTION_Z,
+ SC_VITATA_500,
+ SC_EXTRACT_SALAMINE_JUICE,
+ /**
+ * Shadow Chaser
+ **/
+ SC__REPRODUCE,//445
+ SC__AUTOSHADOWSPELL,
+ SC__SHADOWFORM,
+ SC__BODYPAINT,
+ SC__INVISIBILITY,
+ SC__DEADLYINFECT,//450
+ SC__ENERVATION,
+ SC__GROOMY,
+ SC__IGNORANCE,
+ SC__LAZINESS,
+ SC__UNLUCKY,//455
+ SC__WEAKNESS,
+ SC__STRIPACCESSORY,
+ SC__MANHOLE,
+ SC_CHAOS,
+ SC__BLOODYLUST,//460
+ /**
+ * Elemental Spirits
+ **/
+ SC_CIRCLE_OF_FIRE,
+ SC_CIRCLE_OF_FIRE_OPTION,
+ SC_FIRE_CLOAK,
+ SC_FIRE_CLOAK_OPTION,
+ SC_WATER_SCREEN,//465
+ SC_WATER_SCREEN_OPTION,
+ SC_WATER_DROP,
+ SC_WATER_DROP_OPTION,
+ SC_WATER_BARRIER,
+ SC_WIND_STEP,//470
+ SC_WIND_STEP_OPTION,
+ SC_WIND_CURTAIN,
+ SC_WIND_CURTAIN_OPTION,
+ SC_ZEPHYR,
+ SC_SOLID_SKIN,//475
+ SC_SOLID_SKIN_OPTION,
+ SC_STONE_SHIELD,
+ SC_STONE_SHIELD_OPTION,
+ SC_POWER_OF_GAIA,
+ SC_PYROTECHNIC,//480
+ SC_PYROTECHNIC_OPTION,
+ SC_HEATER,
+ SC_HEATER_OPTION,
+ SC_TROPIC,
+ SC_TROPIC_OPTION,//485
+ SC_AQUAPLAY,
+ SC_AQUAPLAY_OPTION,
+ SC_COOLER,
+ SC_COOLER_OPTION,
+ SC_CHILLY_AIR,//490
+ SC_CHILLY_AIR_OPTION,
+ SC_GUST,
+ SC_GUST_OPTION,
+ SC_BLAST,
+ SC_BLAST_OPTION,//495
+ SC_WILD_STORM,
+ SC_WILD_STORM_OPTION,
+ SC_PETROLOGY,
+ SC_PETROLOGY_OPTION,
+ SC_CURSED_SOIL,//500
+ SC_CURSED_SOIL_OPTION,
+ SC_UPHEAVAL,
+ SC_UPHEAVAL_OPTION,
+ SC_TIDAL_WEAPON,
+ SC_TIDAL_WEAPON_OPTION,//505
+ SC_ROCK_CRUSHER,
+ SC_ROCK_CRUSHER_ATK,
SC_MAX, //Automatically updated max, used in for's to check we are within bounds.
} sc_type;
@@ -652,7 +893,7 @@ enum si_type {
SI_CASH_PLUSONLYJOBEXP = 312,
// SI_PARTYFLEE = 313,
// SI_ANGEL_PROTECT = 314,
-/*
+
SI_ENDURE_MDEF = 315,
SI_ENCHANTBLADE = 316,
SI_DEATHBOUND = 317,
@@ -701,11 +942,11 @@ enum si_type {
SI_CAMOUFLAGE = 360,
SI_ACCELERATION = 361,
SI_HOVERING = 362,
- SI_SUMMON1 = 363,
- SI_SUMMON2 = 364,
- SI_SUMMON3 = 365,
- SI_SUMMON4 = 366,
- SI_SUMMON5 = 367,
+ SI_SPHERE_1 = 363,
+ SI_SPHERE_2 = 364,
+ SI_SPHERE_3 = 365,
+ SI_SPHERE_4 = 366,
+ SI_SPHERE_5 = 367,
SI_MVPCARD_TAOGUNKA = 368,
SI_MVPCARD_MISTRESS = 369,
SI_MVPCARD_ORCHERO = 370,
@@ -719,15 +960,15 @@ enum si_type {
SI_NEUTRALBARRIER_MASTER = 378,
SI_STEALTHFIELD = 379,
SI_STEALTHFIELD_MASTER = 380,
-*/
+
SI_MANU_ATK = 381,
SI_MANU_DEF = 382,
SI_SPL_ATK = 383,
SI_SPL_DEF = 384,
-// SI_REPRODUCE = 385,
+ SI_REPRODUCE = 385,
SI_MANU_MATK = 386,
SI_SPL_MATK = 387,
-/*
+
SI_STR_SCROLL = 388,
SI_INT_SCROLL = 389,
SI_LG_REFLECTDAMAGE = 390,
@@ -812,7 +1053,7 @@ enum si_type {
SI_BLOCKING_PLAY = 469,
SI_MANDRAGORA = 470,
SI_ACTIVATE = 471,
- SI_AB_SECRAMENT = 472,
+ SI_SECRAMENT = 472,
SI_ASSUMPTIO2 = 473,
SI_TK_SEVENWIND = 474,
SI_LIMIT_ODINS_RECALL = 475,
@@ -912,7 +1153,7 @@ enum si_type {
SI_WIND_INSIGNIA = 569,
SI_EARTH_INSIGNIA = 570,
SI_EQUIPED_FLOOR = 571,
-*/
+ SI_ALL_RIDING = 613,//awesome 571-613 gap, we're missing quite a few stuff here.
};
// JOINTBEAT stackable ailments
@@ -1033,6 +1274,7 @@ enum {
OPTION_DRAGON3 = 0x01000000,
OPTION_DRAGON4 = 0x02000000,
OPTION_DRAGON5 = 0x04000000,
+ OPTION_MOUNTING = 0x08000000,//dull name (cuz ind named it :/)
// compound constants
OPTION_CART = OPTION_CART1|OPTION_CART2|OPTION_CART3|OPTION_CART4|OPTION_CART5,
OPTION_DRAGON = OPTION_DRAGON1|OPTION_DRAGON2|OPTION_DRAGON3|OPTION_DRAGON4|OPTION_DRAGON5,
@@ -1123,6 +1365,12 @@ struct status_data {
aspd_rate;
unsigned char
def_ele, ele_lv,
+#if RRMODE
+ /**
+ * in RE weapon level is used in several areas, keeping it here saves performance
+ **/
+ wlv,
+#endif
size, race;
signed char
def, mdef;
@@ -1187,7 +1435,8 @@ struct status_change {
//TODO: See if it is possible to implement the following SC's without requiring extra parameters while the SC is inactive.
unsigned char jb_flag; //Joint Beat type flag
unsigned short mp_matk_min, mp_matk_max; //Previous matk min/max for ground spells (Amplify magic power)
- int sg_id; //ID of the previous Storm gust that hit you
+ //int sg_id; //ID of the previous Storm gust that hit you
+ short comet_x, comet_y; // Point where src casted Comet - required to calculate damage from this point
unsigned char sg_counter; //Storm gust counter (previous hits from storm gust)
struct status_change_entry *data[SC_MAX];
};
@@ -1260,6 +1509,12 @@ unsigned char status_calc_attack_element(struct block_list *bl, struct status_ch
#define status_get_race(bl) status_get_status_data(bl)->race
#define status_get_size(bl) status_get_status_data(bl)->size
#define status_get_mode(bl) status_get_status_data(bl)->mode
+#if RRMODE
+ /**
+ * in RE weapon level is used in several areas, keeping it here saves performance
+ **/
+ #define status_get_wlv(bl) status_get_status_data(bl)->wlv
+#endif
int status_get_party_id(struct block_list *bl);
int status_get_guild_id(struct block_list *bl);
int status_get_emblem_id(struct block_list *bl);
diff --git a/src/map/unit.c b/src/map/unit.c
index a11b5dc28..52b479b25 100644
--- a/src/map/unit.c
+++ b/src/map/unit.c
@@ -444,7 +444,7 @@ int unit_run(struct block_list *bl)
if(to_x == bl->x && to_y == bl->y) {
//If you can't run forward, you must be next to a wall, so bounce back. [Skotlex]
- clif_status_change(bl, SI_BUMP, 1, 0);
+ clif_status_change(bl, SI_BUMP, 1, 0, 0, 0, 0);
//Set running to 0 beforehand so status_change_end knows not to enable spurt [Kevin]
unit_bl2ud(bl)->state.running = 0;
@@ -452,7 +452,7 @@ int unit_run(struct block_list *bl)
skill_blown(bl,bl,skill_get_blewcount(TK_RUN,lv),unit_getdir(bl),0);
clif_fixpos(bl); //Why is a clif_slide (skill_blown) AND a fixpos needed? Ask Aegis.
- clif_status_change(bl, SI_BUMP, 0, 0);
+ clif_status_change(bl, SI_BUMP, 0, 0, 0, 0, 0);
return 0;
}
if (unit_walktoxy(bl, to_x, to_y, 1))
@@ -464,7 +464,7 @@ int unit_run(struct block_list *bl)
} while (--i > 0 && !unit_walktoxy(bl, to_x, to_y, 1));
if (i==0) {
// copy-paste from above
- clif_status_change(bl, SI_BUMP, 1, 0);
+ clif_status_change(bl, SI_BUMP, 1, 0, 0, 0, 0);
//Set running to 0 beforehand so status_change_end knows not to enable spurt [Kevin]
unit_bl2ud(bl)->state.running = 0;
@@ -472,7 +472,73 @@ int unit_run(struct block_list *bl)
skill_blown(bl,bl,skill_get_blewcount(TK_RUN,lv),unit_getdir(bl),0);
clif_fixpos(bl);
- clif_status_change(bl, SI_BUMP, 0, 0);
+ clif_status_change(bl, SI_BUMP, 0, 0, 0, 0, 0);
+ return 0;
+ }
+ return 1;
+}
+
+//Exclusive function to Wug Dash state. [Jobbie/3CeAM]
+int unit_wugdash(struct block_list *bl, struct map_session_data *sd) {
+ struct status_change *sc = status_get_sc(bl);
+ short to_x,to_y,dir_x,dir_y;
+ int lv;
+ int i;
+ if (!(sc && sc->data[SC_WUGDASH]))
+ return 0;
+
+ nullpo_ret(sd);
+ nullpo_ret(bl);
+
+ if (!unit_can_move(bl)) {
+ status_change_end(bl,SC_WUGDASH,-1);
+ return 0;
+ }
+
+ lv = sc->data[SC_WUGDASH]->val1;
+ dir_x = dirx[sc->data[SC_WUGDASH]->val2];
+ dir_y = diry[sc->data[SC_WUGDASH]->val2];
+
+ to_x = bl->x;
+ to_y = bl->y;
+ for(i=0;i<AREA_SIZE;i++)
+ {
+ if(!map_getcell(bl->m,to_x+dir_x,to_y+dir_y,CELL_CHKPASS))
+ break;
+
+ if(sc->data[SC_WUGDASH] && map_count_oncell(bl->m, to_x+dir_x, to_y+dir_y, BL_PC|BL_MOB|BL_NPC))
+ break;
+
+ to_x += dir_x;
+ to_y += dir_y;
+ }
+
+ if(to_x == bl->x && to_y == bl->y) {
+
+ unit_bl2ud(bl)->state.running = 0;
+ status_change_end(bl,SC_WUGDASH,-1);
+
+ if( sd ){
+ clif_fixpos(bl);
+ skill_castend_damage_id(bl, &sd->bl, RA_WUGDASH, lv, gettick(), SD_LEVEL);
+ }
+ return 0;
+ }
+ if (unit_walktoxy(bl, to_x, to_y, 1))
+ return 1;
+ do {
+ to_x -= dir_x;
+ to_y -= dir_y;
+ } while (--i > 0 && !unit_walktoxy(bl, to_x, to_y, 1));
+ if (i==0) {
+
+ unit_bl2ud(bl)->state.running = 0;
+ status_change_end(bl,SC_WUGDASH,-1);
+
+ if( sd ){
+ clif_fixpos(bl);
+ skill_castend_damage_id(bl, &sd->bl, RA_WUGDASH, lv, gettick(), SD_LEVEL);
+ }
return 0;
}
return 1;
@@ -992,7 +1058,7 @@ int unit_skilluse_id2(struct block_list *src, int target_id, short skill_num, sh
if( !target || src->m != target->m || !src->prev || !target->prev )
return 0;
- if( mob_ksprotected(src, target) )
+ if( battle_config.ksprotection && sd && mob_ksprotected(src, target) )
return 0;
//Normally not needed because clif.c checks for it, but the at/char/script commands don't! [Skotlex]
@@ -1130,7 +1196,7 @@ int unit_skilluse_id2(struct block_list *src, int target_id, short skill_num, sh
// moved here to prevent Suffragium from ending if skill fails
if (!(skill_get_castnodex(skill_num, skill_lv)&2))
- casttime = skill_castfix_sc(src, casttime);
+ casttime = skill_castfix_sc(src, casttime, skill_num, skill_lv);
if( casttime > 0 || temp )
{
@@ -1272,7 +1338,7 @@ int unit_skilluse_pos2( struct block_list *src, short skill_x, short skill_y, sh
// moved here to prevent Suffragium from ending if skill fails
if (!(skill_get_castnodex(skill_num, skill_lv)&2))
- casttime = skill_castfix_sc(src, casttime);
+ casttime = skill_castfix_sc(src, casttime, skill_num, skill_lv);
ud->state.skillcastcancel = castcancel&&casttime>0?1:0;
if( !sd || sd->skillitem != skill_num || skill_get_cast(skill_num,skill_lv) )
diff --git a/src/map/unit.h b/src/map/unit.h
index e349a7466..f7b072739 100644
--- a/src/map/unit.h
+++ b/src/map/unit.h
@@ -126,6 +126,10 @@ int unit_changeviewsize(struct block_list *bl,short size);
// 初期化ルーチン
int do_init_unit(void);
int do_final_unit(void);
+/**
+ * Ranger
+ **/
+int unit_wugdash(struct block_list *bl, struct map_session_data *sd);
extern const short dirx[8];
extern const short diry[8];