summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/char/char.c8
-rw-r--r--src/char/int_party.c44
-rw-r--r--src/char/inter.c2
-rw-r--r--src/char_sql/char.c8
-rw-r--r--src/char_sql/int_party.c58
-rw-r--r--src/char_sql/int_storage.c4
-rw-r--r--src/char_sql/inter.c3
-rw-r--r--src/common/core.c26
-rw-r--r--src/common/mmo.h81
-rw-r--r--src/common/showmsg.c27
-rw-r--r--src/common/showmsg.h1
-rw-r--r--src/common/socket.c12
-rw-r--r--src/common/sql.h5
-rw-r--r--src/map/Makefile.in4
-rw-r--r--src/map/atcommand.c410
-rw-r--r--src/map/battle.c781
-rw-r--r--src/map/battle.h18
-rw-r--r--src/map/buyingstore.c20
-rw-r--r--src/map/chrif.c8
-rw-r--r--src/map/clif.c1115
-rw-r--r--src/map/clif.h55
-rw-r--r--src/map/config/Core.h28
-rw-r--r--src/map/config/Data/Const.h33
-rw-r--r--src/map/config/Renewal.h53
-rw-r--r--src/map/config/Secure.h36
-rw-r--r--src/map/config/Skills/General.h23
-rw-r--r--src/map/config/Skills/Mage_Classes.h19
-rw-r--r--src/map/config/Skills/Swordsman_Classes.h19
-rw-r--r--src/map/guild.c19
-rw-r--r--src/map/intif.c19
-rw-r--r--src/map/intif.h2
-rw-r--r--src/map/itemdb.c124
-rw-r--r--src/map/itemdb.h52
-rw-r--r--src/map/log.c30
-rw-r--r--src/map/map.c212
-rw-r--r--src/map/map.h109
-rw-r--r--src/map/mercenary.h6
-rw-r--r--src/map/mob.c33
-rw-r--r--src/map/mob.h5
-rw-r--r--src/map/npc.c75
-rw-r--r--src/map/npc.h21
-rw-r--r--src/map/party.c274
-rw-r--r--src/map/party.h12
-rw-r--r--src/map/pc.c598
-rw-r--r--src/map/pc.h58
-rw-r--r--src/map/script.c1318
-rw-r--r--src/map/skill.c2975
-rw-r--r--src/map/skill.h65
-rw-r--r--src/map/status.c2269
-rw-r--r--src/map/status.h415
-rw-r--r--src/map/storage.c14
-rw-r--r--src/map/unit.c125
-rw-r--r--src/map/unit.h4
53 files changed, 8552 insertions, 3183 deletions
diff --git a/src/char/char.c b/src/char/char.c
index 0f23744c0..90e954002 100644
--- a/src/char/char.c
+++ b/src/char/char.c
@@ -1793,7 +1793,7 @@ int count_users(void)
// Writes char data to the buffer in the format used by the client.
// Used in packets 0x6b (chars info) and 0x6d (new char info)
// Returns the size
-#define MAX_CHAR_BUF 136 //Max size (for WFIFOHEAD calls)
+#define MAX_CHAR_BUF 140 //Max size (for WFIFOHEAD calls)
int mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p)
{
unsigned short offset = 0;
@@ -1828,7 +1828,7 @@ int mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p)
WBUFW(buf,50) = DEFAULT_WALK_SPEED; // p->speed;
WBUFW(buf,52) = p->class_;
WBUFW(buf,54) = p->hair;
- WBUFW(buf,56) = p->option&0x7E80020 ? 0 : p->weapon; //When the weapon is sent and your option is riding, the client crashes on login!?
+ WBUFW(buf,56) = p->option&0x20 ? 0 : p->weapon; //When the weapon is sent and your option is riding, the client crashes on login!?
WBUFW(buf,58) = p->base_level;
WBUFW(buf,60) = min(p->skill_point, INT16_MAX);
WBUFW(buf,62) = p->head_bottom;
@@ -1861,6 +1861,10 @@ int mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p)
WBUFL(buf,128) = p->robe;
offset += 4;
#endif
+#if PACKETVER >= 20110928
+ WBUFL(buf,132) = 0; // change slot feature (0 = disabled, otherwise enabled)
+ offset += 4;
+#endif
return 106+offset;
}
diff --git a/src/char/int_party.c b/src/char/int_party.c
index b340aa9cf..2ae9e5319 100644
--- a/src/char/int_party.c
+++ b/src/char/int_party.c
@@ -309,29 +309,29 @@ int mapif_party_created(int fd,int account_id, int char_id, struct party *p)
}
// パ?ティ情報見つからず
-int mapif_party_noinfo(int fd, int party_id) {
- WFIFOHEAD(fd, 8);
+static void mapif_party_noinfo(int fd, int party_id, int char_id)
+{
+ WFIFOHEAD(fd, 12);
WFIFOW(fd,0) = 0x3821;
- WFIFOW(fd,2) = 8;
- WFIFOL(fd,4) = party_id;
- WFIFOSET(fd,8);
- ShowWarning("int_party: info not found %d\n", party_id);
-
- return 0;
+ WFIFOW(fd,2) = 12;
+ WFIFOL(fd,4) = char_id;
+ WFIFOL(fd,8) = party_id;
+ WFIFOSET(fd,12);
+ ShowWarning("int_party: info not found (party_id=%d char_id=%d)\n", party_id, char_id);
}
// パ?ティ情報まとめ送り
-int mapif_party_info(int fd, struct party *p) {
- unsigned char buf[2048];
-
+static void mapif_party_info(int fd, struct party* p, int char_id)
+{
+ unsigned char buf[8 + sizeof(struct party)];
WBUFW(buf,0) = 0x3821;
- memcpy(buf + 4, p, sizeof(struct party));
- WBUFW(buf,2) = 4 + sizeof(struct party);
+ WBUFW(buf,2) = 8 + sizeof(struct party);
+ WBUFL(buf,4) = char_id;
+ memcpy(WBUFP(buf,8), p, sizeof(struct party));
if (fd < 0)
mapif_sendall(buf, WBUFW(buf,2));
else
mapif_send(fd, buf, WBUFW(buf,2));
- return 0;
}
// パ?ティメンバ追加可否
@@ -472,25 +472,23 @@ int mapif_parse_CreateParty(int fd, char *name, int item, int item2, struct part
int_party_calc_state(p);
idb_put(party_db, p->party.party_id, p);
+ mapif_party_info(fd, &p->party, 0);
mapif_party_created(fd, leader->account_id, leader->char_id, &p->party);
- mapif_party_info(fd, &p->party);
return 0;
}
// パ?ティ情報要求
-int mapif_parse_PartyInfo(int fd, int party_id)
+static void mapif_parse_PartyInfo(int fd, int party_id, int char_id)
{
struct party_data *p;
p = (struct party_data*)idb_get(party_db, party_id);
if (p != NULL)
- mapif_party_info(fd, &p->party);
+ mapif_party_info(fd, &p->party, char_id);
else {
- mapif_party_noinfo(fd, party_id);
+ mapif_party_noinfo(fd, party_id, char_id);
}
-
- return 0;
}
// パーティ追加要求
@@ -524,8 +522,8 @@ int mapif_parse_PartyAddMember(int fd, int party_id, struct party_member *member
int_party_check_lv(p);
}
+ mapif_party_info(-1, &p->party, 0);
mapif_party_memberadded(fd, party_id, member->account_id, member->char_id, 0);
- mapif_party_info(-1, &p->party);
return 0;
}
@@ -574,7 +572,7 @@ int mapif_parse_PartyLeave(int fd, int party_id, int account_id, int char_id)
int_party_check_lv(p);
}
if (party_check_empty(&p->party) == 0)
- mapif_party_info(-1, &p->party);
+ mapif_party_info(-1, &p->party, 0);
return 0;
}
}
@@ -679,7 +677,7 @@ int inter_party_parse_frommap(int fd) {
RFIFOHEAD(fd);
switch(RFIFOW(fd,0)) {
case 0x3020: mapif_parse_CreateParty(fd, (char*)RFIFOP(fd,4), RFIFOB(fd,28), RFIFOB(fd,29), (struct party_member*)RFIFOP(fd,30)); break;
- case 0x3021: mapif_parse_PartyInfo(fd, RFIFOL(fd,2)); break;
+ case 0x3021: mapif_parse_PartyInfo(fd, RFIFOL(fd,2), RFIFOL(fd,6)); break;
case 0x3022: mapif_parse_PartyAddMember(fd, RFIFOL(fd,4), (struct party_member*)RFIFOP(fd,8)); break;
case 0x3023: mapif_parse_PartyChangeOption(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOW(fd,10), RFIFOW(fd,12)); break;
case 0x3024: mapif_parse_PartyLeave(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break;
diff --git a/src/char/inter.c b/src/char/inter.c
index 8d9cac99f..298ed38a5 100644
--- a/src/char/inter.c
+++ b/src/char/inter.c
@@ -52,7 +52,7 @@ int inter_send_packet_length[]={
int inter_recv_packet_length[]={
-1,-1, 7,-1, -1,13,36, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3000-0x300f
6,-1, 0, 0, 0, 0, 0, 0, 10,-1, 0, 0, 0, 0, 0, 0, //0x3010-0x301f
- -1, 6,-1,14, 14,19, 6,-1, 14,14, 0, 0, 0, 0, 0, 0, //0x3020-0x302f
+ -1,10,-1,14, 14,19, 6,-1, 14,14, 0, 0, 0, 0, 0, 0, //0x3020-0x302f Party
-1, 6,-1,-1, 55,19, 6,-1, 14,-1,-1,-1, 18,19,186,-1, //0x3030-0x303f
5, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3040-0x304f
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3050-0x305f
diff --git a/src/char_sql/char.c b/src/char_sql/char.c
index 30800d95b..19ea01f66 100644
--- a/src/char_sql/char.c
+++ b/src/char_sql/char.c
@@ -1591,7 +1591,7 @@ int count_users(void)
// Writes char data to the buffer in the format used by the client.
// Used in packets 0x6b (chars info) and 0x6d (new char info)
// Returns the size
-#define MAX_CHAR_BUF 136 //Max size (for WFIFOHEAD calls)
+#define MAX_CHAR_BUF 140 //Max size (for WFIFOHEAD calls)
int mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p)
{
unsigned short offset = 0;
@@ -1626,7 +1626,7 @@ int mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p)
WBUFW(buf,50) = DEFAULT_WALK_SPEED; // p->speed;
WBUFW(buf,52) = p->class_;
WBUFW(buf,54) = p->hair;
- WBUFW(buf,56) = p->option&0x7E80020 ? 0 : p->weapon; //When the weapon is sent and your option is riding, the client crashes on login!?
+ WBUFW(buf,56) = p->option&0x20 ? 0 : p->weapon; //When the weapon is sent and your option is riding, the client crashes on login!?
WBUFW(buf,58) = p->base_level;
WBUFW(buf,60) = min(p->skill_point, INT16_MAX);
WBUFW(buf,62) = p->head_bottom;
@@ -1659,6 +1659,10 @@ int mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p)
WBUFL(buf,128) = p->robe;
offset += 4;
#endif
+#if PACKETVER >= 20110928
+ WBUFL(buf,132) = 0; // change slot feature (0 = disabled, otherwise enabled)
+ offset += 4;
+#endif
return 106+offset;
}
diff --git a/src/char_sql/int_party.c b/src/char_sql/int_party.c
index 07dbcdb7d..d62e9f6a7 100644
--- a/src/char_sql/int_party.c
+++ b/src/char_sql/int_party.c
@@ -42,7 +42,10 @@ static int int_party_check_lv(struct party_data *p) {
p->min_lv = UINT_MAX;
p->max_lv = 0;
for(i=0;i<MAX_PARTY;i++){
- if(!p->party.member[i].online)
+ /**
+ * - If not online OR if it's a family party and this is the child (doesn't affect exp range)
+ **/
+ if(!p->party.member[i].online || p->party.member[i].char_id == p->family )
continue;
lv=p->party.member[i].lv;
@@ -75,7 +78,13 @@ static void int_party_calc_state(struct party_data *p)
if(p->party.member[i].online)
p->party.count++;
}
- if(p->size == 3) {
+ if( p->size == 2 && ( char_child(p->party.member[0].char_id,p->party.member[1].char_id) || char_child(p->party.member[1].char_id,p->party.member[2].char_id) ) ) {
+ //Child should be able to share with either of their parents [RoM]
+ if(p->party.member[0].class_&0x2000) //first slot is the child?
+ p->family = p->party.member[0].char_id;
+ else
+ p->family = p->party.member[1].char_id;
+ } else if( p->size == 3 ) {
//Check Family State.
p->family = char_family(
p->party.member[0].char_id,
@@ -357,29 +366,29 @@ int mapif_party_created(int fd,int account_id,int char_id,struct party *p)
}
// パーティ情報見つからず
-int mapif_party_noinfo(int fd,int party_id)
+static void mapif_party_noinfo(int fd, int party_id, int char_id)
{
- WFIFOHEAD(fd,8);
- WFIFOW(fd,0)=0x3821;
- WFIFOW(fd,2)=8;
- WFIFOL(fd,4)=party_id;
- WFIFOSET(fd,8);
- ShowWarning("int_party: info not found %d\n",party_id);
- return 0;
+ WFIFOHEAD(fd, 12);
+ WFIFOW(fd,0) = 0x3821;
+ WFIFOW(fd,2) = 12;
+ WFIFOL(fd,4) = char_id;
+ WFIFOL(fd,8) = party_id;
+ WFIFOSET(fd,12);
+ ShowWarning("int_party: info not found (party_id=%d char_id=%d)\n", party_id, char_id);
}
// パーティ情報まとめ送り
-int mapif_party_info(int fd,struct party *p)
+static void mapif_party_info(int fd, struct party* p, int char_id)
{
- unsigned char buf[5+sizeof(struct party)];
- WBUFW(buf,0)=0x3821;
- WBUFW(buf,2)=4+sizeof(struct party);
- memcpy(buf+4,p,sizeof(struct party));
+ unsigned char buf[8 + sizeof(struct party)];
+ WBUFW(buf,0) = 0x3821;
+ WBUFW(buf,2) = 8 + sizeof(struct party);
+ WBUFL(buf,4) = char_id;
+ memcpy(WBUFP(buf,8), p, sizeof(struct party));
if(fd<0)
mapif_sendall(buf,WBUFW(buf,2));
else
mapif_send(fd,buf,WBUFW(buf,2));
- return 0;
}
// パーティメンバ追加可否
int mapif_party_memberadded(int fd, int party_id, int account_id, int char_id, int flag) {
@@ -506,8 +515,8 @@ int mapif_parse_CreateParty(int fd, char *name, int item, int item2, struct part
//Add party to db
int_party_calc_state(p);
idb_put(party_db_, p->party.party_id, p);
+ mapif_party_info(fd, &p->party, 0);
mapif_party_created(fd,leader->account_id,leader->char_id,&p->party);
- mapif_party_info(fd,&p->party);
} else { //Failed to create party.
aFree(p);
mapif_party_created(fd,leader->account_id,leader->char_id,NULL);
@@ -516,16 +525,15 @@ int mapif_parse_CreateParty(int fd, char *name, int item, int item2, struct part
return 0;
}
// パーティ情報要求
-int mapif_parse_PartyInfo(int fd,int party_id)
+static void mapif_parse_PartyInfo(int fd, int party_id, int char_id)
{
struct party_data *p;
p = inter_party_fromsql(party_id);
if (p)
- mapif_party_info(fd,&p->party);
+ mapif_party_info(fd, &p->party, char_id);
else
- mapif_party_noinfo(fd,party_id);
- return 0;
+ mapif_party_noinfo(fd, party_id, char_id);
}
// パーティ追加要求
int mapif_parse_PartyAddMember(int fd, int party_id, struct party_member *member)
@@ -550,7 +558,7 @@ int mapif_parse_PartyAddMember(int fd, int party_id, struct party_member *member
p->party.member[i].leader = 0;
if (p->party.member[i].online) p->party.count++;
p->size++;
- if (p->size == 3) //Check family state.
+ if (p->size == 2 || p->size == 3) // Check family state. And also accept either of their Parents. [RoM]
int_party_calc_state(p);
else //Check even share range.
if (member->lv < p->min_lv || member->lv > p->max_lv || p->family) {
@@ -558,8 +566,8 @@ int mapif_parse_PartyAddMember(int fd, int party_id, struct party_member *member
int_party_check_lv(p);
}
+ mapif_party_info(-1, &p->party, 0);
mapif_party_memberadded(fd, party_id, member->account_id, member->char_id, 0);
- mapif_party_info(-1, &p->party);
inter_party_tosql(&p->party, PS_ADDMEMBER, i);
return 0;
@@ -633,7 +641,7 @@ int mapif_parse_PartyLeave(int fd, int party_id, int account_id, int char_id)
}
if (party_check_empty(p) == 0)
- mapif_party_info(-1,&p->party);
+ mapif_party_info(-1, &p->party, 0);
return 0;
}
// When member goes to other map or levels up.
@@ -746,7 +754,7 @@ int inter_party_parse_frommap(int fd)
RFIFOHEAD(fd);
switch(RFIFOW(fd,0)) {
case 0x3020: mapif_parse_CreateParty(fd, (char*)RFIFOP(fd,4), RFIFOB(fd,28), RFIFOB(fd,29), (struct party_member*)RFIFOP(fd,30)); break;
- case 0x3021: mapif_parse_PartyInfo(fd, RFIFOL(fd,2)); break;
+ case 0x3021: mapif_parse_PartyInfo(fd, RFIFOL(fd,2), RFIFOL(fd,6)); break;
case 0x3022: mapif_parse_PartyAddMember(fd, RFIFOL(fd,4), (struct party_member*)RFIFOP(fd,8)); break;
case 0x3023: mapif_parse_PartyChangeOption(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOW(fd,10), RFIFOW(fd,12)); break;
case 0x3024: mapif_parse_PartyLeave(fd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10)); break;
diff --git a/src/char_sql/int_storage.c b/src/char_sql/int_storage.c
index 0719685ae..e4d2395f1 100644
--- a/src/char_sql/int_storage.c
+++ b/src/char_sql/int_storage.c
@@ -17,7 +17,7 @@
#define STORAGE_MEMINC 16
-/// Save guild_storage data to sql
+/// Save storage data to sql
int storage_tosql(int account_id, struct storage_data* p)
{
memitemdata_to_sql(p->items, MAX_STORAGE, account_id, TABLE_STORAGE);
@@ -25,7 +25,7 @@ int storage_tosql(int account_id, struct storage_data* p)
}
#ifndef TXT_SQL_CONVERT
-/// Load guild_storage data to mem
+/// Load storage data to mem
int storage_fromsql(int account_id, struct storage_data* p)
{
StringBuf buf;
diff --git a/src/char_sql/inter.c b/src/char_sql/inter.c
index 97c48bdf1..50f05f6a3 100644
--- a/src/char_sql/inter.c
+++ b/src/char_sql/inter.c
@@ -47,7 +47,7 @@ char main_chat_nick[16] = "Main";
int inter_recv_packet_length[] = {
-1,-1, 7,-1, -1,13,36, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3000-
6,-1, 0, 0, 0, 0, 0, 0, 10,-1, 0, 0, 0, 0, 0, 0, // 3010-
- -1, 6,-1,14, 14,19, 6,-1, 14,14, 0, 0, 0, 0, 0, 0, // 3020-
+ -1,10,-1,14, 14,19, 6,-1, 14,14, 0, 0, 0, 0, 0, 0, // 3020- Party
-1, 6,-1,-1, 55,19, 6,-1, 14,-1,-1,-1, 18,19,186,-1, // 3030-
5, 9, 0, 0, 0, 0, 0, 0, 7, 6,10,10, 10,-1, 0, 0, // 3040-
-1,-1,10,10, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3050- Auction System [Zephyrus]
@@ -580,7 +580,6 @@ int mapif_parse_WisToGM(int fd)
{
unsigned char buf[2048]; // 0x3003/0x3803 <packet_len>.w <wispname>.24B <min_gm_level>.w <message>.?B
- ShowDebug("Sent packet back!\n");
memcpy(WBUFP(buf,0), RFIFOP(fd,0), RFIFOW(fd,2));
WBUFW(buf, 0) = 0x3803;
mapif_sendall(buf, RFIFOW(fd,2));
diff --git a/src/common/core.c b/src/common/core.c
index d528861c2..5b00f228b 100644
--- a/src/common/core.c
+++ b/src/common/core.c
@@ -180,26 +180,22 @@ const char* get_svn_revision(void)
/*======================================
* CORE : Display title
+ * ASCII By CalciumKid 1/12/2011
*--------------------------------------*/
static void display_title(void)
{
//ClearScreen(); // clear screen and go up/left (0, 0 position in text)
ShowMessage("\n");
- ShowMessage(""CL_WTBL" (=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=)"CL_CLL""CL_NORMAL"\n");
- ShowMessage(""CL_XXBL" ("CL_BT_YELLOW" eAthena Development Team presents "CL_XXBL")"CL_CLL""CL_NORMAL"\n");
- ShowMessage(""CL_XXBL" ("CL_BOLD" ______ __ __ "CL_XXBL")"CL_CLL""CL_NORMAL"\n");
- ShowMessage(""CL_XXBL" ("CL_BOLD" /\\ _ \\/\\ \\__/\\ \\ "CL_XXBL")"CL_CLL""CL_NORMAL"\n");
- ShowMessage(""CL_XXBL" ("CL_BOLD" __\\ \\ \\_\\ \\ \\ ,_\\ \\ \\___ __ ___ __ "CL_XXBL")"CL_CLL""CL_NORMAL"\n");
- ShowMessage(""CL_XXBL" ("CL_BOLD" /'__`\\ \\ __ \\ \\ \\/\\ \\ _ `\\ /'__`\\/' _ `\\ /'__`\\ "CL_XXBL")"CL_CLL""CL_NORMAL"\n");
- ShowMessage(""CL_XXBL" ("CL_BOLD" /\\ __/\\ \\ \\/\\ \\ \\ \\_\\ \\ \\ \\ \\/\\ __//\\ \\/\\ \\/\\ \\_\\.\\_ "CL_XXBL")"CL_CLL""CL_NORMAL"\n");
- ShowMessage(""CL_XXBL" ("CL_BOLD" \\ \\____\\\\ \\_\\ \\_\\ \\__\\\\ \\_\\ \\_\\ \\____\\ \\_\\ \\_\\ \\__/.\\_\\ "CL_XXBL")"CL_CLL""CL_NORMAL"\n");
- ShowMessage(""CL_XXBL" ("CL_BOLD" \\/____/ \\/_/\\/_/\\/__/ \\/_/\\/_/\\/____/\\/_/\\/_/\\/__/\\/_/ "CL_XXBL")"CL_CLL""CL_NORMAL"\n");
- ShowMessage(""CL_XXBL" ("CL_BOLD" _ _ _ _ _ _ _ _ _ _ _ _ _ "CL_XXBL")"CL_CLL""CL_NORMAL"\n");
- ShowMessage(""CL_XXBL" ("CL_BOLD" / \\ / \\ / \\ / \\ / \\ / \\ / \\ / \\ / \\ / \\ / \\ / \\ / \\ "CL_XXBL")"CL_CLL""CL_NORMAL"\n");
- ShowMessage(""CL_XXBL" ("CL_BOLD" ( e | n | g | l | i | s | h ) ( A | t | h | e | n | a ) "CL_XXBL")"CL_CLL""CL_NORMAL"\n");
- ShowMessage(""CL_XXBL" ("CL_BOLD" \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ \\_/ "CL_XXBL")"CL_CLL""CL_NORMAL"\n");
- ShowMessage(""CL_XXBL" ("CL_BOLD" "CL_XXBL")"CL_CLL""CL_NORMAL"\n");
- ShowMessage(""CL_WTBL" (=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=)"CL_CLL""CL_NORMAL"\n\n");
+ ShowMessage(""CL_PASS" "CL_BOLD" "CL_PASS""CL_CLL""CL_NORMAL"\n");
+ ShowMessage(""CL_PASS" "CL_BT_WHITE" RAthena Development Team presents "CL_PASS""CL_CLL""CL_NORMAL"\n");
+ ShowMessage(""CL_PASS" "CL_BOLD" ____ ___ __ __ "CL_PASS""CL_CLL""CL_NORMAL"\n");
+ ShowMessage(""CL_PASS" "CL_BOLD" / __ \\/ | / /_/ /_ ___ ____ ____ _ "CL_PASS""CL_CLL""CL_NORMAL"\n");
+ ShowMessage(""CL_PASS" "CL_BOLD" / /_/ / /| |/ __/ __ \\/ _ \\/ __ \\/ __ `/ "CL_PASS""CL_CLL""CL_NORMAL"\n");
+ ShowMessage(""CL_PASS" "CL_BOLD" / _, _/ ___ / /_/ / / / __/ / / / /_/ / "CL_PASS""CL_CLL""CL_NORMAL"\n");
+ ShowMessage(""CL_PASS" "CL_BOLD" /_/ |_/_/ |_\\__/_/ /_/\\___/_/ /_/\\___,_/ "CL_PASS""CL_CLL""CL_NORMAL"\n");
+ ShowMessage(""CL_PASS" "CL_BOLD" "CL_PASS""CL_CLL""CL_NORMAL"\n");
+ ShowMessage(""CL_PASS" "CL_GREEN" http://rathena.org/board/ "CL_PASS""CL_CLL""CL_NORMAL"\n");
+ ShowMessage(""CL_PASS" "CL_BOLD" "CL_PASS""CL_CLL""CL_NORMAL"\n");
ShowInfo("SVN Revision: '"CL_WHITE"%s"CL_RESET"'.\n", get_svn_revision());
}
diff --git a/src/common/mmo.h b/src/common/mmo.h
index 49a738b08..f8ef63390 100644
--- a/src/common/mmo.h
+++ b/src/common/mmo.h
@@ -41,10 +41,11 @@
// 20100803 - 2010-08-03aRagexeRE+ - 0x6b, 0x6d, 0x827, 0x828, 0x829, 0x82a, 0x82b, 0x82c, 0x842, 0x843
// 20101124 - 2010-11-24aRagexeRE+ - 0x856, 0x857, 0x858
// 20110111 - 2011-01-11aRagexeRE+ - 0x6b, 0x6d
+// 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
@@ -175,6 +176,7 @@ enum item_types {
IT_UNKNOWN2,//9
IT_AMMO, //10
IT_DELAYCONSUME,//11
+ IT_THROWWEAPON= 17,//17
IT_CASH = 18,
IT_MAX
};
@@ -645,21 +647,27 @@ enum {
JOB_STAR_GLADIATOR,
JOB_STAR_GLADIATOR2,
JOB_SOUL_LINKER,
-
+ /**
+ * 3.1 (2.1)
+ **/
JOB_RUNE_KNIGHT = 4054,
JOB_WARLOCK,
JOB_RANGER,
- JOB_ARCHBISHOP,
+ JOB_ARCH_BISHOP,
JOB_MECHANIC,
JOB_GUILLOTINE_CROSS,
-
- JOB_RUNE_KNIGHT_H,
- JOB_WARLOCK_H,
- JOB_RANGER_H,
- JOB_ARCHBISHOP_H,
- JOB_MECHANIC_H,
- JOB_GUILLOTINE_CROSS_H,
-
+ /**
+ * 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,
@@ -667,42 +675,27 @@ enum {
JOB_SURA,
JOB_GENETIC,
JOB_SHADOW_CHASER,
-
- JOB_ROYAL_GUARD_H,
- JOB_SORCERER_H,
- JOB_MINSTREL_H,
- JOB_WANDERER_H,
- JOB_SURA_H,
- JOB_GENETIC_H,
- JOB_SHADOW_CHASER_H,
-
+ /**
+ * 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_H2,
+ JOB_RUNE_KNIGHT_T2,
JOB_ROYAL_GUARD2,
- JOB_ROYAL_GUARD_H2,
+ JOB_ROYAL_GUARD_T2,
JOB_RANGER2,
- JOB_RANGER_H2,
+ JOB_RANGER_T2,
JOB_MECHANIC2,
- JOB_MECHANIC_H2,
-
- JOB_BABY_RUNE = 4096,
- JOB_BABY_WARLOCK,
- JOB_BABY_RANGER,
- JOB_BABY_BISHOP,
- JOB_BABY_MECHANIC,
- JOB_BABY_CROSS,
- JOB_BABY_GUARD,
- JOB_BABY_SORCERER,
- JOB_BABY_MINSTREL,
- JOB_BABY_WANDERER,
- JOB_BABY_SURA,
- JOB_BABY_GENETIC,
- JOB_BABY_CHASER,
-
- JOB_BABY_RUNE2,
- JOB_BABY_GUARD2,
- JOB_BABY_RANGER2,
- JOB_BABY_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/common/socket.c b/src/common/socket.c
index b522ac607..4f7afd8fd 100644
--- a/src/common/socket.c
+++ b/src/common/socket.c
@@ -647,6 +647,14 @@ int WFIFOSET(int fd, size_t len)
ShowFatalError("WFIFOSET: Packet 0x%x is too big. (len=%u, max=%u)\n", (*(uint16*)(s->wdata + s->wdata_size)), (unsigned int)len, 0xFFFF);
exit(EXIT_FAILURE);
}
+ else if( len == 0 )
+ {
+ // abuses the fact, that the code that did WFIFOHEAD(fd,0), already wrote
+ // the packet type into memory, even if it could have overwritten vital data
+ // this can happen when a new packet was added on map-server, but packet len table was not updated
+ ShowWarning("WFIFOSET: Attempted to send zero-length packet, most likely 0x%04x (please report this).\n", WFIFOW(fd,0));
+ return 0;
+ }
if( !s->flag.server && len > socket_max_client_packet )
{// see declaration of socket_max_client_packet for details
@@ -1222,6 +1230,7 @@ int socket_getips(uint32* ips, int max)
void socket_init(void)
{
char *SOCKET_CONF_FILENAME = "conf/packet_athena.conf";
+ unsigned int rlim_cur = FD_SETSIZE;
#ifdef WIN32
{// Start up windows networking
@@ -1265,6 +1274,7 @@ void socket_init(void)
if( err == EPERM )
errmsg = "permission denied";
ShowWarning("socket_init: failed to set socket limit to %d, setting to maximum allowed (original limit=%d, current limit=%d, maximum allowed=%d, error=%s).\n", FD_SETSIZE, rlim_ori, (int)rlp.rlim_cur, (int)rlp.rlim_max, errmsg);
+ rlim_cur = rlp.rlim_cur;
}
}
}
@@ -1294,6 +1304,8 @@ void socket_init(void)
add_timer_func_list(connect_check_clear, "connect_check_clear");
add_timer_interval(gettick()+1000, connect_check_clear, 0, 0, 5*60*1000);
#endif
+
+ ShowInfo("Server supports up to '"CL_WHITE"%u"CL_RESET"' concurrent connections.\n", rlim_cur);
}
diff --git a/src/common/sql.h b/src/common/sql.h
index 5b318ab4d..898e2c778 100644
--- a/src/common/sql.h
+++ b/src/common/sql.h
@@ -14,7 +14,10 @@
#define SQL_SUCCESS 0
#define SQL_NO_DATA 100
-
+// macro definition to determine whether the mySQL engine is running on InnoDB (rather than MyISAM)
+// uncomment this line if the your mySQL tables have been changed to run on InnoDB
+// this macro will adjust how logs are recorded in the database to accommodate the change
+//#define SQL_INNODB
/// Data type identifier.
/// String, enum and blob data types need the buffer length specified.
diff --git a/src/map/Makefile.in b/src/map/Makefile.in
index 09e92dde2..492300c3d 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 \
+ config/Core.h config/Renewal.h config/Secure.h config/Data/Const.h \
+ config/Skills/General.h config/Skills/Mage_Classes.h config/Skills/Swordsman_Classes.h
HAVE_MYSQL=@HAVE_MYSQL@
ifeq ($(HAVE_MYSQL),yes)
diff --git a/src/map/atcommand.c b/src/map/atcommand.c
index b1a395afa..9290f844a 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[22]; int id; } jobs[] = {
+ const struct { char name[24]; int id; } jobs[] = {
{ "novice", 0 },
{ "swordsman", 1 },
{ "mage", 2 },
@@ -1332,43 +1332,30 @@ ACMD_FUNC(jobchange)
{ "soul linker", 4049 },
{ "rune knight", 4054 },
{ "warlock", 4055 },
- { "ranger", 4056 },
+ { "ranger", 4056 },
{ "arch bishop", 4057 },
{ "mechanic", 4058 },
- { "guillotine cross", 4059 },
- { "rune knight2", 4060 },
- { "warlock2", 4061 },
- { "ranger2", 4062 },
- { "arch bishop2", 4063 },
- { "mechanic2", 4064 },
- { "guillotine cross2", 4065 },
+ { "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 },
+ { "sura", 4070 },
{ "genetic", 4071 },
{ "shadow chaser", 4072 },
- { "royal guard2", 4073 },
- { "sorcerer2", 4074 },
- { "minstrel2", 4075 },
- { "wanderer2", 4076 },
- { "sura2", 4077 },
- { "genetic2", 4078 },
- { "shadow chaser2", 4079 },
- { "baby rune knight", 4096 },
- { "baby warlock", 4097 },
- { "baby ranger", 4098 },
- { "baby arch bishop", 4099 },
- { "baby mechanic", 4100 },
- { "baby guillotine cross", 4101 },
- { "baby royal guard", 4102 },
- { "baby sorcerer", 4103 },
- { "baby minstrel", 4104 },
- { "baby wanderer", 4105 },
- { "baby sura", 4106 },
- { "baby genetic", 4107 },
- { "baby shadow chaser", 4108 },
+ { "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++) {
@@ -1393,50 +1380,53 @@ ACMD_FUNC(jobchange)
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 Class -----");
+ 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 3rd) -----");
+ 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 (Trans 3rd) -----");
+ 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 4046 Taekwon");
- clif_displaymessage(fd, "4047 Star Gladiator 4049 Soul Linker");
- clif_displaymessage(fd, "---- Baby 1st / 2nd 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, "---- Baby 3rd 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, "[upper]: -1 (default) to automatically determine the 'level', 0 to force normal job, 1 to force high job.");
+ //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;
}
}
- switch(job)
- {
- case 13: case 21: case 4014: case 4022: case 4036:
- case 4044: case 4080: case 4081: case 4082: case 4083:
- case 4084: case 4085: case 4086: case 4087: case 4109:
- case 4110: case 4111: case 4112:
- return 0; // Deny direct transformation into dummy jobs
- }
+ if (job == 13 || job == 21 || job == 22 || job == 26 || job == 27
+ || job == 4014 || job == 4022 || job == 4036 || job == 4044 || job == 4048
+ ) // Deny direct transformation into dummy jobs
+ return 0;
if (pcdb_checkid(job))
{
@@ -1448,49 +1438,56 @@ ACMD_FUNC(jobchange)
}
} else {
clif_displaymessage(fd, "Please, enter job ID (usage: @job/@jobchange <job name/ID>).");
- 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 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 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 (Trans 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 4046 Taekwon");
- clif_displaymessage(fd, "4047 Star Gladiator 4049 Soul Linker");
- clif_displaymessage(fd, "---- Baby 1st / 2nd 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, "---- Baby 3rd 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, "[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;
}
@@ -1710,8 +1707,7 @@ ACMD_FUNC(item)
if(log_config.enable_logs&0x400)
log_pick_pc(sd, "A", item_id, number, NULL);
- if (!flag)
- clif_displaymessage(fd, msg_txt(18)); // Item created.
+ clif_displaymessage(fd, msg_txt(18)); // Item created.
return 0;
}
@@ -1786,8 +1782,7 @@ ACMD_FUNC(item2)
if(log_config.enable_logs&0x400)
log_pick_pc(sd, "A", item_tmp.nameid, number, &item_tmp);
- if (!flag)
- clif_displaymessage(fd, msg_txt(18)); // Item created.
+ clif_displaymessage(fd, msg_txt(18)); // Item created.
} else {
clif_displaymessage(fd, msg_txt(19)); // Invalid item ID or name.
return -1;
@@ -2929,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;
}
@@ -3070,7 +3065,7 @@ ACMD_FUNC(zeny)
*------------------------------------------*/
ACMD_FUNC(param)
{
- int i, value = 0, new_value;
+ int i, value = 0, new_value, max;
const char* param[] = { "str", "agi", "vit", "int", "dex", "luk" };
short* status[6];
//we don't use direct initialization because it isn't part of the c standard.
@@ -3099,16 +3094,16 @@ ACMD_FUNC(param)
status[4] = &sd->status.dex;
status[5] = &sd->status.luk;
- if(value < 0 && *status[i] <= -value)
- {
- new_value = 1;
- }
- else if(SHRT_MAX - *status[i] < value)
- {
- new_value = SHRT_MAX;
- }
+ if( battle_config.atcommand_max_stat_bypass )
+ max = SHRT_MAX;
else
- {
+ max = pc_maxparameter(sd);
+
+ if(value < 0 && *status[i] <= -value) {
+ new_value = 1;
+ } else if(max - *status[i] < value) {
+ new_value = max;
+ } else {
new_value = *status[i] + value;
}
@@ -3150,7 +3145,10 @@ ACMD_FUNC(stat_all)
value = pc_maxparameter(sd);
max = pc_maxparameter(sd);
} else {
- max = SHRT_MAX;
+ if( battle_config.atcommand_max_stat_bypass )
+ max = SHRT_MAX;
+ else
+ max = pc_maxparameter(sd);
}
count = 0;
@@ -4218,6 +4216,7 @@ ACMD_FUNC(reloadmobdb)
mob_reload();
read_petdb();
merc_reload();
+ read_mercenarydb();
clif_displaymessage(fd, msg_txt(98)); // Monster database has been reloaded.
return 0;
@@ -4231,6 +4230,7 @@ ACMD_FUNC(reloadskilldb)
nullpo_retr(-1, sd);
skill_reload();
merc_skill_reload();
+ read_mercenary_skilldb();
clif_displaymessage(fd, msg_txt(99)); // Skill database has been reloaded.
return 0;
@@ -4482,8 +4482,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);
@@ -4597,7 +4600,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))
{
@@ -6204,24 +6226,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.
@@ -6360,7 +6384,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;
@@ -7850,13 +7877,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;
}
@@ -8072,6 +8158,7 @@ ACMD_FUNC(reject)
*-----------------------------------*/
ACMD_FUNC(cash)
{
+ char output[128];
int value;
nullpo_retr(-1, sd);
@@ -8082,17 +8169,27 @@ ACMD_FUNC(cash)
if( !strcmpi(command+1,"cash") )
{
- if( value > 0 )
+ if( value > 0 ) {
pc_getcash(sd, value, 0);
- else
+ sprintf(output, msg_txt(505), value, sd->cashPoints);
+ clif_disp_onlyself(sd, output, strlen(output));
+ } else {
pc_paycash(sd, -value, 0);
+ sprintf(output, msg_txt(410), value, sd->cashPoints);
+ clif_disp_onlyself(sd, output, strlen(output));
+ }
}
else
{ // @points
- if( value > 0 )
+ if( value > 0 ) {
pc_getcash(sd, 0, value);
- else
+ sprintf(output, msg_txt(506), value, sd->kafraPoints);
+ clif_disp_onlyself(sd, output, strlen(output));
+ } else {
pc_paycash(sd, -value, -value);
+ sprintf(output, msg_txt(411), -value, sd->kafraPoints);
+ clif_disp_onlyself(sd, output, strlen(output));
+ }
}
return 0;
@@ -8668,8 +8765,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
*------------------------------------------*/
@@ -8972,6 +9078,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 },
};
@@ -9112,11 +9222,21 @@ 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;
}
+ //Log atcommands
+ if( log_config.gm && info->level >= log_config.gm && *atcmd_msg == atcommand_symbol )
+ log_atcommand(sd, atcmd_msg);
+ //Log Charcommands
+ else if( log_config.gm && info->level2 >= log_config.gm && *atcmd_msg == charcommand_symbol && ssd != NULL )
+ log_atcommand(sd, message);
+
//Attempt to use the command
if( strcmpi("adjgmlvl",command+1) && ssd ) { lv = ssd->gmlevel; ssd->gmlevel = sd->gmlevel; }
if ( (info->func(fd, (*atcmd_msg == atcommand_symbol) ? sd : ssd, command, params) != 0) )
@@ -9126,14 +9246,6 @@ bool is_atcommand(const int fd, struct map_session_data* sd, const char* message
}
if( strcmpi("adjgmlvl",command+1) && ssd ) ssd->gmlevel = lv;
- //Log atcommands
- if( log_config.gm && info->level >= log_config.gm && *atcmd_msg == atcommand_symbol )
- log_atcommand(sd, atcmd_msg);
-
- //Log Charcommands
- if( log_config.gm && info->level2 >= log_config.gm && *atcmd_msg == charcommand_symbol && ssd != NULL )
- log_atcommand(sd, message);
-
return true;
}
diff --git a/src/map/battle.c b/src/map/battle.c
index f338a50bb..8b0aa22fb 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)
{
@@ -265,9 +303,6 @@ int battle_attr_fix(struct block_list *src, struct block_list *target, int damag
if( tsc->data[SC_SPIDERWEB]->val2 == 0 )
status_change_end(target, SC_SPIDERWEB, INVALID_TIMER);
}
- if( atk_elem == ELE_HOLY && tsc && tsc->count && tsc->data[SC_ORATIO] )
- ratio += tsc->data[SC_ORATIO]->val2;
-
return damage*ratio/100;
}
@@ -319,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 )
{
@@ -337,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;
@@ -361,26 +416,7 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag
clif_skill_nodamage(bl, bl, LK_PARRYING, sce->val1,1);
return 0;
}
-
- if((sce=sc->data[SC_MILLENNIUMSHIELD]) && damage > 0) {
- if(sce->val2 > 0)
- {
- sce->val3 -= damage;
- if( sce->val3 <= 0 )
- { // Reduce remaining shields and create new one.
- sc_start(bl,SC_STUN,15,0,1000);
- sce->val3 = 1000;
- sce->val2--;
- if( sd )
- clif_millenniumshield(sd,sce->val2);
- }
-
- damage = 0; // Nullify damage even if shield is destroyed.
- }
- if(sce->val2 <= 0)
- status_change_end(bl, SC_MILLENNIUMSHIELD, INVALID_TIMER);
- }
-
+
if(sc->data[SC_DODGE] && !sc->opt1 &&
(flag&BF_LONG || sc->data[SC_SPURT])
&& rand()%100 < 20) {
@@ -434,7 +470,7 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag
}
//Finally damage reductions....
- if( sc->data[SC_ASSUMPTIO] && skill_num != RK_DRAGONBREATH )
+ if( sc->data[SC_ASSUMPTIO] )
{
if( map_flag_vs(bl->m) )
damage = damage*2/3; //Receive 66% damage
@@ -447,11 +483,10 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag
damage=damage*(100-sc->data[SC_DEFENDER]->val2)/100;
if(sc->data[SC_ADJUSTMENT] &&
- (flag&(BF_LONG|BF_WEAPON)) == (BF_LONG|BF_WEAPON) &&
- skill_num != RK_DRAGONBREATH)
+ (flag&(BF_LONG|BF_WEAPON)) == (BF_LONG|BF_WEAPON))
damage -= 20*damage/100;
- if(sc->data[SC_FOGWALL] && skill_num != RK_DRAGONBREATH) {
+ if(sc->data[SC_FOGWALL]) {
if(flag&BF_SKILL) //25% reduction
damage -= 25*damage/100;
else if ((flag&(BF_LONG|BF_WEAPON)) == (BF_LONG|BF_WEAPON))
@@ -510,10 +545,18 @@ 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;
- if(flag&BF_WEAPON || skill_num == TF_THROWSTONE || skill_num == RK_DRAGONBREATH){
+ if(flag&BF_WEAPON || skill_num == TF_THROWSTONE){
if(sce->val2>=0)
damage=0;
else
@@ -523,13 +566,6 @@ int battle_calc_damage(struct block_list *src,struct block_list *bl,struct Damag
status_change_end(bl, SC_KYRIE, INVALID_TIMER);
}
- if((sce = sc->data[SC_STONEHARDSKIN]) && damage > 0)
- {
- sce->val2-=damage; // Reduce Stone Skin's HP by damage taken.
- if( sce->val2 <= 0 )
- status_change_end(bl, SC_STONEHARDSKIN, INVALID_TIMER);
- }
-
if (!damage) return 0;
//Probably not the most correct place, but it'll do here
@@ -569,9 +605,11 @@ 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)
+ if (battle_config.pk_mode && sd && bl->type == BL_PC && damage && !map_flag_gvg(sd->bl.m))
{
if (flag & BF_SKILL) { //Skills get a different reduction than non-skills. [Skotlex]
if (flag&BF_WEAPON)
@@ -628,7 +666,6 @@ int battle_calc_bg_damage(struct block_list *src, struct block_list *bl, int dam
case PA_PRESSURE:
case HW_GRAVITATION:
case NJ_ZENYNAGE:
- case RK_DRAGONBREATH:
break;
default:
if( flag&BF_SKILL )
@@ -690,9 +727,13 @@ int battle_calc_gvg_damage(struct block_list *src,struct block_list *bl,int dama
case PA_PRESSURE:
case HW_GRAVITATION:
case NJ_ZENYNAGE:
- case RK_DRAGONBREATH:
break;
default:
+ /* Uncomment if you want god-mode Emperiums at 100 defense. [Kisuka]
+ if (md && md->guardian_data) {
+ damage -= damage * (md->guardian_data->castle->defense/100) * battle_config.castle_defense_rate/100;
+ }
+ */
if (flag & BF_SKILL) { //Skills get a different reduction than non-skills. [Skotlex]
if (flag&BF_WEAPON)
damage = damage * battle_config.gvg_weapon_damage_rate/100;
@@ -747,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);
@@ -772,24 +819,25 @@ int battle_addmastery(struct map_session_data *sd,struct block_list *target,int
case W_1HSPEAR:
case W_2HSPEAR:
if((skill = pc_checkskill(sd,KN_SPEARMASTERY)) > 0) {
- if(!pc_isriding(sd) && !pc_isdragon(sd))
+ if(!pc_isriding(sd))
damage += (skill * 4);
else
damage += (skill * 5);
- // increase damage by level of KN_SPEARMASTERY * 10
- if (pc_checkskill(sd,RK_DRAGONTRAINING) > 0)
- damage += (skill * 10);
}
break;
case W_1HAXE:
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)
@@ -1022,7 +1070,7 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
wd.type=0; //Normal attack
wd.div_=skill_num?skill_get_num(skill_num,skill_lv):1;
wd.amotion=(skill_num && skill_get_inf(skill_num)&INF_GROUND_SKILL)?0:sstatus->amotion; //Amotion should be 0 for ground skills.
- if(skill_num == KN_AUTOCOUNTER || skill_num == RK_DEATHBOUND)
+ if(skill_num == KN_AUTOCOUNTER)
wd.amotion >>= 1;
wd.dmotion=tstatus->dmotion;
wd.blewcount=skill_get_blewcount(skill_num,skill_lv);
@@ -1095,7 +1143,6 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
break;
case KN_AUTOCOUNTER:
- case RK_DEATHBOUND:
wd.flag=(wd.flag&~BF_SKILLMASK)|BF_NORMAL;
break;
@@ -1222,7 +1269,7 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
if (flag.cri)
{
wd.type = 0x0a;
- flag.hit = 1;
+ flag.idef = flag.idef2 = flag.hit = 1;
} else { //Check for Perfect Hit
if(sd && sd->perfect_hit > 0 && rand()%100 < sd->perfect_hit)
flag.hit = 1;
@@ -1309,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
@@ -1436,15 +1486,6 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
if( (i = party_foreachsamemap(party_sub_count, sd, 0)) > 1 ) // exclude the player himself [Inkfish]
ATK_ADDRATE(2*skill*i);
}
- if(sd->status.party_id && sc && sc->data[SC_FIGHTINGSPIRIT])
- {
- i = party_foreachsamemap(party_sub_count, sd, 0);
- if( (sc->data[SC_FIGHTINGSPIRIT]->val2) > 0){
- ATK_ADDRATE(7*i); //Caster gets full effect.
- }else{
- ATK_ADDRATE(7*i/4); //Party members get 1/4.
- }
- }
}
break;
} //End default case
@@ -1767,65 +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:
- skillratio += ((skill_lv + 5) * 100) * (1 + (status_get_lv(src) -100) / 200);
+ 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 weight = 1, dmg = 0;
- if (sd) {
- short index = sd->equip_index[EQI_HAND_R];
-
- if (index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_WEAPON)
- weight = sd->inventory_data[index]->weight; //80% of weight
- }
-
- dmg = (600 + (skill_lv * 80) + (1000 - (weight>1000?1000:weight)) * ((1 + status_get_lv(src) - 100) / 200));
-
- if(sd) // Add clashing spiral bonus damage (Skill level * 50% damage)
- dmg += pc_checkskill(sd,LK_SPIRALPIERCE) * (dmg * 50 /100);
-
- skillratio = dmg;
- break;
+ case RK_HUNDREDSPEAR: {
+ int level = status_get_lv(src);
+ skillratio += 500 + 40 * skill_lv;
+ if( level > 100 )
+ skillratio += skillratio * (level - 100) / 200;
}
- case RK_WINDCUTTER:
- skillratio += ((skill_lv + 2) * 50) * status_get_lv(src) / 100;
break;
- case RK_IGNITIONBREAK:
- {
- int dmg = 300; // Base maximum damage at less than 3 cells.
+ 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 > 7 )
- dmg -= 100; // Greather than 7 cells. (200 damage)
- else if( i > 3 )
- dmg -= 50; // Greater than 3 cells, less than 7. (250 damage)
-
- dmg = (dmg * skill_lv) * (1+ (status_get_lv(src) - 100) / 120);
-
- // Elemental check, +100% damage if your element is fire.
- if( sstatus->rhw.ele == ELE_FIRE )
- dmg += skill_lv * 100 / 100;
-
- skillratio = dmg;
- break;
+ 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 = (sd->inventory_data[index]->wlv * (sd->status.inventory[index].refine + 6) * 100) + sd->inventory_data[index]->atk + sd->inventory_data[index]->weight;
- }
- break;
+ 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 = ((sd?pc_checkskill(sd,RK_RUNEMASTERY):1) + (sstatus->int_ / 8)) * 100;
+ skillratio = 100 * (sd ? pc_checkskill(sd,RK_RUNEMASTERY) : 1) + 100 * (sstatus->int_ / 4);
break;
case RK_PHANTOMTHRUST:
- skillratio = ((skill_lv * 50) + (sd?pc_checkskill(sd,KN_SPEARMASTERY):0) * 10) * status_get_lv(src) / 150;
+ 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);
@@ -1854,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.
@@ -1863,14 +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 &&
- skill_num != AS_GRIMTOOTH) // RE disabled Grimtooth carrying EDP.
+ skill_num != AS_VENOMKNIFE)
ATK_ADDRATE(sc->data[SC_EDP]->val3);
+ #endif
}
switch (skill_num) {
@@ -1887,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 )
@@ -1939,15 +2092,9 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
if (!flag.idef || !flag.idef2)
{ //Defense reduction
short vit_def;
- signed short def1 = status_get_def(target); //Don't use tstatus->def1 due to skill timer reductions.
+ signed char def1 = status_get_def(target); //Don't use tstatus->def1 due to skill timer reductions.
short def2 = (short)tstatus->def2;
- if( sc && sc->data[SC_EXPIATIO] )
- {
- def1 -= def1 * sc->data[SC_EXPIATIO]->val2 / 100;
- def2 -= def2 * sc->data[SC_EXPIATIO]->val2 / 100;
- }
-
if( sd )
{
i = sd->ignore_def[is_boss(target)?RC_BOSS:RC_NONBOSS];
@@ -1987,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);
@@ -2399,11 +2549,10 @@ 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;
}
-
- if ( sc )
- { // I don't see the point in repeating the SC check now that there are more things that use it. [L0ne_W0lf]
+ if( sc ) {
+ //SG_FUSION hp penalty [Komurka]
if (sc->data[SC_FUSION])
- { //SG_FUSION hp penalty [Komurka]
+ {
int hp= sstatus->max_hp;
if (sd && tsd) {
hp = 8*hp/100;
@@ -2413,38 +2562,21 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo
hp = 2*hp/100; //2% hp loss per hit
status_zap(src, hp, 0);
}
-
- if(sc->data[SC_ENCHANTBLADE] && !skill_num && wd.flag&BF_SHORT )
- {
- if (tsc && tsc->data[SC_SAFETYWALL])
- ; // Although this is suposed to be considered a magic atttack, Safety Wall still blocks it? May be impemented wrong.
- else
- {
- struct Damage ebd = battle_calc_attack(BF_MAGIC,src,target,RK_ENCHANTBLADE,sc->data[SC_ENCHANTBLADE]->val1,wd.flag);
- wd.damage += (sc->data[SC_ENCHANTBLADE]->val1 * 20 + 100) * (status_get_lv(src) / 150) + sstatus->int_ + ebd.damage;
- }
- }
-
- if(sc->data[SC_GIANTGROWTH] && !skill_num )
- {
- int rate = battle_config.equip_natural_break_rate;
- rate += 10;
- skill_break_equip(src, EQP_WEAPON, rate, BCT_SELF);
- if( rand() % 100 <= 10 )
- ATK_RATE(300);
- }
-
- if(sc->data[SC_STONEHARDSKIN] && !skill_num)
- { // SC_STRIPWEAPON will reduce damage by 25% so piggyback off that since there is no offensive status for this.
- int rate = battle_config.equip_natural_break_rate;
- rate += 300; //chance to break gear, or reduce attack by 25% in hte case of monsters.
- if( sd )
- skill_break_equip(src,EQP_WEAPON,rate,BCT_ENEMY);
- if (!sd && !(status_get_mode(src)&MD_BOSS))
- status_change_start(src,SC_STRIPWEAPON,rate,0,0,0,0,10000,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;
}
@@ -2536,6 +2668,9 @@ 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;
@@ -2556,17 +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.
+ **/ //1:bugreport:5101 //1:bugreport:5101
+ MATK_ADD((1+sstatus->matk_max) * 2 + 15/10 * sstatus->matk_min + rand()% ( sstatus->matk_max + (1 + (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;
@@ -2612,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;
@@ -2655,15 +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 += ((skill_lv * 20) + 300) * status_get_lv(src) / 100;
+ 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 += ((skill_lv * 100) + 500) * status_get_lv(src) / 100;
+ 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 = 200 + 20 * skill_lv;
+ 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);
@@ -2689,7 +3021,7 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list
}
if(!flag.imdef){
- short mdef = tstatus->mdef;
+ char mdef = tstatus->mdef;
int mdef2= tstatus->mdef2;
if(sd) {
i = sd->ignore_mdef[is_boss(target)?RC_BOSS:RC_NONBOSS];
@@ -2701,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)
@@ -2957,7 +3298,31 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list *
md.damage = skill_calc_heal(src,target,skill_num,skill_lv,false);
break;
case RK_DRAGONBREATH:
- md.damage = (sstatus->hp / 50 + sstatus->max_sp / 4) * (skill_lv * status_get_lv(src)/150) * (95 + 5 * (sd?pc_checkskill(sd,RK_DRAGONTRAINING):10)) / 100;
+ 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
@@ -3059,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;
@@ -3096,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);
@@ -3112,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)
@@ -3318,27 +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 )
{
- if( sc && sc->data[SC_DUPLELIGHT] ) {
- int skilllv = sc->data[SC_DUPLELIGHT]->val1;
- if( rand()%100 < sc->data[SC_DUPLELIGHT]->val2 )
- skill_addtimerskill(src,tick+status_get_adelay(src) / 2,target->id,0,0,AB_DUPLELIGHT_MELEE,skilllv,BF_WEAPON,flag);
- else if( rand()%100 < sc->data[SC_DUPLELIGHT]->val3 )
- skill_addtimerskill(src,tick+status_get_adelay(src) / 2,target->id,0,0,AB_DUPLELIGHT_MAGIC,skilllv,BF_MAGIC,flag);
- }
-
- if(tsc && tsc->data[SC_DEATHBOUND] && !is_boss(src) && map_check_dir(map_calc_dir(src,target->x,target->y),unit_getdir(target)))
- {
- int skilllv = tsc->data[SC_DEATHBOUND]->val1;
- clif_skill_damage(src,src, tick, 0, 0, 0, 0, RK_DEATHBOUND,-1, 1);
- rdamage = wd.damage * ((500 + 100*skilllv) / 100);
- wd.damage = rdamage * 30 / 100;
- status_zap(target, wd.damage, 0);
- skill_blown(src, src, skill_get_blewcount(RK_DEATHBOUND,skilllv), unit_getdir(src), 0);
- status_change_end(target,SC_DEATHBOUND,INVALID_TIMER);
+ 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);
}
- else
- rdamage = battle_calc_return_damage(target, damage, wd.flag);
+ 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);
@@ -3399,11 +3780,6 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t
}
}
}
- if (sc && sc->data[SC_CRUSHSTRIKE])
- {
- skill_castend_damage_id(src, target, RK_CRUSHSTRIKE, 1, tick, flag);
- status_change_end(src,SC_CRUSHSTRIKE, INVALID_TIMER);
- }
if (sd) {
if (wd.flag & BF_WEAPON && src != target && damage > 0) {
if (battle_config.left_cardfix_to_right)
@@ -3551,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;
@@ -3814,6 +4192,8 @@ static const struct _battle_data {
{ "enable_perfect_flee", &battle_config.enable_perfect_flee, BL_PC|BL_PET, BL_NUL, BL_ALL, },
{ "casting_rate", &battle_config.cast_rate, 100, 0, INT_MAX, },
{ "delay_rate", &battle_config.delay_rate, 100, 0, INT_MAX, },
+ { "delay_dependon_dex", &battle_config.delay_dependon_dex, 0, 0, 1, },
+ { "delay_dependon_agi", &battle_config.delay_dependon_agi, 0, 0, 1, },
{ "skill_delay_attack_enable", &battle_config.sdelay_attack_enable, 0, 0, 1, },
{ "left_cardfix_to_right", &battle_config.left_cardfix_to_right, 0, 0, 1, },
{ "skill_add_range", &battle_config.skill_add_range, 0, 0, INT_MAX, },
@@ -3940,16 +4320,14 @@ static const struct _battle_data {
{ "arrow_decrement", &battle_config.arrow_decrement, 1, 0, 2, },
{ "max_aspd", &battle_config.max_aspd, 199, 100, 199, },
{ "max_walk_speed", &battle_config.max_walk_speed, 300, 100, 100*DEFAULT_WALK_SPEED, },
- { "max_lv", &battle_config.max_lv, 99, 0, 150, },
+ { "max_lv", &battle_config.max_lv, 99, 0, 127, },
{ "aura_lv", &battle_config.aura_lv, 99, 0, INT_MAX, },
{ "max_hp", &battle_config.max_hp, 32500, 100, 1000000000, },
{ "max_sp", &battle_config.max_sp, 32500, 100, 1000000000, },
{ "max_cart_weight", &battle_config.max_cart_weight, 8000, 100, 1000000, },
{ "max_parameter", &battle_config.max_parameter, 99, 10, 10000, },
{ "max_baby_parameter", &battle_config.max_baby_parameter, 80, 10, 10000, },
- { "max_third_parameter", &battle_config.max_third_parameter, 120, 10, 10000, },
- { "max_baby_third_parameter", &battle_config.max_baby_third_parameter, 108, 10, 10000, },
- { "max_def", &battle_config.max_def, SHRT_MAX, 0, INT_MAX, },
+ { "max_def", &battle_config.max_def, 99, 0, INT_MAX, },
{ "over_def_bonus", &battle_config.over_def_bonus, 0, 0, 1000, },
{ "skill_log", &battle_config.skill_log, BL_NUL, BL_NUL, BL_ALL, },
{ "battle_log", &battle_config.battle_log, 0, 0, 1, },
@@ -4083,6 +4461,7 @@ static const struct _battle_data {
{ "min_cloth_color", &battle_config.min_cloth_color, 0, 0, INT_MAX, },
{ "max_cloth_color", &battle_config.max_cloth_color, 4, 0, INT_MAX, },
{ "pet_hair_style", &battle_config.pet_hair_style, 100, 0, INT_MAX, },
+ { "castrate_dex_scale", &battle_config.castrate_dex_scale, 150, 1, INT_MAX, },
{ "area_size", &battle_config.area_size, 14, 0, INT_MAX, },
{ "zeny_from_mobs", &battle_config.zeny_from_mobs, 0, 0, 1, },
{ "mobs_level_up", &battle_config.mobs_level_up, 0, 0, 1, },
@@ -4200,13 +4579,11 @@ 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, },
-// MVP Decrease AGI
- { "max_decagi_lv", &battle_config.max_decagi_lv, 11, 1, INT_MAX, },
- { "max_decagi_dur", &battle_config.max_decagi_dur, 120000, 1, INT_MAX, },
- { "max_decagi", &battle_config.max_decagi, 50, 0, INT_MAX, },
-// Third jobs
- { "rune_block_by_skill", &battle_config.rune_block_by_skill, 1, 0, 1, },
- { "rune_block_by_status", &battle_config.rune_block_by_status, 0, 0, 1, },
+ /**
+ * rAthena
+ **/
+ { "max_third_parameter", &battle_config.max_third_parameter, 20, 0, INT_MAX, },
+ { "atcommand_max_stat_bypass", &battle_config.atcommand_max_stat_bypass, 0, 0, 100, },
};
@@ -4253,8 +4630,8 @@ void battle_adjust_conf()
battle_config.max_walk_speed = 100*DEFAULT_WALK_SPEED/battle_config.max_walk_speed;
battle_config.max_cart_weight *= 10;
- if(battle_config.max_def > SHRT_MAX && !battle_config.weapon_defense_type) // added by [Skotlex]
- battle_config.max_def = SHRT_MAX;
+ if(battle_config.max_def > 100 && !battle_config.weapon_defense_type) // added by [Skotlex]
+ battle_config.max_def = 100;
if(battle_config.min_hitrate > battle_config.max_hitrate)
battle_config.min_hitrate = battle_config.max_hitrate;
diff --git a/src/map/battle.h b/src/map/battle.h
index 7570f77b7..41ff70850 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);
@@ -111,6 +111,7 @@ extern struct Battle_Config
int enable_baseatk;
int enable_perfect_flee;
int cast_rate, delay_rate;
+ int delay_dependon_dex, delay_dependon_agi;
int sdelay_attack_enable;
int left_cardfix_to_right;
int skill_add_range;
@@ -234,7 +235,7 @@ extern struct Battle_Config
int max_hp;
int max_sp;
int max_lv, aura_lv;
- int max_parameter, max_baby_parameter, max_third_parameter, max_baby_third_parameter;
+ int max_parameter, max_baby_parameter;
int max_cart_weight;
int skill_log;
int battle_log;
@@ -362,6 +363,7 @@ extern struct Battle_Config
int max_cloth_color; // added by [MouseJstr]
int pet_hair_style; // added by [Skotlex]
+ int castrate_dex_scale; // added by [MouseJstr]
int area_size; // added by [MouseJstr]
int max_def, over_def_bonus; //added by [Skotlex]
@@ -495,12 +497,9 @@ extern struct Battle_Config
int bg_magic_damage_rate;
int bg_misc_damage_rate;
int bg_flee_penalty;
-
- int max_decagi_lv;
- int max_decagi_dur;
- int max_decagi;
- int rune_block_by_skill;
- int rune_block_by_status;
+ // rAthena
+ int max_third_parameter;
+ int atcommand_max_stat_bypass;
} battle_config;
void do_init_battle(void);
@@ -511,4 +510,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/buyingstore.c b/src/map/buyingstore.c
index 94f390c10..8d3179745 100644
--- a/src/map/buyingstore.c
+++ b/src/map/buyingstore.c
@@ -56,12 +56,18 @@ bool buyingstore_setup(struct map_session_data* sd, unsigned char slots)
return false;
}
- if( map[sd->bl.m].flag.novending || map_getcell(sd->bl.m, sd->bl.x, sd->bl.y, CELL_CHKNOVENDING) )
- {// custom: no vending maps/cells
+ if( map[sd->bl.m].flag.novending )
+ {// custom: no vending maps
clif_displaymessage(sd->fd, msg_txt(276)); // "You can't open a shop on this map"
return false;
}
+ if( map_getcell(sd->bl.m, sd->bl.x, sd->bl.y, CELL_CHKNOVENDING) )
+ {// custom: no vending cells
+ clif_displaymessage(sd->fd, msg_txt(204)); // "You can't open a shop on this cell."
+ return false;
+ }
+
if( slots > MAX_BUYINGSTORE_SLOTS )
{
ShowWarning("buyingstore_setup: Requested %d slots, but server supports only %d slots.\n", (int)slots, MAX_BUYINGSTORE_SLOTS);
@@ -105,12 +111,18 @@ void buyingstore_create(struct map_session_data* sd, int zenylimit, unsigned cha
return;
}
- if( map[sd->bl.m].flag.novending || map_getcell(sd->bl.m, sd->bl.x, sd->bl.y, CELL_CHKNOVENDING) )
- {// custom: no vending maps/cells
+ if( map[sd->bl.m].flag.novending )
+ {// custom: no vending maps
clif_displaymessage(sd->fd, msg_txt(276)); // "You can't open a shop on this map"
return;
}
+ if( map_getcell(sd->bl.m, sd->bl.x, sd->bl.y, CELL_CHKNOVENDING) )
+ {// custom: no vending cells
+ clif_displaymessage(sd->fd, msg_txt(204)); // "You can't open a shop on this cell."
+ return;
+ }
+
weight = sd->weight;
// check item list
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 a8cfa48cd..75c00187e 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -63,35 +63,60 @@ static inline int itemtype(int type)
return ( type == IT_PETEGG ) ? IT_WEAPON : type;
}
-#define WBUFPOS(p,pos,x,y,dir) \
- do { \
- uint8 *__p = (p); \
- __p+=(pos); \
- __p[0] = (uint8)((x)>>2); \
- __p[1] = (uint8)(((x)<<6) | (((y)>>4)&0x3f)); \
- __p[2] = (uint8)(((y)<<4) | ((dir)&0xf)); \
- } while(0)
+
+static inline void WBUFPOS(uint8* p, unsigned short pos, short x, short y, unsigned char dir)
+{
+ p += pos;
+ p[0] = (uint8)(x>>2);
+ p[1] = (uint8)((x<<6) | ((y>>4)&0x3f));
+ p[2] = (uint8)((y<<4) | (dir&0xf));
+}
+
+
// client-side: x0+=sx0*0.0625-0.5 and y0+=sy0*0.0625-0.5
-#define WBUFPOS2(p,pos,x0,y0,x1,y1,sx0,sy0) \
- do { \
- uint8 *__p = (p); \
- __p+=(pos); \
- __p[0]=(uint8)((x0)>>2); \
- __p[1]=(uint8)(((x0)<<6) | (((y0)>>4)&0x3f)); \
- __p[2]=(uint8)(((y0)<<4) | (((x1)>>6)&0x0f)); \
- __p[3]=(uint8)(((x1)<<2) | (((y1)>>8)&0x03)); \
- __p[4]=(uint8)(y1); \
- __p[5]=(uint8)(((sx0)<<4) | ((sy0)&0x0f)); \
- } while(0)
-
-#define WFIFOPOS(fd,pos,x,y,dir) WBUFPOS(WFIFOP(fd,pos),0,x,y,dir)
-#define WFIFOPOS2(fd,pos,x0,y0,x1,y1,sx0,sy0) WBUFPOS2(WFIFOP(fd,pos),0,x0,y0,x1,y1,sx0,sy0)
+static inline void WBUFPOS2(uint8* p, unsigned short pos, short x0, short y0, short x1, short y1, unsigned char sx0, unsigned char sy0)
+{
+ p += pos;
+ p[0] = (uint8)(x0>>2);
+ p[1] = (uint8)((x0<<6) | ((y0>>4)&0x3f));
+ p[2] = (uint8)((y0<<4) | ((x1>>6)&0x0f));
+ p[3] = (uint8)((x1<<2) | ((y1>>8)&0x03));
+ p[4] = (uint8)y1;
+ p[5] = (uint8)((sx0<<4) | (sy0&0x0f));
+}
+
+
+static inline void WFIFOPOS(int fd, unsigned short pos, short x, short y, unsigned char dir)
+{
+ WBUFPOS(WFIFOP(fd,pos), 0, x, y, dir);
+}
+
+
+inline void WFIFOPOS2(int fd, unsigned short pos, short x0, short y0, short x1, short y1, unsigned char sx0, unsigned char sy0)
+{
+ WBUFPOS2(WFIFOP(fd,pos), 0, x0, y0, x1, y1, sx0, sy0);
+}
+
//To idenfity disguised characters.
-#define disguised(bl) ((bl)->type==BL_PC && ((TBL_PC*)bl)->disguise)
+static inline bool disguised(struct block_list* bl)
+{
+ return (bool)( bl->type == BL_PC && ((TBL_PC*)bl)->disguise );
+}
+
+
+//Guarantees that the given string does not exceeds the allowed size, as well as making sure it's null terminated. [Skotlex]
+static inline unsigned int mes_len_check(char* mes, unsigned int len, unsigned int max)
+{
+ if( len > max )
+ len = max;
+
+ mes[len-1] = '\0';
+
+ return len;
+}
+
-//Guarantees that the given string does not exceeds the allowed size, as well as making sure it's null terminated. [Skotlex\]
-#define mes_len_check(mes, len, max) if (len > max) { mes[max-1] = '\0'; len = max; } else mes[len-1] = '\0';
static char map_ip_str[128];
static uint32 map_ip;
static uint32 bind_ip = INADDR_ANY;
@@ -129,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)
{
@@ -137,7 +163,7 @@ void clif_setport(uint16 port)
}
/*==========================================
- * map鯖のip読み出し
+ * Returns map server IP
*------------------------------------------*/
uint32 clif_getip(void)
{
@@ -159,7 +185,7 @@ uint32 clif_refresh_ip(void)
}
/*==========================================
- * map鯖のport読み出し
+ * Returns map port which is set by clif_setport()
*------------------------------------------*/
uint16 clif_getport(void)
{
@@ -185,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)
{
@@ -248,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)
{
@@ -529,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)
{
@@ -632,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)
{
@@ -1080,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)
{
@@ -1099,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)
{
@@ -1111,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)
{
@@ -1123,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)
@@ -1143,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;
@@ -1161,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];
@@ -1193,8 +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.data[SC_MILLENNIUMSHIELD] && sd->sc.data[SC_MILLENNIUMSHIELD]->val2 > 0) // Ensure that we have shields to display.
- clif_millenniumshield(sd,sd->sc.data[SC_MILLENNIUMSHIELD]->val2);
+ 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:
@@ -1850,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)
{
@@ -1922,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)
{
@@ -1991,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)
{
@@ -2434,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)
{
@@ -2514,31 +2564,35 @@ int clif_updatestatus(struct map_session_data *sd,int type)
WFIFOL(fd,4)=sd->battle_status.amotion;
break;
case SP_ATK1:
- WFIFOL(fd,4)=sd->battle_status.batk;
+ WFIFOL(fd,4)=sd->battle_status.batk +sd->battle_status.rhw.atk +sd->battle_status.lhw.atk;
break;
case SP_DEF1:
- WFIFOL(fd,4)=sd->battle_status.def2;
+ WFIFOL(fd,4)=sd->battle_status.def;
break;
case SP_MDEF1:
- WFIFOL(fd,4)= sd->battle_status.mdef2;
+ WFIFOL(fd,4)=sd->battle_status.mdef;
break;
case SP_ATK2:
- WFIFOL(fd,4)=sd->battle_status.rhw.atk + sd->battle_status.rhw.atk2 + sd->battle_status.equipment_atk;
+ WFIFOL(fd,4)=sd->battle_status.rhw.atk2 + sd->battle_status.lhw.atk2;
break;
case SP_DEF2:
- WFIFOL(fd,4)=sd->battle_status.def;
+ WFIFOL(fd,4)=sd->battle_status.def2;
break;
case SP_MDEF2:
- WFIFOL(fd,4)=sd->battle_status.mdef;
+ //negative check (in case you have something like Berserk active)
+ len = sd->battle_status.mdef2 - (sd->battle_status.vit>>1);
+ if (len < 0) len = 0;
+ WFIFOL(fd,4)= len;
+ len = 8;
break;
case SP_CRITICAL:
WFIFOL(fd,4)=sd->battle_status.cri/10;
break;
case SP_MATK1:
- WFIFOL(fd,4)=sd->weapon_matk + sd->battle_status.rhw.atk2 + sd->equipment_matk;
+ WFIFOL(fd,4)=sd->battle_status.matk_max;
break;
case SP_MATK2:
- WFIFOL(fd,4)=sd->battle_status.status_matk;
+ WFIFOL(fd,4)=sd->battle_status.matk_min;
break;
@@ -2563,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:
@@ -2575,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;
@@ -2672,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)
{
@@ -2865,14 +2922,17 @@ int clif_initialstatus(struct map_session_data *sd)
WBUFB(buf,14)=min(sd->status.luk, UINT8_MAX);
WBUFB(buf,15)=pc_need_status_point(sd,SP_LUK,1);
- WBUFW(buf,16) = sd->battle_status.batk;
- WBUFW(buf,18) = sd->battle_status.rhw.atk + sd->battle_status.lhw.atk2 + sd->battle_status.equipment_atk; //atk bonus
- WBUFW(buf,20) = sd->weapon_matk + sd->battle_status.rhw.atk2 + sd->equipment_matk;
- WBUFW(buf,22) = sd->battle_status.status_matk;
- WBUFW(buf,24) = sd->battle_status.def2;
- WBUFW(buf,26) = sd->battle_status.def; // def
- WBUFW(buf,28) = sd->battle_status.mdef2;
- WBUFW(buf,30) = sd->battle_status.mdef; // mdef
+ WBUFW(buf,16) = sd->battle_status.batk + sd->battle_status.rhw.atk + sd->battle_status.lhw.atk;
+ WBUFW(buf,18) = sd->battle_status.rhw.atk2 + sd->battle_status.lhw.atk2; //atk bonus
+ WBUFW(buf,20) = sd->battle_status.matk_max;
+ WBUFW(buf,22) = sd->battle_status.matk_min;
+ WBUFW(buf,24) = sd->battle_status.def; // def
+ WBUFW(buf,26) = sd->battle_status.def2;
+ WBUFW(buf,28) = sd->battle_status.mdef; // mdef
+ fd = sd->battle_status.mdef2 - (sd->battle_status.vit>>1);
+ if (fd < 0) fd = 0; //Negative check for Frenzy'ed characters.
+ WBUFW(buf,30) = fd;
+ fd = sd->fd;
WBUFW(buf,32) = sd->battle_status.hit;
WBUFW(buf,34) = sd->battle_status.flee;
WBUFW(buf,36) = sd->battle_status.flee2/10;
@@ -2892,20 +2952,11 @@ int clif_initialstatus(struct map_session_data *sd)
clif_updatestatus(sd,SP_ATTACKRANGE);
clif_updatestatus(sd,SP_ASPD);
- clif_updatestatus(sd,SP_ATK1);
- clif_updatestatus(sd,SP_ATK2);
- clif_updatestatus(sd,SP_MATK1);
- clif_updatestatus(sd,SP_MATK2);
- clif_updatestatus(sd,SP_DEF1);
- clif_updatestatus(sd,SP_DEF2);
- clif_updatestatus(sd,SP_MDEF1);
- clif_updatestatus(sd,SP_MDEF2);
-
return 0;
}
/*==========================================
- *矢装備
+ * 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)
{
@@ -2947,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)
{
@@ -2983,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)
{
@@ -3069,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)
{
@@ -3462,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)
{
@@ -3526,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)
{
@@ -3542,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)
{
@@ -3557,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)
{
@@ -3571,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)
{
@@ -3586,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)
{
@@ -3603,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)
{
@@ -3658,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)
{
@@ -3675,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)
{
@@ -3688,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)
{
@@ -3714,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)) )
@@ -3796,7 +3855,10 @@ void clif_getareachar_unit(struct map_session_data* sd,struct block_list *bl)
//Modifies the type of damage according to status changes [Skotlex]
//Aegis data specifies that: 4 endure against single hit sources, 9 against multi-hit.
-#define clif_calc_delay(type,div,damage,delay) ((delay)==0&&(damage)>0?((div)>1?9:4):type)
+static inline int clif_calc_delay(int type, int div, int damage, int delay)
+{
+ return ( delay == 0 && damage > 0 ) ? ( div > 1 ? 9 : 4 ) : type;
+}
/*==========================================
* Estimates walk delay based on the damage criteria. [Skotlex]
@@ -3894,11 +3956,12 @@ int clif_damage(struct block_list* src, struct block_list* dst, unsigned int tic
WBUFL(buf,2) = -src->id;
if (disguised(dst))
WBUFL(buf,6) = dst->id;
- if(damage > 0) WBUFW(buf,22) = -1;
#if PACKETVER < 20071113
+ if(damage > 0) WBUFW(buf,22) = -1;
if(damage2 > 0) WBUFW(buf,27) = -1;
#else
- if(damage2 > 0) WBUFW(buf,29) = -1;
+ if(damage > 0) WBUFL(buf,22) = -1;
+ if(damage2 > 0) WBUFL(buf,29) = -1;
#endif
clif_send(buf,packet_len(cmd),src,SELF);
}
@@ -4019,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)
{
@@ -4059,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)
{
@@ -4075,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)
{
@@ -4220,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)
{
@@ -4257,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;
@@ -4308,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)
{
@@ -4419,8 +4484,7 @@ int clif_skillcastcancel(struct block_list* bl)
/// btype==5 "no shout" MsgStringTable[164]
/// btype==6 "no PKing" MsgStringTable[165]
/// btype==7 "no alligning" MsgStringTable[383]
-/// btype==8: "Insufficient level for joining a Party"
-/// btype>=9: Ignored.
+/// btype>=8: ignored
/// if(skill_id==AL_WARP) "not enough skill level" MsgStringTable[214]
/// if(skill_id==TF_STEAL) "steal failed" MsgStringTable[205]
/// if(skill_id==TF_POISON) "envenom failed" MsgStringTable[207]
@@ -4436,38 +4500,7 @@ int clif_skillcastcancel(struct block_list* bl)
/// type==8 "blue gemstone needed" MsgStringTable[247]
/// type==9 "overweight" MsgStringTable[580]
/// type==10 "skill failed" MsgStringTable[285]
-/// type==11 "This skill can't be used on that object"
-/// type==12 "You can't use skill because you have exceeded the number Ansila possession limit"
-/// type==13 "need Holy Water"
-/// type==14 "need Ancilla to cast skill"
-/// type==15 "Can't be duplicated with certain distance"
-/// type==16 "In order to use this skill, you need other skill"
-/// type==17 "This skill can't be used alone"
-/// type==18 "This skill can be used to certain direction only"
-/// type==19 "Can't summon anymore"
-/// type==20 "There is no summoned sphere"
-/// type==21 "There exists no usable imitaion skill"
-/// type==22 "You can't reuse this skill"
-/// type==23 "Skill can't be used in this state"
-/// type==24 "Paintbrush is needed"
-/// type==25 "available only on the dragon"
-/// type==26 "Skill can't be used on designated spot "
-/// type==27 "Assistant SP is not enough"
-/// type==31 "Can only be used for linked to weapon blocking"
-/// type==32 "Need a weapon coated with poison of a guillotine cross v"
-/// type==33 "Can only be used while riding Madogear"
-/// type==37 "Load a Cannon Ball"
-/// type==40 "Can only be used in Hovering state"
-/// type==43 "Need a Guillotine Poison"
-/// type==50 "Can't be used while on Magic Gear"
-/// type==51 "Need a Magic Book"
-/// type==52 "Feel sleepy since Magic Book is too difficult to understand"
-/// type==53 "Not enough saved point"
-/// type==54 "Can't read a Magic Book anymore"
-/// type==57 "usable only when cart is put on"
-/// type==60 "Can't cast anymore"
-/// type==71 "[ITEMID] need AMOUNT"
-/// type==72 "Need to put on [ITEMID] in order to use"
+/// type>=11 ignored
///
/// if(success!=0) doesn't display any of the previous messages
/// Note: when this packet is received an unknown flag is always set to 0,
@@ -4496,13 +4529,11 @@ int clif_skill_fail(struct map_session_data *sd,int skill_id,int type,int btype)
if(skill_id == TF_POISON && battle_config.display_skill_fail&8)
return 0;
- // This is the correct packet structure.
- // If you need to pack 2 numbers into bytes 4~7 (btype) use MakeDWord [Gepard]
WFIFOHEAD(fd,packet_len(0x110));
WFIFOW(fd,0) = 0x110;
WFIFOW(fd,2) = skill_id;
WFIFOL(fd,4) = btype;
- WFIFOB(fd,8) = 0;
+ WFIFOB(fd,8) = 0;// success
WFIFOB(fd,9) = type;
WFIFOSET(fd,packet_len(0x110));
@@ -4677,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)
{
@@ -4710,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)
{
@@ -4736,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)
@@ -4774,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)
{
@@ -4841,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)
{
@@ -4877,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);
@@ -4904,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;
}
@@ -4975,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];
@@ -4992,8 +5025,7 @@ int clif_status_change(struct block_list *bl,int type,int flag,unsigned int tick
type == SI_TENSIONRELAX || type == SI_LANDENDOW || type == SI_AUTOBERSERK ||
type == SI_BUMP || type == SI_READYSTORM || type == SI_READYDOWN ||
type == SI_READYTURN || type == SI_READYCOUNTER || type == SI_DODGE ||
- type == SI_DEVIL || type == SI_NIGHT || type == SI_INTRAVISION ||
- type == SI_CLOAKING)
+ type == SI_DEVIL || type == SI_NIGHT || type == SI_INTRAVISION)
tick=0;
if( battle_config.display_status_timers && tick>0 )
@@ -5006,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;
@@ -5041,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
*------------------------------------------*/
@@ -5065,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)
{
@@ -5088,7 +5120,7 @@ void clif_GlobalMessage(struct block_list* bl, const char* message)
WBUFW(buf,0)=0x8d;
WBUFW(buf,2)=len+8;
WBUFL(buf,4)=bl->id;
- strncpy((char *) WBUFP(buf,8),message,len);
+ safestrncpy((char *) WBUFP(buf,8),message,len);
clif_send((unsigned char *) buf,WBUFW(buf,2),bl,ALL_CLIENT);
}
@@ -5097,7 +5129,7 @@ void clif_GlobalMessage(struct block_list* bl, const char* message)
*------------------------------------------*/
void clif_MainChatMessage(const char* message)
{
- char buf[200];
+ uint8 buf[200];
int len;
if(!message)
@@ -5111,8 +5143,8 @@ void clif_MainChatMessage(const char* message)
WBUFW(buf,0)=0x8d;
WBUFW(buf,2)=len+8;
WBUFL(buf,4)=0;
- strncpy((char *) WBUFP(buf,8),message,len);
- clif_send((unsigned char *) buf,WBUFW(buf,2),NULL,CHAT_MAINCHAT);
+ safestrncpy((char *) WBUFP(buf,8),message,len);
+ clif_send(buf,WBUFW(buf,2),NULL,CHAT_MAINCHAT);
}
/*==========================================
@@ -5138,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)
{
@@ -5152,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)
{
@@ -5200,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)
{
@@ -5249,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)
{
@@ -5318,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)
{
@@ -5331,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)
{
@@ -5381,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)
{
@@ -5400,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)
{
@@ -5429,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)
{
@@ -5447,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)
{
@@ -5547,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)
{
@@ -5571,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)
{
@@ -5621,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)
{
@@ -5963,43 +6001,54 @@ void clif_party_invite(struct map_session_data *sd,struct map_session_data *tsd)
WFIFOSET(fd,packet_len(cmd));
}
-/*==========================================
- * Party invitation result.
- * R 00fd <nick>.24S <flag>.B
- * R 02c5 <nick>.24S <flag>.L
- * Flag values are:
- * 0 -> char is already in a party
- * 1 -> party invite was rejected
- * 2 -> party invite was accepted
- * 3 -> party is full
- * 4 -> char of the same account already joined the party
- *------------------------------------------*/
-void clif_party_inviteack(struct map_session_data* sd, const char* nick, int flag)
+
+/// Party invite result.
+/// R 00fd <nick>.24S <result>.B
+/// R 02c5 <nick>.24S <result>.L
+/// result=0 : char is already in a party -> MsgStringTable[80]
+/// result=1 : party invite was rejected -> MsgStringTable[81]
+/// result=2 : party invite was accepted -> MsgStringTable[82]
+/// result=3 : party is full -> MsgStringTable[83]
+/// result=4 : char of the same account already joined the party -> MsgStringTable[608]
+/// result=5 : char blocked party invite -> MsgStringTable[1324] (since 20070904)
+/// result=7 : char is not online or doesn't exist -> MsgStringTable[71] (since 20070904)
+/// result=8 : (%s) TODO instance related? -> MsgStringTable[1388] (since 20080527)
+/// return=9 : TODO map prohibits party joining? -> MsgStringTable[1871] (since 20110205)
+void clif_party_inviteack(struct map_session_data* sd, const char* nick, int result)
{
int fd;
nullpo_retv(sd);
fd=sd->fd;
+#if PACKETVER < 20070904
+ if( result == 7 ) {
+ clif_displaymessage(fd, msg_txt(3));
+ return;
+ }
+#endif
+
#if PACKETVER < 20070821
WFIFOHEAD(fd,packet_len(0xfd));
WFIFOW(fd,0) = 0xfd;
safestrncpy((char*)WFIFOP(fd,2),nick,NAME_LENGTH);
- WFIFOB(fd,26) = flag;
+ WFIFOB(fd,26) = result;
WFIFOSET(fd,packet_len(0xfd));
#else
WFIFOHEAD(fd,packet_len(0x2c5));
WFIFOW(fd,0) = 0x2c5;
safestrncpy((char*)WFIFOP(fd,2),nick,NAME_LENGTH);
- WFIFOL(fd,26) = flag;
+ WFIFOL(fd,26) = result;
WFIFOSET(fd,packet_len(0x2c5));
#endif
}
+
/*==========================================
- * パーティ設定送信
- * 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)
{
@@ -7197,29 +7247,35 @@ void clif_guild_expulsionlist(struct map_session_data* sd)
WFIFOSET(fd,WFIFOW(fd,2));
}
-/*==========================================
- * ギルド会話
- *------------------------------------------*/
-int clif_guild_message(struct guild *g,int account_id,const char *mes,int len)
-{
+
+/// Notification of a guild chat message (ZC_GUILD_CHAT)
+/// 017f <packet len>.W <message>.?B
+void clif_guild_message(struct guild *g,int account_id,const char *mes,int len)
+{// TODO: account_id is not used, candidate for deletion? [Ai4rei]
struct map_session_data *sd;
- unsigned char *buf;
+ uint8 buf[256];
- buf = (unsigned char*)aMallocA((len + 4)*sizeof(unsigned char));
+ if( len == 0 )
+ {
+ return;
+ }
+ else if( len > sizeof(buf)-5 )
+ {
+ ShowWarning("clif_guild_message: Truncated message '%s' (len=%d, max=%d, guild_id=%d).\n", mes, len, sizeof(buf)-5, g->guild_id);
+ len = sizeof(buf)-5;
+ }
WBUFW(buf, 0) = 0x17f;
- WBUFW(buf, 2) = len + 4;
- memcpy(WBUFP(buf,4), mes, len);
+ WBUFW(buf, 2) = len + 5;
+ safestrncpy((char*)WBUFP(buf,4), mes, len+1);
if ((sd = guild_getavailablesd(g)) != NULL)
clif_send(buf, WBUFW(buf,2), &sd->bl, GUILD_NOBG);
+}
- if(buf) aFree(buf);
- return 0;
-}
/*==========================================
- * ギルドスキル割り振り通知
+ * 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)
{
@@ -7239,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)
{
@@ -7278,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)
{
@@ -7331,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)
{
@@ -7348,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)
{
@@ -7363,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)
{
@@ -7377,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)
{
@@ -7390,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)
@@ -7459,18 +7515,9 @@ void clif_parse_ReqMarriage(int fd, struct map_session_data *sd)
/*==========================================
*
*------------------------------------------*/
-int clif_disp_onlyself(struct map_session_data *sd, const char *mes, int len)
+void clif_disp_onlyself(struct map_session_data *sd, const char *mes, int len)
{
- int fd;
- nullpo_ret(sd);
- fd = sd->fd;
- if (!fd || !len) return 0; //Disconnected player.
- WFIFOHEAD(fd, len+5);
- WFIFOW(fd, 0) = 0x17f;
- WFIFOW(fd, 2) = len + 5;
- memcpy(WFIFOP(fd,4), mes, len);
- WFIFOSET(fd, WFIFOW(fd,2));
- return 1;
+ clif_disp_message(&sd->bl, mes, len, SELF);
}
/*==========================================
@@ -7478,13 +7525,22 @@ int clif_disp_onlyself(struct map_session_data *sd, const char *mes, int len)
*------------------------------------------*/
void clif_disp_message(struct block_list* src, const char* mes, int len, enum send_target target)
{
- unsigned char buf[1024];
- if (!len) return;
+ unsigned char buf[256];
+
+ if( len == 0 )
+ {
+ return;
+ }
+ else if( len > sizeof(buf)-5 )
+ {
+ ShowWarning("clif_disp_message: Truncated message '%s' (len=%d, max=%d, aid=%d).\n", mes, len, sizeof(buf)-5, src->id);
+ len = sizeof(buf)-5;
+ }
+
WBUFW(buf, 0) = 0x17f;
WBUFW(buf, 2) = len + 5;
- memcpy(WBUFP(buf,4), mes, len);
+ safestrncpy((char*)WBUFP(buf,4), mes, len+1);
clif_send(buf, WBUFW(buf,2), src, target);
- return;
}
/*==========================================
@@ -7556,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]
@@ -7609,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)
{
@@ -7707,12 +7764,12 @@ int clif_messagecolor(struct block_list* bl, unsigned long color, const char* ms
}
// messages (from mobs/npcs) [Valaris]
-int clif_message(struct block_list* bl, const char* msg)
+void clif_message(struct block_list* bl, const char* msg)
{
unsigned short msg_len = strlen(msg) + 1;
uint8 buf[256];
- nullpo_ret(bl);
+ nullpo_retv(bl);
if( msg_len > sizeof(buf)-8 )
{
@@ -7723,11 +7780,9 @@ int clif_message(struct block_list* bl, const char* msg)
WBUFW(buf,0) = 0x8d;
WBUFW(buf,2) = msg_len + 8;
WBUFL(buf,4) = bl->id;
- memcpy(WBUFP(buf,8), msg, msg_len);
+ safestrncpy((char*)WBUFP(buf,8), msg, msg_len);
clif_send(buf, WBUFW(buf,2), bl, AREA_CHAT_WOC);
-
- return 0;
}
// refresh the client's screen, getting rid of any effects
@@ -8001,29 +8056,27 @@ void clif_slide(struct block_list *bl, int x, int y)
/*------------------------------------------
* @me command by lordalfa, rewritten implementation by Skotlex
*------------------------------------------*/
-int clif_disp_overhead(struct map_session_data *sd, const char* mes)
+void clif_disp_overhead(struct map_session_data *sd, const char* mes)
{
unsigned char buf[256]; //This should be more than sufficient, the theorical max is CHAT_SIZE + 8 (pads and extra inserted crap)
int len_mes = strlen(mes)+1; //Account for \0
- if (len_mes + 8 >= 256) {
+ if (len_mes > sizeof(buf)-8) {
ShowError("clif_disp_overhead: Message too long (length %d)\n", len_mes);
- len_mes = 247; //Trunk it to avoid problems.
+ len_mes = sizeof(buf)-8; //Trunk it to avoid problems.
}
// send message to others
WBUFW(buf,0) = 0x8d;
WBUFW(buf,2) = len_mes + 8; // len of message + 8 (command+len+id)
WBUFL(buf,4) = sd->bl.id;
- memcpy(WBUFP(buf,8), mes, len_mes);
+ safestrncpy((char*)WBUFP(buf,8), mes, len_mes);
clif_send(buf, WBUFW(buf,2), &sd->bl, AREA_CHAT_WOC);
// send back message to the speaker
WBUFW(buf,0) = 0x8e;
WBUFW(buf, 2) = len_mes + 4;
- memcpy(WBUFP(buf,4), mes, len_mes);
+ safestrncpy((char*)WBUFP(buf,4), mes, len_mes);
clif_send(buf, WBUFW(buf,2), &sd->bl, SELF);
-
- return 0;
}
/*==========================
@@ -8457,7 +8510,7 @@ static int clif_guess_PacketVer(int fd, int get_previous, int *error)
// ------------
// clif_parse_*
// ------------
-// パケット読み取って色々操作
+// Parses incoming (player) connection
/*==========================================
*
*------------------------------------------*/
@@ -8546,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)
{
@@ -8711,9 +8765,6 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd)
if (sd->sc.option&OPTION_RIDING)
clif_status_load(&sd->bl, SI_RIDING, 1);
- if (sd->sc.option&OPTION_DRAGON)
- clif_status_load(&sd->bl, SI_RIDING, 1);
-
if(sd->status.manner < 0)
sc_start(&sd->bl,SC_NOCHAT,100,0,0);
@@ -8932,7 +8983,7 @@ void clif_parse_WalkToXY(int fd, struct map_session_data *sd)
return;
}
- if (sd->sc.opt1 && (sd->sc.opt1 == OPT1_STONEWAIT || sd->sc.opt1 == OPT1_BURNING))
+ if (sd->sc.opt1 && sd->sc.opt1 == OPT1_STONEWAIT)
; //You CAN walk on this OPT1 value.
else if( sd->progressbar.npc_id )
clif_progressbar_abort(sd);
@@ -9021,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;
@@ -9040,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);
@@ -9182,8 +9249,7 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type,
if (sd->sc.count &&
(sd->sc.data[SC_TRICKDEAD] ||
sd->sc.data[SC_AUTOCOUNTER] ||
- sd->sc.data[SC_BLADESTOP] ||
- sd->sc.data[SC_DEATHBOUND]))
+ sd->sc.data[SC_BLADESTOP]))
return;
pc_stop_walking(sd, 1);
@@ -9229,7 +9295,7 @@ void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action_type,
return;
}
- if (sd->ud.skilltimer != INVALID_TIMER || (sd->sc.opt1 && sd->sc.opt1 != OPT1_BURNING))
+ if (sd->ud.skilltimer != INVALID_TIMER || sd->sc.opt1)
break;
if (sd->sc.count && (
@@ -9454,7 +9520,7 @@ void clif_parse_Broadcast(int fd, struct map_session_data* sd)
return;
// as the length varies depending on the command used, just block unreasonably long strings
- mes_len_check(msg, len, CHAT_SIZE_MAX);
+ len = mes_len_check(msg, len, CHAT_SIZE_MAX);
intif_broadcast(msg, len, 0);
@@ -9525,7 +9591,6 @@ void clif_parse_DropItem(int fd, struct map_session_data *sd)
if (sd->sc.count && (
sd->sc.data[SC_AUTOCOUNTER] ||
sd->sc.data[SC_BLADESTOP] ||
- sd->sc.data[SC_DEATHBOUND] ||
(sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOITEM)
))
break;
@@ -9552,7 +9617,7 @@ void clif_parse_UseItem(int fd, struct map_session_data *sd)
return;
}
- if (sd->sc.opt1 > 0 && sd->sc.opt1 != OPT1_STONEWAIT && sd->sc.opt1 != OPT1_BURNING)
+ if (sd->sc.opt1 > 0 && sd->sc.opt1 != OPT1_STONEWAIT)
return;
//This flag enables you to use items while in an NPC. [Skotlex]
@@ -9591,7 +9656,7 @@ void clif_parse_EquipItem(int fd,struct map_session_data *sd)
if(sd->npc_id) {
if (sd->npc_id != sd->npc_item_flag)
return;
- } else if (sd->state.storage_flag || (sd->sc.opt1 && sd->sc.opt1 != OPT1_BURNING))
+ } else if (sd->state.storage_flag || sd->sc.opt1)
; //You can equip/unequip stuff while storage is open/under status changes
else if (pc_cant_act(sd))
return;
@@ -9840,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)
{
@@ -9867,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)
{
@@ -9875,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)
{
@@ -9889,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)
{
@@ -9897,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)
{
@@ -9905,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)
{
@@ -9921,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)
{
@@ -9932,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)
{
@@ -9942,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|OPTION_DRAGON));
+ /**
+ * 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)
{
@@ -9971,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)
{
@@ -9979,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)
{
@@ -10059,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)
{
@@ -10115,7 +10182,7 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd)
{
if( sd->skillitem != skillnum )
{
- clif_skill_fail(sd, skillnum, 0x04, 0);
+ clif_skill_fail(sd, skillnum, 4, 0);
return;
}
}
@@ -10166,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)
{
@@ -10276,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)
{
@@ -10297,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)
{
@@ -10305,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);
@@ -10344,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)
{
@@ -10449,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)
{
@@ -10466,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)
{
@@ -10492,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)
{
@@ -10501,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)
{
@@ -10511,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)
{
@@ -10558,7 +10636,7 @@ void clif_parse_LocalBroadcast(int fd, struct map_session_data* sd)
return;
// as the length varies depending on the command used, just block unreasonably long strings
- mes_len_check(msg, len, CHAT_SIZE_MAX);
+ len = mes_len_check(msg, len, CHAT_SIZE_MAX);
clif_broadcast(&sd->bl, msg, len, 0, ALL_SAMEMAP);
@@ -10570,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)
{
@@ -10592,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)
{
@@ -10609,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)
{
@@ -10626,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)
{
@@ -10643,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)
{
@@ -10774,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)
{
@@ -10787,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)
{
@@ -10800,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)
{
@@ -11075,10 +11157,14 @@ void clif_parse_OpenVending(int fd, struct map_session_data* sd)
if( sd->sc.data[SC_NOCHAT] && sd->sc.data[SC_NOCHAT]->val1&MANNER_NOROOM )
return;
- if( map[sd->bl.m].flag.novending || map_getcell(sd->bl.m,sd->bl.x,sd->bl.y,CELL_CHKNOVENDING) ) {
+ if( map[sd->bl.m].flag.novending ) {
clif_displaymessage (sd->fd, msg_txt(276)); // "You can't open a shop on this map"
return;
}
+ if( map_getcell(sd->bl.m,sd->bl.x,sd->bl.y,CELL_CHKNOVENDING) ) {
+ clif_displaymessage (sd->fd, msg_txt(204)); // "You can't open a shop on this cell."
+ return;
+ }
if( message[0] == '\0' ) // invalid input
return;
@@ -11250,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)
{
@@ -11274,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)
{
@@ -11282,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)
{
@@ -11350,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)
{
@@ -11377,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)
{
@@ -11385,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)
{
@@ -11401,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)
{
@@ -11428,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)
{
@@ -11475,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
*------------------------------------------*/
@@ -11996,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)
{
@@ -12014,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)
{
@@ -12048,7 +12137,7 @@ void clif_parse_NoviceExplosionSpirits(int fd, struct map_session_data *sd)
if( ( sd->class_&MAPID_UPPERMASK ) == MAPID_SUPER_NOVICE )
{
unsigned int next = pc_nextbaseexp(sd);
-
+ if( next == 0 ) next = pc_thisbaseexp(sd);
if( next )
{
int percent = (int)( ( (float)sd->status.base_exp/(float)next )*1000. );
@@ -13142,6 +13231,12 @@ void clif_Auction_results(struct map_session_data *sd, short count, short pages,
WFIFOSET(fd,WFIFOW(fd,2));
}
+
+/// Result from request to add an item (ZC_ACK_AUCTION_ADD_ITEM)
+/// 0256 <index>.W <result>.B
+/// result:
+/// 0 = success
+/// 1 = failure
static void clif_Auction_setitem(int fd, int index, bool fail)
{
WFIFOHEAD(fd,packet_len(0x256));
@@ -13151,6 +13246,13 @@ static void clif_Auction_setitem(int fd, int index, bool fail)
WFIFOSET(fd,packet_len(0x256));
}
+
+/// Request to initialize 'new auction' data (CZ_AUCTION_CREATE)
+/// 024b <type>.W
+/// type:
+/// 0 = create (any other action in auction window)
+/// 1 = cancel (cancel pressed on register tab)
+/// ? = junk, uninitialized value (ex. when switching between list filters)
void clif_parse_Auction_cancelreg(int fd, struct map_session_data *sd)
{
if( sd->auction.amount > 0 )
@@ -13159,6 +13261,9 @@ void clif_parse_Auction_cancelreg(int fd, struct map_session_data *sd)
sd->auction.amount = 0;
}
+
+/// Request to add an item to the action (CZ_AUCTION_ADD_ITEM)
+/// 024c <index>.W <count>.L
void clif_parse_Auction_setitem(int fd, struct map_session_data *sd)
{
int idx = RFIFOW(fd,2) - 2;
@@ -13174,8 +13279,8 @@ void clif_parse_Auction_setitem(int fd, struct map_session_data *sd)
return;
}
- if( amount != 1 || amount < 0 || amount > sd->status.inventory[idx].amount )
- { // By client, amount is allways set to 1. Maybe this is a future implementation.
+ if( amount != 1 || amount > sd->status.inventory[idx].amount )
+ { // By client, amount is always set to 1. Maybe this is a future implementation.
ShowWarning("Character %s trying to set invalid amount in auctions.\n", sd->status.name);
return;
}
@@ -13224,7 +13329,7 @@ void clif_Auction_message(int fd, unsigned char flag)
/// result:
/// 0 = You have ended the auction
/// 1 = You cannot end the auction
-/// 2 = Bid number is incorrect
+/// 2 = Auction ID is incorrect
void clif_Auction_close(int fd, unsigned char flag)
{
WFIFOHEAD(fd,packet_len(0x25e));
@@ -13233,6 +13338,9 @@ void clif_Auction_close(int fd, unsigned char flag)
WFIFOSET(fd,packet_len(0x25e));
}
+
+/// Request to add an auction (CZ_AUCTION_ADD)
+/// 024d <now money>.L <max money>.L <delete hour>.W
void clif_parse_Auction_register(int fd, struct map_session_data *sd)
{
struct auction_data auction;
@@ -13277,9 +13385,9 @@ void clif_parse_Auction_register(int fd, struct map_session_data *sd)
auction.auction_id = 0;
auction.seller_id = sd->status.char_id;
- safestrncpy(auction.seller_name, sd->status.name, NAME_LENGTH);
+ safestrncpy(auction.seller_name, sd->status.name, sizeof(auction.seller_name));
auction.buyer_id = 0;
- memset(&auction.buyer_name, '\0', NAME_LENGTH);
+ memset(auction.buyer_name, '\0', sizeof(auction.buyer_name));
if( sd->status.inventory[sd->auction.index].nameid == 0 || sd->status.inventory[sd->auction.index].amount < sd->auction.amount )
{
@@ -13293,7 +13401,7 @@ void clif_parse_Auction_register(int fd, struct map_session_data *sd)
return;
}
- safestrncpy(auction.item_name, item->jname, ITEM_NAME_LENGTH);
+ safestrncpy(auction.item_name, item->jname, sizeof(auction.item_name));
auction.type = item->type;
memcpy(&auction.item, &sd->status.inventory[sd->auction.index], sizeof(struct item));
auction.item.amount = 1;
@@ -13309,6 +13417,9 @@ void clif_parse_Auction_register(int fd, struct map_session_data *sd)
}
}
+
+/// Cancels an auction (CZ_AUCTION_ADD_CANCEL)
+/// 024e <auction id>.L
void clif_parse_Auction_cancel(int fd, struct map_session_data *sd)
{
unsigned int auction_id = RFIFOL(fd,2);
@@ -13316,6 +13427,9 @@ void clif_parse_Auction_cancel(int fd, struct map_session_data *sd)
intif_Auction_cancel(sd->status.char_id, auction_id);
}
+
+/// Closes an auction (CZ_AUCTION_REQ_MY_SELL_STOP)
+/// 025d <auction id>.L
void clif_parse_Auction_close(int fd, struct map_session_data *sd)
{
unsigned int auction_id = RFIFOL(fd,2);
@@ -13323,6 +13437,9 @@ void clif_parse_Auction_close(int fd, struct map_session_data *sd)
intif_Auction_close(sd->status.char_id, auction_id);
}
+
+/// Places a bid on an auction (CZ_AUCTION_BUY)
+/// 024f <auction id>.L <money>.L
void clif_parse_Auction_bid(int fd, struct map_session_data *sd)
{
unsigned int auction_id = RFIFOL(fd,2);
@@ -13345,23 +13462,34 @@ void clif_parse_Auction_bid(int fd, struct map_session_data *sd)
}
}
-/*------------------------------------------
- * Auction Search
- * S 0251 <search type>.w <search price>.l <search text>.24B <page number>.w
- * Search Type: 0 Armor 1 Weapon 2 Card 3 Misc 4 By Text 5 By Price 6 Sell 7 Buy
- *------------------------------------------*/
+
+/// Auction Search (CZ_AUCTION_ITEM_SEARCH)
+/// 0251 <search type>.W <auction id>.L <search text>.24B <page number>.W
+/// search type:
+/// 0 = armor
+/// 1 = weapon
+/// 2 = card
+/// 3 = misc
+/// 4 = name search
+/// 5 = auction id search
void clif_parse_Auction_search(int fd, struct map_session_data* sd)
{
char search_text[NAME_LENGTH];
short type = RFIFOW(fd,2), page = RFIFOW(fd,32);
- int price = RFIFOL(fd,4);
+ int price = RFIFOL(fd,4); // FIXME: bug #5071
clif_parse_Auction_cancelreg(fd, sd);
- safestrncpy(search_text, (char*)RFIFOP(fd,8), NAME_LENGTH);
+ safestrncpy(search_text, (char*)RFIFOP(fd,8), sizeof(search_text));
intif_Auction_requestlist(sd->status.char_id, type, price, search_text, page);
}
+
+/// Requests list of own currently active bids or auctions (CZ_AUCTION_REQ_MY_INFO)
+/// 025c <type>.W
+/// type:
+/// 0 = sell (own auctions)
+/// 1 = buy (own bids)
void clif_parse_Auction_buysell(int fd, struct map_session_data* sd)
{
short type = RFIFOW(fd,2) + 6;
@@ -14288,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)
@@ -14813,19 +14941,6 @@ void clif_search_store_info_click_ack(struct map_session_data* sd, short x, shor
WFIFOSET(fd,packet_len(0x83d));
}
-// Correct packet for RK_MILLENIUMSHIELD. Shows spirit spheres.
-void clif_millenniumshield(struct map_session_data *sd, int num)
-{
-#if PACKETVER >= 20081217
- unsigned char buf[10];
-
- WBUFW(buf,0)=0x440;
- WBUFL(buf,2)=sd->bl.id;
- WBUFW(buf,6)=num;
- WBUFW(buf,8)=0;
- clif_send(buf,packet_len(0x440),&sd->bl,AREA);
-#endif
-}
/// Parse function for packet debugging
void clif_parse_debug(int fd,struct map_session_data *sd)
@@ -14858,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
*------------------------------------------*/
@@ -15027,7 +15319,7 @@ int clif_parse(int fd)
}
/*==========================================
- * パケットデータベース読み込み
+ * Reads packet_db.txt and setups its array reference
*------------------------------------------*/
static int packetdb_readdb(void)
{
@@ -15157,7 +15449,7 @@ static int packetdb_readdb(void)
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 25,
//#0x0440
- 10, 4, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 4, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -15569,6 +15861,13 @@ static int packetdb_readdb(void)
if(p2) *p2++=0;
k = atoi(str2[j]);
// if (packet_db[packet_ver][cmd].pos[j] != k && clif_config.prefer_packet_db) // not used for now
+
+ if( j >= MAX_PACKET_POS )
+ {
+ ShowError("Too many positions found for packet 0x%04x (max=%d).\n", cmd, MAX_PACKET_POS);
+ break;
+ }
+
packet_db[packet_ver][cmd].pos[j] = k;
}
}
diff --git a/src/map/clif.h b/src/map/clif.h
index 9d1207901..8b6271075 100644
--- a/src/map/clif.h
+++ b/src/map/clif.h
@@ -27,14 +27,18 @@ struct battleground_data;
struct quest;
struct party_booking_ad_info;
#include <stdarg.h>
-// packet DB
-#define MAX_PACKET_DB 0x900
-#define MAX_PACKET_VER 26
+
+enum
+{// packet DB
+ MAX_PACKET_DB = 0x900,
+ MAX_PACKET_VER = 26,
+ MAX_PACKET_POS = 20,
+};
struct s_packet_db {
short len;
void (*func)(int, struct map_session_data *);
- short pos[20];
+ short pos[MAX_PACKET_POS];
};
// packet_db[SERVER] is reserved for server use
@@ -339,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);
@@ -357,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);
@@ -406,7 +410,7 @@ int clif_party_created(struct map_session_data *sd,int result);
int clif_party_member_info(struct party_data *p, struct map_session_data *sd);
int clif_party_info(struct party_data *p, struct map_session_data *sd);
void clif_party_invite(struct map_session_data *sd,struct map_session_data *tsd);
-void clif_party_inviteack(struct map_session_data* sd, const char* nick, int flag);
+void clif_party_inviteack(struct map_session_data* sd, const char* nick, int result);
int clif_party_option(struct party_data *p,struct map_session_data *sd,int flag);
int clif_party_withdraw(struct party_data* p, struct map_session_data* sd, int account_id, const char* name, int flag);
int clif_party_message(struct party_data* p, int account_id, const char* mes, int len);
@@ -437,7 +441,7 @@ int clif_guild_memberpositionchanged(struct guild *g,int idx);
int clif_guild_emblem(struct map_session_data *sd,struct guild *g);
void clif_guild_emblem_area(struct block_list* bl);
int clif_guild_notice(struct map_session_data *sd,struct guild *g);
-int clif_guild_message(struct guild *g,int account_id,const char *mes,int len);
+void clif_guild_message(struct guild *g,int account_id,const char *mes,int len);
int clif_guild_skillup(struct map_session_data *sd,int skill_num,int lv);
int clif_guild_reqalliance(struct map_session_data *sd,int account_id,const char *name);
int clif_guild_allianceack(struct map_session_data *sd,int flag);
@@ -468,7 +472,7 @@ int clif_font(struct map_session_data *sd);
// atcommand
int clif_displaymessage(const int fd,const char* mes);
-int clif_disp_onlyself(struct map_session_data *sd,const char *mes,int len);
+void clif_disp_onlyself(struct map_session_data *sd,const char *mes,int len);
void clif_disp_message(struct block_list* src, const char* mes, int len, enum send_target target);
int clif_broadcast(struct block_list *bl, const char* mes, int len, int type, enum send_target target);
void clif_MainChatMessage(const char* message); //luzza
@@ -502,7 +506,7 @@ void clif_weather(int m); // [Valaris]
int clif_specialeffect(struct block_list* bl, int type, enum send_target target); // special effects [Valaris]
void clif_specialeffect_single(struct block_list* bl, int type, int fd);
int clif_messagecolor(struct block_list* bl, unsigned long color, const char* msg); // Mob/Npc color talk [SnakeDrak]
-int clif_message(struct block_list *bl, const char* msg); // messages (from mobs/npcs) [Valaris]
+void clif_message(struct block_list *bl, const char* msg); // messages (from mobs/npcs) [Valaris]
int clif_GM_kickack(struct map_session_data *sd,int id);
void clif_GM_kick(struct map_session_data *sd,struct map_session_data *tsd);
@@ -510,7 +514,7 @@ void clif_manner_message(struct map_session_data* sd, uint32 type);
void clif_GM_silence(struct map_session_data* sd, struct map_session_data* tsd, uint8 type);
int clif_timedout(struct map_session_data *sd);
-int clif_disp_overhead(struct map_session_data *sd, const char* mes);
+void clif_disp_overhead(struct map_session_data *sd, const char* mes);
void clif_get_weapon_view(struct map_session_data* sd, unsigned short *rhand, unsigned short *lhand);
@@ -625,8 +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);
-
-// Third jobs
-void clif_millenniumshield(struct map_session_data *sd, int num);
-
+/**
+ * 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/config/Core.h b/src/map/config/Core.h
new file mode 100644
index 000000000..5073d5262
--- /dev/null
+++ b/src/map/config/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/config/Data/Const.h b/src/map/config/Data/Const.h
new file mode 100644
index 000000000..31f68fdbc
--- /dev/null
+++ b/src/map/config/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
diff --git a/src/map/config/Renewal.h b/src/map/config/Renewal.h
new file mode 100644
index 000000000..a1ab30427
--- /dev/null
+++ b/src/map/config/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/config/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
diff --git a/src/map/config/Secure.h b/src/map/config/Secure.h
new file mode 100644
index 000000000..6f3da3b90
--- /dev/null
+++ b/src/map/config/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
diff --git a/src/map/config/Skills/General.h b/src/map/config/Skills/General.h
new file mode 100644
index 000000000..7869c0cc9
--- /dev/null
+++ b/src/map/config/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/config/Skills/Mage_Classes.h b/src/map/config/Skills/Mage_Classes.h
new file mode 100644
index 000000000..26cd1d03c
--- /dev/null
+++ b/src/map/config/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/config/Skills/Swordsman_Classes.h b/src/map/config/Skills/Swordsman_Classes.h
new file mode 100644
index 000000000..3792fa5a3
--- /dev/null
+++ b/src/map/config/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/guild.c b/src/map/guild.c
index 0b77aa9a1..8c5988dc8 100644
--- a/src/map/guild.c
+++ b/src/map/guild.c
@@ -52,13 +52,14 @@ struct guild_expcache {
};
static struct eri *expcache_ers; //For handling of guild exp payment.
+#define MAX_GUILD_SKILL_REQUIRE 5
struct{
int id;
int max;
struct{
short id;
short lv;
- }need[6];
+ }need[MAX_GUILD_SKILL_REQUIRE];
} guild_skill_tree[MAX_GUILDSKILL];
int guild_payexp_timer(int tid, unsigned int tick, int id, intptr_t data);
@@ -124,7 +125,7 @@ static bool guild_read_guildskill_tree_db(char* split[], int columns, int curren
guild_skill_tree[id].max = 1;
}
- for( k = 0; k < 5; k++ )
+ for( k = 0; k < MAX_GUILD_SKILL_REQUIRE; k++ )
{
guild_skill_tree[id].need[k].id = atoi(split[k*2+2]);
guild_skill_tree[id].need[k].lv = atoi(split[k*2+3]);
@@ -147,7 +148,7 @@ int guild_check_skill_require(struct guild *g,int id)
if (idx < 0 || idx >= MAX_GUILDSKILL)
return 0;
- for(i=0;i<5;i++)
+ for(i=0;i<MAX_GUILD_SKILL_REQUIRE;i++)
{
if(guild_skill_tree[idx].need[i].id == 0) break;
if(guild_skill_tree[idx].need[i].lv > guild_checkskill(g,guild_skill_tree[idx].need[i].id))
@@ -322,10 +323,14 @@ int guild_send_xy_timer_sub(DBKey key,void *data,va_list ap)
nullpo_ret(g);
+ if( !g->connect_member )
+ {// no members connected to this guild so do not iterate
+ return 0;
+ }
+
for(i=0;i<g->max_member;i++){
- //struct map_session_data* sd = g->member[i].sd;
- struct map_session_data* sd = map_charid2sd(g->member[i].char_id); // temporary crashfix
- if( sd != NULL && (sd->guild_x != sd->bl.x || sd->guild_y != sd->bl.y) && !sd->bg_id )
+ struct map_session_data* sd = g->member[i].sd;
+ if( sd != NULL && sd->fd && (sd->guild_x != sd->bl.x || sd->guild_y != sd->bl.y) && !sd->bg_id )
{
clif_guild_xy(sd);
sd->guild_x = sd->bl.x;
@@ -1943,7 +1948,7 @@ void do_init_guild(void)
sv_readdb(db_path, "castle_db.txt", ',', 4, 5, -1, &guild_read_castledb);
memset(guild_skill_tree,0,sizeof(guild_skill_tree));
- sv_readdb(db_path, "guild_skill_tree.txt", ',', 12, 12, -1, &guild_read_guildskill_tree_db); //guild skill tree [Komurka]
+ sv_readdb(db_path, "guild_skill_tree.txt", ',', 2+MAX_GUILD_SKILL_REQUIRE*2, 2+MAX_GUILD_SKILL_REQUIRE*2, -1, &guild_read_guildskill_tree_db); //guild skill tree [Komurka]
add_timer_func_list(guild_payexp_timer,"guild_payexp_timer");
add_timer_func_list(guild_send_xy_timer, "guild_send_xy_timer");
diff --git a/src/map/intif.c b/src/map/intif.c
index 1b69c0837..9fea3be43 100644
--- a/src/map/intif.c
+++ b/src/map/intif.c
@@ -381,14 +381,15 @@ int intif_create_party(struct party_member *member,char *name,int item,int item2
return 0;
}
// パーティ情報要求
-int intif_request_partyinfo(int party_id)
+int intif_request_partyinfo(int party_id, int char_id)
{
if (CheckForCharServer())
return 0;
- WFIFOHEAD(inter_fd,6);
+ WFIFOHEAD(inter_fd,10);
WFIFOW(inter_fd,0) = 0x3021;
WFIFOL(inter_fd,2) = party_id;
- WFIFOSET(inter_fd,6);
+ WFIFOL(inter_fd,6) = char_id;
+ WFIFOSET(inter_fd,10);
return 0;
}
// パーティ追加要求
@@ -1007,15 +1008,15 @@ int intif_parse_PartyCreated(int fd)
// パーティ情報
int intif_parse_PartyInfo(int fd)
{
- if( RFIFOW(fd,2)==8){
- ShowWarning("intif: party noinfo %d\n",RFIFOL(fd,4));
- party_recv_noinfo(RFIFOL(fd,4));
+ if( RFIFOW(fd,2) == 12 ){
+ ShowWarning("intif: party noinfo (char_id=%d party_id=%d)\n", RFIFOL(fd,4), RFIFOL(fd,8));
+ party_recv_noinfo(RFIFOL(fd,8), RFIFOL(fd,4));
return 0;
}
- if( RFIFOW(fd,2)!=sizeof(struct party)+4 )
- ShowError("intif: party info : data size error %d %d %d\n",RFIFOL(fd,4),RFIFOW(fd,2),sizeof(struct party)+4);
- party_recv_info((struct party *)RFIFOP(fd,4));
+ if( RFIFOW(fd,2) != 8+sizeof(struct party) )
+ ShowError("intif: party info : data size error (char_id=%d party_id=%d packet_len=%d expected_len=%d)\n", RFIFOL(fd,4), RFIFOL(fd,8), RFIFOW(fd,2), 8+sizeof(struct party));
+ party_recv_info((struct party *)RFIFOP(fd,8), RFIFOL(fd,4));
return 0;
}
// パーティ追加通知
diff --git a/src/map/intif.h b/src/map/intif.h
index 73dc5b863..1df990108 100644
--- a/src/map/intif.h
+++ b/src/map/intif.h
@@ -30,7 +30,7 @@ int intif_send_guild_storage(int account_id, struct guild_storage *gstor);
int intif_create_party(struct party_member *member,char *name,int item,int item2);
-int intif_request_partyinfo(int party_id);
+int intif_request_partyinfo(int party_id, int char_id);
int intif_party_addmember(int party_id,struct party_member *member);
int intif_party_changeoption(int party_id, int account_id, int exp, int item);
diff --git a/src/map/itemdb.c b/src/map/itemdb.c
index e8afebdfe..3fc0a5704 100644
--- a/src/map/itemdb.c
+++ b/src/map/itemdb.c
@@ -663,46 +663,6 @@ static bool itemdb_read_itemdelay(char* str[], int columns, int current)
return true;
}
-/*==================================================================
- * Reads item stacking restrictions
- *----------------------------------------------------------------*/
-static bool itemdb_read_stack(char* fields[], int columns, int current)
-{// <item id>,<stack limit amount>,<type>
- unsigned short nameid, amount;
- unsigned int type;
- struct item_data* id;
-
- nameid = (unsigned short)strtoul(fields[0], NULL, 10);
-
- if( ( id = itemdb_exists(nameid) ) == NULL )
- {
- ShowWarning("itemdb_read_stack: Unknown item id '%hu'.\n", nameid);
- return false;
- }
-
- if( !itemdb_isstackable2(id) )
- {
- ShowWarning("itemdb_read_stack: Item id '%hu' is not stackable.\n", nameid);
- return false;
- }
-
- amount = (unsigned short)strtoul(fields[1], NULL, 10);
- type = strtoul(fields[2], NULL, 10);
-
- if( !amount )
- {// ignore
- return true;
- }
-
- id->stack.amount = amount;
- id->stack.inventory = (type&1)!=0;
- id->stack.cart = (type&2)!=0;
- id->stack.storage = (type&4)!=0;
- id->stack.guildstorage = (type&8)!=0;
-
- return true;
-}
-
/// Reads items allowed to be sold in buying stores
static bool itemdb_read_buyingstore(char* fields[], int columns, int current)
@@ -746,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
*------------------------------------------*/
@@ -776,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;
@@ -813,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]);
@@ -875,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 )
@@ -987,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 )
@@ -1046,7 +1049,6 @@ static void itemdb_read(void)
sv_readdb(db_path, "item_noequip.txt", ',', 2, 2, -1, &itemdb_read_noequip);
sv_readdb(db_path, "item_trade.txt", ',', 3, 3, -1, &itemdb_read_itemtrade);
sv_readdb(db_path, "item_delay.txt", ',', 2, 2, MAX_ITEMDELAYS, &itemdb_read_itemdelay);
- sv_readdb(db_path, "item_stack.txt", ',', 3, 3, -1, &itemdb_read_stack);
sv_readdb(db_path, "item_buyingstore.txt", ',', 1, 1, -1, &itemdb_read_buyingstore);
}
@@ -1090,8 +1092,8 @@ void itemdb_reload(void)
struct s_mapiterator* iter;
struct map_session_data* sd;
- int i;
-
+ int i,d,k;
+
// clear the previous itemdb data
for( i = 0; i < ARRAYLENGTH(itemdb_array); ++i )
if( itemdb_array[i] )
@@ -1100,9 +1102,37 @@ void itemdb_reload(void)
itemdb_other->clear(itemdb_other, itemdb_final_sub);
memset(itemdb_array, 0, sizeof(itemdb_array));
-
+
// read new data
itemdb_read();
+
+ //Epoque's awesome @reloaditemdb fix - thanks! [Ind]
+ //- Fixes the need of a @reloadmobdb after a @reloaditemdb to re-link monster drop data
+ for( i = 0; i < MAX_MOB_DB; i++ ) {
+ struct mob_db *entry;
+ if( !((i < 1324 || i > 1363) && (i < 1938 || i > 1946)) )
+ continue;
+ entry = mob_db(i);
+ for(d = 0; d < MAX_MOB_DROP; d++) {
+ struct item_data *id;
+ if( !entry->dropitem[d].nameid )
+ continue;
+ id = itemdb_search(entry->dropitem[d].nameid);
+
+ for (k = 0; k < MAX_SEARCH; k++) {
+ if (id->mob[k].chance <= entry->dropitem[d].p)
+ break;
+ }
+
+ if (k == MAX_SEARCH)
+ continue;
+
+ if (id->mob[k].id != i)
+ memmove(&id->mob[k+1], &id->mob[k], (MAX_SEARCH-k-1)*sizeof(id->mob[0]));
+ id->mob[k].chance = entry->dropitem[d].p;
+ id->mob[k].id = i;
+ }
+ }
// readjust itemdb pointer cache for each player
iter = mapit_geteachpc();
diff --git a/src/map/itemdb.h b/src/map/itemdb.h
index 6a201008e..801b81be8 100644
--- a/src/map/itemdb.h
+++ b/src/map/itemdb.h
@@ -5,14 +5,20 @@
#define _ITEMDB_H_
#include "../common/mmo.h" // ITEM_NAME_LENGTH
+#include "map.h" //RRMODE
#define MAX_RANDITEM 11000
// The maximum number of item delays
-#define MAX_ITEMDELAYS 18
+#define MAX_ITEMDELAYS 10
#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;
@@ -78,14 +87,6 @@ struct item_data {
unsigned autoequip: 1;
unsigned buyingstore : 1;
} flag;
- struct
- {// item stacking limitation
- unsigned short amount;
- unsigned int inventory:1;
- unsigned int cart:1;
- unsigned int storage:1;
- unsigned int guildstorage:1;
- } stack;
short gm_lv_trade_override; //GM-level to override trade_restriction
};
@@ -151,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/log.c b/src/map/log.c
index 72cfe46d3..af7ae3121 100644
--- a/src/map/log.c
+++ b/src/map/log.c
@@ -1,6 +1,7 @@
// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
// For more information, see LICENCE in the main folder
+#include "../common/sql.h" // SQL_INNODB
#include "../common/strlib.h"
#include "../common/nullpo.h"
#include "../common/showmsg.h"
@@ -21,6 +22,15 @@ struct Log_Config log_config;
char timestring[255];
time_t curtime;
+#ifdef SQL_INNODB
+// database is using an InnoDB engine so do not use DELAYED
+#define LOG_QUERY "INSERT"
+#else
+// database is using a MyISAM engine so use DELAYED
+#define LOG_QUERY "INSERT DELAYED"
+#endif
+
+
//FILTER OPTIONS
//0 = Don't log
//1 = Log any item
@@ -70,7 +80,7 @@ int log_branch(struct map_session_data *sd)
{
SqlStmt* stmt;
stmt = SqlStmt_Malloc(logmysql_handle);
- if( SQL_SUCCESS != SqlStmt_Prepare(stmt, "INSERT DELAYED INTO `%s` (`branch_date`, `account_id`, `char_id`, `char_name`, `map`) VALUES (NOW(), '%d', '%d', ?, '%s')", log_config.log_branch_db, sd->status.account_id, sd->status.char_id, mapindex_id2name(sd->mapindex) )
+ if( SQL_SUCCESS != SqlStmt_Prepare(stmt, LOG_QUERY " INTO `%s` (`branch_date`, `account_id`, `char_id`, `char_name`, `map`) VALUES (NOW(), '%d', '%d', ?, '%s')", log_config.log_branch_db, sd->status.account_id, sd->status.char_id, mapindex_id2name(sd->mapindex) )
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, sd->status.name, strnlen(sd->status.name, NAME_LENGTH))
|| SQL_SUCCESS != SqlStmt_Execute(stmt) )
{
@@ -107,14 +117,14 @@ int log_pick_pc(struct map_session_data *sd, const char *type, int nameid, int a
if( log_config.sql_logs )
{
if( itm == NULL ) { //We log common item
- if (SQL_ERROR == Sql_Query(logmysql_handle, "INSERT DELAYED INTO `%s` (`time`, `char_id`, `type`, `nameid`, `amount`, `map`) VALUES (NOW(), '%d', '%s', '%d', '%d', '%s')",
+ if (SQL_ERROR == Sql_Query(logmysql_handle, LOG_QUERY " INTO `%s` (`time`, `char_id`, `type`, `nameid`, `amount`, `map`) VALUES (NOW(), '%d', '%s', '%d', '%d', '%s')",
log_config.log_pick_db, sd->status.char_id, type, nameid, amount, mapindex_id2name(sd->mapindex)) )
{
Sql_ShowDebug(logmysql_handle);
return 0;
}
} else { //We log Extended item
- if (SQL_ERROR == Sql_Query(logmysql_handle, "INSERT DELAYED INTO `%s` (`time`, `char_id`, `type`, `nameid`, `amount`, `refine`, `card0`, `card1`, `card2`, `card3`, `map`) VALUES (NOW(), '%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%s')",
+ if (SQL_ERROR == Sql_Query(logmysql_handle, LOG_QUERY " INTO `%s` (`time`, `char_id`, `type`, `nameid`, `amount`, `refine`, `card0`, `card1`, `card2`, `card3`, `map`) VALUES (NOW(), '%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%s')",
log_config.log_pick_db, sd->status.char_id, type, itm->nameid, amount, itm->refine, itm->card[0], itm->card[1], itm->card[2], itm->card[3], mapindex_id2name(sd->mapindex)) )
{
Sql_ShowDebug(logmysql_handle);
@@ -162,14 +172,14 @@ int log_pick_mob(struct mob_data *md, const char *type, int nameid, int amount,
if( log_config.sql_logs )
{
if( itm == NULL ) { //We log common item
- if (SQL_ERROR == Sql_Query(logmysql_handle, "INSERT DELAYED INTO `%s` (`time`, `char_id`, `type`, `nameid`, `amount`, `map`) VALUES (NOW(), '%d', '%s', '%d', '%d', '%s')",
+ if (SQL_ERROR == Sql_Query(logmysql_handle, LOG_QUERY " INTO `%s` (`time`, `char_id`, `type`, `nameid`, `amount`, `map`) VALUES (NOW(), '%d', '%s', '%d', '%d', '%s')",
log_config.log_pick_db, md->class_, type, nameid, amount, mapname) )
{
Sql_ShowDebug(logmysql_handle);
return 0;
}
} else { //We log Extended item
- if (SQL_ERROR == Sql_Query(logmysql_handle, "INSERT DELAYED INTO `%s` (`time`, `char_id`, `type`, `nameid`, `amount`, `refine`, `card0`, `card1`, `card2`, `card3`, `map`) VALUES (NOW(), '%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%s')",
+ if (SQL_ERROR == Sql_Query(logmysql_handle, LOG_QUERY " INTO `%s` (`time`, `char_id`, `type`, `nameid`, `amount`, `refine`, `card0`, `card1`, `card2`, `card3`, `map`) VALUES (NOW(), '%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%s')",
log_config.log_pick_db, md->class_, type, itm->nameid, amount, itm->refine, itm->card[0], itm->card[1], itm->card[2], itm->card[3], mapname) )
{
Sql_ShowDebug(logmysql_handle);
@@ -208,7 +218,7 @@ int log_zeny(struct map_session_data *sd, char *type, struct map_session_data *s
#ifndef TXT_ONLY
if( log_config.sql_logs )
{
- if (SQL_ERROR == Sql_Query(logmysql_handle, "INSERT DELAYED INTO `%s` (`time`, `char_id`, `src_id`, `type`, `amount`, `map`) VALUES (NOW(), '%d', '%d', '%s', '%d', '%s')",
+ if (SQL_ERROR == Sql_Query(logmysql_handle, LOG_QUERY " INTO `%s` (`time`, `char_id`, `src_id`, `type`, `amount`, `map`) VALUES (NOW(), '%d', '%d', '%s', '%d', '%s')",
log_config.log_zeny_db, sd->status.char_id, src_sd->status.char_id, type, amount, mapindex_id2name(sd->mapindex)) )
{
Sql_ShowDebug(logmysql_handle);
@@ -240,7 +250,7 @@ int log_mvpdrop(struct map_session_data *sd, int monster_id, int *log_mvp)
#ifndef TXT_ONLY
if( log_config.sql_logs )
{
- if (SQL_ERROR == Sql_Query(logmysql_handle, "INSERT DELAYED INTO `%s` (`mvp_date`, `kill_char_id`, `monster_id`, `prize`, `mvpexp`, `map`) VALUES (NOW(), '%d', '%d', '%d', '%d', '%s') ",
+ if (SQL_ERROR == Sql_Query(logmysql_handle, LOG_QUERY " INTO `%s` (`mvp_date`, `kill_char_id`, `monster_id`, `prize`, `mvpexp`, `map`) VALUES (NOW(), '%d', '%d', '%d', '%d', '%s') ",
log_config.log_mvpdrop_db, sd->status.char_id, monster_id, log_mvp[0], log_mvp[1], mapindex_id2name(sd->mapindex)) )
{
Sql_ShowDebug(logmysql_handle);
@@ -276,7 +286,7 @@ int log_atcommand(struct map_session_data* sd, const char* message)
SqlStmt* stmt;
stmt = SqlStmt_Malloc(logmysql_handle);
- if( SQL_SUCCESS != SqlStmt_Prepare(stmt, "INSERT DELAYED INTO `%s` (`atcommand_date`, `account_id`, `char_id`, `char_name`, `map`, `command`) VALUES (NOW(), '%d', '%d', ?, '%s', ?)", log_config.log_gm_db, sd->status.account_id, sd->status.char_id, mapindex_id2name(sd->mapindex) )
+ if( SQL_SUCCESS != SqlStmt_Prepare(stmt, LOG_QUERY " INTO `%s` (`atcommand_date`, `account_id`, `char_id`, `char_name`, `map`, `command`) VALUES (NOW(), '%d', '%d', ?, '%s', ?)", log_config.log_gm_db, sd->status.account_id, sd->status.char_id, mapindex_id2name(sd->mapindex) )
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, sd->status.name, strnlen(sd->status.name, NAME_LENGTH))
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (char*)message, safestrnlen(message, 255))
|| SQL_SUCCESS != SqlStmt_Execute(stmt) )
@@ -314,7 +324,7 @@ int log_npc(struct map_session_data* sd, const char* message)
{
SqlStmt* stmt;
stmt = SqlStmt_Malloc(logmysql_handle);
- if( SQL_SUCCESS != SqlStmt_Prepare(stmt, "INSERT DELAYED INTO `%s` (`npc_date`, `account_id`, `char_id`, `char_name`, `map`, `mes`) VALUES (NOW(), '%d', '%d', ?, '%s', ?)", log_config.log_npc_db, sd->status.account_id, sd->status.char_id, mapindex_id2name(sd->mapindex) )
+ if( SQL_SUCCESS != SqlStmt_Prepare(stmt, LOG_QUERY " INTO `%s` (`npc_date`, `account_id`, `char_id`, `char_name`, `map`, `mes`) VALUES (NOW(), '%d', '%d', ?, '%s', ?)", log_config.log_npc_db, sd->status.account_id, sd->status.char_id, mapindex_id2name(sd->mapindex) )
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, sd->status.name, strnlen(sd->status.name, NAME_LENGTH))
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (char*)message, safestrnlen(message, 255))
|| SQL_SUCCESS != SqlStmt_Execute(stmt) )
@@ -365,7 +375,7 @@ int log_chat(const char* type, int type_id, int src_charid, int src_accid, const
SqlStmt* stmt;
stmt = SqlStmt_Malloc(logmysql_handle);
- if( SQL_SUCCESS != SqlStmt_Prepare(stmt, "INSERT DELAYED INTO `%s` (`time`, `type`, `type_id`, `src_charid`, `src_accountid`, `src_map`, `src_map_x`, `src_map_y`, `dst_charname`, `message`) VALUES (NOW(), '%s', '%d', '%d', '%d', '%s', '%d', '%d', ?, ?)", log_config.log_chat_db, type, type_id, src_charid, src_accid, map, x, y)
+ if( SQL_SUCCESS != SqlStmt_Prepare(stmt, LOG_QUERY " INTO `%s` (`time`, `type`, `type_id`, `src_charid`, `src_accountid`, `src_map`, `src_map_x`, `src_map_y`, `dst_charname`, `message`) VALUES (NOW(), '%s', '%d', '%d', '%d', '%s', '%d', '%d', ?, ?)", log_config.log_chat_db, type, type_id, src_charid, src_accid, map, x, y)
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, (char*)dst_charname, safestrnlen(dst_charname, NAME_LENGTH))
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, (char*)message, safestrnlen(message, CHAT_SIZE_MAX))
|| SQL_SUCCESS != SqlStmt_Execute(stmt) )
diff --git a/src/map/map.c b/src/map/map.c
index a4b419f65..5dab6634d 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";
@@ -1565,6 +1566,8 @@ int map_quit(struct map_session_data *sd)
if (sd->npc_id)
npc_event_dequeue(sd);
+ if( sd->bg_id )
+ bg_team_leave(sd,1);
npc_script_event(sd, NPCE_LOGOUT);
//Unit_free handles clearing the player related data,
@@ -1584,9 +1587,6 @@ int map_quit(struct map_session_data *sd)
status_change_end(&sd->bl, SC_WEIGHT50, INVALID_TIMER);
status_change_end(&sd->bl, SC_WEIGHT90, INVALID_TIMER);
if (battle_config.debuff_on_logout&1) {
- status_change_end(&sd->bl, SC_DECREASEAGI, INVALID_TIMER);
- status_change_end(&sd->bl, SC_BENEDICTIO, INVALID_TIMER);
- status_change_end(&sd->bl, SC_AETERNA, INVALID_TIMER);
status_change_end(&sd->bl, SC_ORCISH, INVALID_TIMER);
status_change_end(&sd->bl, SC_STRIPWEAPON, INVALID_TIMER);
status_change_end(&sd->bl, SC_STRIPARMOR, INVALID_TIMER);
@@ -1594,8 +1594,6 @@ int map_quit(struct map_session_data *sd)
status_change_end(&sd->bl, SC_STRIPHELM, INVALID_TIMER);
status_change_end(&sd->bl, SC_EXTREMITYFIST, INVALID_TIMER);
status_change_end(&sd->bl, SC_EXPLOSIONSPIRITS, INVALID_TIMER);
- status_change_end(&sd->bl, SC_JOINTBEAT, INVALID_TIMER);
- status_change_end(&sd->bl, SC_MINDBREAKER, INVALID_TIMER);
if(sd->sc.data[SC_REGENERATION] && sd->sc.data[SC_REGENERATION]->val4)
status_change_end(&sd->bl, SC_REGENERATION, INVALID_TIMER);
//TO-DO Probably there are way more NPC_type negative status that are removed
@@ -1606,61 +1604,12 @@ int map_quit(struct map_session_data *sd)
}
if (battle_config.debuff_on_logout&2)
{
- status_change_end(&sd->bl, SC_MAGNIFICAT, INVALID_TIMER);
status_change_end(&sd->bl, SC_MAXIMIZEPOWER, INVALID_TIMER);
status_change_end(&sd->bl, SC_MAXOVERTHRUST, INVALID_TIMER);
- status_change_end(&sd->bl, SC_AURABLADE, INVALID_TIMER);
- status_change_end(&sd->bl, SC_PARRYING, INVALID_TIMER);
- status_change_end(&sd->bl, SC_CONCENTRATION, INVALID_TIMER);
- status_change_end(&sd->bl, SC_TENSIONRELAX, INVALID_TIMER);
- status_change_end(&sd->bl, SC_MAGICPOWER, INVALID_TIMER);
- status_change_end(&sd->bl, SC_EDP, INVALID_TIMER);
- status_change_end(&sd->bl, SC_TRUESIGHT, INVALID_TIMER);
- status_change_end(&sd->bl, SC_WINDWALK, INVALID_TIMER);
- status_change_end(&sd->bl, SC_MELTDOWN, INVALID_TIMER);
- status_change_end(&sd->bl, SC_CARTBOOST, INVALID_TIMER);
- status_change_end(&sd->bl, SC_MEMORIZE, INVALID_TIMER);
- status_change_end(&sd->bl, SC_DEVOTION, INVALID_TIMER);
- status_change_end(&sd->bl, SC_SACRIFICE, INVALID_TIMER);
status_change_end(&sd->bl, SC_STEELBODY, INVALID_TIMER);
status_change_end(&sd->bl, SC_PRESERVE, INVALID_TIMER);
status_change_end(&sd->bl, SC_KAAHI, INVALID_TIMER);
- status_change_end(&sd->bl, SC_KAUPE, INVALID_TIMER);
- status_change_end(&sd->bl, SC_DOUBLECAST, INVALID_TIMER);
- status_change_end(&sd->bl, SC_SHRINK, INVALID_TIMER);
- status_change_end(&sd->bl, SC_SIGHTBLASTER, INVALID_TIMER);
status_change_end(&sd->bl, SC_SPIRIT, INVALID_TIMER);
- status_change_end(&sd->bl, SC_KAITE, INVALID_TIMER);
- status_change_end(&sd->bl, SC_UTSUSEMI, INVALID_TIMER);
- status_change_end(&sd->bl, SC_BUNSINJYUTSU, INVALID_TIMER);
- status_change_end(&sd->bl, SC_SUITON, INVALID_TIMER);
- // Third jobs
- status_change_end(&sd->bl, SC_MILLENNIUMSHIELD, INVALID_TIMER);
- status_change_end(&sd->bl, SC_DEATHBOUND, INVALID_TIMER);
- status_change_end(&sd->bl, SC_REFRESH, INVALID_TIMER);
- status_change_end(&sd->bl, SC_STONEHARDSKIN, INVALID_TIMER);
- //status_change_end(&sd->bl, SC_CLOAKINGEXCEED, INVALID_TIMER);
- //status_change_end(&sd->bl, SC_HALLUCINATIONWALK_POSTDELAY, INVALID_TIMER);
- //status_change_end(&sd->bl, SC_WEAPONBLOCKING_POSTDELAY, INVALID_TIMER);
- //status_change_end(&sd->bl, SC_ROLLINGCUTTER, INVALID_TIMER);
- //status_change_end(&sd->bl, SC_ELECTRICSHOCKER, INVALID_TIMER);
- //status_change_end(&sd->bl, SC_WUGDASH, INVALID_TIMER);
- //status_change_end(&sd->bl, SC_WUGBITE, INVALID_TIMER);
- //status_change_end(&sd->bl, SC_CAMOUFLAGE, INVALID_TIMER);
- //status_change_end(&sd->bl, SC_MAGNETICFIELD, INVALID_TIMER);
- //status_change_end(&sd->bl, SC_NEUTRALBARRIER, INVALID_TIMER);
- //status_change_end(&sd->bl, SC_NEUTRALBARRIER_MASTER, INVALID_TIMER);
- //status_change_end(&sd->bl, SC_STEALTHFIELD_MASTER, INVALID_TIMER);
- //status_change_end(&sd->bl, SC_SHADOWFORM, INVALID_TIMER);
- //status_change_end(&sd->bl, SC_INVISIBILITY, INVALID_TIMER);
- //status_change_end(&sd->bl, SC_RAISINGDRAGON, INVALID_TIMER);
- //status_change_end(&sd->bl, SC_NOEQUIPACCESSARY, INVALID_TIMER);
- //status_change_end(&sd->bl, SC_MANHOLE, INVALID_TIMER);
- //status_change_end(&sd->bl, SC_PROPERTYWALK, INVALID_TIMER);
- //status_change_end(&sd->bl, SC_DEEP_SLEEP, INVALID_TIMER);
- //status_change_end(&sd->bl, SC_WARMER, INVALID_TIMER);
- //status_change_end(&sd->bl, SC_GN_TRAINING_SWORD, INVALID_TIMER);
- //status_change_end(&sd->bl, SC_GN_REMODELING_CART, INVALID_TIMER);
}
}
@@ -3259,6 +3208,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);
}
@@ -3580,41 +3532,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"RAthena 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://rathena.org/\n");
+ ShowInfo(CL_GREEN"IRC Channel:"CL_RESET"\tirc://irc.rizon.net/#rthena\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);
}
/*======================================================
@@ -3645,6 +3595,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[])
{
@@ -3665,31 +3625,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 6fbb36cdc..51678d590 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 "./config/Core.h"
+
#include <stdarg.h>
struct npc_data;
@@ -68,17 +73,17 @@ enum E_MAPSERVER_ST
#define JOBL_UPPER 0x1000 //4096
#define JOBL_BABY 0x2000 //8192
-#define JOBL_3 0x4000 //16384
+#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...
enum {
MAPID_NOVICE = 0x0,
-//1st classes
MAPID_SWORDMAN,
MAPID_MAGE,
MAPID_ARCHER,
@@ -92,7 +97,7 @@ enum {
MAPID_XMAS,
MAPID_SUMMER,
//2_1 classes
- MAPID_SUPER_NOVICE = JOBL_2_1|MAPID_NOVICE,
+ MAPID_SUPER_NOVICE = JOBL_2_1|0x0,
MAPID_KNIGHT,
MAPID_WIZARD,
MAPID_HUNTER,
@@ -101,29 +106,15 @@ enum {
MAPID_ASSASSIN,
MAPID_STAR_GLADIATOR,
//2_2 classes
- MAPID_CRUSADER = JOBL_2_2|MAPID_SWORDMAN,
+ MAPID_CRUSADER = JOBL_2_2|0x1,
MAPID_SAGE,
MAPID_BARDDANCER,
MAPID_MONK,
MAPID_ALCHEMIST,
MAPID_ROGUE,
MAPID_SOUL_LINKER,
-//3_1 classes
- MAPID_RUNE_KNIGHT = JOBL_3|JOBL_2_1|MAPID_SWORDMAN,
- MAPID_WARLOCK,
- MAPID_RANGER,
- MAPID_ARCHBISHOP,
- MAPID_MECHANIC,
- MAPID_GUILLOTINE_CROSS,
-//3_2 classes
- MAPID_ROYAL_GUARD = JOBL_3|JOBL_2_2|MAPID_SWORDMAN,
- MAPID_SORCERER,
- MAPID_MINSTRELWANDERER,
- MAPID_SURA,
- MAPID_GENETIC,
- MAPID_SHADOW_CHASER,
-//1st, advanced
- MAPID_NOVICE_HIGH = JOBL_UPPER|MAPID_NOVICE,
+//1-1, advanced
+ MAPID_NOVICE_HIGH = JOBL_UPPER|0x0,
MAPID_SWORDMAN_HIGH,
MAPID_MAGE_HIGH,
MAPID_ARCHER_HIGH,
@@ -131,35 +122,21 @@ enum {
MAPID_MERCHANT_HIGH,
MAPID_THIEF_HIGH,
//2_1 advanced
- MAPID_LORD_KNIGHT = JOBL_UPPER|JOBL_2_1|MAPID_SWORDMAN,
+ MAPID_LORD_KNIGHT = JOBL_UPPER|JOBL_2_1|0x1,
MAPID_HIGH_WIZARD,
MAPID_SNIPER,
MAPID_HIGH_PRIEST,
MAPID_WHITESMITH,
MAPID_ASSASSIN_CROSS,
//2_2 advanced
- MAPID_PALADIN = JOBL_UPPER|JOBL_2_2|MAPID_SWORDMAN,
+ MAPID_PALADIN = JOBL_UPPER|JOBL_2_2|0x1,
MAPID_PROFESSOR,
MAPID_CLOWNGYPSY,
MAPID_CHAMPION,
MAPID_CREATOR,
MAPID_STALKER,
-//3_1 advanced
- MAPID_RUNE_KNIGHT_H = JOBL_3|JOBL_UPPER|JOBL_2_1|MAPID_SWORDMAN,
- MAPID_WARLOCK_H,
- MAPID_RANGER_H,
- MAPID_ARCHBISHOP_H,
- MAPID_MECHANIC_H,
- MAPID_GUILLOTINE_CROSS_H,
-//3_2 advanced
- MAPID_ROYAL_GUARD_H = JOBL_3|JOBL_UPPER|JOBL_2_2|MAPID_SWORDMAN,
- MAPID_SORCERER_H,
- MAPID_MINSTRELWANDERER_H,
- MAPID_SURA_H,
- MAPID_GENETIC_H,
- MAPID_SHADOW_CHASER_H,
-//1st baby
- MAPID_BABY = JOBL_BABY|MAPID_NOVICE,
+//1-1 baby
+ MAPID_BABY = JOBL_BABY|0x0,
MAPID_BABY_SWORDMAN,
MAPID_BABY_MAGE,
MAPID_BABY_ARCHER,
@@ -168,7 +145,7 @@ enum {
MAPID_BABY_THIEF,
MAPID_BABY_TAEKWON,
//2_1 baby
- MAPID_SUPER_BABY = JOBL_BABY|JOBL_2_1|MAPID_NOVICE,
+ MAPID_SUPER_BABY = JOBL_BABY|JOBL_2_1|0x0,
MAPID_BABY_KNIGHT,
MAPID_BABY_WIZARD,
MAPID_BABY_HUNTER,
@@ -177,27 +154,38 @@ enum {
MAPID_BABY_ASSASSIN,
MAPID_BABY_STAR_GLADIATOR,
//2_2 baby
- MAPID_BABY_CRUSADER = JOBL_BABY|JOBL_2_2|MAPID_SWORDMAN,
+ MAPID_BABY_CRUSADER = JOBL_BABY|JOBL_2_2|0x1,
MAPID_BABY_SAGE,
MAPID_BABY_BARDDANCER,
MAPID_BABY_MONK,
MAPID_BABY_ALCHEMIST,
MAPID_BABY_ROGUE,
MAPID_BABY_SOUL_LINKER,
-//3_1 baby
- MAPID_BABY_RUNE = JOBL_3|JOBL_BABY|JOBL_2_1|MAPID_SWORDMAN,
- MAPID_BABY_WARLOCK,
- MAPID_BABY_RANGER,
- MAPID_BABY_BISHOP,
- MAPID_BABY_MECHANIC,
- MAPID_BABY_CROSS,
-//3_2 baby
- MAPID_BABY_GUARD = JOBL_3|JOBL_BABY|JOBL_2_2|MAPID_SWORDMAN,
- MAPID_BABY_SORCERER,
- MAPID_BABY_MINSTRELWANDERER,
- MAPID_BABY_SURA,
- MAPID_BABY_GENETIC,
- MAPID_BABY_CHASER
+ 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
@@ -313,7 +301,7 @@ struct spawn_data {
signed short xs,ys;
unsigned short num; //Number of mobs using this structure
unsigned short active; //Number of mobs that are already spawned (for mob_remove_damaged: no)
- unsigned int delay1,delay2; //Min delay before respawning after spawn/death
+ unsigned int delay1,delay2; //Spawn delay (fixed base + random variance)
struct {
unsigned int size :2; //Holds if mob has to be tiny/large
unsigned int ai :2; //Holds if mob is special ai.
@@ -380,7 +368,7 @@ enum _sp {
SP_WEAPON_ATK,SP_WEAPON_ATK_RATE, // 1081-1082
SP_DELAYRATE,SP_HP_DRAIN_RATE_RACE,SP_SP_DRAIN_RATE_RACE, // 1083-1085
SP_IGNORE_MDEF_RATE,SP_IGNORE_DEF_RATE,SP_SKILL_HEAL2,SP_ADDEFF_ONSKILL, //1086-1089
- SP_ADD_HEAL_RATE,SP_ADD_HEAL2_RATE,SP_FIXEDCASTRATE,SP_BASE_MATK,SP_WEAPON_MATK,SP_EQUIPMENT_MATK, //1090-1095
+ SP_ADD_HEAL_RATE,SP_ADD_HEAL2_RATE, //1090-1091
SP_RESTART_FULL_RECOVER=2000,SP_NO_CASTCANCEL,SP_NO_SIZEFIX,SP_NO_MAGIC_DAMAGE,SP_NO_WEAPON_DAMAGE,SP_NO_GEMSTONE, // 2000-2005
SP_NO_CASTCANCEL2,SP_NO_MISC_DAMAGE,SP_UNBREAKABLE_WEAPON,SP_UNBREAKABLE_ARMOR, SP_UNBREAKABLE_HELM, // 2006-2010
@@ -520,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]
@@ -687,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);
@@ -711,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;
@@ -741,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/mercenary.h b/src/map/mercenary.h
index 1cc689208..f040a3913 100644
--- a/src/map/mercenary.h
+++ b/src/map/mercenary.h
@@ -69,6 +69,12 @@ int mercenary_kills(struct mercenary_data *md);
int mercenary_checkskill(struct mercenary_data *md, int skill_id);
+/**
+ * atcommand.c required
+ **/
+int read_mercenarydb(void);
+int read_mercenary_skilldb(void);
+
int do_init_mercenary(void);
#endif /* _MERCENARY_H_ */
diff --git a/src/map/mob.c b/src/map/mob.c
index 49ca6eb23..df547c77d 100644
--- a/src/map/mob.c
+++ b/src/map/mob.c
@@ -1311,7 +1311,7 @@ static bool mob_ai_sub_hard(struct mob_data *md, unsigned int tick)
return false;
// Abnormalities
- if((md->sc.opt1 > 0 && md->sc.opt1 != OPT1_STONEWAIT && md->sc.opt1 != OPT1_BURNING) || md->sc.data[SC_BLADESTOP])
+ if((md->sc.opt1 > 0 && md->sc.opt1 != OPT1_STONEWAIT) || md->sc.data[SC_BLADESTOP])
{ //Should reset targets.
md->target_id = md->attacked_id = 0;
return false;
@@ -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;
@@ -3574,7 +3593,8 @@ static bool mob_parse_dbrow(char** str)
db->dropitem[i].p = 0; //No drop.
continue;
}
- type = itemdb_type(db->dropitem[i].nameid);
+ id = itemdb_search(db->dropitem[i].nameid);
+ type = id->type;
rate = atoi(str[k+1]);
if( (class_ >= 1324 && class_ <= 1363) || (class_ >= 1938 && class_ <= 1946) )
{ //Treasure box drop rates [Skotlex]
@@ -3618,7 +3638,6 @@ static bool mob_parse_dbrow(char** str)
//calculate and store Max available drop chance of the item
if( db->dropitem[i].p && (class_ < 1324 || class_ > 1363) && (class_ < 1938 || class_ > 1946) )
{ //Skip treasure chests.
- id = itemdb_search(db->dropitem[i].nameid);
if (id->maxchance == -1 || (id->maxchance < db->dropitem[i].p) ) {
id->maxchance = db->dropitem[i].p; //item has bigger drop chance or sold in shops
}
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 897475f73..880626344 100644
--- a/src/map/npc.c
+++ b/src/map/npc.c
@@ -96,7 +96,7 @@ static struct script_event_s
struct view_data* npc_get_viewdata(int class_)
{ //Returns the viewdata for normal npc classes.
- if (class_ == INVISIBLE_CLASS)
+ if( class_ == HIDDEN_WARP_CLASS || class_ == INVISIBLE_CLASS )
return &npc_viewdb[0];
if (npcdb_checkid(class_) || class_ == WARP_CLASS)
return &npc_viewdb[class_];
@@ -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 config/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 config/Secure.h) [RR]
+ **/
+#if SECURE_NPCTIMEOUT
+ /**
+ * Update the last NPC iteration
+ **/
+ sd->npc_idle_tick = gettick();
+#endif
run_script_main(sd->st);
return 0;
@@ -1389,14 +1424,28 @@ int npc_buylist(struct map_session_data* sd, int n, unsigned short* item_list)
static int npc_selllist_sub(struct map_session_data* sd, int n, unsigned short* item_list, struct npc_data* nd)
{
char npc_ev[EVENT_NAME_LENGTH];
- int i, idx;
+ char card_slot[NAME_LENGTH];
+ int i, j, idx;
int key_nameid = 0;
int key_amount = 0;
+ int key_refine = 0;
+ int key_attribute = 0;
+ int key_identify = 0;
+ int key_card = 0;
// discard old contents
script_cleararray_pc(sd, "@sold_nameid", (void*)0);
script_cleararray_pc(sd, "@sold_quantity", (void*)0);
+ script_cleararray_pc(sd, "@sold_refine", (void*)0);
+ script_cleararray_pc(sd, "@sold_attribute", (void*)0);
+ script_cleararray_pc(sd, "@sold_identify", (void*)0);
+ for( j = 0; MAX_SLOTS > j; j++ )
+ {// clear each of the card slot entries
+ snprintf(card_slot, sizeof(card_slot), "@sold_card%d", j + 1);
+ script_cleararray_pc(sd, card_slot, (void*)0);
+ }
+
// save list of to be sold items
for( i = 0; i < n; i++ )
{
@@ -1404,6 +1453,19 @@ static int npc_selllist_sub(struct map_session_data* sd, int n, unsigned short*
script_setarray_pc(sd, "@sold_nameid", i, (void*)(intptr_t)sd->status.inventory[idx].nameid, &key_nameid);
script_setarray_pc(sd, "@sold_quantity", i, (void*)(intptr_t)item_list[i*2+1], &key_amount);
+
+ if( itemdb_isequip(sd->status.inventory[idx].nameid) )
+ {// process equipment based information into the arrays
+ script_setarray_pc(sd, "@sold_refine", i, (void*)(intptr_t)sd->status.inventory[idx].refine, &key_refine);
+ script_setarray_pc(sd, "@sold_attribute", i, (void*)(intptr_t)sd->status.inventory[idx].attribute, &key_attribute);
+ script_setarray_pc(sd, "@sold_identify", i, (void*)(intptr_t)sd->status.inventory[idx].identify, &key_identify);
+
+ for( j = 0; MAX_SLOTS > j; j++ )
+ {// store each of the cards from the equipment in the array
+ snprintf(card_slot, sizeof(card_slot), "@sold_card%d", j + 1);
+ script_setarray_pc(sd, card_slot, i, (void*)(intptr_t)sd->status.inventory[idx].card[j], &key_card);
+ }
+ }
}
// invoke event
@@ -3058,8 +3120,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 29e3d79cb..ac411697e 100644
--- a/src/map/npc.h
+++ b/src/map/npc.h
@@ -69,15 +69,19 @@ struct npc_data {
#define START_NPC_NUM 110000000
-#define WARP_CLASS 45
-#define WARP_DEBUG_CLASS 722
-#define FLAG_CLASS 722
-#define INVISIBLE_CLASS 32767
+enum actor_classes
+{
+ WARP_CLASS = 45,
+ HIDDEN_WARP_CLASS = 139, // server-side only, never sent to client
+ WARP_DEBUG_CLASS = 722,
+ FLAG_CLASS = 722,
+ INVISIBLE_CLASS = 32767,
+};
#define MAX_NPC_CLASS 1000
//Checks if a given id is a valid npc id. [Skotlex]
//Since new npcs are added all the time, the max valid value is the one before the first mob (Scorpion = 1001)
-#define npcdb_checkid(id) ( ( (id) >= 46 && (id) <= 125) || (id) == 139 || ( (id) > 400 && (id) < MAX_NPC_CLASS ) || (id) == INVISIBLE_CLASS )
+#define npcdb_checkid(id) ( ( (id) >= 46 && (id) <= 125) || (id) == HIDDEN_WARP_CLASS || ( (id) > 400 && (id) < MAX_NPC_CLASS ) || (id) == INVISIBLE_CLASS )
#ifdef PCRE_SUPPORT
void npc_chat_finalize(struct npc_data* nd);
@@ -153,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 config/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 88f53bcb0..a8a524046 100644
--- a/src/map/party.c
+++ b/src/map/party.c
@@ -28,8 +28,8 @@
#include <string.h>
-static DBMap* party_db; // int party_id -> struct party_data*
-static DBMap* party_booking_db; // Party Booking [Spiria]
+static DBMap* party_db; // int party_id -> struct party_data* (releases data)
+static DBMap* party_booking_db; // int char_id -> struct party_booking_ad_info* (releases data) // Party Booking [Spiria]
static unsigned long party_booking_nextid = 1;
int party_send_xy_timer(int tid, unsigned int tick, int id, intptr_t data);
@@ -38,18 +38,36 @@ int party_send_xy_timer(int tid, unsigned int tick, int id, intptr_t data);
* Fills the given party_member structure according to the sd provided.
* Used when creating/adding people to a party. [Skotlex]
*------------------------------------------*/
-static void party_fill_member(struct party_member *member, struct map_session_data *sd)
+static void party_fill_member(struct party_member* member, struct map_session_data* sd, unsigned int leader)
{
member->account_id = sd->status.account_id;
member->char_id = sd->status.char_id;
- memcpy(member->name, sd->status.name, NAME_LENGTH);
+ safestrncpy(member->name, sd->status.name, NAME_LENGTH);
member->class_ = sd->status.class_;
member->map = sd->mapindex;
member->lv = sd->status.base_level;
member->online = 1;
- member->leader = 0;
+ member->leader = leader;
}
+
+/// Get the member_id of a party member.
+/// Return -1 if not in party.
+int party_getmemberid(struct party_data* p, struct map_session_data* sd)
+{
+ int member_id;
+ nullpo_retr(-1, p);
+ if( sd == NULL )
+ return -1;// no player
+ ARR_FIND(0, MAX_PARTY, member_id,
+ p->party.member[member_id].account_id == sd->status.account_id &&
+ p->party.member[member_id].char_id == sd->status.char_id);
+ if( member_id == MAX_PARTY )
+ return -1;// not found
+ return member_id;
+}
+
+
/*==========================================
* Request an available sd of this party
*------------------------------------------*/
@@ -72,6 +90,8 @@ static TBL_PC* party_sd_check(int party_id, int account_id, int char_id)
if (!(sd && sd->status.char_id == char_id))
return NULL;
+ if( sd->status.party_id == 0 )
+ sd->status.party_id = party_id;// auto-join if not in a party
if (sd->status.party_id != party_id)
{ //If player belongs to a different party, kick him out.
intif_party_leave(party_id,account_id,char_id);
@@ -143,8 +163,7 @@ int party_create(struct map_session_data *sd,char *name,int item,int item2)
sd->party_creating = true;
- party_fill_member(&leader, sd);
- leader.leader = 1;
+ party_fill_member(&leader, sd, 1);
intif_create_party(&leader,name,item,item2);
return 0;
@@ -175,63 +194,26 @@ void party_created(int account_id,int char_id,int fail,int party_id,char *name)
}
-int party_request_info(int party_id)
+int party_request_info(int party_id, int char_id)
{
- return intif_request_partyinfo(party_id);
+ return intif_request_partyinfo(party_id, char_id);
}
-/// Checks if each char having a party actually belongs to that party.
-/// If check fails, the char gets marked as 'not in a party'.
-int party_check_member(struct party *p)
+/// Invoked (from char-server) when the party info is not found.
+int party_recv_noinfo(int party_id, int char_id)
{
- int i;
- struct map_session_data *sd;
- struct s_mapiterator* iter;
-
- nullpo_ret(p);
+ struct map_session_data* sd;
- iter = mapit_getallusers();
- for( sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC*)mapit_next(iter) )
+ party_broken(party_id);
+ if( char_id != 0 )// requester
{
- if( sd->status.party_id != p->party_id )
- continue;
-
- ARR_FIND( 0, MAX_PARTY, i, p->member[i].account_id == sd->status.account_id && p->member[i].char_id == sd->status.char_id );
- if( i == MAX_PARTY )
- {
- ShowWarning("party_check_member: '%s' (acc:%d) is not member of party '%s' (id:%d)\n",sd->status.name,sd->status.account_id,p->name,p->party_id);
+ sd = map_charid2sd(char_id);
+ if( sd && sd->status.party_id == party_id )
sd->status.party_id = 0;
- }
- }
- mapit_free(iter);
-
- return 0;
-}
-
-/// Marks all chars belonging to this party as 'not in a party'.
-int party_recv_noinfo(int party_id)
-{
- struct map_session_data *sd;
- struct s_mapiterator* iter;
-
- iter = mapit_getallusers();
- for( sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC*)mapit_next(iter) )
- {
- if( sd->status.party_id == party_id )
- sd->status.party_id = 0; // erase party
}
- mapit_free(iter);
-
return 0;
}
-static void* create_party(DBKey key, va_list args)
-{
- struct party_data *p;
- p=(struct party_data *)aCalloc(1,sizeof(struct party_data));
- return p;
-}
-
static void party_check_state(struct party_data *p)
{
int i;
@@ -259,42 +241,92 @@ static void party_check_state(struct party_data *p)
}
}
-int party_recv_info(struct party *sp)
+int party_recv_info(struct party* sp, int char_id)
{
- struct party_data *p;
+ struct party_data* p;
+ struct party_member* member;
+ struct map_session_data* sd;
+ int removed[MAX_PARTY];// member_id in old data
+ int removed_count = 0;
+ int added[MAX_PARTY];// member_id in new data
+ int added_count = 0;
int i;
- bool party_new = false;
+ int member_id;
nullpo_ret(sp);
- p = (struct party_data*)idb_ensure(party_db, sp->party_id, create_party);
- if (!p->party.party_id) //party just received.
+ p = (struct party_data*)idb_get(party_db, sp->party_id);
+ if( p != NULL )// diff members
+ {
+ for( member_id = 0; member_id < MAX_PARTY; ++member_id )
+ {
+ member = &p->party.member[member_id];
+ if( member->char_id == 0 )
+ continue;// empty
+ ARR_FIND(0, MAX_PARTY, i,
+ sp->member[i].account_id == member->account_id &&
+ sp->member[i].char_id == member->char_id);
+ if( i == MAX_PARTY )
+ removed[removed_count++] = member_id;
+ }
+ for( member_id = 0; member_id < MAX_PARTY; ++member_id )
+ {
+ member = &sp->member[member_id];
+ if( member->char_id == 0 )
+ continue;// empty
+ ARR_FIND(0, MAX_PARTY, i,
+ p->party.member[i].account_id == member->account_id &&
+ p->party.member[i].char_id == member->char_id);
+ if( i == MAX_PARTY )
+ added[added_count++] = member_id;
+ }
+ }
+ else
+ {
+ for( member_id = 0; member_id < MAX_PARTY; ++member_id )
+ if( sp->member[member_id].char_id != 0 )
+ added[added_count++] = member_id;
+ CREATE(p, struct party_data, 1);
+ idb_put(party_db, sp->party_id, p);
+ }
+ while( removed_count > 0 )// no longer in party
{
- party_new = true;
- party_check_member(sp);
+ member_id = removed[--removed_count];
+ sd = p->data[member_id].sd;
+ if( sd == NULL )
+ continue;// not online
+ party_member_withdraw(sp->party_id, sd->status.account_id, sd->status.char_id);
}
- memcpy(&p->party,sp,sizeof(struct party));
+ memcpy(&p->party, sp, sizeof(struct party));
memset(&p->state, 0, sizeof(p->state));
memset(&p->data, 0, sizeof(p->data));
- for(i=0;i<MAX_PARTY;i++){
- if (!p->party.member[i].account_id)
- continue;
- p->data[i].sd = party_sd_check(p->party.party_id, p->party.member[i].account_id, p->party.member[i].char_id);
+ for( member_id = 0; member_id < MAX_PARTY; member_id++ )
+ {
+ member = &p->party.member[member_id];
+ if ( member->char_id == 0 )
+ continue;// empty
+ p->data[member_id].sd = party_sd_check(sp->party_id, member->account_id, member->char_id);
}
party_check_state(p);
- if (party_new) {
- //Send party data to all players.
- struct map_session_data *sd;
- for(i=0;i<MAX_PARTY;i++){
- sd = p->data[i].sd;
- if(!sd) continue;
- clif_charnameupdate(sd); //Update other people's display. [Skotlex]
- clif_party_member_info(p,sd);
- clif_party_option(p,sd,0x100);
- clif_party_info(p,NULL);
- }
+ while( added_count > 0 )// new in party
+ {
+ member_id = added[--added_count];
+ sd = p->data[member_id].sd;
+ if( sd == NULL )
+ continue;// not online
+ clif_charnameupdate(sd); //Update other people's display. [Skotlex]
+ clif_party_member_info(p,sd);
+ clif_party_option(p,sd,0x100);
+ clif_party_info(p,NULL);
+ if( p->instance_id != 0 )
+ clif_instance_join(sd->fd, p->instance_id);
+ }
+ if( char_id != 0 )// requester
+ {
+ sd = map_charid2sd(char_id);
+ if( sd && sd->status.party_id == sp->party_id && party_getmemberid(p,sd) == -1 )
+ sd->status.party_id = 0;// was not in the party
}
-
return 0;
}
@@ -306,8 +338,8 @@ int party_invite(struct map_session_data *sd,struct map_session_data *tsd)
nullpo_ret(sd);
if( ( p = party_search(sd->status.party_id) ) == NULL )
return 0;
- if( tsd == NULL) { //TODO: Find the correct reply packet.
- clif_displaymessage(sd->fd, msg_txt(3));
+ if( tsd == NULL) {
+ clif_party_inviteack(sd, "", 7);
return 0;
}
@@ -385,7 +417,7 @@ void party_reply_invite(struct map_session_data *sd,int party_id,int flag)
if( flag == 1 && !sd->party_creating && !sd->party_joining )
{// accepted and allowed
sd->party_joining = true;
- party_fill_member(&member, sd);
+ party_fill_member(&member, sd, 0);
intif_party_addmember(sd->party_invite, &member);
}
else
@@ -407,7 +439,7 @@ void party_member_joined(struct map_session_data *sd)
int i;
if (!p)
{
- party_request_info(sd->status.party_id);
+ party_request_info(sd->status.party_id, sd->status.char_id);
return;
}
ARR_FIND( 0, MAX_PARTY, i, p->party.member[i].account_id == sd->status.account_id && p->party.member[i].char_id == sd->status.char_id );
@@ -456,14 +488,6 @@ int party_member_added(int party_id,int account_id,int char_id, int flag)
sd->status.party_id = party_id;
- ARR_FIND( 0, MAX_PARTY, i, p->party.member[i].account_id == 0 );
- if (i < MAX_PARTY) {
- //TODO: This is a hack to allow the following clif calls to send the data to the new player.
- //The correct player data is set when party_recv_info arrives soon afterwards.
- party_fill_member(&p->party.member[i], sd);
- p->data[i].sd = sd;
- }
-
clif_party_member_info(p,sd);
clif_party_option(p,sd,0x100);
clif_party_info(p,sd);
@@ -542,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--;
@@ -849,11 +873,16 @@ int party_send_xy_timer(int tid, unsigned int tick, int id, intptr_t data)
for( p = (struct party_data*)iter->first(iter,NULL); iter->exists(iter); p = (struct party_data*)iter->next(iter,NULL) )
{
int i;
+
+ if( !p->party.count )
+ {// no online party members so do not iterate
+ continue;
+ }
+
// for each member of this party,
for( i = 0; i < MAX_PARTY; i++ )
{
- //struct map_session_data* sd = p->data[i].sd;
- struct map_session_data* sd = map_charid2sd(p->party.member[i].char_id); //temporary crashfix
+ struct map_session_data* sd = p->data[i].sd;
if( !sd ) continue;
if( p->data[i].x != sd->bl.x || p->data[i].y != sd->bl.y )
@@ -888,13 +917,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
@@ -921,8 +1001,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 1c59197b3..4918d9a3a 100644
--- a/src/map/party.h
+++ b/src/map/party.h
@@ -51,11 +51,12 @@ void do_init_party(void);
void do_final_party(void);
struct party_data* party_search(int party_id);
struct party_data* party_searchname(const char* str);
+int party_getmemberid(struct party_data* p, struct map_session_data* sd);
struct map_session_data* party_getavailablesd(struct party_data *p);
int party_create(struct map_session_data *sd,char *name, int item, int item2);
void party_created(int account_id,int char_id,int fail,int party_id,char *name);
-int party_request_info(int party_id);
+int party_request_info(int party_id, int char_id);
int party_invite(struct map_session_data *sd,struct map_session_data *tsd);
void party_member_joined(struct map_session_data *sd);
int party_member_added(int party_id,int account_id,int char_id,int flag);
@@ -63,8 +64,8 @@ int party_leave(struct map_session_data *sd);
int party_removemember(struct map_session_data *sd,int account_id,char *name);
int party_member_withdraw(int party_id,int account_id,int char_id);
void party_reply_invite(struct map_session_data *sd,int party_id,int flag);
-int party_recv_noinfo(int party_id);
-int party_recv_info(struct party *sp);
+int party_recv_noinfo(int party_id, int char_id);
+int party_recv_info(struct party* sp, int char_id);
int party_recv_movemap(int party_id,int account_id,int char_id, unsigned short map,int online,int lv);
int party_broken(int party_id);
int party_optionchanged(int party_id,int account_id,int exp,int item,int flag);
@@ -91,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 440c684f4..21588a12d 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|OPTION_DRAGON);
+ 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 config/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);
}
@@ -1814,14 +1828,14 @@ int pc_bonus(struct map_session_data *sd,int type,int val)
break;
case SP_BASE_ATK:
if(sd->state.lr_flag != 2) {
- bonus = status->equipment_atk + val;
- status->equipment_atk = cap_value(bonus, 0, USHRT_MAX);
+ bonus = status->batk + val;
+ status->batk = cap_value(bonus, 0, USHRT_MAX);
}
break;
case SP_DEF1:
if(sd->state.lr_flag != 2) {
bonus = status->def + val;
- status->def = cap_value(bonus, SHRT_MIN, SHRT_MAX);
+ status->def = cap_value(bonus, CHAR_MIN, CHAR_MAX);
}
break;
case SP_DEF2:
@@ -1833,7 +1847,7 @@ int pc_bonus(struct map_session_data *sd,int type,int val)
case SP_MDEF1:
if(sd->state.lr_flag != 2) {
bonus = status->mdef + val;
- status->mdef = cap_value(bonus, SHRT_MIN, SHRT_MAX);
+ status->mdef = cap_value(bonus, CHAR_MIN, CHAR_MAX);
}
break;
case SP_MDEF2:
@@ -1925,10 +1939,6 @@ int pc_bonus(struct map_session_data *sd,int type,int val)
if(sd->state.lr_flag != 2)
sd->castrate+=val;
break;
- case SP_FIXEDCASTRATE:
- if(sd->state.lr_flag != 2)
- sd->fixedcastrate+=val;
- break;
case SP_MAXHPRATE:
if(sd->state.lr_flag != 2)
sd->hprate+=val;
@@ -1976,7 +1986,7 @@ int pc_bonus(struct map_session_data *sd,int type,int val)
break;
case SP_ASPD_RATE: //Stackable increase - Made it linear as per rodatazone
if(sd->state.lr_flag != 2)
- status->aspd_rate -= 10 * val;
+ status->aspd_rate -= 10*val;
break;
case SP_HP_RECOV_RATE:
if(sd->state.lr_flag != 2)
@@ -2010,14 +2020,6 @@ int pc_bonus(struct map_session_data *sd,int type,int val)
if(sd->state.lr_flag != 2)
sd->matk_rate += val;
break;
- case SP_WEAPON_MATK:
- if(sd->state.lr_flag != 2)
- sd->weapon_matk += val;
- break;
- case SP_EQUIPMENT_MATK:
- if(sd->state.lr_flag != 2)
- sd->equipment_matk += val;
- break;
case SP_IGNORE_DEF_ELE:
if(val >= ELE_MAX) {
ShowError("pc_bonus: SP_IGNORE_DEF_ELE: Invalid element %d\n", val);
@@ -2713,23 +2715,6 @@ int pc_bonus2(struct map_session_data *sd,int type,int type2,int val)
}
break;
- case SP_FIXEDCASTRATE:
- if(sd->state.lr_flag == 2)
- break;
- ARR_FIND(0, ARRAYLENGTH(sd->fixedskillcast), i, sd->fixedskillcast[i].id == 0 || sd->fixedskillcast[i].id == type2);
- if (i == ARRAYLENGTH(sd->fixedskillcast))
- { //Better mention this so the array length can be updated. [Skotlex]
- ShowDebug("run_script: bonus2 bFixedCastRate reached it's limit (%d skills per character), bonus skill %d (+%d%%) lost.\n", ARRAYLENGTH(sd->fixedskillcast), type2, val);
- break;
- }
- if(sd->fixedskillcast[i].id == type2)
- sd->fixedskillcast[i].val += val;
- else {
- sd->fixedskillcast[i].id = type2;
- sd->fixedskillcast[i].val = val;
- }
- break;
-
case SP_HP_LOSS_RATE:
if(sd->state.lr_flag != 2) {
sd->hp_loss.value = type2;
@@ -3199,25 +3184,19 @@ int pc_modifysellvalue(struct map_session_data *sd,int orig_value)
int pc_checkadditem(struct map_session_data *sd,int nameid,int amount)
{
int i;
- struct item_data* data;
nullpo_ret(sd);
if(amount > MAX_AMOUNT)
return ADDITEM_OVERAMOUNT;
- data = itemdb_search(nameid);
-
- if(!itemdb_isstackable2(data))
+ if(!itemdb_isstackable(nameid))
return ADDITEM_NEW;
- if( data->stack.inventory && amount > data->stack.amount )
- return ADDITEM_OVERAMOUNT;
-
for(i=0;i<MAX_INVENTORY;i++){
// FIXME: This does not consider the checked item's cards, thus could check a wrong slot for stackability.
if(sd->status.inventory[i].nameid==nameid){
- if( amount > MAX_AMOUNT - sd->status.inventory[i].amount || ( data->stack.inventory && amount > data->stack.amount - sd->status.inventory[i].amount ) )
+ if(sd->status.inventory[i].amount+amount > MAX_AMOUNT)
return ADDITEM_OVERAMOUNT;
return ADDITEM_EXIST;
}
@@ -3411,16 +3390,18 @@ int pc_additem(struct map_session_data *sd,struct item *item_data,int amount)
return 5;
data = itemdb_search(item_data->nameid);
-
- if( data->stack.inventory && amount > data->stack.amount )
- {// item stack limitation
- return 7;
- }
-
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 )
@@ -3429,7 +3410,7 @@ int pc_additem(struct map_session_data *sd,struct item *item_data,int amount)
{
if( sd->status.inventory[i].nameid == item_data->nameid && memcmp(&sd->status.inventory[i].card, &item_data->card, sizeof(item_data->card)) == 0 )
{
- if( amount > MAX_AMOUNT - sd->status.inventory[i].amount || ( data->stack.inventory && amount > data->stack.amount - sd->status.inventory[i].amount ) )
+ if( amount > MAX_AMOUNT - sd->status.inventory[i].amount )
return 5;
sd->status.inventory[i].amount += amount;
clif_additem(sd,i,amount,0);
@@ -3615,7 +3596,6 @@ int pc_isUseitem(struct map_session_data *sd,int n)
//Not consumable item
if( item->type != IT_HEALING && item->type != IT_USABLE && item->type != IT_CASH )
return 0;
- // This contradicts official behavior. Items with no scripts should be consumed regardless. [L0ne_W0lf]
if( !item->script ) //if it has no script, you can't really consume it!
return 0;
@@ -3694,6 +3674,7 @@ int pc_isUseitem(struct map_session_data *sd,int n)
if( nameid == 12243 && sd->md->db->lv < 80 )
return 0;
break;
+
case 12213: //Neuralizer
if( !map[sd->bl.m].flag.reset )
return 0;
@@ -3703,7 +3684,15 @@ int pc_isUseitem(struct map_session_data *sd,int n)
if( nameid >= 12153 && nameid <= 12182 && sd->md != NULL )
return 0; // Mercenary Scrolls
- if (nameid >= 12725 && nameid <= 12733 && !pc_isUseitem_check_runeskill(sd, sd->status.inventory[n].nameid) )
+ /**
+ * 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]
@@ -3729,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))
@@ -3744,45 +3734,6 @@ int pc_isUseitem(struct map_session_data *sd,int n)
return 1;
}
-
-int pc_isUseitem_check_runeskill(TBL_PC *sd, int nameid)
-{
- struct {
- int runeid;
- int skillid;
- } rune2skill_table[] = {
- { 12725, RK_REFRESH },
- { 12726, RK_CRUSHSTRIKE },
- { 12727, RK_MILLENNIUMSHIELD },
- { 12728, RK_VITALITYACTIVATION },
- { 12729, RK_FIGHTINGSPIRIT },
- { 12730, RK_ABUNDANCE },
- { 12731, RK_GIANTGROWTH },
- { 12732, RK_STORMBLAST },
- { 12733, RK_STONEHARDSKIN },
- };
-
- int i;
- int skillid;
-
- nullpo_retr(0, sd);
-
- ARR_FIND(0, ARRAYLENGTH(rune2skill_table), i, rune2skill_table[i].runeid == nameid);
- if ( i == ARRAYLENGTH(rune2skill_table) ) {
- ShowError("pc_isUseitem_check_runeskill: rune %d skill not found.\n", nameid);
- return 0;
- }
-
- skillid = rune2skill_table[i].skillid;
- if ( battle_config.rune_block_by_skill && skillnotok(skillid, sd) )
- return 0;
- if ( battle_config.rune_block_by_status && status_skill2sc(skillid) != SC_NONE && sd->sc.data[status_skill2sc(skillid)] )
- return 0;
-
- return 1;
-}
-
-
/*==========================================
* アイテムを使う
*------------------------------------------*/
@@ -3904,11 +3855,6 @@ int pc_cart_additem(struct map_session_data *sd,struct item *item_data,int amoun
return 1;
data = itemdb_search(item_data->nameid);
- if( data->stack.cart && amount > data->stack.amount )
- {// item stack limitation
- return 1;
- }
-
if( !itemdb_cancartstore(item_data, pc_isGM(sd)) )
{ // Check item trade restrictions [Skotlex]
clif_displaymessage (sd->fd, msg_txt(264));
@@ -3929,7 +3875,7 @@ int pc_cart_additem(struct map_session_data *sd,struct item *item_data,int amoun
if( i < MAX_CART )
{// item already in cart, stack it
- if( amount > MAX_AMOUNT - sd->status.cart[i].amount || ( data->stack.cart && amount > data->stack.amount - sd->status.cart[i].amount ) )
+ if(sd->status.cart[i].amount+amount > MAX_AMOUNT)
return 1; // no room
sd->status.cart[i].amount+=amount;
@@ -4575,21 +4521,6 @@ int pc_jobid2mapid(unsigned short b_class)
case JOB_ALCHEMIST: return MAPID_ALCHEMIST;
case JOB_ROGUE: return MAPID_ROGUE;
case JOB_SOUL_LINKER: return MAPID_SOUL_LINKER;
- //3_1 classes
- case JOB_RUNE_KNIGHT: return MAPID_RUNE_KNIGHT;
- case JOB_WARLOCK: return MAPID_WARLOCK;
- case JOB_RANGER: return MAPID_RANGER;
- case JOB_ARCHBISHOP: return MAPID_ARCHBISHOP;
- case JOB_MECHANIC: return MAPID_MECHANIC;
- case JOB_GUILLOTINE_CROSS: return MAPID_GUILLOTINE_CROSS;
- //3_2 classes
- case JOB_ROYAL_GUARD: return MAPID_ROYAL_GUARD;
- case JOB_SORCERER: return MAPID_SORCERER;
- case JOB_MINSTREL:
- 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;
//1st: advanced
case JOB_NOVICE_HIGH: return MAPID_NOVICE_HIGH;
case JOB_SWORDMAN_HIGH: return MAPID_SWORDMAN_HIGH;
@@ -4613,21 +4544,6 @@ int pc_jobid2mapid(unsigned short b_class)
case JOB_CHAMPION: return MAPID_CHAMPION;
case JOB_CREATOR: return MAPID_CREATOR;
case JOB_STALKER: return MAPID_STALKER;
- //3_1 advanced
- case JOB_RUNE_KNIGHT_H: return MAPID_RUNE_KNIGHT_H;
- case JOB_WARLOCK_H: return MAPID_WARLOCK_H;
- case JOB_RANGER_H: return MAPID_RANGER_H;
- case JOB_ARCHBISHOP_H: return MAPID_ARCHBISHOP_H;
- case JOB_MECHANIC_H: return MAPID_MECHANIC_H;
- case JOB_GUILLOTINE_CROSS_H:return MAPID_GUILLOTINE_CROSS_H;
- //3_2 advanced
- case JOB_ROYAL_GUARD_H: return MAPID_ROYAL_GUARD_H;
- case JOB_SORCERER_H: return MAPID_SORCERER_H;
- case JOB_MINSTREL_H:
- case JOB_WANDERER_H: return MAPID_MINSTRELWANDERER_H;
- case JOB_SURA_H: return MAPID_SURA_H;
- case JOB_GENETIC_H: return MAPID_GENETIC_H;
- case JOB_SHADOW_CHASER_H: return MAPID_SHADOW_CHASER_H;
//1-1 baby
case JOB_BABY: return MAPID_BABY;
case JOB_BABY_SWORDMAN: return MAPID_BABY_SWORDMAN;
@@ -4652,21 +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 baby classes
- case JOB_BABY_RUNE: return MAPID_BABY_RUNE;
- case JOB_BABY_WARLOCK: return MAPID_BABY_WARLOCK;
- case JOB_BABY_RANGER: return MAPID_BABY_RANGER;
- case JOB_BABY_BISHOP: return MAPID_BABY_BISHOP;
- case JOB_BABY_MECHANIC: return MAPID_BABY_MECHANIC;
- case JOB_BABY_CROSS: return MAPID_BABY_CROSS;
- //3_2 baby classes
- case JOB_BABY_GUARD: return MAPID_BABY_GUARD;
- case JOB_BABY_SORCERER: return MAPID_BABY_SORCERER;
- case JOB_BABY_WANDERER:
- case JOB_BABY_MINSTREL: return MAPID_BABY_MINSTRELWANDERER;
- case JOB_BABY_SURA: return MAPID_BABY_SURA;
- case JOB_BABY_GENETIC: return MAPID_BABY_GENETIC;
- case JOB_BABY_CHASER: return MAPID_BABY_CHASER;
+ //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;
}
@@ -4708,20 +4639,6 @@ int pc_mapid2jobid(unsigned short class_, int sex)
case MAPID_ALCHEMIST: return JOB_ALCHEMIST;
case MAPID_ROGUE: return JOB_ROGUE;
case MAPID_SOUL_LINKER: return JOB_SOUL_LINKER;
- //3_1 classes
- case MAPID_RUNE_KNIGHT: return JOB_RUNE_KNIGHT;
- case MAPID_WARLOCK: return JOB_WARLOCK;
- case MAPID_RANGER: return JOB_RANGER;
- case MAPID_ARCHBISHOP: return JOB_ARCHBISHOP;
- case MAPID_MECHANIC: return JOB_MECHANIC;
- case MAPID_GUILLOTINE_CROSS:return JOB_GUILLOTINE_CROSS;
- //3_2 classes
- 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;
//1st: advanced
case MAPID_NOVICE_HIGH: return JOB_NOVICE_HIGH;
case MAPID_SWORDMAN_HIGH: return JOB_SWORDMAN_HIGH;
@@ -4744,20 +4661,6 @@ int pc_mapid2jobid(unsigned short class_, int sex)
case MAPID_CHAMPION: return JOB_CHAMPION;
case MAPID_CREATOR: return JOB_CREATOR;
case MAPID_STALKER: return JOB_STALKER;
- //3_1 advanced
- case MAPID_RUNE_KNIGHT_H: return JOB_RUNE_KNIGHT_H;
- case MAPID_WARLOCK_H: return JOB_WARLOCK_H;
- case MAPID_RANGER_H: return JOB_RANGER_H;
- case MAPID_ARCHBISHOP_H: return JOB_ARCHBISHOP_H;
- case MAPID_MECHANIC_H: return JOB_MECHANIC_H;
- case MAPID_GUILLOTINE_CROSS_H: return JOB_GUILLOTINE_CROSS_H;
- //3_2 advanced
- case MAPID_ROYAL_GUARD_H: return JOB_ROYAL_GUARD_H;
- case MAPID_SORCERER_H: return JOB_SORCERER_H;
- case MAPID_MINSTRELWANDERER_H: return sex?JOB_MINSTREL_H:JOB_WANDERER_H;
- case MAPID_SURA_H: return JOB_SURA_H;
- case MAPID_GENETIC_H: return JOB_GENETIC_H;
- case MAPID_SHADOW_CHASER_H: return JOB_SHADOW_CHASER_H;
//1-1 baby
case MAPID_BABY: return JOB_BABY;
case MAPID_BABY_SWORDMAN: return JOB_BABY_SWORDMAN;
@@ -4781,20 +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 baby classes
- case MAPID_BABY_RUNE: return JOB_BABY_RUNE;
- case MAPID_BABY_WARLOCK: return JOB_BABY_WARLOCK;
- case MAPID_BABY_RANGER: return JOB_BABY_RANGER;
- case MAPID_BABY_BISHOP: return JOB_BABY_BISHOP;
- case MAPID_BABY_MECHANIC: return JOB_BABY_MECHANIC;
- case MAPID_BABY_CROSS: return JOB_BABY_CROSS;
- //3_2 baby classes
- case MAPID_BABY_GUARD: return JOB_BABY_GUARD;
- case MAPID_BABY_SORCERER: return JOB_BABY_SORCERER;
- case MAPID_BABY_MINSTRELWANDERER: return sex?JOB_BABY_MINSTREL:JOB_BABY_WANDERER;
- case MAPID_BABY_SURA: return JOB_BABY_SURA;
- case MAPID_BABY_GENETIC: return JOB_BABY_GENETIC;
- case MAPID_BABY_CHASER: return JOB_BABY_CHASER;
+ //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;
}
@@ -4922,86 +4839,9 @@ const char* job_name(int class_)
return msg_txt(617);
case JOB_SOUL_LINKER:
return msg_txt(618);
-
- case JOB_RUNE_KNIGHT:
- case JOB_WARLOCK:
- case JOB_RANGER:
- case JOB_ARCHBISHOP:
- case JOB_MECHANIC:
- case JOB_GUILLOTINE_CROSS:
- return msg_txt(625 - JOB_RUNE_KNIGHT +class_);
-
- case JOB_RUNE_KNIGHT_H:
- case JOB_WARLOCK_H:
- case JOB_RANGER_H:
- case JOB_ARCHBISHOP_H:
- case JOB_MECHANIC_H:
- case JOB_GUILLOTINE_CROSS_H:
- return msg_txt(625 - JOB_RUNE_KNIGHT_H +class_);
-
- case JOB_ROYAL_GUARD:
- case JOB_SORCERER:
- case JOB_MINSTREL:
- case JOB_WANDERER:
- case JOB_SURA:
- case JOB_GENETIC:
- case JOB_SHADOW_CHASER:
- return msg_txt(631 - JOB_ROYAL_GUARD +class_);
-
- case JOB_ROYAL_GUARD_H:
- case JOB_SORCERER_H:
- case JOB_MINSTREL_H:
- case JOB_WANDERER_H:
- case JOB_SURA_H:
- case JOB_GENETIC_H:
- case JOB_SHADOW_CHASER_H:
- return msg_txt(631 - JOB_ROYAL_GUARD_H +class_);
-
- case JOB_RUNE_KNIGHT2:
- case JOB_RUNE_KNIGHT_H2:
- return msg_txt(625);
-
- case JOB_ROYAL_GUARD2:
- case JOB_ROYAL_GUARD_H2:
- return msg_txt(631);
-
- case JOB_RANGER2:
- case JOB_RANGER_H2:
- return msg_txt(627);
-
- case JOB_MECHANIC2:
- case JOB_MECHANIC_H2:
- return msg_txt(629);
-
- case JOB_BABY_RUNE:
- case JOB_BABY_WARLOCK:
- case JOB_BABY_RANGER:
- case JOB_BABY_BISHOP:
- case JOB_BABY_MECHANIC:
- case JOB_BABY_CROSS:
- case JOB_BABY_GUARD:
- case JOB_BABY_SORCERER:
- case JOB_BABY_MINSTREL:
- case JOB_BABY_WANDERER:
- case JOB_BABY_SURA:
- case JOB_BABY_GENETIC:
- case JOB_BABY_CHASER:
- return msg_txt(638 - JOB_BABY_RUNE +class_);
-
- case JOB_BABY_RUNE2:
- return msg_txt(638);
-
- case JOB_BABY_GUARD2:
- return msg_txt(644);
-
- case JOB_BABY_RANGER2:
- return msg_txt(640);
-
- case JOB_BABY_MECHANIC2:
- return msg_txt(642);
-
+
default:
- return msg_txt(651);
+ return msg_txt(650);
}
}
@@ -5150,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;
@@ -5191,7 +5031,6 @@ int pc_gainexp(struct map_session_data *sd, struct block_list *src, unsigned int
{
float nextbp=0, nextjp=0;
unsigned int nextb=0, nextj=0;
- int leveldiff = src ? ( sd->status.base_level - status_get_lv(src) ) : 0, modifier = 100;
nullpo_ret(sd);
if(sd->bl.prev == NULL || pc_isdead(sd))
@@ -5230,52 +5069,6 @@ int pc_gainexp(struct map_session_data *sd, struct block_list *src, unsigned int
}
}
- /*Adjust exp by mob level difference vs player level.
- Higher level creatures give more exp, lower level creatures give less
- and you'll get normal experience if they're very close to your level.
-
- -2 to +5 = 100%
- -3 = 105%
- -4 = 110%
- -5 = 115%
- -6 = 120%
- -7 = 125%
- -8 = 130%
- -9 = 135%
- -10 = 140%
- -11 or lower = 40%
-
- +6 to +10 = 95%
- +11 to +15 = 90%
- +15 to +20 = 85%
- +21 to +25 = 60%
- +26 to +30 = 35%
- +31 or higher = 10% */
-
- if (leveldiff >= 6 && leveldiff <= 10)
- modifier = -5;
- if (leveldiff >= 11 && leveldiff <= 15)
- modifier = -10;
- if (leveldiff >= 16 && leveldiff <= 20)
- modifier = -15;
- if (leveldiff >= 21 && leveldiff <= 25)
- modifier = -40;
- if (leveldiff >= 26 && leveldiff <= 30)
- modifier = -65;
- if (leveldiff > 30)
- modifier = -90;
- if (leveldiff <= -3 && leveldiff >= -10)
- modifier = ((leveldiff * -5)-10);
- if (leveldiff <= -10)
- modifier = -60;
-
- if ( modifier < 0 )
- modifier = modifier * -1;
- if ( modifier != 100 ) {
- base_exp = (int)((float)base_exp - (((float)modifier/100) * (float)base_exp));
- job_exp = (int)((float)job_exp - (((float)modifier/100) * (float)job_exp));
- }
-
//Cap exp to the level up requirement of the previous level when you are at max level, otherwise cap at UINT_MAX (this is required for some S. Novice bonuses). [Skotlex]
if (base_exp) {
nextb = nextb?UINT_MAX:pc_thisbaseexp(sd);
@@ -5410,12 +5203,7 @@ int pc_gets_status_point(int level)
if (battle_config.use_statpoint_table) //Use values from "db/statpoint.txt"
return (statp[level+1] - statp[level]);
else //Default increase
- {
- if (level < 100)
- return ((level+15) / 5);
- else
- return ((level+130) / 10);
- }
+ return ((level+15) / 5);
}
/// Returns the number of stat points needed to change the specified stat by val.
@@ -5429,18 +5217,17 @@ int pc_need_status_point(struct map_session_data* sd, int type, int val)
return 0;
low = pc_getstat(sd,type);
- if ( low >= pc_maxparameter(sd) && val > 0 )
- return 0; // Official servers show '0' when max is reached
high = low + val;
if ( val < 0 )
swap(low, high);
for ( ; low < high; low++ )
- if( low < 100 )
- sp += ( 1 + (low + 9) / 10 );
- else
- sp += ( 16 + 4*((low - 100) / 5) );
+#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;
}
@@ -5789,9 +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, KN_RIDING) ) //RK_DRAGONTRAINING not needed for riding (bug?), assuming KN_RIDING is.
- i&=~OPTION_DRAGON;
-
+ 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);
@@ -6565,13 +6359,6 @@ int pc_itemheal(struct map_session_data *sd,int itemid, int hp,int sp)
sp -= sp * sd->sc.data[SC_CRITICALWOUND]->val2 / 100;
}
- if (sd->sc.data[SC_VITALITYACTIVATION])
- {
- hp += hp * sd->sc.data[SC_VITALITYACTIVATION]->val2 / 100; //HP +50%
- sp -= sp * sd->sc.data[SC_VITALITYACTIVATION]->val3 / 100; //SP -50%
- }
-
-
return status_heal(&sd->bl, hp, sp, 1);
}
@@ -6690,14 +6477,6 @@ int pc_jobchange(struct map_session_data *sd,int job, int upper)
clif_updatestatus(sd,SP_JOBEXP);
clif_updatestatus(sd,SP_NEXTJOBEXP);
- //New job may have new max_parameter, so update stat points needed to raise a stat
- clif_updatestatus(sd,SP_USTR);
- clif_updatestatus(sd,SP_UAGI);
- clif_updatestatus(sd,SP_UVIT);
- clif_updatestatus(sd,SP_UINT);
- clif_updatestatus(sd,SP_UDEX);
- clif_updatestatus(sd,SP_ULUK);
-
for(i=0;i<EQI_MAX;i++) {
if(sd->equip_index[i] >= 0)
if(!pc_isequip(sd,sd->equip_index[i]))
@@ -6726,9 +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, KN_RIDING)) //RK_DRAGONTRAINING not needed for riding (bug?), assuming KN_RIDING is.
+ 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);
@@ -6856,19 +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)) // Knight and Crusader/Royal Guard
- || (type&OPTION_DRAGON && !(p_type&OPTION_DRAGON))) // Rune Knight Dragon
- && (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) //Knight and Crusader/Royal Guard
- || (!(type&OPTION_DRAGON) && p_type&OPTION_DRAGON)) // Rune Knight Dragon
- && (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))
@@ -6885,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)
@@ -6976,29 +6794,13 @@ 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;
}
/*==========================================
- * Enable Riding Dragons for Rune Knight class.
- *------------------------------------------*/
-int pc_setdragon(TBL_PC* sd, int flag, int color)
-{
- int dragon[5] = {OPTION_DRAGON1,OPTION_DRAGON2,OPTION_DRAGON3,OPTION_DRAGON4,OPTION_DRAGON5};
-
- if( flag ){
- if( pc_checkskill(sd,KN_RIDING) > 0 ) //Possible to rent dragons without RK_DRAGONTRAINING; Source, iRO. (Bug?)
- pc_setoption(sd, sd->sc.option|dragon[color]);
- } else if( pc_isdragon(sd) ){
- pc_setoption(sd, sd->sc.option&~OPTION_DRAGON);
- }
-
- return 0;
-}
-/*==========================================
* アイテムドロップ可不可判定
*------------------------------------------*/
int pc_candrop(struct map_session_data *sd,struct item *item)
@@ -8149,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;
@@ -8408,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);
@@ -8427,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 4619af878..16c31e69c 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
@@ -249,7 +252,7 @@ struct map_session_data {
struct { //skillatk raises bonus dmg% of skills, skillheal increases heal%, skillblown increases bonus blewcount for some skills.
unsigned short id;
short val;
- } skillatk[MAX_PC_BONUS], skillheal[5], skillheal2[5], skillblown[MAX_PC_BONUS], skillcast[MAX_PC_BONUS], fixedskillcast[MAX_PC_BONUS];
+ } skillatk[MAX_PC_BONUS], skillheal[5], skillheal2[5], skillblown[MAX_PC_BONUS], skillcast[MAX_PC_BONUS];
struct {
short value;
int rate;
@@ -307,9 +310,9 @@ struct map_session_data {
// zeroed vars end here.
- int castrate,fixedcastrate,delayrate,hprate,sprate,dsprate;
+ int castrate,delayrate,hprate,sprate,dsprate;
int hprecov_rate,sprecov_rate;
- int matk_rate,weapon_matk,equipment_matk;
+ int matk_rate;
int critical_rate,hit_rate,flee_rate,flee2_rate,def_rate,def2_rate,mdef_rate,mdef2_rate;
int itemid;
@@ -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,7 +430,24 @@ struct map_session_data {
unsigned int bg_id;
unsigned short user_font;
- int produce_itemusedid; //used to determine the type of item used when creating items via script.
+ /**
+ * For the Secure NPC Timeout option (check config/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;
@@ -428,7 +455,8 @@ struct map_session_data {
};
//Update this max as necessary. 55 is the value needed for Super Baby currently
-#define MAX_SKILL_TREE 77
+//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)
@@ -528,7 +556,7 @@ enum equip_index {
#define pc_issit(sd) ( (sd)->vd.dead_sit == 2 )
#define pc_isidle(sd) ( (sd)->chatID || (sd)->state.vending || (sd)->state.buyingstore || DIFF_TICK(last_tick, (sd)->idletime) >= battle_config.idle_no_share )
#define pc_istrading(sd) ( (sd)->npc_id || (sd)->state.vending || (sd)->state.buyingstore || (sd)->state.trading )
-#define pc_cant_act(sd) ( (sd)->npc_id || (sd)->state.vending || (sd)->state.buyingstore || (sd)->chatID || ((sd)->sc.opt1 && (sd)->sc.opt1 != OPT1_BURNING) || (sd)->state.trading || (sd)->state.storage_flag )
+#define pc_cant_act(sd) ( (sd)->npc_id || (sd)->state.vending || (sd)->state.buyingstore || (sd)->chatID || (sd)->sc.opt1 || (sd)->state.trading || (sd)->state.storage_flag )
#define pc_setdir(sd,b,h) ( (sd)->ud.dir = (b) ,(sd)->head_dir = (h) )
#define pc_setchatid(sd,n) ( (sd)->chatID = n )
#define pc_ishiding(sd) ( (sd)->sc.option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) )
@@ -540,8 +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_3 ? ((sd)->class_&JOBL_BABY ? battle_config.max_baby_third_parameter : battle_config.max_third_parameter) : ((sd)->class_&JOBL_BABY ? battle_config.max_baby_parameter : battle_config.max_parameter)) )
-#define pc_isdragon(sd) ( (sd)->sc.option&OPTION_DRAGON )
+#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)
@@ -554,8 +586,7 @@ enum equip_index {
( \
( (class_) >= JOB_NOVICE && (class_) < JOB_MAX_BASIC ) \
|| ( (class_) >= JOB_NOVICE_HIGH && (class_) <= JOB_SOUL_LINKER ) \
-|| ( (class_) >= JOB_RUNE_KNIGHT && (class_) <= JOB_MECHANIC_H2 ) \
-|| ( (class_) >= JOB_BABY_RUNE && (class_) < JOB_MAX ) \
+|| ( (class_) >= JOB_RUNE_KNIGHT && (class_) < JOB_MAX ) \
)
int pc_class2idx(int class_);
@@ -667,7 +698,6 @@ int pc_equipitem(struct map_session_data*,int,int);
int pc_unequipitem(struct map_session_data*,int,int);
int pc_checkitem(struct map_session_data*);
int pc_useitem(struct map_session_data*,int);
-int pc_isUseitem_check_runeskill(TBL_PC *sd, int nameid);
int pc_skillatk_bonus(struct map_session_data *sd, int skill_num);
int pc_skillheal_bonus(struct map_session_data *sd, int skill_num);
@@ -686,7 +716,6 @@ int pc_setfalcon(struct map_session_data* sd, int flag);
int pc_setriding(struct map_session_data* sd, int flag);
int pc_changelook(struct map_session_data *,int,int);
int pc_equiplookall(struct map_session_data *sd);
-int pc_setdragon(struct map_session_data* sd, int flag, int color);
int pc_readparam(struct map_session_data*,int);
int pc_setparam(struct map_session_data*,int,int);
@@ -792,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 0f3c09e1e..2ffcad83c 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -171,8 +171,16 @@ enum { LABEL_NEXTLINE=1,LABEL_START };
static unsigned char* script_buf = NULL;
static int script_pos = 0, script_size = 0;
-#define GETVALUE(buf,i) ((int)MakeDWord(MakeWord((buf)[i],(buf)[i+1]),MakeWord((buf)[i+2],0)))
-#define SETVALUE(buf,i,n) ((buf)[i]=GetByte(n,0),(buf)[i+1]=GetByte(n,1),(buf)[i+2]=GetByte(n,2))
+static inline int GETVALUE(const unsigned char* buf, int i)
+{
+ return (int)MakeDWord(MakeWord(buf[i], buf[i+1]), MakeWord(buf[i+2], 0));
+}
+static inline void SETVALUE(unsigned char* buf, int i, int n)
+{
+ buf[i] = GetByte(n, 0);
+ buf[i+1] = GetByte(n, 1);
+ buf[i+2] = GetByte(n, 2);
+}
// String buffer structures.
// str_data stores string information
@@ -317,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,
@@ -3357,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 config/Secure.h) [RR]
+ **/
+ #if SECURE_NPCTIMEOUT
+ /**
+ * We're done with this NPC session, so we cancel the timer (if existent) and move on
+ **/
+ if( sd->npc_idle_timer != INVALID_TIMER ) {
+ delete_timer(sd->npc_idle_timer,npc_rr_secure_timeout_timer);
+ sd->npc_idle_timer = INVALID_TIMER;
+ }
+ #endif
if(st->bk_st)
{
//Remove tag for removal.
@@ -3399,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 config/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
}
}
@@ -7022,8 +7052,7 @@ BUILDIN_FUNC(bonus)
case SP_ADD_SKILL_BLOW:
case SP_CASTRATE:
case SP_ADDEFF_ONSKILL:
- case SP_FIXEDCASTRATE:
- // these bonuses support skill names
+ // these bonuses support skill names
val1 = ( script_isstring(st,3) ? skill_name2id(script_getstr(st,3)) : script_getnum(st,3) );
break;
default:
@@ -7426,7 +7455,7 @@ BUILDIN_FUNC(setoption)
flag = script_getnum(st,3);
else if( !option ){// Request to remove everything.
flag = 0;
- option = OPTION_CART|OPTION_FALCON|OPTION_RIDING|OPTION_DRAGON;
+ option = OPTION_CART|OPTION_FALCON|OPTION_RIDING;
}
if( flag ){// Add option
if( option&OPTION_WEDDING && !battle_config.wedding_modifydisplay )
@@ -7542,7 +7571,7 @@ BUILDIN_FUNC(checkriding)
if( sd == NULL )
return 0;// no player attached, report source
- if( pc_isriding(sd) || pc_isdragon(sd) )
+ if( pc_isriding(sd) || sd->sc.option&OPTION_MOUNTING )
script_pushint(st, 1);
else
script_pushint(st, 0);
@@ -7571,31 +7600,6 @@ BUILDIN_FUNC(setriding)
return 0;
}
-/// Sets if the player is riding a dragon.
-/// <flag> defaults to 1
-/// <color> defaults to 0
-///
-/// setdragon <flag>{,<color>};
-/// setdragon <flag>;
-/// setdragon;
-BUILDIN_FUNC(setdragon)
-{
- int flag = 1, color = 0;
- TBL_PC* sd;
-
- sd = script_rid2sd(st);
- if( sd == NULL )
- return 0;// no player attached, report source
-
- if( script_hasdata(st,2) )
- flag = script_getnum(st,2);
- if( script_hasdata(st,3) )
- color = cap_value(script_getnum(st,3),0,4);
-
- pc_setdragon(sd, flag, color);
- return 0;
-}
-
/// Sets the save point of the player.
///
/// save "<map name>",<x>,<y>
@@ -7787,31 +7791,9 @@ BUILDIN_FUNC(produce)
sd = script_rid2sd(st);
if( sd == NULL )
return 0;
-
- if( script_hasdata(st,3) )
- { // only used with Rune Knights RK_RUNEMASTERY as part of the calculation.
- struct item_data* id = NULL;
- struct script_data* data;
-
- data = script_getdata(st,3);
- get_val(st, data);
-
- if( data_isstring(data) )
- id = itemdb_searchname(conv_str(st, data));
- else
- id = itemdb_exists(conv_num(st, data));
-
- if( id == NULL )
- {
- ShowError("buildin_produce: Invalid item '%s'.\n", script_getstr(st,3));
- return 1;
- }
- else
- sd->produce_itemusedid = id->nameid;
- }
trigger=script_getnum(st,2);
- clif_skill_produce_mix_list(sd, trigger);
+ clif_skill_produce_mix_list(sd, -1, trigger);
return 0;
}
/*==========================================
@@ -9186,7 +9168,7 @@ BUILDIN_FUNC(roclass)
}
/*==========================================
- *携帯卵孵化機使用
+ * Tells client to open a hatching window, used for pet incubator
*------------------------------------------*/
BUILDIN_FUNC(birthpet)
{
@@ -9634,6 +9616,7 @@ BUILDIN_FUNC(getmapflag)
switch(i) {
case MF_NOMEMO: script_pushint(st,map[m].flag.nomemo); break;
case MF_NOTELEPORT: script_pushint(st,map[m].flag.noteleport); break;
+ case MF_NOSAVE: script_pushint(st,map[m].flag.nosave); break;
case MF_NOBRANCH: script_pushint(st,map[m].flag.nobranch); break;
case MF_NOPENALTY: script_pushint(st,map[m].flag.noexppenalty); break;
case MF_NOZENYPENALTY: script_pushint(st,map[m].flag.nozenypenalty); break;
@@ -9642,23 +9625,26 @@ BUILDIN_FUNC(getmapflag)
case MF_PVP_NOGUILD: script_pushint(st,map[m].flag.pvp_noguild); break;
case MF_GVG: script_pushint(st,map[m].flag.gvg); break;
case MF_GVG_NOPARTY: script_pushint(st,map[m].flag.gvg_noparty); break;
- case MF_GVG_DUNGEON: script_pushint(st,map[m].flag.gvg_dungeon); break;
- case MF_GVG_CASTLE: script_pushint(st,map[m].flag.gvg_castle); break;
case MF_NOTRADE: script_pushint(st,map[m].flag.notrade); break;
- case MF_NODROP: script_pushint(st,map[m].flag.nodrop); break;
case MF_NOSKILL: script_pushint(st,map[m].flag.noskill); break;
case MF_NOWARP: script_pushint(st,map[m].flag.nowarp); break;
+ case MF_PARTYLOCK: script_pushint(st,map[m].flag.partylock); break;
case MF_NOICEWALL: script_pushint(st,map[m].flag.noicewall); break;
case MF_SNOW: script_pushint(st,map[m].flag.snow); break;
- case MF_CLOUDS: script_pushint(st,map[m].flag.clouds); break;
- case MF_CLOUDS2: script_pushint(st,map[m].flag.clouds2); break;
case MF_FOG: script_pushint(st,map[m].flag.fog); break;
- 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;
- case MF_NIGHTENABLED: script_pushint(st,map[m].flag.nightenabled); 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_NOGO: script_pushint(st,map[m].flag.nogo); break;
+ case MF_CLOUDS: script_pushint(st,map[m].flag.clouds); break;
+ case MF_CLOUDS2: script_pushint(st,map[m].flag.clouds2); break;
+ case MF_FIREWORKS: script_pushint(st,map[m].flag.fireworks); break;
+ case MF_GVG_CASTLE: script_pushint(st,map[m].flag.gvg_castle); break;
+ case MF_GVG_DUNGEON: script_pushint(st,map[m].flag.gvg_dungeon); break;
+ case MF_NIGHTENABLED: script_pushint(st,map[m].flag.nightenabled); break;
case MF_NOBASEEXP: script_pushint(st,map[m].flag.nobaseexp); break;
case MF_NOJOBEXP: script_pushint(st,map[m].flag.nojobexp); break;
case MF_NOMOBLOOT: script_pushint(st,map[m].flag.nomobloot); break;
@@ -9668,12 +9654,13 @@ BUILDIN_FUNC(getmapflag)
case MF_NIGHTMAREDROP: script_pushint(st,map[m].flag.pvp_nightmaredrop); break;
case MF_RESTRICTED: script_pushint(st,map[m].flag.restricted); break;
case MF_NOCOMMAND: script_pushint(st,map[m].nocommand); break;
+ case MF_NODROP: script_pushint(st,map[m].flag.nodrop); break;
case MF_JEXP: script_pushint(st,map[m].jexp); break;
case MF_BEXP: script_pushint(st,map[m].bexp); break;
case MF_NOVENDING: script_pushint(st,map[m].flag.novending); break;
case MF_LOADEVENT: script_pushint(st,map[m].flag.loadevent); break;
case MF_NOCHAT: script_pushint(st,map[m].flag.nochat); break;
- case MF_PARTYLOCK: script_pushint(st,map[m].flag.partylock); break;
+ case MF_NOEXPPENALTY: script_pushint(st,map[m].flag.noexppenalty ); break;
case MF_GUILDLOCK: script_pushint(st,map[m].flag.guildlock); break;
case MF_TOWN: script_pushint(st,map[m].flag.town); break;
case MF_AUTOTRADE: script_pushint(st,map[m].flag.autotrade); break;
@@ -9681,7 +9668,7 @@ BUILDIN_FUNC(getmapflag)
case MF_MONSTER_NOTELEPORT: script_pushint(st,map[m].flag.monster_noteleport); break;
case MF_PVP_NOCALCRANK: script_pushint(st,map[m].flag.pvp_nocalcrank); break;
case MF_BATTLEGROUND: script_pushint(st,map[m].flag.battleground); break;
- case MF_RESET: script_pushint(st,map[m].flag.reset); break;
+ case MF_RESET: script_pushint(st,map[m].flag.reset); break;
}
}
@@ -9702,56 +9689,61 @@ BUILDIN_FUNC(setmapflag)
m = map_mapname2mapid(str);
if(m >= 0) {
switch(i) {
- case MF_NOMEMO: map[m].flag.nomemo=1; break;
- case MF_NOTELEPORT: map[m].flag.noteleport=1; break;
- case MF_NOBRANCH: map[m].flag.nobranch=1; break;
- case MF_NOPENALTY: map[m].flag.noexppenalty=1; map[m].flag.nozenypenalty=1; break;
- case MF_NOZENYPENALTY: map[m].flag.nozenypenalty=1; break;
- case MF_PVP: map[m].flag.pvp=1; break;
- case MF_PVP_NOPARTY: map[m].flag.pvp_noparty=1; break;
- case MF_PVP_NOGUILD: map[m].flag.pvp_noguild=1; break;
- case MF_GVG: map[m].flag.gvg=1; break;
- case MF_GVG_NOPARTY: map[m].flag.gvg_noparty=1; break;
- case MF_GVG_DUNGEON: map[m].flag.gvg_dungeon=1; break;
- case MF_GVG_CASTLE: map[m].flag.gvg_castle=1; break;
- case MF_NOTRADE: map[m].flag.notrade=1; break;
- case MF_NODROP: map[m].flag.nodrop=1; break;
- case MF_NOSKILL: map[m].flag.noskill=1; break;
- case MF_NOWARP: map[m].flag.nowarp=1; break;
- case MF_NOICEWALL: map[m].flag.noicewall=1; break;
- case MF_SNOW: map[m].flag.snow=1; break;
- case MF_CLOUDS: map[m].flag.clouds=1; break;
- case MF_CLOUDS2: map[m].flag.clouds2=1; break;
- case MF_FOG: map[m].flag.fog=1; break;
- 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;
- 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;
- case MF_NOJOBEXP: map[m].flag.nojobexp=1; break;
- case MF_NOMOBLOOT: map[m].flag.nomobloot=1; break;
- case MF_NOMVPLOOT: map[m].flag.nomvploot=1; break;
- case MF_NORETURN: map[m].flag.noreturn=1; break;
- case MF_NOWARPTO: map[m].flag.nowarpto=1; break;
- case MF_NIGHTMAREDROP: map[m].flag.pvp_nightmaredrop=1; break;
- case MF_RESTRICTED: map[m].flag.restricted=1; break;
+ case MF_NOMEMO: map[m].flag.nomemo = 1; break;
+ case MF_NOTELEPORT: map[m].flag.noteleport = 1; break;
+ case MF_NOSAVE: map[m].flag.nosave = 1; break;
+ case MF_NOBRANCH: map[m].flag.nobranch = 1; break;
+ case MF_NOPENALTY: map[m].flag.noexppenalty = 1; map[m].flag.nozenypenalty = 1; break;
+ case MF_NOZENYPENALTY: map[m].flag.nozenypenalty = 1; break;
+ case MF_PVP: map[m].flag.pvp = 1; break;
+ case MF_PVP_NOPARTY: map[m].flag.pvp_noparty = 1; break;
+ case MF_PVP_NOGUILD: map[m].flag.pvp_noguild = 1; break;
+ case MF_GVG: map[m].flag.gvg = 1; break;
+ case MF_GVG_NOPARTY: map[m].flag.gvg_noparty = 1; break;
+ case MF_NOTRADE: map[m].flag.notrade = 1; break;
+ case MF_NOSKILL: map[m].flag.noskill = 1; break;
+ case MF_NOWARP: map[m].flag.nowarp = 1; break;
+ case MF_PARTYLOCK: map[m].flag.partylock = 1; break;
+ case MF_NOICEWALL: map[m].flag.noicewall = 1; break;
+ case MF_SNOW: map[m].flag.snow = 1; break;
+ case MF_FOG: map[m].flag.fog = 1; break;
+ case MF_SAKURA: map[m].flag.sakura = 1; break;
+ case MF_LEAVES: map[m].flag.leaves = 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_NOGO: map[m].flag.nogo = 1; break;
+ case MF_CLOUDS: map[m].flag.clouds = 1; break;
+ case MF_CLOUDS2: map[m].flag.clouds2 = 1; break;
+ case MF_FIREWORKS: map[m].flag.fireworks = 1; break;
+ case MF_GVG_CASTLE: map[m].flag.gvg_castle = 1; break;
+ case MF_GVG_DUNGEON: map[m].flag.gvg_dungeon = 1; break;
+ case MF_NIGHTENABLED: map[m].flag.nightenabled = 1; break;
+ case MF_NOBASEEXP: map[m].flag.nobaseexp = 1; break;
+ case MF_NOJOBEXP: map[m].flag.nojobexp = 1; break;
+ case MF_NOMOBLOOT: map[m].flag.nomobloot = 1; break;
+ case MF_NOMVPLOOT: map[m].flag.nomvploot = 1; break;
+ case MF_NORETURN: map[m].flag.noreturn = 1; break;
+ case MF_NOWARPTO: map[m].flag.nowarpto = 1; break;
+ case MF_NIGHTMAREDROP: map[m].flag.pvp_nightmaredrop = 1; break;
+ case MF_RESTRICTED: map[m].flag.restricted = 1; break;
case MF_NOCOMMAND: map[m].nocommand = (!val || atoi(val) <= 0) ? 100 : atoi(val); break;
+ case MF_NODROP: map[m].flag.nodrop = 1; break;
case MF_JEXP: map[m].jexp = (!val || atoi(val) < 0) ? 100 : atoi(val); break;
case MF_BEXP: map[m].bexp = (!val || atoi(val) < 0) ? 100 : atoi(val); break;
- case MF_NOVENDING: map[m].flag.novending=1; break;
- case MF_LOADEVENT: map[m].flag.loadevent=1; break;
- case MF_NOCHAT: map[m].flag.nochat=1; break;
- case MF_PARTYLOCK: map[m].flag.partylock=1; break;
- case MF_GUILDLOCK: map[m].flag.guildlock=1; break;
- case MF_TOWN: map[m].flag.town=1; break;
- case MF_AUTOTRADE: map[m].flag.autotrade=1; break;
- case MF_ALLOWKS: map[m].flag.allowks=1; break;
- case MF_MONSTER_NOTELEPORT: map[m].flag.monster_noteleport=1; break;
- case MF_PVP_NOCALCRANK: map[m].flag.pvp_nocalcrank=1; break;
- case MF_BATTLEGROUND: map[m].flag.battleground = (!val || atoi(val) < 0 || atoi(val) > 2) ? 1 : atoi(val); break;
- case MF_RESET: map[m].flag.reset=1; break;
+ case MF_NOVENDING: map[m].flag.novending = 1; break;
+ case MF_LOADEVENT: map[m].flag.loadevent = 1; break;
+ case MF_NOCHAT: map[m].flag.nochat = 1; break;
+ case MF_NOEXPPENALTY: map[m].flag.noexppenalty = 1; break;
+ case MF_GUILDLOCK: map[m].flag.guildlock = 1; break;
+ case MF_TOWN: map[m].flag.town = 1; break;
+ case MF_AUTOTRADE: map[m].flag.autotrade = 1; break;
+ case MF_ALLOWKS: map[m].flag.allowks = 1; break;
+ case MF_MONSTER_NOTELEPORT: map[m].flag.monster_noteleport = 1; break;
+ case MF_PVP_NOCALCRANK: map[m].flag.pvp_nocalcrank = 1; break;
+ case MF_BATTLEGROUND: (!val || atoi(val) < 0 || atoi(val) > 2) ? 1 : atoi(val); break;
+ case MF_RESET: map[m].flag.reset = 1; break;
}
}
@@ -9768,57 +9760,61 @@ BUILDIN_FUNC(removemapflag)
m = map_mapname2mapid(str);
if(m >= 0) {
switch(i) {
- case MF_NOMEMO: map[m].flag.nomemo=0; break;
- case MF_NOTELEPORT: map[m].flag.noteleport=0; break;
- case MF_NOSAVE: map[m].flag.nosave=0; break;
- case MF_NOBRANCH: map[m].flag.nobranch=0; break;
- case MF_NOPENALTY: map[m].flag.noexppenalty=0; map[m].flag.nozenypenalty=0; break;
- case MF_PVP: map[m].flag.pvp=0; break;
- case MF_PVP_NOPARTY: map[m].flag.pvp_noparty=0; break;
- case MF_PVP_NOGUILD: map[m].flag.pvp_noguild=0; break;
- case MF_GVG: map[m].flag.gvg=0; break;
- case MF_GVG_NOPARTY: map[m].flag.gvg_noparty=0; break;
- case MF_GVG_DUNGEON: map[m].flag.gvg_dungeon=0; break;
- case MF_GVG_CASTLE: map[m].flag.gvg_castle=0; break;
- case MF_NOZENYPENALTY: map[m].flag.nozenypenalty=0; break;
- case MF_NOTRADE: map[m].flag.notrade=0; break;
- case MF_NODROP: map[m].flag.nodrop=0; break;
- case MF_NOSKILL: map[m].flag.noskill=0; break;
- case MF_NOWARP: map[m].flag.nowarp=0; break;
- case MF_NOICEWALL: map[m].flag.noicewall=0; break;
- case MF_SNOW: map[m].flag.snow=0; break;
- case MF_CLOUDS: map[m].flag.clouds=0; break;
- case MF_CLOUDS2: map[m].flag.clouds2=0; break;
- case MF_FOG: map[m].flag.fog=0; break;
- 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;
- 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;
- case MF_NOJOBEXP: map[m].flag.nojobexp=0; break;
- case MF_NOMOBLOOT: map[m].flag.nomobloot=0; break;
- case MF_NOMVPLOOT: map[m].flag.nomvploot=0; break;
- case MF_NORETURN: map[m].flag.noreturn=0; break;
- case MF_NOWARPTO: map[m].flag.nowarpto=0; break;
- case MF_NIGHTMAREDROP: map[m].flag.pvp_nightmaredrop=0; break;
- case MF_RESTRICTED: map[m].flag.restricted=0; break;
- case MF_NOCOMMAND: map[m].nocommand=0; break;
- case MF_JEXP: map[m].jexp=100; break;
- case MF_BEXP: map[m].bexp=100; break;
- case MF_NOVENDING: map[m].flag.novending=0; break;
- case MF_LOADEVENT: map[m].flag.loadevent=0; break;
- case MF_NOCHAT: map[m].flag.nochat=0; break;
- case MF_PARTYLOCK: map[m].flag.partylock=0; break;
- case MF_GUILDLOCK: map[m].flag.guildlock=0; break;
- case MF_TOWN: map[m].flag.town=0; break;
- case MF_AUTOTRADE: map[m].flag.autotrade=0; break;
- case MF_ALLOWKS: map[m].flag.allowks=0; break;
- case MF_MONSTER_NOTELEPORT: map[m].flag.monster_noteleport=0; break;
- case MF_PVP_NOCALCRANK: map[m].flag.pvp_nocalcrank=0; break;
- case MF_BATTLEGROUND: map[m].flag.battleground=0; break;
- case MF_RESET: map[m].flag.reset=0; break;
+ case MF_NOMEMO: map[m].flag.nomemo = 0; break;
+ case MF_NOTELEPORT: map[m].flag.noteleport = 0; break;
+ case MF_NOSAVE: map[m].flag.nosave = 0; break;
+ case MF_NOBRANCH: map[m].flag.nobranch = 0; break;
+ case MF_NOPENALTY: map[m].flag.noexppenalty = 0; map[m].flag.nozenypenalty = 0; break;
+ case MF_NOZENYPENALTY: map[m].flag.nozenypenalty = 0; break;
+ case MF_PVP: map[m].flag.pvp = 0; break;
+ case MF_PVP_NOPARTY: map[m].flag.pvp_noparty = 0; break;
+ case MF_PVP_NOGUILD: map[m].flag.pvp_noguild = 0; break;
+ case MF_GVG: map[m].flag.gvg = 0; break;
+ case MF_GVG_NOPARTY: map[m].flag.gvg_noparty = 0; break;
+ case MF_NOTRADE: map[m].flag.notrade = 0; break;
+ case MF_NOSKILL: map[m].flag.noskill = 0; break;
+ case MF_NOWARP: map[m].flag.nowarp = 0; break;
+ case MF_PARTYLOCK: map[m].flag.partylock = 0; break;
+ case MF_NOICEWALL: map[m].flag.noicewall = 0; break;
+ case MF_SNOW: map[m].flag.snow = 0; break;
+ case MF_FOG: map[m].flag.fog = 0; break;
+ case MF_SAKURA: map[m].flag.sakura = 0; break;
+ case MF_LEAVES: map[m].flag.leaves = 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_NOGO: map[m].flag.nogo = 0; break;
+ case MF_CLOUDS: map[m].flag.clouds = 0; break;
+ case MF_CLOUDS2: map[m].flag.clouds2 = 0; break;
+ case MF_FIREWORKS: map[m].flag.fireworks = 0; break;
+ case MF_GVG_CASTLE: map[m].flag.gvg_castle = 0; break;
+ case MF_GVG_DUNGEON: map[m].flag.gvg_dungeon = 0; break;
+ case MF_NIGHTENABLED: map[m].flag.nightenabled = 0; break;
+ case MF_NOBASEEXP: map[m].flag.nobaseexp = 0; break;
+ case MF_NOJOBEXP: map[m].flag.nojobexp = 0; break;
+ case MF_NOMOBLOOT: map[m].flag.nomobloot = 0; break;
+ case MF_NOMVPLOOT: map[m].flag.nomvploot = 0; break;
+ case MF_NORETURN: map[m].flag.noreturn = 0; break;
+ case MF_NOWARPTO: map[m].flag.nowarpto = 0; break;
+ case MF_NIGHTMAREDROP: map[m].flag.pvp_nightmaredrop = 0; break;
+ case MF_RESTRICTED: map[m].flag.restricted = 0; break;
+ case MF_NOCOMMAND: map[m].nocommand = 0; break;
+ case MF_NODROP: map[m].flag.nodrop = 0; break;
+ case MF_JEXP: map[m].jexp = 0; break;
+ case MF_BEXP: map[m].bexp = 0; break;
+ case MF_NOVENDING: map[m].flag.novending = 0; break;
+ case MF_LOADEVENT: map[m].flag.loadevent = 0; break;
+ case MF_NOCHAT: map[m].flag.nochat = 0; break;
+ case MF_NOEXPPENALTY: map[m].flag.noexppenalty = 0; break;
+ case MF_GUILDLOCK: map[m].flag.guildlock = 0; break;
+ case MF_TOWN: map[m].flag.town = 0; break;
+ case MF_AUTOTRADE: map[m].flag.autotrade = 0; break;
+ case MF_ALLOWKS: map[m].flag.allowks = 0; break;
+ case MF_MONSTER_NOTELEPORT: map[m].flag.monster_noteleport = 0; break;
+ case MF_PVP_NOCALCRANK: map[m].flag.pvp_nocalcrank = 0; break;
+ case MF_BATTLEGROUND: map[m].flag.battleground = 0; break;
+ case MF_RESET: map[m].flag.reset = 0; break;
}
}
@@ -12583,6 +12579,792 @@ BUILDIN_FUNC(charisalpha)
return 0;
}
+//=======================================================
+// charisupper <str>, <index>
+//-------------------------------------------------------
+BUILDIN_FUNC(charisupper)
+{
+ const char *str = script_getstr(st,2);
+ int pos = script_getnum(st,3);
+
+ int val = ( str && pos >= 0 && (unsigned int)pos < strlen(str) ) ? ISUPPER( str[pos] ) : 0;
+
+ script_pushint(st,val);
+ return 0;
+}
+
+//=======================================================
+// charislower <str>, <index>
+//-------------------------------------------------------
+BUILDIN_FUNC(charislower)
+{
+ const char *str = script_getstr(st,2);
+ int pos = script_getnum(st,3);
+
+ int val = ( str && pos >= 0 && (unsigned int)pos < strlen(str) ) ? ISLOWER( str[pos] ) : 0;
+
+ script_pushint(st,val);
+ return 0;
+}
+
+//=======================================================
+// charat <str>, <index>
+//-------------------------------------------------------
+BUILDIN_FUNC(charat)
+{
+ const char *str = script_getstr(st,2);
+ int pos = script_getnum(st,3);
+ char *output;
+
+ output = (char*)aMallocA(2*sizeof(char));
+ output[0] = '\0';
+
+ if(str && pos >= 0 && (unsigned int)pos < strlen(str))
+ sprintf(output, "%c", str[pos]);
+
+ script_pushstr(st, output);
+ return 0;
+}
+
+//=======================================================
+// setchar <string>, <char>, <index>
+//-------------------------------------------------------
+BUILDIN_FUNC(setchar)
+{
+ const char *str = script_getstr(st,2);
+ const char *c = script_getstr(st,3);
+ int index = script_getnum(st,4);
+ char *output;
+ size_t len = strlen(str);
+
+ output = (char*)aMallocA(len + 1);
+ memcpy(output, str, len);
+ output[len] = '\0';
+
+ if(index >= 0 && index < len)
+ output[index] = c[0];
+
+ script_pushstr(st, output);
+ return 0;
+}
+
+//=======================================================
+// insertchar <string>, <char>, <index>
+//-------------------------------------------------------
+BUILDIN_FUNC(insertchar)
+{
+ const char *str = script_getstr(st,2);
+ const char *c = script_getstr(st,3);
+ int index = script_getnum(st,4);
+ char *output;
+ size_t len = strlen(str);
+
+ if(index < 0)
+ index = 0;
+ else if(index > len)
+ index = len;
+
+ output = (char*)aMallocA(len + 2);
+
+ memcpy(output, str, index);
+ output[index] = c[0];
+ memcpy(&output[index+1], &str[index], len - index);
+ output[len+1] = '\0';
+
+ script_pushstr(st, output);
+ return 0;
+}
+
+//=======================================================
+// delchar <string>, <index>
+//-------------------------------------------------------
+BUILDIN_FUNC(delchar)
+{
+ const char *str = script_getstr(st,2);
+ int index = script_getnum(st,3);
+ char *output;
+ size_t len = strlen(str);
+
+ if(index < 0 || index > len) {
+ //return original
+ ++len;
+ output = (char*)aMallocA(len);
+ memcpy(output, str, len);
+ script_pushstr(st, output);
+ return 0;
+ }
+
+ output = (char*)aMallocA(len);
+
+ memcpy(output, str, index);
+ memcpy(&output[index], &str[index+1], len - index);
+
+ script_pushstr(st, output);
+ return 0;
+}
+
+//=======================================================
+// strtoupper <str>
+//-------------------------------------------------------
+BUILDIN_FUNC(strtoupper)
+{
+ const char *str = script_getstr(st,2);
+ char *output;
+ int i = 0;
+
+ output = (char*)aMallocA(strlen(str) + 1);
+
+ while(str[i] != '\0')
+ output[i++] = TOUPPER(str[i]);
+ output[i] = '\0';
+
+ script_pushstr(st, output);
+ return 0;
+}
+
+//=======================================================
+// strtolower <str>
+//-------------------------------------------------------
+BUILDIN_FUNC(strtolower)
+{
+ const char *str = script_getstr(st,2);
+ char *output;
+ int i = 0;
+
+ output = (char*)aMallocA(strlen(str) + 1);
+
+ while(str[i] != '\0')
+ output[i++] = TOLOWER(str[i]);
+ output[i] = '\0';
+
+ script_pushstr(st, output);
+ return 0;
+}
+
+//=======================================================
+// substr <str>, <start>, <end>
+//-------------------------------------------------------
+BUILDIN_FUNC(substr)
+{
+ const char *str = script_getstr(st,2);
+ char *output;
+ int start = script_getnum(st,3);
+ int end = script_getnum(st,4);
+
+ int len = 0;
+
+ if(start >= 0 && end < strlen(str) && start <= end) {
+ len = end - start + 1;
+ output = (char*)aMallocA(len + 1);
+ memcpy(output, &str[start], len);
+ } else
+ output = (char*)aMallocA(1);
+
+ output[len] = '\0';
+
+ script_pushstr(st, output);
+ return 0;
+}
+
+//=======================================================
+// explode <dest_string_array>, <str>, <delimiter>
+// Note: delimiter is limited to 1 char
+//-------------------------------------------------------
+BUILDIN_FUNC(explode)
+{
+ struct script_data* data = script_getdata(st, 2);
+ const char *str = script_getstr(st,3);
+ const char delimiter = script_getstr(st, 4)[0];
+ int32 id;
+ size_t len = strlen(str);
+ int i = 0, j = 0;
+ int start;
+
+
+ char *temp;
+ const char* name;
+
+ TBL_PC* sd = NULL;
+
+ temp = (char*)aMallocA(len + 1);
+
+ if( !data_isreference(data) )
+ {
+ ShowError("script:explode: not a variable\n");
+ script_reportdata(data);
+ st->state = END;
+ return 1;// not a variable
+ }
+
+ id = reference_getid(data);
+ start = reference_getindex(data);
+ name = reference_getname(data);
+
+ if( not_array_variable(*name) )
+ {
+ ShowError("script:explode: illegal scope\n");
+ script_reportdata(data);
+ st->state = END;
+ return 1;// not supported
+ }
+
+ if( !is_string_variable(name) )
+ {
+ ShowError("script:explode: not string array\n");
+ script_reportdata(data);
+ st->state = END;
+ return 1;// data type mismatch
+ }
+
+ if( not_server_variable(*name) )
+ {
+ sd = script_rid2sd(st);
+ if( sd == NULL )
+ return 0;// no player attached
+ }
+
+ while(str[i] != '\0') {
+ if(str[i] == delimiter && start < 127) { //break at delimiter but ignore after reaching last array index
+ temp[j] = '\0';
+ set_reg(st, sd, reference_uid(id, start++), name, (void*)temp, reference_getref(data));
+ j = 0;
+ ++i;
+ } else {
+ temp[j++] = str[i++];
+ }
+ }
+ //set last string
+ temp[j] = '\0';
+ set_reg(st, sd, reference_uid(id, start), name, (void*)temp, reference_getref(data));
+
+ aFree(temp);
+ return 0;
+}
+
+//=======================================================
+// implode <string_array>
+// implode <string_array>, <glue>
+//-------------------------------------------------------
+BUILDIN_FUNC(implode)
+{
+ struct script_data* data = script_getdata(st, 2);
+ const char *glue = NULL, *name, *temp;
+ int32 glue_len = 0, array_size, id;
+ size_t len = 0;
+ int i, k = 0;
+
+ TBL_PC* sd = NULL;
+
+ char *output;
+
+ if( !data_isreference(data) )
+ {
+ ShowError("script:implode: not a variable\n");
+ script_reportdata(data);
+ st->state = END;
+ return 1;// not a variable
+ }
+
+ id = reference_getid(data);
+ name = reference_getname(data);
+
+ if( not_array_variable(*name) )
+ {
+ ShowError("script:implode: illegal scope\n");
+ script_reportdata(data);
+ st->state = END;
+ return 1;// not supported
+ }
+
+ if( !is_string_variable(name) )
+ {
+ ShowError("script:implode: not string array\n");
+ script_reportdata(data);
+ st->state = END;
+ return 1;// data type mismatch
+ }
+
+ if( not_server_variable(*name) )
+ {
+ sd = script_rid2sd(st);
+ if( sd == NULL )
+ return 0;// no player attached
+ }
+
+ //count chars
+ array_size = getarraysize(st, id, reference_getindex(data), is_string_variable(name), reference_getref(data)) - 1;
+
+ if(array_size == -1) //empty array check (AmsTaff)
+ {
+ ShowWarning("script:implode: array length = 0\n");
+ output = (char*)aMallocA(sizeof(char)*5);
+ sprintf(output,"%s","NULL");
+ } else {
+ for(i = 0; i <= array_size; ++i) {
+ temp = (char*) get_val2(st, reference_uid(id, i), reference_getref(data));
+ len += strlen(temp);
+ script_removetop(st, -1, 0);
+ }
+
+ //allocate mem
+ if( script_hasdata(st,3) ) {
+ glue = script_getstr(st,3);
+ glue_len = strlen(glue);
+ len += glue_len * (array_size);
+ }
+ output = (char*)aMallocA(len + 1);
+
+ //build output
+ for(i = 0; i < array_size; ++i) {
+ temp = (char*) get_val2(st, reference_uid(id, i), reference_getref(data));
+ len = strlen(temp);
+ memcpy(&output[k], temp, len);
+ k += len;
+ if(glue_len != 0) {
+ memcpy(&output[k], glue, glue_len);
+ k += glue_len;
+ }
+ script_removetop(st, -1, 0);
+ }
+ temp = (char*) get_val2(st, reference_uid(id, array_size), reference_getref(data));
+ len = strlen(temp);
+ memcpy(&output[k], temp, len);
+ k += len;
+ script_removetop(st, -1, 0);
+
+ output[k] = '\0';
+ }
+
+ script_pushstr(st, output);
+ return 0;
+}
+
+//=======================================================
+// sprintf(<format>, ...);
+// Implements C sprintf, except format %n. The resulting string is
+// returned, instead of being saved in variable by reference.
+//-------------------------------------------------------
+BUILDIN_FUNC(sprintf)
+{
+ unsigned int len, argc = 0, arg = 0, buf2_len = 0;
+ const char* format;
+ char* p;
+ char* q;
+ char* buf = NULL;
+ char* buf2 = NULL;
+ struct script_data* data;
+ StringBuf final_buf;
+
+ // Fetch init data
+ format = script_getstr(st, 2);
+ argc = script_lastdata(st)-2;
+ len = strlen(format);
+
+ // Skip parsing, where no parsing is required.
+ if(len==0){
+ script_pushconststr(st,"");
+ return 0;
+ }
+
+ // Pessimistic alloc
+ CREATE(buf, char, len+1);
+
+ // Need not be parsed, just solve stuff like %%.
+ if(argc==0){
+ sprintf(buf, format);
+ script_pushstrcopy(st, buf);
+ aFree(buf);
+ return 0;
+ }
+
+ safestrncpy(buf, format, len+1);
+
+ // Issue sprintf for each parameter
+ StringBuf_Init(&final_buf);
+ q = buf;
+ while((p = strchr(q, '%'))!=NULL){
+ if(p!=q){
+ len = p-q+1;
+ if(buf2_len<len){
+ RECREATE(buf2, char, len);
+ buf2_len = len;
+ }
+ safestrncpy(buf2, q, len);
+ StringBuf_AppendStr(&final_buf, buf2);
+ q = p;
+ }
+ p = q+1;
+ if(*p=='%'){ // %%
+ StringBuf_AppendStr(&final_buf, "%");
+ q+=2;
+ continue;
+ }
+ if(*p=='n'){ // %n
+ ShowWarning("buildin_sprintf: Format %%n not supported! Skipping...\n");
+ script_reportsrc(st);
+ q+=2;
+ continue;
+ }
+ if(arg>=argc){
+ ShowError("buildin_sprintf: Not enough arguments passed!\n");
+ if(buf) aFree(buf);
+ if(buf2) aFree(buf2);
+ StringBuf_Destroy(&final_buf);
+ script_pushconststr(st,"");
+ return 1;
+ }
+ if((p = strchr(q+1, '%'))==NULL){
+ p = strchr(q, 0); // EOS
+ }
+ len = p-q+1;
+ if(buf2_len<len){
+ RECREATE(buf2, char, len);
+ buf2_len = len;
+ }
+ safestrncpy(buf2, q, len);
+ q = p;
+
+ // Note: This assumes the passed value being the correct
+ // type to the current format specifier. If not, the server
+ // probably crashes or returns anything else, than expected,
+ // but it would behave in normal code the same way so it's
+ // the scripter's responsibility.
+ data = script_getdata(st, arg+3);
+ if(data_isstring(data)){ // String
+ StringBuf_Printf(&final_buf, buf2, script_getstr(st, arg+3));
+ }else if(data_isint(data)){ // Number
+ StringBuf_Printf(&final_buf, buf2, script_getnum(st, arg+3));
+ }else if(data_isreference(data)){ // Variable
+ char* name = reference_getname(data);
+ if(name[strlen(name)-1]=='$'){ // var Str
+ StringBuf_Printf(&final_buf, buf2, script_getstr(st, arg+3));
+ }else{ // var Int
+ StringBuf_Printf(&final_buf, buf2, script_getnum(st, arg+3));
+ }
+ }else{ // Unsupported type
+ ShowError("buildin_sprintf: Unknown argument type!\n");
+ if(buf) aFree(buf);
+ if(buf2) aFree(buf2);
+ StringBuf_Destroy(&final_buf);
+ script_pushconststr(st,"");
+ return 1;
+ }
+ arg++;
+ }
+
+ // Append anything left
+ if(*q){
+ StringBuf_AppendStr(&final_buf, q);
+ }
+
+ // Passed more, than needed
+ if(arg<argc){
+ ShowWarning("buildin_sprintf: Unused arguments passed.\n");
+ script_reportsrc(st);
+ }
+
+ script_pushstrcopy(st, StringBuf_Value(&final_buf));
+
+ if(buf) aFree(buf);
+ if(buf2) aFree(buf2);
+ StringBuf_Destroy(&final_buf);
+
+ return 0;
+}
+
+//=======================================================
+// sscanf(<str>, <format>, ...);
+// Implements C sscanf.
+//-------------------------------------------------------
+BUILDIN_FUNC(sscanf){
+ unsigned int argc, arg = 0, len;
+ struct script_data* data;
+ struct map_session_data* sd = NULL;
+ const char* str;
+ const char* format;
+ const char* p;
+ const char* q;
+ char* buf = NULL;
+ char* buf_p;
+ char* ref_str = NULL;
+ int ref_int;
+
+ // Get data
+ str = script_getstr(st, 2);
+ format = script_getstr(st, 3);
+ argc = script_lastdata(st)-3;
+
+ len = strlen(format);
+ CREATE(buf, char, len*2+1);
+
+ // Issue sscanf for each parameter
+ *buf = 0;
+ q = format;
+ while((p = strchr(q, '%'))){
+ if(p!=q){
+ strncat(buf, q, (size_t)(p-q));
+ q = p;
+ }
+ p = q+1;
+ if(*p=='*' || *p=='%'){ // Skip
+ strncat(buf, q, 2);
+ q+=2;
+ continue;
+ }
+ if(arg>=argc){
+ ShowError("buildin_sscanf: Not enough arguments passed!\n");
+ script_pushint(st, -1);
+ if(buf) aFree(buf);
+ if(ref_str) aFree(ref_str);
+ return 1;
+ }
+ if((p = strchr(q+1, '%'))==NULL){
+ p = strchr(q, 0); // EOS
+ }
+ len = p-q;
+ strncat(buf, q, len);
+ q = p;
+
+ // Validate output
+ data = script_getdata(st, arg+4);
+ if(!data_isreference(data) || !reference_tovariable(data)){
+ ShowError("buildin_sscanf: Target argument is not a variable!\n");
+ script_pushint(st, -1);
+ if(buf) aFree(buf);
+ if(ref_str) aFree(ref_str);
+ return 1;
+ }
+ buf_p = reference_getname(data);
+ if(not_server_variable(*buf_p) && (sd = script_rid2sd(st))==NULL){
+ script_pushint(st, -1);
+ if(buf) aFree(buf);
+ if(ref_str) aFree(ref_str);
+ return 0;
+ }
+
+ // Save value if any
+ if(buf_p[strlen(buf_p)-1]=='$'){ // String
+ if(ref_str==NULL){
+ CREATE(ref_str, char, strlen(str)+1);
+ }
+ if(sscanf(str, buf, ref_str)==0){
+ break;
+ }
+ set_reg(st, sd, add_str(buf_p), buf_p, (void *)(ref_str), reference_getref(data));
+ }else{ // Number
+ if(sscanf(str, buf, &ref_int)==0){
+ break;
+ }
+ set_reg(st, sd, add_str(buf_p), buf_p, (void *)(ref_int), reference_getref(data));
+ }
+ arg++;
+
+ // Disable used format (%... -> %*...)
+ buf_p = strchr(buf, 0);
+ memmove(buf_p-len+2, buf_p-len+1, len);
+ *(buf_p-len+1) = '*';
+ }
+
+ // Passed more, than needed
+ if(arg<argc){
+ ShowWarning("buildin_sscanf: Unused arguments passed.\n");
+ script_reportsrc(st);
+ }
+
+ script_pushint(st, arg);
+ if(buf) aFree(buf);
+ if(ref_str) aFree(ref_str);
+
+ return 0;
+}
+
+//=======================================================
+// strpos(<haystack>, <needle>)
+// strpos(<haystack>, <needle>, <offset>)
+//
+// Implements PHP style strpos. Adapted from code from
+// http://www.daniweb.com/code/snippet313.html, Dave Sinkula
+//-------------------------------------------------------
+BUILDIN_FUNC(strpos) {
+ const char *haystack = script_getstr(st,2);
+ const char *needle = script_getstr(st,3);
+ int i;
+ size_t len;
+
+ if( script_hasdata(st,4) )
+ i = script_getnum(st,4);
+ else
+ i = 0;
+
+ if ( strlen(needle) == 0 ) {
+ script_pushint(st, -1);
+ return 0;
+ }
+
+ len = strlen(haystack);
+ for ( ; i < len; ++i ) {
+ if ( haystack[i] == *needle ) {
+ // matched starting char -- loop through remaining chars
+ const char *h, *n;
+ for ( h = &haystack[i], n = needle; *h && *n; ++h, ++n ) {
+ if ( *h != *n ) {
+ break;
+ }
+ }
+ if ( !*n ) { // matched all of 'needle' to null termination
+ script_pushint(st, i);
+ return 0;
+ }
+ }
+ }
+ script_pushint(st, -1);
+ return 0;
+}
+
+//===============================================================
+// replacestr <input>, <search>, <replace>{, <usecase>{, <count>}}
+//
+// Note: Finds all instances of <search> in <input> and replaces
+// with <replace>. If specified will only replace as many
+// instances as specified in <count>. By default will be case
+// sensitive.
+//---------------------------------------------------------------
+BUILDIN_FUNC(replacestr)
+{
+ const char *input = script_getstr(st, 2);
+ const char *find = script_getstr(st, 3);
+ const char *replace = script_getstr(st, 4);
+ size_t inputlen = strlen(input);
+ size_t findlen = strlen(find);
+ struct StringBuf output;
+ bool usecase = true;
+
+ int count = 0;
+ int numFinds = 0;
+ int i = 0, f = 0;
+
+ if(findlen == 0) {
+ ShowError("script:replacestr: Invalid search length.\n");
+ st->state = END;
+ return 1;
+ }
+
+ if(script_hasdata(st, 5)) {
+ if(script_isint(st,5))
+ usecase = script_getnum(st, 5) != 0;
+ else {
+ ShowError("script:replacestr: Invalid usecase value. Expected int got string\n");
+ st->state = END;
+ return 1;
+ }
+ }
+
+ if(script_hasdata(st, 6)) {
+ if(script_isint(st,6))
+ count = script_getnum(st, 6);
+ else {
+ ShowError("script:replacestr: Invalid count value. Expected int got string\n");
+ st->state = END;
+ return 1;
+ }
+ }
+
+ StringBuf_Init(&output);
+
+ for(; i < inputlen; i++) {
+ if(count && count == numFinds) { //found enough, stop looking
+ break;
+ }
+
+ for(f = 0; f <= findlen; f++) {
+ if(f == findlen) { //complete match
+ numFinds++;
+ StringBuf_AppendStr(&output, replace);
+
+ i += findlen - 1;
+ break;
+ } else {
+ if(usecase) {
+ if((i + f) > inputlen || input[i + f] != find[f]) {
+ StringBuf_Printf(&output, "%c", input[i]);
+ break;
+ }
+ } else {
+ if(((i + f) > inputlen || input[i + f] != find[f]) && TOUPPER(input[i+f]) != TOUPPER(find[f])) {
+ StringBuf_Printf(&output, "%c", input[i]);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ //append excess after enough found
+ if(i < inputlen)
+ StringBuf_AppendStr(&output, &(input[i]));
+
+ script_pushstrcopy(st, StringBuf_Value(&output));
+ StringBuf_Destroy(&output);
+ return 0;
+}
+
+//========================================================
+// countstr <input>, <search>{, <usecase>}
+//
+// Note: Counts the number of times <search> occurs in
+// <input>. By default will be case sensitive.
+//--------------------------------------------------------
+BUILDIN_FUNC(countstr)
+{
+ const char *input = script_getstr(st, 2);
+ const char *find = script_getstr(st, 3);
+ size_t inputlen = strlen(input);
+ size_t findlen = strlen(find);
+ bool usecase = true;
+
+ int numFinds = 0;
+ int i = 0, f = 0;
+
+ if(findlen == 0) {
+ ShowError("script:countstr: Invalid search length.\n");
+ st->state = END;
+ return 1;
+ }
+
+ if(script_hasdata(st, 4)) {
+ if(script_isint(st,4))
+ usecase = script_getnum(st, 4) != 0;
+ else {
+ ShowError("script:countstr: Invalid usecase value. Expected int got string\n");
+ st->state = END;
+ return 1;
+ }
+ }
+
+ for(; i < inputlen; i++) {
+ for(f = 0; f <= findlen; f++) {
+ if(f == findlen) { //complete match
+ numFinds++;
+ i += findlen - 1;
+ break;
+ } else {
+ if(usecase) {
+ if((i + f) > inputlen || input[i + f] != find[f]) {
+ break;
+ }
+ } else {
+ if(((i + f) > inputlen || input[i + f] != find[f]) && TOUPPER(input[i+f]) != TOUPPER(find[f])) {
+ break;
+ }
+ }
+ }
+ }
+ }
+ script_pushint(st, numFinds);
+ return 0;
+}
+
+
/// Changes the display name and/or display class of the npc.
/// Returns 0 is successful, 1 if the npc does not exist.
///
@@ -13122,7 +13904,7 @@ BUILDIN_FUNC(setitemscript)
n=script_getnum(st,4);
i_data = itemdb_exists(item_id);
- if (!i_data || script==NULL || script[0]!='{') {
+ if (!i_data || script==NULL || ( script[0] && script[0]!='{' )) {
script_pushint(st,0);
return 0;
}
@@ -13140,7 +13922,7 @@ BUILDIN_FUNC(setitemscript)
if(*dstscript)
script_free_code(*dstscript);
- *dstscript = parse_script(script, "script_setitemscript", 0, 0);
+ *dstscript = script[0] ? parse_script(script, "script_setitemscript", 0, 0) : NULL;
script_pushint(st,1);
return 0;
}
@@ -14991,87 +15773,133 @@ BUILDIN_FUNC(searchstores)
searchstore_open(sd, uses, effect);
return 0;
}
-
-/// Returns the successful use of a Rune Knight Runestone.
-///
-/// SuccessRuneUse()
-///
-BUILDIN_FUNC(successruneuse)
+/// Displays a number as large digital clock.
+/// showdigit <value>[,<type>];
+BUILDIN_FUNC(showdigit)
{
- struct item_data* id = NULL;
+ unsigned int type = 0;
+ int value;
struct map_session_data* sd;
- struct script_data* data;
if( ( sd = script_rid2sd(st) ) == NULL )
- return 0; // no player attached, report source
-
- data = script_getdata(st,2);
- get_val(st, data); // convert into value in case of a variable
-
- if( data_isstring(data) )
- id = itemdb_searchname(conv_str(st, data));
- else
- id = itemdb_exists(conv_num(st, data));
-
- if( id == NULL )
{
- ShowError("buildin_successruneuse: Invalid item '%s'.\n", script_getstr(st,2));
- script_pushint(st,0);
- return 1;
+ return 0;
}
- if( (sd->class_&~(JOBL_UPPER|JOBL_BABY)) == MAPID_RUNE_KNIGHT )
+ value = script_getnum(st,2);
+
+ if( script_hasdata(st,3) )
{
- int skilllv = pc_checkskill(sd,RK_RUNEMASTERY);
- int i = (sd->status.dex + sd->status.luk ) / 20 + (skilllv?55+skilllv:0) + 30;
+ type = script_getnum(st,3);
- if (rand() % 100 < i)
- script_pushint(st, 1);
- else
+ if( type > 3 )
{
- script_pushint(st, 0);
+ ShowError("buildin_showdigit: Invalid type %u.\n", type);
+ return 1;
+ }
+ }
- i = rand() % 100; // reroll for fail effects
- if( i < 3 )
- {
- long damage = (1000 * id->weight) - (sd->battle_status.mdef + sd->battle_status.mdef2);
- clif_damage(&sd->bl, &sd->bl, gettick(), 0, 0, damage, 0, 0, 0);
- status_damage(&sd->bl, &sd->bl, damage, 0, 0, 0);
- }
- else if( i < 13 )
- { // Random status effect
- struct {
- sc_type type;
- int duration;
- } effects[] = {
- { SC_FREEZE, 30000 },
- { SC_STUN, 5000 },
- { SC_SLEEP, 20000 },
- { SC_SILENCE, 20000 },
- { SC_BLIND, 20000 },
- };
- i = rand()%ARRAYLENGTH(effects); // redesignate i to random status effect+duration.
- sc_start(&sd->bl, effects[i].type, 100, 1, effects[i].duration);
- }
- else if( i < 15 )
- pc_randomwarp(sd, CLR_TELEPORT);
- else if( i < 18 )
- ; // Unknown effect, however weight of the item used is taken into account.
- else if( i < 19 )
- {
- if (!status_isimmune(&sd->bl))
- status_percent_heal(&sd->bl, 100, 100);
+ 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;
}
- else if( i >= 20 )
- ; // Unknown effect
}
+ pc_setoption(sd, sd->sc.option|option);
+ script_pushint(st,1);
}
- else
- script_pushint(st, 0);
+ 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);
@@ -15180,7 +16008,6 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(setfalcon,"?"),
BUILDIN_DEF(checkfalcon,""),
BUILDIN_DEF(setriding,"?"),
- BUILDIN_DEF(setdragon,"??"),
BUILDIN_DEF(checkriding,""),
BUILDIN_DEF2(savepoint,"save","sii"),
BUILDIN_DEF(savepoint,"sii"),
@@ -15190,7 +16017,7 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(openstorage,""),
BUILDIN_DEF(guildopenstorage,""),
BUILDIN_DEF(itemskill,"vi"),
- BUILDIN_DEF(produce,"i?"),
+ BUILDIN_DEF(produce,"i"),
BUILDIN_DEF(cooking,"i"),
BUILDIN_DEF(monster,"siisii?"),
BUILDIN_DEF(getmobdrops,"i"),
@@ -15354,6 +16181,22 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(unequip,"i"), // unequip command [Spectre]
BUILDIN_DEF(getstrlen,"s"), //strlen [Valaris]
BUILDIN_DEF(charisalpha,"si"), //isalpha [Valaris]
+ BUILDIN_DEF(charat,"si"),
+ BUILDIN_DEF(setchar,"ssi"),
+ BUILDIN_DEF(insertchar,"ssi"),
+ BUILDIN_DEF(delchar,"si"),
+ BUILDIN_DEF(strtoupper,"s"),
+ BUILDIN_DEF(strtolower,"s"),
+ BUILDIN_DEF(charisupper, "si"),
+ BUILDIN_DEF(charislower, "si"),
+ BUILDIN_DEF(substr,"sii"),
+ BUILDIN_DEF(explode, "rss"),
+ BUILDIN_DEF(implode, "r?"),
+ BUILDIN_DEF(sprintf,"s*"), // [Mirei]
+ BUILDIN_DEF(sscanf,"ss*"), // [Mirei]
+ BUILDIN_DEF(strpos,"ss?"),
+ BUILDIN_DEF(replacestr,"sss??"),
+ BUILDIN_DEF(countstr,"ss?"),
BUILDIN_DEF(setnpcdisplay,"sv??"),
BUILDIN_DEF(compare,"ss"), // Lordalfa - To bring strstr to scripting Engine.
BUILDIN_DEF(getiteminfo,"ii"), //[Lupus] returns Items Buy / sell Price, etc info
@@ -15437,7 +16280,7 @@ struct script_function buildin_func[] = {
BUILDIN_DEF(pushpc,"ii"),
BUILDIN_DEF(buyingstore,"i"),
BUILDIN_DEF(searchstores,"ii"),
- BUILDIN_DEF(successruneuse,"?"),
+ BUILDIN_DEF(showdigit,"i?"),
// WoE SE
BUILDIN_DEF(agitstart2,""),
BUILDIN_DEF(agitend2,""),
@@ -15469,7 +16312,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 26d812d86..a7e75b6f4 100644
--- a/src/map/skill.c
+++ b/src/map/skill.c
@@ -37,7 +37,7 @@
#include <stdlib.h>
#include <string.h>
#include <time.h>
-#include <math.h>
+
#define SKILLUNITTIMER_INTERVAL 100
@@ -59,13 +59,28 @@ 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
-#define splash_target(bl) (bl->type==BL_MOB?BL_SKILL|BL_CHAR:BL_CHAR)
+static inline int splash_target(struct block_list* bl)
+{
+ return ( bl->type == BL_MOB ) ? BL_SKILL|BL_CHAR : BL_CHAR;
+}
/// Returns the id of the skill, or 0 if not found.
int skill_name2id(const char* name)
@@ -143,9 +158,7 @@ int skill_get_itemqty(int id, int idx) { skill_get (skill_db[id].amount[idx],
int skill_get_zeny( int id ,int lv ) { skill_get (skill_db[id].zeny[lv-1], id, lv); }
int skill_get_num( int id ,int lv ) { skill_get (skill_db[id].num[lv-1], id, lv); }
int skill_get_cast( int id ,int lv ) { skill_get (skill_db[id].cast[lv-1], id, lv); }
-int skill_get_fixedcast( int id ,int lv ) { skill_get (skill_db[id].fixedcast[lv-1], id, lv); }
int skill_get_delay( int id ,int lv ) { skill_get (skill_db[id].delay[lv-1], id, lv); }
-int skill_get_cooldown( int id ,int lv ) { skill_get (skill_db[id].cooldown[lv-1], id, lv); }
int skill_get_walkdelay( int id ,int lv ) { skill_get (skill_db[id].walkdelay[lv-1], id, lv); }
int skill_get_time( int id ,int lv ) { skill_get (skill_db[id].upkeep_time[lv-1], id, lv); }
int skill_get_time2( int id ,int lv ) { skill_get (skill_db[id].upkeep_time2[lv-1], id, lv); }
@@ -169,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)
{
@@ -240,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
@@ -260,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 )
@@ -269,14 +319,10 @@ int skill_get_range2 (struct block_list *bl, int id, int lv)
int skill_calc_heal(struct block_list *src, struct block_list *target, int skill_id, int skill_lv, bool heal)
{
- int skill, hp, mod = 100;
+ int skill, hp;
struct map_session_data *sd = BL_CAST(BL_PC, src);
struct map_session_data *tsd = BL_CAST(BL_PC, target);
struct status_change* sc;
- struct status_data *status;
- bool FullCalc = false;
-
- status = status_get_status_data(src);
switch( skill_id )
{
@@ -292,83 +338,43 @@ int skill_calc_heal(struct block_list *src, struct block_list *target, int skill
hp = (skill_lv>6)?666:skill_lv*100;
break;
default:
- FullCalc = true; // Enables full calculation, which adds heal variance.
if (skill_lv >= battle_config.max_heal_lv)
return battle_config.max_heal;
-
- // iRO Wiki states as of 2011/08/22:
- // heal = ( [(Base Level + INT) / 5] ?30 ) ?(Heal Level / 10) ?(1 + (Modifiers / 100)) + MATK
- // fixme: Does not match up with iRO's heal, level 1 or level 10
- // with 219 matk + HP_MEDITATO (10) (no gear), level 1 = 361; level 10 = 1839
- if( skill_id == AB_HIGHNESSHEAL ) {
- skill = pc_checkskill(sd,AL_HEAL);
- if( skill < 0 )
- skill = 10;
- }
- else
- skill = skill_lv;
-
- // Calculate base heal rate
- hp = ( ( ( status_get_lv(src) + status_get_int(src) ) / 5) * 30 ) * skill / 10;
-
- // Increment heal by skill/type modifiers
+ #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) )
- mod += skill * 2;
+ hp += hp * skill * 2 / 100;
else if( src->type == BL_HOM && (skill = merc_hom_checkskill(((TBL_HOM*)src), HLIF_BRAIN)) > 0 )
- mod += skill * 2;
+ hp += hp * skill * 2 / 100;
break;
- }
+ }
+
+ if( ( (target && target->type == BL_MER) || !heal ) && skill_id != NPC_EVILLAND )
+ hp >>= 1;
- // Increment heal by item-based modifiers
if( sd && (skill = pc_skillheal_bonus(sd, skill_id)) )
- mod += skill;
+ hp += hp*skill/100;
+
if( tsd && (skill = pc_skillheal2_bonus(tsd, skill_id)) )
- mod += skill;
+ hp += hp*skill/100;
sc = status_get_sc(target);
if( sc && sc->count )
{
if( sc->data[SC_CRITICALWOUND] && heal ) // Critical Wound has no effect on offensive heal. [Inkfish]
- mod -= sc->data[SC_CRITICALWOUND]->val2;
+ hp -= hp * sc->data[SC_CRITICALWOUND]->val2/100;
if( sc->data[SC_INCHEALRATE] && skill_id != NPC_EVILLAND && skill_id != BA_APPLEIDUN )
- mod += sc->data[SC_INCHEALRATE]->val1; // Only affects Heal, Sanctuary and PotionPitcher.(like bHealPower) [Inkfish]
- if( sc->data[SC_VITALITYACTIVATION] && heal && skill_id != BA_APPLEIDUN )
- mod += sc->data[SC_VITALITYACTIVATION]->val2;
+ hp += hp * sc->data[SC_INCHEALRATE]->val1/100; // Only affects Heal, Sanctuary and PotionPitcher.(like bHealPower) [Inkfish]
}
-
- // Adjust the HP recovered rate by adding all of the modifiers together.
- hp = hp * mod / 100;
-
- // Get weapon level and weapon matk for variance calculations if it's a player.
- // Mobs have their own variance, we've assumed:
- // Weapon Level = 1
- // Weapom_Matk = ?
- // Need more information before that can be implemented.
- if( sd && FullCalc)
- {
- int matk = 0;
- int smatk = sd->battle_status.status_matk;
- int ematk = sd->equipment_matk;
- int wmatk = 0;
- int wlv = 1;
- int index = sd->equip_index[EQI_HAND_R];
-
- if( index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_WEAPON )
- wlv = sd->inventory_data[index]->wlv;
-
- wmatk = (int)( sd->weapon_matk + ( (float)( ( rand() % 20 ) - 10 ) / 100 * wlv * sd->weapon_matk ) + ( sd->battle_status.rhw.atk2 ) );
- matk = ( smatk + wmatk + ematk );
-
- hp += matk;
- }
-
- // mercenaries only take half-effectiveness from heals.
- if( ( (target && target->type == BL_MER) || !heal ) && skill_id != NPC_EVILLAND )
- hp >>= 1;
-
- // Give Highness Heal it's extra heal
- if( skill_id == AB_HIGHNESSHEAL )
- hp = hp * (170 + 30 * skill_lv) / 100;
return hp;
}
@@ -430,6 +436,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) {
@@ -462,6 +471,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)) ||
@@ -472,6 +487,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);
}
@@ -523,6 +555,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
@@ -639,6 +673,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 &&
@@ -735,7 +772,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;
@@ -981,20 +1025,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,15,skilllv,src->id,0,0,skill_get_time(skillid,skilllv));
+ 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 ( sd )
+ 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 = (skilllv*4) + sd->status.job_level / 2;
- sc_start(bl, SC_BLIND, rate, skilllv, skill_get_time(skillid, skilllv));
- sc_start(bl, SC_ADORAMUS, rate, skilllv, skill_get_time2(skillid, skilllv));
+ 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)
@@ -1105,7 +1233,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);
}
}
}
@@ -1381,7 +1509,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);
}
}
}
@@ -1516,7 +1644,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++) {
@@ -1531,8 +1659,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
@@ -1721,8 +1849,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;
@@ -1744,19 +1878,8 @@ 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 )
- {
- if( sc && sc->data[SC_DEATHBOUND] && !is_boss(bl) && map_check_dir(map_calc_dir(src,bl->x,bl->y),unit_getdir(bl)))
- {
- int skilllv = sc->data[SC_DEATHBOUND]->val1;
- clif_skill_damage(src,src, tick, 0, 0, 0, 0, RK_DEATHBOUND,-1, 1);
- rdamage = damage * ((500 + 100*skilllv) / 100);
- damage = rdamage * 70 / 100;
- skill_blown(src, src, skill_get_blewcount(skillid,skilllv), unit_getdir(src), 0);
- status_change_end(dsrc,SC_DEATHBOUND,INVALID_TIMER);
- }
- else
- 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);
@@ -1872,7 +1995,6 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds
case NPC_CRITICALSLASH:
case TF_DOUBLE:
case GS_CHAINACTION:
- case RK_DEATHBOUND:
dmg.dmotion = clif_damage(src,bl,tick,dmg.amotion,dmg.dmotion,damage,dmg.div_,dmg.type,dmg.damage2);
break;
@@ -1882,7 +2004,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;
@@ -1897,8 +2043,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){
@@ -1911,11 +2071,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);
@@ -1949,6 +2109,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)
@@ -1960,6 +2126,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);
}
@@ -2015,9 +2183,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 && skillid == RK_CRUSHSTRIKE )
- skill_break_equip(src,EQP_WEAPON,2000,BCT_SELF);
+ 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) &&
(
@@ -2044,7 +2222,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)
{
@@ -2115,6 +2292,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;
@@ -2427,15 +2615,60 @@ static int skill_timerskill(int tid, unsigned int tick, int id, intptr_t data)
}
}
break;
- case RK_HUNDREDSPEAR:
- if(src->type == BL_PC)
+ /**
+ * Warlock
+ **/
+ case WL_CHAINLIGHTNING_ATK:
{
- int skill_lv = pc_checkskill((struct map_session_data *)src,KN_SPEARBOOMERANG);
- if(skill_lv > 0)
- skill_attack(BF_WEAPON,src,src,target,KN_SPEARBOOMERANG,skill_lv,tick,skl->flag);
- }
- else
- skill_attack(BF_WEAPON,src,src,target,KN_SPEARBOOMERANG,1,tick,skl->flag);
+ 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);
@@ -2459,7 +2692,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.
@@ -2660,9 +2899,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;
@@ -2731,6 +3004,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:
@@ -2860,7 +3135,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
@@ -2887,7 +3190,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
@@ -2895,7 +3201,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 )
@@ -3015,10 +3321,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;
@@ -3105,6 +3421,9 @@ 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;
@@ -3162,17 +3481,329 @@ 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);
- case RK_HUNDREDSPEAR:
- skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
- if(rand()%100 < (10 + 3*skilllv)) {
- skill_blown(src,bl,6,-1,0);
- skill_addtimerskill(src,tick+800,bl->id,0,0,skillid,skilllv,BF_WEAPON,flag);
- }
+ 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) {
@@ -3209,9 +3840,6 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int
skill_consume_requirement(sd,skillid,skilllv,2);
}
- if( sd && skill_get_cooldown(skillid,skilllv) )
- skill_blockpc_start (sd, skillid, skill_get_cooldown(skillid, skilllv));
-
return 0;
}
@@ -3268,6 +3896,9 @@ 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.
@@ -3303,12 +3934,20 @@ 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 = skill_calc_heal(src, bl, (skillid == AB_HIGHNESSHEAL)?AL_HEAL:skillid, (skillid == AB_HIGHNESSHEAL)?10:skilllv, true);
int heal_get_jobexp;
-
- if( status_isimmune(bl) || (dstmd && (dstmd->class_ == MOBID_EMPERIUM || mob_is_battleground(dstmd))) )
+ //Highness Heal: starts at 1.5 boost + 0.5 for each level
+ if( skillid == AB_HIGHNESSHEAL ) {
+ heal = heal * ( 15 + 5 * skilllv ) / 10;
+ }
+ 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 )
@@ -3421,12 +4060,8 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
case AL_DECAGI:
case MER_DECAGI:
- if (skilllv = battle_config.max_decagi_lv)
- clif_skill_nodamage (src, bl, skillid, skilllv,
- sc_start(bl, type, (40 + skilllv * 2 + (status_get_lv(src) + sstatus->int_)/5), (battle_config.max_decagi - 2), battle_config.max_decagi_dur));
- else
- clif_skill_nodamage (src, bl, skillid, skilllv,
- sc_start(bl, type, (40 + skilllv * 2 + (status_get_lv(src) + sstatus->int_)/5), skilllv, skill_get_time(skillid,skilllv)));
+ clif_skill_nodamage (src, bl, skillid, skilllv,
+ sc_start(bl, type, (40 + skilllv * 2 + (status_get_lv(src) + sstatus->int_)/5), skilllv, skill_get_time(skillid,skilllv)));
break;
case AL_CRUCIS:
@@ -3721,7 +4356,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:
@@ -3762,7 +4400,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:
@@ -3779,17 +4416,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:
- case RK_MILLENNIUMSHIELD:
- case RK_CRUSHSTRIKE:
- case RK_GIANTGROWTH:
- case RK_STONEHARDSKIN:
- case RK_VITALITYACTIVATION:
- case RK_ABUNDANCE:
+ /**
+ * 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;
@@ -4047,14 +4699,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;
@@ -4075,12 +4727,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:
@@ -4156,7 +4828,6 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
case BS_ADRENALINE2:
case BS_WEAPONPERFECT:
case BS_OVERTHRUST:
- case RK_FIGHTINGSPIRIT: //Splash range in skill_db is 0, should be map-wide according to party_foreachsamemap
if (sd == NULL || sd->status.party_id == 0 || (flag & 1)) {
clif_skill_nodamage(bl,bl,skillid,skilllv,
sc_start2(bl,type,100,skilllv,(src == bl)? 1:0,skill_get_time(skillid,skilllv)));
@@ -4225,6 +4896,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;
@@ -4240,6 +4916,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);
@@ -4305,7 +4986,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
if(pc_steal_item(sd,bl,skilllv))
clif_skill_nodamage(src,bl,skillid,skilllv,1);
else
- clif_skill_fail(sd,skillid,10,0);
+ clif_skill_fail(sd,skillid,0x0a,0);
}
break;
@@ -4559,6 +5240,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;
@@ -4577,6 +5259,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:
@@ -4594,14 +5277,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.
@@ -4765,7 +5448,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);
@@ -5778,19 +6462,6 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
skill_castend_nodamage_id);
}
break;
- case ALL_PARTYFLEE:
- if( sd && !(flag&1) )
- {
- if( !sd->status.party_id )
- {
- clif_skill_fail(sd,skillid,0,0);
- break;
- }
- party_foreachsamemap(skill_area_sub, sd, skill_get_splash(skillid, skilllv), src, skillid, skilllv, tick, flag|BCT_PARTY|1, skill_castend_nodamage_id);
- }
- else
- clif_skill_nodamage(src,bl,skillid,skilllv,sc_start(bl,type,100,skilllv,skill_get_time(skillid,skilllv)));
- break;
case NPC_TALK:
case ALL_WEWISH:
clif_skill_nodamage(src,bl,skillid,skilllv,1);
@@ -5802,271 +6473,606 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
}
break;
case RK_ENCHANTBLADE:
- i = status_get_int(src) + status_get_lv(src) / 10;
- clif_skill_nodamage(src,bl,skillid,skilllv,
- sc_start(bl,type,100,i,skill_get_time(skillid,skilllv)));
+ 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_IGNITIONBREAK:
- if(flag&1)
- skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
- else
+ 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, bl,
- skill_get_splash(skillid, skilllv),BL_CHAR,
- src,skillid,skilllv,tick, flag|BCT_ENEMY|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_DRAGONHOWLING:
- if(flag&1)
- sc_start(bl,SC_FEAR,50 + skilllv * 6,skilllv,skill_get_time2(skillid,skilllv));
- else
+ 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 )
{
- clif_skill_nodamage(src,bl,skillid,skilllv,1);
- 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);
+ 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 = sstatus->max_hp * 25 / 100;
- status_heal(bl,heal,0,0);
+ 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_change_clear_buffs(bl,6);
+ status_heal(bl,heal,0,1);
+ status_change_clear_buffs(bl,2);
}
break;
- case RK_STORMBLAST:
- if( flag&1 )
- skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
+
+ 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);
- 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);
}
break;
- case RK_PHANTOMTHRUST:
- if(battle_check_target(src,bl,BCT_ENEMY) > 0 || battle_check_target(src,bl,BCT_PARTY) > 0)
+
+ 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:
{
- if(!map[bl->m].flag.gvg && !map[bl->m].flag.battleground && !(status_get_mode(bl)&MD_BOSS))
+ 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) )
{
- int x = 0, y = 0;
- if(bl->x > src->x) x = 1;
- else if(bl->x < src->x) x = -1;
- if(bl->y >= src->y) y = 1;
- else if(bl->y < src->y) y = -1;
- unit_movepos(bl, src->x+x, src->y+y, 1, 0);
- clif_slide(bl,src->x+x, src->y+y);
+ if( sd ) clif_skill_fail(sd,skillid,0x02,0);
+ break;
}
- clif_skill_nodamage(src,bl,skillid,skilllv,1);
- if (battle_check_target(src,bl,BCT_ENEMY) > 0 )
- skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
+ 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) {
- if (skill_produce_mix(sd, skillid, 12333, 0, 0, 0, 1))
- clif_skill_nodamage(src,bl,skillid,skilllv,1);
- else
- clif_skill_fail(sd,skillid,0,0);
+ 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:
- if( sd == NULL || sd->status.party_id == 0 || (flag & 1) ) {
- int lv = 1;
- switch(skillid) {
- case AB_CLEMENTIA: if( sd ) lv = pc_checkskill(sd,AL_BLESSING); break;
- case AB_CANTO: if( sd ) lv = pc_checkskill(sd,AL_INCAGI); break;
- }
- clif_skill_nodamage(bl, bl, skillid, skilllv,
- sc_start4(bl,type,100,lv,0,sd?sd->status.job_level:0,0,skill_get_time(skillid,skilllv)));
+ {
+ 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 )
{
- int lv = (sd?pc_checkskill(sd, AL_HEAL):1);
if( sd && tstatus && !battle_check_undead(tstatus->race, tstatus->def_ele) )
{
- int heal = skill_calc_heal(src, bl, AL_HEAL, lv, true);
- if( status_isimmune(bl) )
- heal = 0;
-
- if( sd->status.party_id && (i = party_foreachsamemap(party_sub_count, sd, 0)) > 1 )
- heal += ((heal / 100) * (i * 10) / 4);
-
- clif_skill_nodamage(bl, bl, skillid, heal, 1);
- status_heal(bl, heal, 0, 0);
+ 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_PRAEFATIO:
- if( (flag&1) || sd == NULL || sd->status.party_id == 0 )
- {
- if( dstsd && dstsd->special_state.no_magic_damage )
- break;
- if ( sd && sd->status.party_id && (i = party_foreachsamemap(party_sub_count, sd, 0)) > 0)
- {
- clif_skill_nodamage(bl, bl, skillid, skilllv,
- sc_start4(bl, type, 100, skilllv, 0, 0, i, skill_get_time(skillid, skilllv)));
- }
- }
- else
- 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));
+ 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);
- 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);
}
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 || sd->status.party_id == 0 )
+ if( flag&1 || sd == NULL )
{
- if( tsc && (rand()%100 < 40+10*skilllv) )
+ if( (tsc && (tsc->data[SC_SLEEP] || tsc->data[SC_STUN] ||
+ tsc->data[SC_SILENCE]))&& (rand()%100 < 30+5*skilllv) )
{
- switch(skillid)
- {
- case AB_LAUDAAGNUS:
- if( tsc->data[SC_STONE] || tsc->data[SC_FREEZE] || tsc->data[SC_BLIND] ) //TODO: Freezing, Crystallization and Burning
- {
- status_change_end(bl, SC_STONE, INVALID_TIMER);
- status_change_end(bl, SC_FREEZE, INVALID_TIMER);
- status_change_end(bl, SC_BLIND, INVALID_TIMER);
- }
- else
- clif_skill_nodamage(bl, bl, skillid, skilllv, sc_start(bl, type, 100, skilllv, skill_get_time(skillid, skilllv)));
- break;
- case AB_LAUDARAMUS:
- if( tsc->data[SC_STUN] || tsc->data[SC_SLEEP] || tsc->data[SC_SILENCE] ) // TODO: Howling of Mandragora, and Deep Sleep
- {
- status_change_end(bl, SC_STUN, INVALID_TIMER);
- status_change_end(bl, SC_SLEEP, INVALID_TIMER);
- status_change_end(bl, SC_SILENCE, INVALID_TIMER);
- }
- else
- clif_skill_nodamage(bl, bl, skillid, skilllv, sc_start(bl, type, 100, skilllv, skill_get_time(skillid, skilllv)));
- break;
- }
+ 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);
- if( rand()%100 >= 60+10*skilllv )
+ 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 (sd)
+ 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;
}
+ break;
- if(status_isimmune(bl) || !tsc || !tsc->count)
- break;
- for(i=0;i<SC_MAX;i++)
+ case WL_SUMMONFB:
+ case WL_SUMMONBL:
+ case WL_SUMMONWB:
+ case WL_SUMMONSTONE:
{
- if (!tsc->data[i])
- continue;
- //Initial list of status effects NOT cancelled by Clearance.
- switch (i) {
- case SC_WEIGHT50: case SC_WEIGHT90: case SC_TWOHANDQUICKEN:
- case SC_QUAGMIRE: case SC_SLOWPOISON: case SC_BENEDICTIO:
- case SC_TRICKDEAD: case SC_HALLUCINATION: case SC_ASPDPOTION0:
- case SC_ASPDPOTION1: case SC_SPEEDUP1: 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_AUTOGUARD: case SC_REFLECTSHIELD:
- case SC_MAGICROD: case SC_SAFETYWALL: case SC_FIREWEAPON:
- case SC_WATERWEAPON: case SC_WINDWEAPON: case SC_EARTHWEAPON:
- case SC_VOLCANO: case SC_DELUGE: case SC_VIOLENTGALE:
- case SC_AUTOBERSERK: case SC_CARTBOOST: case SC_BLADESTOP:
- case SC_ARMOR_ELEMENT: case SC_STOP: case SC_EXPLOSIONSPIRITS:
- case SC_NOCHAT: case SC_PARRYING: case SC_TENSIONRELAX:
- case SC_SACRIFICE: case SC_BASILICA: case SC_GUILDAURA:
- case SC_BLEEDING: case SC_JOINTBEAT: case SC_FOGWALL:
- case SC_SPIDERWEB: case SC_RUN: case SC_SPURT:
- case SC_SHADOWWEAPON: case SC_GHOSTWEAPON: case SC_SPIRIT:
- case SC_WATKFOOD: case SC_MATKFOOD: case SC_KAITE:
- case SC_KAAHI: case SC_KAUPE: case SC_ONEHAND:
- case SC_CHASEWALK: case SC_SLOWDOWN: case SC_DOUBLECAST:
- case SC_GRAVITATION: case SC_CLOSECONFINE: case SC_CLOSECONFINE2:
- case SC_UTSUSEMI: case SC_BUNSINJYUTSU: case SC_SUITON:
- case SC_STRFOOD: case SC_AGIFOOD: case SC_VITFOOD:
- case SC_DEXFOOD: case SC_INTFOOD: case SC_LUKFOOD:
- case SC_FLEEFOOD: case SC_HITFOOD: case SC_JAILED:
- case SC_SUMMER: case SC_WEDDING: case SC_DANCING:
- case SC_EXPBOOST: case SC_LIFEINSURANCE: case SC_ITEMBOOST:
- case SC_BOSSMAPINFO: 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_MERC_FLEEUP: case SC_MERC_ATKUP:
- case SC_MERC_HPUP: case SC_MERC_SPUP: case SC_MERC_HITUP:
- case SC_SLOWCAST: /*case SC_CRITICALWOUND:*/ case SC_SPEEDUP0:
- case SC_DEF_RATE: case SC_MDEF_RATE: case SC_INCHEALRATE:
- case SC_S_LIFEPOTION: case SC_L_LIFEPOTION: case SC_INCCRI:
- case SC_SPCOST_RATE: case SC_COMMONSC_RESIST: case SC_ELEMENTALCHANGE:
- case SC_INCFLEE2: case SC_PNEUMA: case SC_AUTOTRADE:
- case SC_KSPROTECTED: case SC_ARMOR_RESIST: case SC_HELLPOWER:
- case SC_JEXPBOOST: case SC_ITEMSCRIPT: case SC_INVINCIBLE:
- case SC_INVINCIBLEOFF: 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_SEVENWIND: case SC_NEN:
- case SC_READYSTORM: case SC_READYDOWN: case SC_READYTURN:
- case SC_READYCOUNTER: case SC_DODGE: case SC_WARM:
- case SC_SMA: 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_PARTYFLEE: /*case SC_ANGEL_PROTECT:*/
- case SC_EPICLESIS: case SC_DEATHBOUND: case SC_FIGHTINGSPIRIT:
- case SC_ABUNDANCE: case SC_MILLENNIUMSHIELD:
- // not implemented
- //case SC_BUCHEDENOEL: case SC_POPECOOKIE:
- //case SC_SAVAGE_STEAK: case SC_COCKTAIL_WARG_BLOOD: case SC_MINOR_BBQ:
- //case SC_SIROMA_ICE_TEA: case SC_DROCERA_HERB_STEAMED: case SC_PUTTI_TAILS_NOODLES:
- //case SC_CRIFOOD: case SC_STR_SCROLL: case SC_INT_SCROLL:
- //case SC_ACARAJE:
- //
- continue;
- case SC_ASSUMPTIO:
- if( bl->type == BL_MOB )
- continue;
+ 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;
}
- if(i==SC_BERSERK) 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, INVALID_TIMER);
+
+ 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 AB_SILENTIUM:
- if (flag&1)
- sc_start(bl,SC_SILENCE,100,skilllv,skill_get_time(skillid,skilllv));
- else {
+
+ 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);
- 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);
+ }
+ 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;
@@ -6090,9 +7096,6 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
skill_consume_requirement(sd,skillid,skilllv,2);
}
- if( sd && skill_get_cooldown(skillid,skilllv) )
- skill_blockpc_start (sd, skillid, skill_get_cooldown(skillid, skilllv));
-
map_freeblock_unlock();
return 0;
}
@@ -6277,13 +7280,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 )
@@ -6319,7 +7324,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 &&
@@ -6496,7 +7501,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 )
@@ -6628,6 +7633,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:
@@ -6690,6 +7698,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);
@@ -6937,35 +7956,119 @@ 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);
- clif_skill_damage(src, src, tick, 0, 0, -1, 1, skillid, -1, 0);
- map_foreachinarea(skill_area_sub,
- src->m,x-i,y-i,x+i,y+i,(BL_CHAR|BL_SKILL),
- src,skillid,skilllv,tick,flag|BCT_ENEMY|1,
- skill_castend_damage_id);
+ 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 RK_DRAGONBREATH:
+ 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_area_sub,
- src->m,x-i,y-i,x+i,y+i,(BL_CHAR|BL_SKILL),
- src,skillid,skilllv,tick,flag|BCT_ENEMY|1,
- skill_castend_damage_id);
+ 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 AB_EPICLESIS:
- if( skill_unitsetting(src, skillid, skilllv, x, y, 0) )
+ case NC_SILVERSNIPER:
{
- i = skill_get_splash(skillid,skilllv); // Use Splash 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);
+ 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);
return 1;
@@ -6981,9 +8084,6 @@ int skill_castend_pos2(struct block_list* src, int x, int y, int skillid, int sk
skill_consume_requirement(sd,skillid,skilllv,2);
}
- if( sd && skill_get_cooldown(skillid,skilllv) )
- skill_blockpc_start (sd, skillid, skill_get_cooldown(skillid, skilllv));
-
return 0;
}
@@ -7017,7 +8117,11 @@ int skill_castend_map (struct map_session_data *sd, short skill_num, const char
sd->sc.data[SC_BERSERK] ||
sd->sc.data[SC_BASILICA] ||
sd->sc.data[SC_MARIONETTE] ||
- sd->sc.data[SC_DEATHBOUND]
+ /**
+ * 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;
@@ -7306,6 +8410,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) )
@@ -7455,6 +8570,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));
@@ -7529,6 +8655,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:
@@ -7608,8 +8745,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;
@@ -7992,6 +9129,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);
@@ -8158,6 +9305,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;
@@ -8173,60 +9324,70 @@ 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:
- sg->val2--; // track when units should be healed. Initial tick heals immediately.
- if ( !battle_check_undead(tstatus->race, tstatus->def_ele) && bl->type == BL_PC)
- { //Effect only players who are not undead element.
-
- //Unknown if any status effects should prevent Epiclesis.
- //if( tsc->data[SC_BERSERK] )
- // break;
-
- //FIXME: Apply status effect if standing in unit, should cancel upon stepping out of skill_get_splash() area.
- if( tsc && !tsc->data[SC_EPICLESIS] )
- sc_start(bl, type, 100, sg->skill_lv, skill_get_time(sg->skill_id,sg->skill_lv));
-
- //There's probably a better way to handle this...
- if( sg->val2 < 1 )
+ if( bl->type == BL_PC && !battle_check_undead(tstatus->race, tstatus->def_ele) && tstatus->race != RC_DEMON )
+ {
+ int hp, sp;
+ switch( sg->skill_lv )
{
- int heal, sp;
- struct map_session_data *sd = (struct map_session_data *)bl;
-
- if( tstatus->hp < tstatus->max_hp )
- {
- heal = tstatus->max_hp * (((sg->skill_lv - 1) / 2) + 3) / 100;
- if( tstatus->hp + heal > tstatus->max_hp )
- heal = tstatus->max_hp - tstatus->hp;
- if( heal > 0 )
- {
- clif_heal(sd->fd,SP_HP,heal);
- status_heal(bl, heal, 0, 0);
- }
- }
-
- if( tstatus->sp < tstatus->max_sp )
- {
- sp = tstatus->max_sp * (((sg->skill_lv - 1) / 2) + 2) / 100;
- if( tstatus->sp + sp > tstatus->max_sp )
- sp = tstatus->max_sp - tstatus->sp;
- if( sp > 0 )
- {
- clif_heal(sd->fd,SP_SP,sp);
- status_heal(bl, 0, sp, 0);
- }
- }
- sg->val2 = 3; // then every three seconds after.
+ 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;
- sg->val3--; // track when units should be unhidden. Initial tick unhides units immediately.
- if( sg->val3 < 1 )
- {
- status_change_end(bl,SC_HIDING,-1);
- status_change_end(bl,SC_CLOAKING,-1);
- sg->val3 = 5; //then every five seconds after.
- }
+ 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;
}
@@ -8265,7 +9426,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:
+ case UNT_EPICLESIS://Arch Bishop
if (sce)
status_change_end(bl, type, INVALID_TIMER);
break;
@@ -8274,7 +9435,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);
@@ -8511,12 +9671,18 @@ static int skill_check_condition_char_sub (struct block_list *bl, va_list ap)
return 1;
}
case AB_ADORAMUS:
- {
- int skilllv = pc_checkskill(sd,skillid);
- if( (tsd->class_&MAPID_UPPERMASK) == MAPID_PRIEST && tsd->status.sp >= 2*skilllv)
- p_sd[(*c)++]=tsd->bl.id;
+ { // 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;
@@ -8568,8 +9734,11 @@ int skill_check_pc_partner (struct map_session_data *sd, short skill_id, short*
return c;
case AB_ADORAMUS:
if( c > 0 && (tsd = map_id2sd(p_sd[0])) != NULL )
- status_charge(&tsd->bl, 0, 2*(*skill_lv));
- return c;
+ {
+ 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)
{
@@ -8588,7 +9757,7 @@ int skill_check_pc_partner (struct map_session_data *sd, short skill_id, short*
memset (p_sd, 0, sizeof(p_sd));
i = map_foreachinrange(skill_check_condition_char_sub, &sd->bl, range, BL_PC, &sd->bl, &c, &p_sd, skill_id);
- if (skill_id != PR_BENEDICTIO && skill_id != AB_ADORAMUS) //Apply the average lv to encore skills.
+ if (skill_id != PR_BENEDICTIO) //Apply the average lv to encore skills.
*skill_lv = (i+(*skill_lv))/(c+1); //I know c should be one, but this shows how it could be used for the average of n partners.
return c;
}
@@ -9002,34 +10171,97 @@ int skill_check_condition_castbegin(struct map_session_data* sd, short skill, sh
return 0;
}
break;
+ /**
+ * Arch Bishop
+ **/
case AB_ANCILLA:
- i = pc_search_inventory(sd,12333);
- if( i >= 0 && sd->status.inventory[i].amount >= 3 )
{
- clif_skill_fail(sd, skill, 12, 0);
- return 0;
+ 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;
- case AB_EPICLESIS: // Skill should fail if items are not present. Why the curveball, RO?
- if ( require.itemid[0] )
+ /**
+ * 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]) )
{
- i = pc_search_inventory(sd,require.itemid[0]);
- if( i < 0 || sd->status.inventory[i].amount < require.amount[0] )
- {
- clif_skill_fail(sd,skill,14,0); //Ancilla required
- return 0;
- }
+ //clif_skill_fail(sd,skill,0x47,require.amount[0],require.itemid[0]);
+ clif_skill_fail(sd,skill,0,0);
+ return 0;
}
- if ( require.itemid[1] )
+ break;
+ case WL_SUMMONFB:
+ case WL_SUMMONBL:
+ case WL_SUMMONWB:
+ case WL_SUMMONSTONE:
+ if( sc )
{
- i = pc_search_inventory(sd,require.itemid[1]);
- if(i < 0 || sd->status.inventory[i].amount < require.amount[1] )
- {
- clif_skill_fail(sd,skill,13,0); //Holy Water required
+ 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) {
@@ -9114,26 +10346,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;
- case ST_DRAGON:
- if(!pc_isdragon(sd)) {
- clif_skill_fail(sd,skill,25,0);
+ /**
+ * Wug
+ **/
+ case ST_WUG:
+ if( !(sd->sc.option&OPTION_WUG) ) {
+ clif_skill_fail(sd,skill,0,0);
return 0;
}
break;
-/*
- case ST_WARG:
- if(!pc_iswarg(sd)) {
+ /**
+ * Riding Wug
+ **/
+ case ST_RIDINGWUG:
+ if( !(sd->sc.option&OPTION_WUGRIDER) ){
clif_skill_fail(sd,skill,0,0);
return 0;
}
break;
- case ST_MADOGEAR:
- if(!pc_ismadogear(sd)) {
- clif_skill_fail(sd,skill,33,0);
+ /**
+ * 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) {
@@ -9208,15 +10465,16 @@ int skill_check_condition_castend(struct map_session_data* sd, short skill, shor
return 0;
}
- require = skill_get_requirement(sd,skill,lv);// Adoramus need this.
-
// perform skill-specific checks (and actions)
switch( skill )
{
case PR_BENEDICTIO:
- case AB_ADORAMUS:
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:
{
@@ -9236,10 +10494,38 @@ 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;
+ require = skill_get_requirement(sd,skill,lv);
+
if( require.hp > 0 && status->hp <= (unsigned int)require.hp) {
clif_skill_fail(sd,skill,2,0);
return 0;
@@ -9272,15 +10558,8 @@ int skill_check_condition_castend(struct map_session_data* sd, short skill, shor
clif_skill_fail(sd,skill,7,0);// red gemstone required
else if( require.itemid[i] == ITEMID_BLUE_GEMSTONE )
clif_skill_fail(sd,skill,8,0);// blue gemstone required
- else if( require.itemid[i] == 523 )
- clif_skill_fail(sd,skill,13,0); //Holy Water required
- else if( require.itemid[i] == 12333 )
- clif_skill_fail(sd,skill,14,0); //Ancilla required
else
- {
- //clif_skill_fail(sd,skill,71,require.amount[i],require.itemid[i]);
clif_skill_fail(sd,skill,0,0);
- }
return 0;
}
}
@@ -9428,6 +10707,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;
@@ -9439,13 +10722,7 @@ struct skill_condition skill_get_requirement(struct map_session_data* sd, short
if( itemid_isgemstone(req.itemid[i]) && skill != HW_GANBANTEIN )
{
- if( sd->special_state.no_gemstone ||
-// FIXME: [Inkfish]
-// check partners every time trying to get requirement info? not wise
-// but neither check it in castbegin
-// PR_BENEDICTIO is instant cast, so you probably can store info in castbegin and use it in castend without it being modified.
-// but AB_ADORAMUS has cast time. partner info may change during casting.
- (skill == AB_ADORAMUS && skill_check_pc_partner(sd,skill,&lv, 1, 0) )) // Do not require Gemstone if next to another priest.
+ if( sd->special_state.no_gemstone )
{ //Make it substract 1 gem rather than skipping the cost.
if( --req.amount[i] < 1 )
req.itemid[i] = 0;
@@ -9530,39 +10807,22 @@ struct skill_condition skill_get_requirement(struct map_session_data* sd, short
*------------------------------------------*/
int skill_castfix (struct block_list *bl, int skill_id, int skill_lv)
{
- int scale = 0, max_fixedReduction = 0;
- int time = skill_get_cast(skill_id, skill_lv); // Skill's base cast time.
- int fixedcasttime = skill_get_fixedcast(skill_id, skill_lv); // Skills fixed cast time.
+ int time = skill_get_cast(skill_id, skill_lv);
struct map_session_data *sd;
- struct status_change *sc;
nullpo_ret(bl);
sd = BL_CAST(BL_PC, bl);
- sc = status_get_sc(bl);
-
- // calculate base cast time (reduced by dex and int)
- if( !(skill_get_castnodex(skill_id, skill_lv)&1) )
- {
- // iRO Wiki states as of 2011/08/22:
- // castTime = (1 - SQRT((DEX * 2 + INT) / 530)) * (1 - sum_castReduction/100%) * baseCast * 0.8 + (1 - max_fixedReduction/100%) * baseCast * 0.2
- // let's do (DEX * 2 + INT) here; the rest will come after.
- scale = cap_value((status_get_dex(bl) * 2 + status_get_int(bl)) * 10000, 0, INT_MAX);
- }
- //apply variable cast rate modifiers via status effects.
- if( !(skill_get_castnodex(skill_id, skill_lv)&2) && sc && sc->count )
- {
- if (sc->data[SC_SLOWCAST])
- time += time * sc->data[SC_SLOWCAST]->val2 / 100;
- if (sc->data[SC_SUFFRAGIUM])
- time -= time * sc->data[SC_SUFFRAGIUM]->val2 / 100;
- if (sc->data[SC_MEMORIZE])
- time>>=1;
- if (sc->data[SC_POEMBRAGI])
- time -= time * sc->data[SC_POEMBRAGI]->val2 / 100;
+ // calculate base cast time (reduced by dex)
+ 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 / CONST_CASTRATE_SCALE;
+ else
+ return 0; // instant cast
}
- // calculate variable cast time reduced by item/card bonuses
+ // calculate cast time reduced by item/card bonuses
if( !(skill_get_castnodex(skill_id, skill_lv)&4) && sd )
{
int i;
@@ -9577,51 +10837,61 @@ int skill_castfix (struct block_list *bl, int skill_id, int skill_lv)
}
}
}
-
- // apply fixed cast rate modifiers via status effects.
- if( !(skill_get_castnodex(skill_id, skill_lv)&2) && sc && sc->count )
- {
- if( sc->data[SC_AB_SECRAMENT] && sc->data[SC_AB_SECRAMENT]->val2 > max_fixedReduction )
- max_fixedReduction = sc->data[SC_AB_SECRAMENT]->val2;
- }
-
- // calculate fixed cast time reduced by item/card bonuses
- if( !(skill_get_castnodex(skill_id, skill_lv)&4) && sd )
- {
- int i;
- if( sd->fixedcastrate != 100 )
- fixedcasttime = fixedcasttime * sd->fixedcastrate / 100;
- for( i = 0; i < ARRAYLENGTH(sd->skillcast) && sd->skillcast[i].id; i++ )
- {
- if( sd->skillcast[i].id == skill_id )
- {
- fixedcasttime+= fixedcasttime * sd->skillcast[i].val / 100;
- break;
- }
- }
- }
-
- // Apply more of the cast time formula for variable cast time post reduction.
- // Now let's do (1 - SQRT(scale / 530)) * (1 - sum_castReduction/100%)
- // Ensure this value is not reduced past 0.
- time = cap_value((100 - (int)sqrt(scale/530.)) * time / 100, 0, INT_MAX);
-
- // Reduce fixedcasttime by only the highest max_fixedReduction found
- if( max_fixedReduction )
- fixedcasttime -= fixedcasttime * max_fixedReduction / 100;
-
- // Apply the modified fixed cast time to variable cast time.
- time += fixedcasttime;
-
// 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;
}
/*==========================================
+ * Does cast-time reductions based on sc data.
+ *------------------------------------------*/
+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;
+ if (sc->data[SC_SUFFRAGIUM]) {
+ time -= time * sc->data[SC_SUFFRAGIUM]->val2 / 100;
+ status_change_end(bl, SC_SUFFRAGIUM, INVALID_TIMER);
+ }
+ if (sc->data[SC_MEMORIZE]) {
+ time>>=1;
+ if ((--sc->data[SC_MEMORIZE]->val2) <= 0)
+ status_change_end(bl, SC_MEMORIZE, INVALID_TIMER);
+ }
+ 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
+}
+
+/*==========================================
* Does delay reductions based on dex/agi, sc data, item bonuses, ...
*------------------------------------------*/
int skill_delayfix (struct block_list *bl, int skill_id, int skill_lv)
@@ -9657,6 +10927,23 @@ int skill_delayfix (struct block_list *bl, int skill_id, int skill_lv)
if( sc && !sc->data[SC_BASILICA] )
time = 0; // There is no Delay on Basilica creation, only on cancel
break;
+ default:
+ if (battle_config.delay_dependon_dex && !(delaynodex&1))
+ { // if skill delay is allowed to be reduced by dex
+ int scale = battle_config.castrate_dex_scale - status_get_dex(bl);
+ if (scale > 0)
+ time = time * scale / battle_config.castrate_dex_scale;
+ else //To be capped later to minimum.
+ time = 0;
+ }
+ if (battle_config.delay_dependon_agi && !(delaynodex&1))
+ { // if skill delay is allowed to be reduced by agi
+ int scale = battle_config.castrate_dex_scale - status_get_agi(bl);
+ if (scale > 0)
+ time = time * scale / battle_config.castrate_dex_scale;
+ else //To be capped later to minimum.
+ time = 0;
+ }
}
if ( sc && sc->data[SC_SPIRIT] )
@@ -10162,8 +11449,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)
@@ -10321,6 +11608,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;
+}
/*==========================================
*
@@ -10487,6 +11816,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;
@@ -10554,6 +11892,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;
+}
/*==========================================
*
@@ -10595,6 +11964,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);
@@ -10793,14 +12172,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)
@@ -10969,6 +12370,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 )
@@ -11035,6 +12444,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);
@@ -11407,6 +12821,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;
@@ -11428,22 +12845,27 @@ 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)
- { // Now we figure out how many runes we're going to make. :3
- int skill_lv = pc_checkskill(sd,skill_id);
- if( skill_lv > 4 && skill_lv < 10) // level 5~9 can make 1~2 runes
- qty=(rand()%2)+1;
- else if( skill_lv == 10 ) // Level 10 can make 1~3 runes
- qty=(rand()%3)+1;
-
- // Check to see if the amount of runes will exceed 20.
- i = pc_search_inventory(sd,nameid);
- if( i >= 0 && sd->status.inventory[i].amount+qty > 20 ) // Cancel creation if created stones will exceed 20.
- {
- clif_msg(sd,0x61b);
- return 0;
+ 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++){
@@ -11451,10 +12873,7 @@ int skill_produce_mix (struct map_session_data *sd, int skill_id, int nameid, in
if( (id=skill_produce_db[idx].mat_id[i]) <= 0 )
continue;
num++;
- if (skill_id == RK_RUNEMASTERY)
- x=skill_produce_db[idx].mat_amount[i]; // RK_RUNEMASTERY only uses one set of required items, even if making more than 1 item
- else
- 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);
@@ -11499,6 +12918,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]
@@ -11547,57 +12970,21 @@ int skill_produce_mix (struct map_session_data *sd, int skill_id, int nameid, in
make_per = make_per * battle_config.pp_rate / 100;
break;
case SA_CREATECON: // Elemental Converter Creation
- case AB_ANCILLA: // Ancilla Creation
make_per = 100000; // should be 100% success rate
break;
- case RK_RUNEMASTERY: //Information from iROWiki and RuneItemInfo.lua
- {
- int skill_lv = pc_checkskill(sd,skill_id);
-
- make_per = 5100 + 20 * skill_lv; // Base chance.
-
- //Take stats into account before applying non-modified values.
- make_per += (status->dex / 30 + status->luk / 10) + sd->status.job_level / 10 * 100;
-
- switch(sd->produce_itemusedid)
- { // Add success rate based on what type of stone is used.
- case 12737:
- make_per += 200; break;
- case 12734:
- make_per += 500; break;
- case 12738:
- make_per += 800; break;
- case 12735:
- make_per += 1100; break;
- case 12736:
- make_per += 1400; break;
- default:
- break;
- }
- sd->produce_itemusedid = 0;
-
- switch(nameid)
- { // Reduce success rate based on what rank stone we're making.
- case 12727: // Runstone_Verkana
- make_per -= 2000; // S Class
- break;
- case 12725: // Runstone_Nosiege
- case 12730: // Runstone_Urj
- make_per -= 1500; // A Rank
- break;
- case 12728: // Runstone_Isia
- case 12732: // Runstone_Pertz
- make_per -= 1000; // B Rank
- break;
- case 12726: // Runstone_Rhydo
- case 12729: // Runstone_Asir
- case 12731: // Runstone_Turisus
- case 12733: // Runstone_Hagalas
- make_per -= 500; // C Rank
- 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)
@@ -11636,6 +13023,7 @@ int skill_produce_mix (struct map_session_data *sd, int skill_id, int nameid, in
if(make_per < 1) make_per = 1;
+
if(rand()%10000 < make_per || qty > 1){ //Success, or crafting multiple items.
struct item tmp_item;
memset(&tmp_item,0,sizeof(tmp_item));
@@ -11666,6 +13054,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:
@@ -11735,7 +13127,6 @@ int skill_produce_mix (struct map_session_data *sd, int skill_id, int nameid, in
case AM_TWILIGHT2:
case AM_TWILIGHT3:
case ASC_CDP:
- case RK_RUNEMASTERY:
clif_produceeffect(sd,2,nameid);
clif_misceffect(&sd->bl,5);
break;
@@ -11745,6 +13136,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.
@@ -11790,6 +13186,7 @@ int skill_produce_mix (struct map_session_data *sd, int skill_id, int nameid, in
clif_misceffect(&sd->bl,2);
break;
case RK_RUNEMASTERY:
+ case GC_CREATENEWPOISON:
clif_produceeffect(sd,3,nameid);
clif_misceffect(&sd->bl,6);
break;
@@ -11846,6 +13243,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;
+}
+
/*==========================================
*
@@ -12023,6 +13539,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:
@@ -12229,6 +13746,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
}
/*==========================================
@@ -12259,7 +13860,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]);
@@ -12301,7 +13905,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);
@@ -12359,9 +13966,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;
- else if( strcmpi(split[10],"dragon")==0 ) skill_db[i].state = ST_DRAGON;
- else if( strcmpi(split[10],"warg")==0 ) skill_db[i].state = ST_WARG;
- else if( strcmpi(split[10],"madogear")==0 ) skill_db[i].state = ST_MADOGEAR;
+ /**
+ * 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);
@@ -12374,20 +13989,21 @@ static bool skill_parse_row_requiredb(char* split[], int columns, int current)
}
static bool skill_parse_row_castdb(char* split[], int columns, int current)
-{// SkillID,CastingTime,FixedCastingTime,AfterCastActDelay,Cooldown,AfterCastWalkDelay,Duration1,Duration2
+{// SkillID,CastingTime,AfterCastActDelay,AfterCastWalkDelay,Duration1,Duration2
int i = atoi(split[0]);
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].fixedcast);
- skill_split_atoi(split[3],skill_db[i].delay);
- skill_split_atoi(split[4],skill_db[i].cooldown);
- skill_split_atoi(split[5],skill_db[i].walkdelay);
- skill_split_atoi(split[6],skill_db[i].upkeep_time);
- skill_split_atoi(split[7],skill_db[i].upkeep_time2);
-
+ 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;
}
@@ -12397,7 +14013,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);
@@ -12411,7 +14030,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;
@@ -12497,6 +14119,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
@@ -12511,7 +14177,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]);
@@ -12527,13 +14196,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" , ',', 8, 8, 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);
@@ -12541,6 +14211,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 0cadd92d7..97bd54252 100644
--- a/src/map/skill.h
+++ b/src/map/skill.h
@@ -90,8 +90,8 @@ struct s_skill_db {
char desc[40];
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],fixedcast[MAX_SKILL_LEVEL],cooldown[MAX_SKILL_LEVEL];
- int upkeep_time[MAX_SKILL_LEVEL],upkeep_time2[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],cooldown[MAX_SKILL_LEVEL];
int castcancel,cast_def_rate;
int inf2,maxcount[MAX_SKILL_LEVEL],skill_type;
int blewcount[MAX_SKILL_LEVEL];
@@ -239,9 +239,7 @@ int skill_get_state(int id);
int skill_get_zeny( int id ,int lv );
int skill_get_num( int id ,int lv );
int skill_get_cast( int id ,int lv );
-int skill_get_fixedcast( int id ,int lv );
int skill_get_delay( int id ,int lv );
-int skill_get_cooldown( int id ,int lv );
int skill_get_walkdelay( int id ,int lv );
int skill_get_time( int id ,int lv );
int skill_get_time2( int id ,int lv );
@@ -292,6 +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_id, int skill_lv);
int skill_delayfix( struct block_list *bl, int skill_id, int skill_lv);
// Skill conditions check and remove [Inkfish]
@@ -369,9 +368,14 @@ enum {
ST_RECOV_WEIGHT_RATE,
ST_MOVE_ENABLE,
ST_WATER,
- ST_DRAGON,
- ST_WARG,
- ST_MADOGEAR
+ /**
+ * 3rd States
+ **/
+ ST_RIDINGDRAGON,
+ ST_WUG,
+ ST_RIDINGWUG,
+ ST_MADO,
+ ST_ELEMENTALSPIRIT,
};
enum e_skill {
@@ -1314,7 +1318,7 @@ enum e_skill {
GN_S_PHARMACY,
GN_SLINGITEM_RANGEMELEEATK,
- AB_SECRAMENT = 2515,
+ AB_SECRAMENT=2515,
WM_SEVERE_RAINSTORM_MELEE,
SR_HOWLINGOFLION,
SR_RIDEINLIGHTNING,
@@ -1505,7 +1509,7 @@ enum {
UNT_EVILLAND,
UNT_DARK_RUNNER, //TODO
UNT_DARK_TRANSFER, //TODO
- UNT_EPICLESIS,
+ UNT_EPICLESIS, //TODO
UNT_EARTHSTRAIN, //TODO
UNT_MANHOLE, //TODO
UNT_DIMENSIONDOOR, //TODO
@@ -1551,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 f704ee0d6..dd528660b 100644
--- a/src/map/status.c
+++ b/src/map/status.c
@@ -35,7 +35,7 @@
#include <stdlib.h>
#include <memory.h>
#include <string.h>
-#include <math.h>
+
//Regen related flags.
enum e_regen
@@ -52,12 +52,17 @@ static int hp_coefficient2[CLASS_COUNT];
static int hp_sigma_val[CLASS_COUNT][MAX_LEVEL+1];
static int sp_coefficient[CLASS_COUNT];
static int aspd_base[CLASS_COUNT][MAX_WEAPON_TYPE]; //[blackhole89]
-static int shield_aspd_base[CLASS_COUNT];
static int refinebonus[MAX_REFINE_BONUS][3]; // 精錬ボーナステーブル(refine_db.txt)
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;
@@ -400,7 +405,7 @@ void initChangeTables(void)
set_sc( CASH_INCAGI , SC_INCREASEAGI , SI_INCREASEAGI , SCB_AGI|SCB_SPEED );
set_sc( CASH_ASSUMPTIO , SC_ASSUMPTIO , SI_ASSUMPTIO , SCB_NONE );
- set_sc( ALL_PARTYFLEE , SC_PARTYFLEE , SI_PARTYFLEE , SCB_FLEE );
+ //set_sc( ALL_PARTYFLEE , SC_INCFLEE , SI_PARTYFLEE , SCB_NONE );
set_sc( CR_SHRINK , SC_SHRINK , SI_SHRINK , SCB_NONE );
set_sc( RG_CLOSECONFINE , SC_CLOSECONFINE2 , SI_CLOSECONFINE2 , SCB_NONE );
@@ -413,30 +418,6 @@ void initChangeTables(void)
add_sc( SA_ELEMENTGROUND , SC_ELEMENTALCHANGE );
add_sc( SA_ELEMENTWIND , SC_ELEMENTALCHANGE );
- set_sc( RK_ENCHANTBLADE , SC_ENCHANTBLADE , SI_ENCHANTBLADE , SCB_NONE );
- set_sc( RK_DEATHBOUND , SC_DEATHBOUND , SI_DEATHBOUND , SCB_NONE );
- set_sc( RK_MILLENNIUMSHIELD , SC_MILLENNIUMSHIELD , SI_BLANK , SCB_NONE );
- set_sc( RK_CRUSHSTRIKE , SC_CRUSHSTRIKE , SI_CRUSHSTRIKE , 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_DEF2|SCB_MDEF2 );
- set_sc( RK_VITALITYACTIVATION, SC_VITALITYACTIVATION , SI_VITALITYACTIVATION , SCB_REGEN );
- set_sc( RK_FIGHTINGSPIRIT , SC_FIGHTINGSPIRIT , SI_FIGHTINGSPIRIT , SCB_ASPD );
- set_sc( RK_ABUNDANCE , SC_ABUNDANCE , SI_ABUNDANCE , SCB_NONE );
-
- set_sc( AB_ADORAMUS , SC_ADORAMUS , SI_ADORAMUS , SCB_AGI|SCB_SPEED );
- add_sc( AB_CLEMENTIA , SC_BLESSING );
- add_sc( AB_CANTO , SC_INCREASEAGI );
- add_sc( AB_PRAEFATIO , SC_KYRIE );
- set_sc( AB_EPICLESIS , SC_EPICLESIS , SI_EPICLESIS , SCB_MAXHP );
- 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_NONE );
- set_sc( AB_DUPLELIGHT , SC_DUPLELIGHT , SI_DUPLELIGHT , SCB_NONE );
- set_sc( AB_SECRAMENT , SC_AB_SECRAMENT , SI_AB_SECRAMENT , SCB_NONE );
-
set_sc( HLIF_AVOID , SC_AVOID , SI_BLANK , SCB_SPEED );
set_sc( HLIF_CHANGE , SC_CHANGE , SI_BLANK , SCB_VIT|SCB_INT );
set_sc( HFLI_FLEET , SC_FLEET , SI_BLANK , SCB_ASPD|SCB_BATK|SCB_WATK );
@@ -470,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,
@@ -514,7 +651,6 @@ void initChangeTables(void)
StatusIconChangeTable[SC_SPL_DEF] = SI_SPL_DEF;
StatusIconChangeTable[SC_MANU_MATK] = SI_MANU_MATK;
StatusIconChangeTable[SC_SPL_MATK] = SI_SPL_MATK;
-
//Cash Items
StatusIconChangeTable[SC_FOOD_STR_CASH] = SI_FOOD_STR_CASH;
StatusIconChangeTable[SC_FOOD_AGI_CASH] = SI_FOOD_AGI_CASH;
@@ -542,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;
@@ -586,8 +797,6 @@ void initChangeTables(void)
StatusChangeFlagTable[SC_SPCOST_RATE] |= SCB_ALL;
StatusChangeFlagTable[SC_WALKSPEED] |= SCB_SPEED;
StatusChangeFlagTable[SC_ITEMSCRIPT] |= SCB_ALL;
- StatusChangeFlagTable[SC_FEAR] |= SCB_HIT|SCB_FLEE;
-
// Cash Items
StatusChangeFlagTable[SC_FOOD_STR_CASH] = SCB_STR;
StatusChangeFlagTable[SC_FOOD_AGI_CASH] = SCB_AGI;
@@ -601,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;
}
@@ -627,6 +841,14 @@ static void initDummyData(void)
dummy_status.mode = MD_CANMOVE;
}
+
+//For copying a status_data structure from b to a, without overwriting current Hp and Sp
+static inline void status_cpy(struct status_data* a, const struct status_data* b)
+{
+ memcpy((void*)&a->max_hp, (const void*)&b->max_hp, sizeof(struct status_data)-(sizeof(a->hp)+sizeof(a->sp)));
+}
+
+
/*==========================================
* 精錬ボーナス
*------------------------------------------*/
@@ -748,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]
@@ -765,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);
}
@@ -917,9 +1142,6 @@ int status_heal(struct block_list *bl,int hp,int sp, int flag)
}
if(sp) {
- if (sc && sc->data[SC_BERSERK] && sc->data[SC_ABUNDANCE]) // SP does not regenerate during Frenzy.
- sp = 0;
-
if((unsigned int)sp > status->max_sp - status->sp)
sp = status->max_sp - status->sp;
}
@@ -1199,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;
@@ -1233,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).
@@ -1279,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;
@@ -1299,28 +1521,42 @@ int status_check_visibility(struct block_list *src, struct block_list *target)
// Basic ASPD value
int status_base_amotion_pc(struct map_session_data* sd, struct status_data* status)
{
- int amotion, shield = 0;
+ int amotion;
// base weapon delay
amotion = (sd->status.weapon < MAX_WEAPON_TYPE)
? (aspd_base[pc_class2idx(sd->status.class_)][sd->status.weapon]) // single weapon
: (aspd_base[pc_class2idx(sd->status.class_)][sd->weapontype1] + aspd_base[pc_class2idx(sd->status.class_)][sd->weapontype2])*7/10; // dual-wield
- if (sd->status.shield)
- shield = shield_aspd_base[pc_class2idx(sd->status.class_)] * 10;
-
// percentual delay reduction from stats
- amotion-= ( amotion - shield ) * (4*status->agi + status->dex)/1000;
-
+ amotion-= amotion * (4*status->agi + status->dex)/1000;
+
// raw delay adjustment from bAspd bonus
amotion+= sd->aspd_add;
-
- return amotion;
+#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;
}
static unsigned short status_base_atk(const struct block_list *bl, const struct status_data *status)
{
- int flag = 0, str, dex, dstr, base;
+ int flag = 0, str, dex, dstr;
if(!(bl->type&battle_config.enable_baseatk))
return 0;
@@ -1338,10 +1574,10 @@ static unsigned short status_base_atk(const struct block_list *bl, const struct
flag = 1;
}
if (flag) {
- base =str = status->dex;
+ str = status->dex;
dex = status->str;
} else {
- base = str = status->str;
+ str = status->str;
dex = status->dex;
}
//Normally only players have base-atk, but homunc have a different batk
@@ -1350,12 +1586,33 @@ static unsigned short status_base_atk(const struct block_list *bl, const struct
dstr = str/10;
str += dstr*dstr;
if (bl->type == BL_PC)
- str = (((TBL_PC*)bl)->status.base_level*10/4 + base*10 + dex*10/5 + status->luk*10/3)/10;
+ str+= dex/5 + status->luk/5;
return cap_value(str, 0, USHRT_MAX);
}
-#define status_base_matk_max(status) (status->int_+(status->int_/5)*(status->int_/5))
-#define status_base_matk_min(status) (status->int_+(status->int_/7)*(status->int_/7))
+
+static inline unsigned short status_base_matk_max(const struct status_data* status)
+{
+ #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
+{
+ #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
+}
+
//Fills in the misc data that can be calculated from the other status info (except for level)
void status_calc_misc(struct block_list *bl, struct status_data *status, int level)
@@ -1366,23 +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);
- //Renewal calculation? HIT is currently coming up too high.
- status->hit += 175 + status->dex + (unsigned short)floor((double)status->luk/3) + level;
- status->flee += 100 + status->agi + level;
-
- // Values are still off by roughly 1~3 points. Getting there though.
- status->def2 += (level*10/2 + status->vit*10/2 + status->agi*10/5)/10;
- if( bl->type != BL_MOB )
- status->mdef2 += (level*10/4 + status->int_*10 + status->vit*10/5 + status->dex*10/5)/10;
- else
- status->mdef2 = status->mdef; // Mobs use their mdef as their mdef2.
-
- //Status MATK = floor(Base Level/4 + INT + INT/2 + DEX/5 + LUK/3)
- status->status_matk = (unsigned short)floor((double)level/4 + (double)status->int_ + (double)status->int_/2 + (double)status->dex/5 + (double)status->luk/3);
+#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;
@@ -1399,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:
@@ -1561,11 +1830,8 @@ int status_calc_mob_(struct mob_data* md, bool first)
status->max_sp += 200 * gc->defense;
status->hp = status->max_hp;
status->sp = status->max_sp;
- if( gc->castle_id < 24 )
- {
- status->def += (gc->defense+2)/3;
- status->mdef += (gc->defense+2)/3;
- }
+ status->def += (gc->defense+2)/3;
+ status->mdef += (gc->defense+2)/3;
}
if(md->class_ != MOBID_EMPERIUM) {
status->batk += status->batk * 10*md->guardian_data->guardup_lv/100;
@@ -1712,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.
@@ -1772,9 +2050,6 @@ int status_calc_pc_(struct map_session_data* sd, bool first)
sd->critical_rate = sd->hit_rate = sd->flee_rate = sd->flee2_rate = 100;
sd->def_rate = sd->def2_rate = sd->mdef_rate = sd->mdef2_rate = 100;
sd->regen.state.block = 0;
- sd->fixedcastrate=100;
- sd->weapon_matk = 0;
- sd->equipment_matk = 0;
// zeroed arrays, order follows the order in pc.h.
// add new arrays to the end of zeroed area in pc.h (see comments) and size here. [zzo]
@@ -1818,7 +2093,7 @@ int status_calc_pc_(struct map_session_data* sd, bool first)
status->mode = MD_MASK&~(MD_BOSS|MD_PLANT|MD_DETECTOR|MD_ANGRY|MD_TARGETWEAK);
status->size = (sd->class_&JOBL_BABY)?0:1;
- if (battle_config.character_size && (pc_isriding(sd) || pc_isdragon(sd))) { //[Lupus]
+ if (battle_config.character_size && pc_isriding(sd)) { //[Lupus]
if (sd->class_&JOBL_BABY) {
if (battle_config.character_size&2)
status->size++;
@@ -1940,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) {
@@ -1952,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];
@@ -1979,11 +2268,7 @@ int status_calc_pc_(struct map_session_data* sd, bool first)
}
}
else if(sd->inventory_data[index]->type == IT_ARMOR) {
- int r = sd->status.inventory[index].refine;
- int per = 0, refine=(r>0)?1:0;
- for(per=1; per<r; per++)
- refine += (per/4) + 1;
- refinedef += refine;
+ refinedef += sd->status.inventory[index].refine*refinebonus[0][0];
if(sd->inventory_data[index]->script) {
run_script(sd->inventory_data[index]->script,0,sd->bl.id,0);
if (!calculating) //Abort, run_script retriggered this. [Skotlex]
@@ -2008,7 +2293,7 @@ int status_calc_pc_(struct map_session_data* sd, bool first)
memcpy(sd->param_equip,sd->param_bonus,sizeof(sd->param_equip));
memset(sd->param_bonus, 0, sizeof(sd->param_bonus));
- status->def += refinedef;
+ status->def += (refinedef+50)/100;
//Parse Cards
for(i=0;i<EQI_MAX-1;i++) {
@@ -2103,7 +2388,7 @@ int status_calc_pc_(struct map_session_data* sd, bool first)
sd->left_weapon.atkmods[1] = atkmods[1][sd->weapontype2];
sd->left_weapon.atkmods[2] = atkmods[2][sd->weapontype2];
- if((pc_isriding(sd) || pc_isdragon(sd)) &&
+ if(pc_isriding(sd) &&
(sd->status.weapon==W_1HSPEAR || sd->status.weapon==W_2HSPEAR))
{ //When Riding with spear, damage modifier to mid-class becomes
//same as versus large size.
@@ -2312,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
@@ -2320,15 +2604,22 @@ int status_calc_pc_(struct map_session_data* sd, bool first)
sd->def_rate = 0;
if(sd->def_rate != 100) {
i = status->def * sd->def_rate/100;
+#if RRMODE
status->def = cap_value(i, SHRT_MIN, SHRT_MAX);
- }
-
+#else
+ status->def = cap_value(i, CHAR_MIN, CHAR_MAX);
+#endif
+ }
+#if RRMODE == 0
+ /**
+ * The following setting does not affect Renewal Mode
+ **/
if (!battle_config.weapon_defense_type && status->def > battle_config.max_def)
{
status->def2 += battle_config.over_def_bonus*(status->def -battle_config.max_def);
- status->def = (unsigned short)battle_config.max_def;
+ status->def = (unsigned char)battle_config.max_def;
}
-
+#endif
// ----- EQUIPMENT-MDEF CALCULATION -----
// Apply relative modifiers from equipment
@@ -2336,15 +2627,22 @@ int status_calc_pc_(struct map_session_data* sd, bool first)
sd->mdef_rate = 0;
if(sd->mdef_rate != 100) {
i = status->mdef * sd->mdef_rate/100;
+#if RRMODE
status->mdef = cap_value(i, SHRT_MIN, SHRT_MAX);
- }
-
+#else
+ status->mdef = cap_value(i, CHAR_MIN, CHAR_MAX);
+#endif
+ }
+#if RRMODE == 0
+ /**
+ * The following setting does not affect Renewal Mode
+ **/
if (!battle_config.magic_defense_type && status->mdef > battle_config.max_def)
{
status->mdef2 += battle_config.over_def_bonus*(status->mdef -battle_config.max_def);
- status->mdef = (signed short)battle_config.max_def;
+ status->mdef = (signed char)battle_config.max_def;
}
-
+#endif
// ----- ASPD CALCULATION -----
// Unlike other stats, ASPD rate modifiers from skills/SCs/items/etc are first all added together, then the final modifier is applied
@@ -2362,8 +2660,7 @@ int status_calc_pc_(struct map_session_data* sd, bool first)
status->aspd_rate -= ((skill+1)/2) * 10;
if(pc_isriding(sd))
status->aspd_rate += 500-100*pc_checkskill(sd,KN_CAVALIERMASTERY);
- if(pc_isdragon(sd))
- status->aspd_rate += 750-75*pc_checkskill(sd,RK_DRAGONTRAINING); // Officiak is rumoured to be 75+5*skilllv...giving you 125% ASPD?
+
status->adelay = 2*status->amotion;
@@ -2381,8 +2678,6 @@ int status_calc_pc_(struct map_session_data* sd, bool first)
sd->max_weight += 2000*skill;
if(pc_isriding(sd) && pc_checkskill(sd,KN_RIDING)>0)
sd->max_weight += 10000;
- if(pc_isdragon(sd) && (skill=pc_checkskill(sd,RK_DRAGONTRAINING))>0)
- sd->max_weight += 5000+2000*skill; //+200 weight per level of RK_DRAGINTRAINING
if(sc->data[SC_KNOWLEDGE])
sd->max_weight += sd->max_weight*sc->data[SC_KNOWLEDGE]->val1/10;
if((skill=pc_checkskill(sd,ALL_INCCARRY))>0)
@@ -2408,8 +2703,6 @@ int status_calc_pc_(struct map_session_data* sd, bool first)
sd->dsprate = 0;
if(sd->castrate < 0)
sd->castrate = 0;
- if( sd->fixedcastrate < 0 )
- sd->fixedcastrate = 0;
if(sd->delayrate < 0)
sd->delayrate = 0;
if(sd->hprecov_rate < 0)
@@ -2431,17 +2724,6 @@ int status_calc_pc_(struct map_session_data* sd, bool first)
sd->magic_addrace[RC_DRAGON]+=skill;
sd->subrace[RC_DRAGON]+=skill;
}
- if( (skill = pc_checkskill(sd, AB_EUCHARISTICA)) > 0 )
- {
- sd->right_weapon.addrace[RC_DEMON]+=skill;
- sd->right_weapon.addele[ELE_DARK]+=skill;
- sd->left_weapon.addrace[RC_DEMON]+=skill;
- sd->left_weapon.addele[ELE_DARK]+=skill;
- sd->magic_addrace[RC_DEMON]+=skill;
- sd->magic_addele[ELE_DARK]+=skill;
- sd->subrace[RC_DEMON]+=skill;
- sd->subele[ELE_DARK]+=skill;
- }
if(sc->count){
if(sc->data[SC_CONCENTRATE])
@@ -2480,7 +2762,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 -----
@@ -2594,8 +2875,13 @@ int status_calc_homunculus_(struct homun_data *hd, bool first)
status->adelay = status->amotion; //It seems adelay = amotion for Homunculus.
status_calc_misc(&hd->bl, status, hom->level);
+#if RRMODE
+ /**
+ * In RE Mode matk_max is used as source of weaponMATK, but homuns don't have it -- so we swap the values here.
+ **/
+ status->matk_max = status->matk_min;
+#endif
status_cpy(&hd->battle_status, status);
-
return 1;
}
@@ -2612,9 +2898,17 @@ static signed short status_calc_hit(struct block_list *,struct status_change *,i
static signed short status_calc_critical(struct block_list *,struct status_change *,int);
static signed short status_calc_flee(struct block_list *,struct status_change *,int);
static signed short status_calc_flee2(struct block_list *,struct status_change *,int);
-static signed short status_calc_def(struct block_list *,struct status_change *,int);
+#if RRMODE
+ static short status_calc_def(struct block_list *bl, struct status_change *sc, int);
+#else
+ static signed char status_calc_def(struct block_list *,struct status_change *,int);
+#endif
static signed short status_calc_def2(struct block_list *,struct status_change *,int);
-static signed short status_calc_mdef(struct block_list *,struct status_change *,int);
+#if RRMODE
+ static short status_calc_mdef(struct block_list *bl, struct status_change *sc, int);
+#else
+ static signed char status_calc_mdef(struct block_list *,struct status_change *,int);
+#endif
static signed short status_calc_mdef2(struct block_list *,struct status_change *,int);
static unsigned short status_calc_speed(struct block_list *,struct status_change *,int);
static short status_calc_aspd_rate(struct block_list *,struct status_change *,int);
@@ -2792,8 +3086,6 @@ void status_calc_regen_rate(struct block_list *bl, struct regen_data *regen, str
} else
regen->flag&=~sce->val4; //Remove regen as specified by val4
}
- if( sc->data[SC_VITALITYACTIVATION] )
- regen->flag &=~RGN_SP;
}
/// Recalculates parts of an object's battle status according to the specified flags.
@@ -2857,7 +3149,7 @@ void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag)
if(flag&SCB_LUK) {
status->luk = status_calc_luk(bl, sc, b_status->luk);
- flag|=SCB_BATK|SCB_CRI|SCB_FLEE2|SCB_MATK;
+ flag|=SCB_BATK|SCB_CRI|SCB_FLEE2;
}
if(flag&SCB_BATK && b_status->batk) {
@@ -3048,38 +3340,27 @@ void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag)
}
if(flag&SCB_MATK) {
- int wlv = 1, wmatk = 0;
-
//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);
- // iRO Wiki states as of 2011/02/24:
- // Status MATK = floor(Base Level/4 + INT + INT/2 + DEX/5 + LUK/3)
- status->status_matk = status_get_lv(bl)/4 + status->int_ + status->int_/2 + status->dex/5 + status->luk/3;
-
- if( sd )
- {
- short index = sd->equip_index[EQI_HAND_R];
- wmatk = sd->weapon_matk + sd->battle_status.rhw.atk2 + sd->equipment_matk;
- if( index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_WEAPON )
- wlv = sd->inventory_data[index]->wlv;
- }
-
- // Variance = ア 0.1 * Weapon Level * Base Weapon MATK
- // Used in a lot of magical attack calculations still.
- status->matk_min = status->status_matk + wmatk;
- status->matk_max = status->status_matk + wmatk + (wmatk * wlv / 10);
-
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;
@@ -3160,14 +3441,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
@@ -3228,32 +3510,26 @@ void status_calc_bl_(struct block_list* bl, enum scb_flag flag, bool first)
clif_updatestatus(sd,SP_ASPD);
if(b_status.speed != status->speed)
clif_updatestatus(sd,SP_SPEED);
- if(b_status.rhw.atk != status->rhw.atk || b_status.lhw.atk != status->lhw.atk || b_status.batk != status->batk
- || b_status.rhw.atk2 != status->rhw.atk2 || b_status.lhw.atk2 != status->lhw.atk2 || b_status.equipment_atk != status->equipment_atk)
- {
+ if(b_status.rhw.atk != status->rhw.atk || b_status.lhw.atk != status->lhw.atk || b_status.batk != status->batk)
clif_updatestatus(sd,SP_ATK1);
- clif_updatestatus(sd,SP_ATK2);
- clif_updatestatus(sd,SP_MATK1);
- }
- if(b_status.def != status->def || b_status.def2 != status->def2)
- {
+ if(b_status.def != status->def)
clif_updatestatus(sd,SP_DEF1);
+ if(b_status.rhw.atk2 != status->rhw.atk2 || b_status.lhw.atk2 != status->lhw.atk2)
+ clif_updatestatus(sd,SP_ATK2);
+ if(b_status.def2 != status->def2)
clif_updatestatus(sd,SP_DEF2);
- }
if(b_status.flee2 != status->flee2)
clif_updatestatus(sd,SP_FLEE2);
if(b_status.cri != status->cri)
clif_updatestatus(sd,SP_CRITICAL);
if(b_status.matk_max != status->matk_max)
- {
clif_updatestatus(sd,SP_MATK1);
+ if(b_status.matk_min != status->matk_min)
clif_updatestatus(sd,SP_MATK2);
- }
- if(b_status.mdef != status->mdef || b_status.mdef2 != status->mdef2)
- {
+ if(b_status.mdef != status->mdef)
clif_updatestatus(sd,SP_MDEF1);
+ if(b_status.mdef2 != status->mdef2)
clif_updatestatus(sd,SP_MDEF2);
- }
if(b_status.rhw.range != status->rhw.range)
clif_updatestatus(sd,SP_ATTACKRANGE);
if(b_status.max_hp != status->max_hp)
@@ -3343,6 +3619,9 @@ 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;
@@ -3384,6 +3663,9 @@ 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;
@@ -3417,8 +3699,6 @@ static unsigned short status_calc_vit(struct block_list *bl, struct status_chang
vit += sc->data[SC_MARIONETTE2]->val3&0xFF;
if(sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_HIGH && vit < 50)
vit = 50;
- if(sc->data[SC_LAUDAAGNUS])
- vit += sc->data[SC_LAUDAAGNUS]->val2;
return (unsigned short)cap_value(vit,0,USHRT_MAX);
}
@@ -3529,8 +3809,6 @@ static unsigned short status_calc_luk(struct block_list *bl, struct status_chang
luk += sc->data[SC_MARIONETTE2]->val4&0xFF;
if(sc->data[SC_SPIRIT] && sc->data[SC_SPIRIT]->val2 == SL_HIGH && luk < 50)
luk = 50;
- if(sc->data[SC_LAUDARAMUS])
- luk += sc->data[SC_LAUDARAMUS]->val2;
return (unsigned short)cap_value(luk,0,USHRT_MAX);
}
@@ -3567,6 +3845,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);
}
@@ -3611,6 +3896,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);
}
@@ -3649,6 +3941,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);
}
@@ -3680,7 +3974,7 @@ static signed short status_calc_hit(struct block_list *bl, struct status_change
if(sc->data[SC_MERC_HITUP])
hit += sc->data[SC_MERC_HITUP]->val2;
if(sc->data[SC_FEAR])
- hit -= hit * 20/100;
+ hit -= hit * 20 / 100;
return (short)cap_value(hit,1,SHRT_MAX);
}
@@ -3726,12 +4020,31 @@ static signed short status_calc_flee(struct block_list *bl, struct status_change
flee -= sc->data[SC_GATLINGFEVER]->val4;
if(sc->data[SC_SPEED])
flee += 10 + sc->data[SC_SPEED]->val1 * 10;
- if(sc->data[SC_PARTYFLEE])
- flee += sc->data[SC_PARTYFLEE]->val1 * 10;
if(sc->data[SC_MERC_FLEEUP])
flee += sc->data[SC_MERC_FLEEUP]->val2;
if(sc->data[SC_FEAR])
- flee -= flee * 20/100;
+ 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);
}
@@ -3748,12 +4061,18 @@ static signed short status_calc_flee2(struct block_list *bl, struct status_chang
return (short)cap_value(flee2,10,SHRT_MAX);
}
-
-static signed short status_calc_def(struct block_list *bl, struct status_change *sc, int def)
+#if RRMODE
+ static short status_calc_def(struct block_list *bl, struct status_change *sc, int def)
+#else
+ static signed char status_calc_def(struct block_list *bl, struct status_change *sc, int def)
+#endif
{
if(!sc || !sc->count)
- return (signed short)cap_value(def,SHRT_MIN,SHRT_MAX);
-
+#if RRMODE
+ return (short)cap_value(def,SHRT_MIN,SHRT_MAX);
+#else
+ return (signed char)cap_value(def,CHAR_MIN,CHAR_MAX);
+#endif
if(sc->data[SC_BERSERK])
return 0;
if(sc->data[SC_SKA])
@@ -3788,8 +4107,31 @@ static signed short 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;
-
- return (signed short)cap_value(def,SHRT_MIN,SHRT_MAX);
+ 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;
+#if RRMODE
+ return (short)cap_value(def,SHRT_MIN,SHRT_MAX);
+#else
+ return (signed char)cap_value(def,CHAR_MIN,CHAR_MAX);
+#endif
}
static signed short status_calc_def2(struct block_list *bl, struct status_change *sc, int def2)
@@ -3820,16 +4162,36 @@ 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_STONEHARDSKIN])
- def2 += sc->data[SC_STONEHARDSKIN]->val3;
+ 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);
}
-static signed short status_calc_mdef(struct block_list *bl, struct status_change *sc, int mdef)
+#if RRMODE
+ static short status_calc_mdef(struct block_list *bl, struct status_change *sc, int mdef)
+#else
+ static signed char status_calc_mdef(struct block_list *bl, struct status_change *sc, int mdef)
+#endif
{
if(!sc || !sc->count)
- return (signed short)cap_value(mdef,SHRT_MIN,SHRT_MAX);
+#if RRMODE
+ return (short)cap_value(mdef,SHRT_MIN,SHRT_MAX);
+#else
+ return (signed char)cap_value(mdef,CHAR_MIN,CHAR_MAX);
+#endif
if(sc->data[SC_BERSERK])
return 0;
@@ -3849,8 +4211,22 @@ static signed short 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.
-
- return (signed short)cap_value(mdef,SHRT_MIN,SHRT_MAX);
+ 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;
+
+#if RRMODE
+ return (short)cap_value(mdef,SHRT_MIN,SHRT_MAX);
+#else
+ return (signed char)cap_value(mdef,CHAR_MIN,CHAR_MAX);
+#endif
}
static signed short status_calc_mdef2(struct block_list *bl, struct status_change *sc, int mdef2)
@@ -3862,8 +4238,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_STONEHARDSKIN])
- mdef2 += sc->data[SC_STONEHARDSKIN]->val3;
+ if(sc->data[SC_ANALYZE])
+ mdef2 -= mdef2 * ( 14 * sc->data[SC_ANALYZE]->val1 ) / 100;
return (short)cap_value(mdef2,1,SHRT_MAX);
}
@@ -3890,11 +4266,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;
- if( sd && pc_isdragon(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;
}
@@ -3919,7 +4301,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 );
@@ -3943,8 +4325,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_ADORAMUS] )
- val = max( val, 25 );
+ 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 );
@@ -4012,7 +4410,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);
@@ -4081,12 +4484,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])
@@ -4107,9 +4514,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_FIGHTINGSPIRIT])
- aspd_rate -= sc->data[SC_FIGHTINGSPIRIT]->val3;
-
+ 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);
}
@@ -4123,7 +4562,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);
@@ -4149,7 +4588,10 @@ static unsigned int status_calc_maxhp(struct block_list *bl, struct status_chang
maxhp += maxhp * sc->data[SC_MERC_HPUP]->val2/100;
if(sc->data[SC_EPICLESIS])
- maxhp += maxhp * sc->data[SC_EPICLESIS]->val2/100;
+ 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);
}
@@ -4184,6 +4626,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);
}
@@ -4202,6 +4647,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);
}
@@ -4336,7 +4783,7 @@ struct status_data *status_get_base_status(struct block_list *bl)
}
}
-signed short status_get_def(struct block_list *bl)
+signed char status_get_def(struct block_list *bl)
{
struct unit_data *ud;
struct status_data *status = status_get_status_data(bl);
@@ -4344,7 +4791,11 @@ signed short status_get_def(struct block_list *bl)
ud = unit_bl2ud(bl);
if (ud && ud->skilltimer != INVALID_TIMER)
def -= def * skill_get_castdef(ud->skillid)/100;
+#if RRMODE
return cap_value(def, SHRT_MIN, SHRT_MAX);
+#else
+ return cap_value(def, CHAR_MIN, CHAR_MAX);
+#endif
}
unsigned short status_get_speed(struct block_list *bl)
@@ -4569,22 +5020,6 @@ void status_set_viewdata(struct block_list *bl, int class_)
class_ = JOB_BABY_CRUSADER2;
break;
}
- /*
- else
- if (sd->sc.option&OPTION_DRAGON) // For completeness' sake. These aren't actually needed...except maybe in older clients.
- switch (class_)
- {
- case JOB_RUNE_KNIGHT:
- class_ = JOB_RUNE_KNIGHT2;
- break;
- case JOB_RUNE_KNIGHT_H:
- class_ = JOB_RUNE_KNIGHT_H2;
- break;
- case JOB_BABY_RUNE:
- class_ = JOB_BABY_RUNE2;
- break;
- }
- */
sd->vd.class_ = class_;
clif_get_weapon_view(sd, &sd->vd.weapon, &sd->vd.shield);
sd->vd.head_top = sd->status.head_top;
@@ -4689,7 +5124,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;
@@ -4722,7 +5157,6 @@ int status_get_sc_def(struct block_list *bl, enum sc_type type, int rate, int ti
case SC_STONE:
case SC_QUAGMIRE:
case SC_SUITON:
- case SC_ADORAMUS:
return 0;
}
@@ -4741,7 +5175,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:
+ case SC_ADORAMUS://Arch Bishop
if (sd) tick>>=1; //Half duration for players.
case SC_STONE:
case SC_FREEZE:
@@ -4771,6 +5205,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))
@@ -4873,8 +5341,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 duration = tick;
+ int opt_flag, calc_flag, undead_flag, val_flag = 0, tick_time = 0;
nullpo_ret(bl);
sc = status_get_sc(bl);
@@ -4889,35 +5356,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
if( !sc )
return 0; //Unable to receive status changes
- if( sc->data[SC_REFRESH] )
- {
- if( type >= SC_COMMON_MIN && type <= SC_COMMON_MAX && type != SC_STUN ) // Immune to all common status ailments except stun (iROWiki)
- return 0;
- switch( type )
- {
- case SC_FEAR:
- case SC_BURNING:
- // Not implemented yet. (kRO 3-x balance update)
- //case SC_POISONINGWEAPON:
- //case SC_TOXIN:
- //case SC_PARALYSE:
- //case SC_VENOMBLEED:
- //case SC_MAGICMUSHROOM:
- //case SC_DEATHHURT:
- //case SC_PYREXIA:
- //case SC_OBLIVIONCURSE:
- //case SC_LEECHESEND:
- //case SC_FROSTMISTY:
- //case SC_MARSHOFABYSS:
- //case SC_DEEP_SLEEP:
- //case SC_COLD:
- //case SC_FREEZE_SP:
- //case SC_MANDRAGORA:
- return 0;
- }
- }
-
- if( status_isdead(bl) )
+ if( status_isdead(bl) && type != SC_NOCHAT ) // SC_NOCHAT should work even on dead characters
return 0;
if( bl->type == BL_MOB && type != SC_SAFETYWALL && type != SC_PNEUMA )
@@ -4940,17 +5379,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_BURNING:
+ 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)
@@ -4967,13 +5416,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_ADORAMUS]
+ sc->option&OPTION_MADOGEAR //Adrenaline doesn't affect Mado Gear [Ind]
)
return 0;
break;
@@ -4981,16 +5433,17 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
if(sd && !pc_check_weapontype(sd,skill_get_weapontype(BS_ADRENALINE2)))
return 0;
if (sc->data[SC_QUAGMIRE] ||
- sc->data[SC_DECREASEAGI] ||
- sc->data[SC_ADORAMUS]
+ sc->data[SC_DECREASEAGI]
)
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:
- if(sc->data[SC_DECREASEAGI] ||
- sc->data[SC_ADORAMUS])
+ if(sc->data[SC_DECREASEAGI])
return 0;
case SC_CONCENTRATE:
case SC_INCREASEAGI:
@@ -5001,6 +5454,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]
@@ -5152,6 +5607,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
@@ -5160,8 +5619,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:
@@ -5170,7 +5627,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;
}
}
@@ -5189,7 +5665,6 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
break;
case SC_INCREASEAGI:
status_change_end(bl, SC_DECREASEAGI, INVALID_TIMER);
- status_change_end(bl, SC_ADORAMUS, INVALID_TIMER);
break;
case SC_QUAGMIRE:
status_change_end(bl, SC_CONCENTRATE, INVALID_TIMER);
@@ -5197,7 +5672,6 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
status_change_end(bl, SC_WINDWALK, INVALID_TIMER);
//Also blocks the ones below...
case SC_DECREASEAGI:
- case SC_ADORAMUS:
status_change_end(bl, SC_CARTBOOST, INVALID_TIMER);
//Also blocks the ones below...
case SC_DONTFORGETME:
@@ -5208,6 +5682,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]
@@ -5255,10 +5730,9 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
status_change_end(bl, SC_ASSUMPTIO, INVALID_TIMER);
break;
case SC_CARTBOOST:
- if(sc->data[SC_DECREASEAGI] || sc->data[SC_ADORAMUS])
+ if(sc->data[SC_DECREASEAGI])
{ //Cancel Decrease Agi, but take no further effect [Skotlex]
status_change_end(bl, SC_DECREASEAGI, INVALID_TIMER);
- status_change_end(bl, SC_ADORAMUS, INVALID_TIMER);
return 0;
}
break;
@@ -5312,10 +5786,6 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
case SC_FOOD_LUK_CASH:
status_change_end(bl, SC_LUKFOOD, INVALID_TIMER);
break;
- case SC_FIGHTINGSPIRIT:
- if (sc->data[SC_FIGHTINGSPIRIT])
- status_change_end(bl, SC_FIGHTINGSPIRIT, INVALID_TIMER);
- break;
}
//Check for overlapping fails
@@ -5355,8 +5825,6 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
case SC_MARIONETTE2:
case SC_NOCHAT:
case SC_CHANGE: //Otherwise your Hp/Sp would get refilled while still within effect of the last invocation.
- case SC_FEAR:
- case SC_BURNING:
return 0;
case SC_COMBO:
case SC_DANCING:
@@ -5413,10 +5881,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
{
case SC_DECREASEAGI:
case SC_INCREASEAGI:
- case SC_ADORAMUS:
val2 = 2 + val1; //Agi change
- if (val3) //Canto Candidus: Add joblv/10 additional AGI (8/31/2011)
- val2 += (val3/10);
break;
case SC_ENDURE:
val2 = 7; // Hit-count [Celest]
@@ -5456,6 +5921,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]
@@ -5466,17 +5933,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
break;
case SC_KYRIE:
val2 = status->max_hp * (val1 * 2 + 10) / 100; //%Max HP to absorb
- // val4 holds current about of party memebers when casting AB_PRAEFATIO,
- // as Praefatio's barrier has more health and blocks more hits than Kyrie Elesion.
- if( val4 < 1 ) //== PR_KYRIE
- val3 = (val1 / 2 + 5);
- else
- { //== AB_PRAEFATIO
- val2 += val4 * 2; //Increase barrier strength per party member.
- val3 = 6 + val1;
- }
- if( sd )
- val1 = min(val1,pc_checkskill(sd,PR_KYRIE)); // use skill level to determine barrier health.
+ val3 = (val1 / 2 + 5); //Hits
break;
case SC_MAGICPOWER:
//val1: Skill lv
@@ -5601,10 +6058,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.
@@ -5612,9 +6069,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;
@@ -5635,6 +6097,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)
@@ -5666,7 +6129,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;
@@ -5680,7 +6143,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:
@@ -5691,7 +6154,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 )
@@ -5705,12 +6168,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;
@@ -5740,7 +6203,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.
@@ -5811,7 +6274,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
@@ -5834,13 +6297,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;
@@ -6000,11 +6463,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
break;
case SC_BLESSING:
if ((!undead_flag && status->race!=RC_DEMON) || bl->type == BL_PC)
- {
val2 = val1;
- if (val3) //Clementia: Add joblv/10 additional STR/INT/DEX (8/31/2011)
- val2 += (val3/10);
- }
else
val2 = 0; //0 -> Half stat.
break;
@@ -6110,7 +6569,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.
@@ -6213,70 +6672,6 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
case SC_KAIZEL:
val2 = 10*val1; //% of life to be revived with
break;
- case SC_MILLENNIUMSHIELD:
- val2 = (rand()%100<20) ? 4 : ((rand()%100<30) ? 3 : ((rand()%100<50) ? 2 : 0)); // 20% for 4, 30% for 3, 50% for 2
- val3 = 1000; // Initial Sheild health. (Additional sheilds health are set in battle.c when shield is broken.)
- if( sd && val2 > 0)
- clif_millenniumshield(sd,val2);
- break;
- case SC_STONEHARDSKIN:
- val2 = (status->hp * 20 / 100);
- if( val2 > 0 )
- status_heal(bl, -val2, 0, 0); // Reduce health by 20%
- if ( sd )
- val3 = (sd->status.job_level * pc_checkskill(sd,RK_RUNEMASTERY)) / 4;
- break;
- case SC_VITALITYACTIVATION:
- val2 = 50; // Increase HP recovery effects by 50%
- val3 = 50; // Reduce SP recovery effects by 50%
- break;
- case SC_FIGHTINGSPIRIT: // attack is handled in battle.c
- //val2 holds the source of the skill (1 = caster, 0 = party member.)
- //official ASPD bonus appears to be (Rune Mastery Level / 10 x 4).
- val3 = 10 * (sd?pc_checkskill(sd,RK_RUNEMASTERY):1); //Kind of dirty means to implement 4aspd increase.
- break;
- case SC_ABUNDANCE:
- val3 = tick / 10000;
- if(val3 < 1)
- val3 = 1;
- tick = 10000;
- break;
- case SC_EPICLESIS:
- val2 = 5 * val1; // % HP gained * level of Epiclesis cast.
- break;
- case SC_ORATIO:
- val2 = 2 * val1; // % Damage increased by level of Oratio cast.
- break;
- case SC_LAUDAAGNUS:
- case SC_LAUDARAMUS:
- val2 = 4+val1; // Bonus status points gained
- break;
- case SC_RENOVATIO:
- val2 = tick / 5000; // Heal every 5 seconds.
- tick = 5000;
- break;
- case SC_EXPIATIO:
- val2 = 5*val1; // DEF reduced by 5*Skill Level percent.
- break;
- case SC_DUPLELIGHT:
- val2 = 10+2*val1; //Chance of MELEE proc
- val3 = 10+2*val1; //Chance of MAGIC proc
- break;
-
- case SC_AB_SECRAMENT:
- val2 = 10*val1; //Fixed cast time reduced by 10*Skill Level
- break;
- case SC_FEAR:
- if (tick < 2000)
- val3 = 2000;
- else
- val3 = tick - 2000;
- tick = 2000;
- break;
- case SC_BURNING:
- val4 = tick/2000;
- tick = 3000;
- break;
// case SC_ARMOR_ELEMENT:
// case SC_ARMOR_RESIST:
// Mod your resistance against elements:
@@ -6310,6 +6705,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 )
@@ -6341,7 +7217,6 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
case SC_STUN:
case SC_SLEEP:
case SC_STONE:
- case SC_BURNING:
if (sd && pc_issit(sd)) //Avoid sprite sync problems.
pc_setstand(sd);
case SC_TRICKDEAD:
@@ -6356,13 +7231,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_FEAR:
+ 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:
@@ -6376,11 +7253,12 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
switch(type)
{
//OPT1
- case SC_STONE: sc->opt1 = OPT1_STONEWAIT; break;
- 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;
+ case SC_STONE: sc->opt1 = OPT1_STONEWAIT; break;
+ 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;
@@ -6390,7 +7268,6 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
case SC_ANGELUS: sc->opt2 |= OPT2_ANGELUS; break;
case SC_BLEEDING: sc->opt2 |= OPT2_BLEEDING; break;
case SC_DPOISON: sc->opt2 |= OPT2_DPOISON; break;
- case SC_FEAR: sc->opt2 |= OPT2_FEAR; break;
//OPT3
case SC_TWOHANDQUICKEN:
case SC_ONEHAND:
@@ -6486,6 +7363,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;
@@ -6532,11 +7410,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]
- || (bl->type == BL_MOB && type == SC_ORATIO)) ) // Required to show the proper status for monsters. Possible this may need an overhaul.
- clif_status_change(bl,StatusIconChangeTable[type],1,duration);
+ 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]))
@@ -6590,6 +7472,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:
@@ -6725,8 +7617,8 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const
return 0;
if (tid == INVALID_TIMER) {
- if( (type == SC_ENDURE) && sce->val4 )
- //Do not end infinite endure or speed adjustment.
+ if (type == SC_ENDURE && sce->val4)
+ //Do not end infinite endure.
return 0;
if (sce->timer != INVALID_TIMER) //Could be a SC with infinite duration
delete_timer(sce->timer,status_change_timer);
@@ -6911,7 +7803,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);
}
@@ -6919,7 +7811,7 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const
case SC_NOCHAT:
if (sd && sd->status.manner < 0 && tid != INVALID_TIMER)
sd->status.manner = 0;
- if (sd)
+ if (sd && tid == INVALID_TIMER)
{
clif_changestatus(&sd->bl,SP_MANNER,sd->status.manner);
clif_updatestatus(sd,SP_MANNER);
@@ -7056,10 +7948,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:
- if ( sd )
- clif_millenniumshield(sd,0);
+ 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;
@@ -7068,7 +8038,6 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const
case SC_FREEZE:
case SC_STUN:
case SC_SLEEP:
- case SC_BURNING:
sc->opt1 = 0;
break;
@@ -7084,15 +8053,13 @@ int status_change_end_(struct block_list* bl, enum sc_type type, int tid, const
case SC_SIGNUMCRUCIS:
sc->opt2 &= ~OPT2_SIGNUMCRUCIS;
break;
- case SC_FEAR:
- sc->opt2 &= ~OPT2_FEAR;
- break;
case SC_HIDING:
sc->option &= ~OPTION_HIDE;
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;
@@ -7222,9 +8189,8 @@ 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 )
- || (bl->type == BL_MOB && type == SC_ORATIO)) ) // Required to remove SI_ORATIO indicator from monsters.
- clif_status_change(bl,StatusIconChangeTable[type],0,0);
+ if( vd && (pcdb_checkid(vd->class_) || bl->type == BL_MER ) )
+ clif_status_change(bl,StatusIconChangeTable[type],0,0,0,0,0);
else if (sd)
clif_status_load(bl,StatusIconChangeTable[type],0);
@@ -7617,60 +8583,460 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data)
}
break;
case SC_ABUNDANCE:
- if((--sce->val3) > 0)
+ if(--(sce->val4) > 0)
{
- int sp = 60;
- if(sd) {
- if( sd->status.sp < sd->status.max_sp )
+ 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 )
{
- if( sd->status.sp + sp > sd->status.max_sp ) //No overhealing SP.
- sp = sd->status.max_sp - sd->status.sp;
- clif_heal(sd->fd,SP_SP,sp);
- status_heal(bl, 0, sp, 0);
+ 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;
+ }
}
- }
- sc_timer_next(10000+tick, status_change_timer, bl->id, data);
+
+ 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->val2) > 0) {
- int heal = status->max_hp * 3 / 100;
- if( status->hp + heal > status->max_hp )
- heal = status->max_hp - status->hp;
- if(heal > 0)
- {
- clif_heal(sd->fd,SP_HP,heal);
- status_heal(bl, heal, 0, 0);
+ 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);
}
- sc_timer_next(5000+tick, status_change_timer, bl->id, data);
return 0;
}
break;
+
case SC_FEAR:
- if(sce->val3 > 0)
+ if( --(sce->val4) >= 0 )
{
- sc_timer_next(sce->val3+tick, status_change_timer, bl->id, data);
- sce->val3 = 0;
+ if( sce->val2 > 0 )
+ sce->val2--;
+ sc_timer_next(1000 + tick, status_change_timer, bl->id, data);
+ return 0;
}
break;
- case SC_BURNING:
- if(--(sce->val4) >= 0)
+
+ case SC_SPHERE_1:
+ case SC_SPHERE_2:
+ case SC_SPHERE_3:
+ case SC_SPHERE_4:
+ case SC_SPHERE_5:
+ if( --(sce->val4) >= 0 )
{
- int flag, hp = 0;
- struct block_list *src = map_id2bl(sce->val2);
+ 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;
- hp = 1000+(status->max_hp*3 /100);
+ 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();
- clif_damage(bl,bl,tick,status->amotion,0,hp,1,9,0);
- status_damage(src, bl, hp, 0, 0, 1);
+ 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( 3000 + tick, status_change_timer, bl->id, data);
+ 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
@@ -7701,11 +9067,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);
}
@@ -7731,7 +9101,7 @@ int status_change_timer_sub(struct block_list* bl, va_list ap)
/*==========================================
* Clears buffs/debuffs of a character.
- * type&1 -> buffs, type&2 -> debuffs, type&4 -> sc_refresh
+ * type&1 -> buffs, type&2 -> debuffs
*------------------------------------------*/
int status_change_clear_buffs (struct block_list* bl, int type)
{
@@ -7790,13 +9160,6 @@ int status_change_clear_buffs (struct block_list* bl, int type)
case SC_EXPBOOST:
case SC_JEXPBOOST:
case SC_ITEMBOOST:
- case SC_GIANTGROWTH:
- case SC_REFRESH:
- case SC_STONEHARDSKIN:
- case SC_VITALITYACTIVATION:
- case SC_FIGHTINGSPIRIT:
- case SC_ABUNDANCE:
- case SC_MILLENNIUMSHIELD:
continue;
//Debuffs that can be removed.
@@ -7813,33 +9176,8 @@ int status_change_clear_buffs (struct block_list* bl, int type)
case SC_STRIPSHIELD:
case SC_STRIPARMOR:
case SC_STRIPHELM:
- //Cannot be removed by Refresh.
- if (type&4)
- continue;
- case SC_ADORAMUS:
if (!(type&2))
continue;
-
- //Debuffs that can be removed by Refresh..
- case SC_FEAR:
- case SC_BURNING:
- //case SC_POISONINGWEAPON:
- //case SC_TOXIN:
- //case SC_PARALYSE:
- //case SC_VENOMBLEED:
- //case SC_MAGICMUSHROOM:
- //case SC_DEATHHURT:
- //case SC_PYREXIA:
- //case SC_OBLIVIONCURSE:
- //case SC_LEECHESEND:
- //case SC_FROSTMISTY:
- //case SC_MARSHOFABYSS:
- //case SC_DEEP_SLEEP:
- //case SC_COLD:
- //case SC_FREEZE_SP:
- //case SC_MANDRAGORA:
- if (!(type&4))
- continue;
break;
//The rest are buffs that can be removed.
case SC_BERSERK:
@@ -8065,6 +9403,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_;
@@ -8088,7 +9445,6 @@ static bool status_readdb_job1(char* fields[], int columns, int current)
{
aspd_base[idx][i] = atoi(fields[i+5]);
}
- shield_aspd_base[idx] = atoi(fields[MAX_WEAPON_TYPE+5]);
return true;
}
@@ -8151,8 +9507,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));
- memset(shield_aspd_base, 0, sizeof(shield_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
@@ -8174,10 +9531,14 @@ int status_readdb(void)
// read databases
//
- sv_readdb(db_path, "job_db1.txt", ',', 5+MAX_WEAPON_TYPE+1, 5+MAX_WEAPON_TYPE+1, -1, &status_readdb_job1);
- sv_readdb(db_path, "job_db2.txt", ',', 1, 1+MAX_LEVEL, -1, &status_readdb_job2);
- sv_readdb(db_path, "size_fix.txt", ',', MAX_WEAPON_TYPE, MAX_WEAPON_TYPE, ARRAYLENGTH(atkmods), &status_readdb_sizefix);
- sv_readdb(db_path, "refine_db.txt", ',', 3+MAX_REFINE+1, 3+MAX_REFINE+1, ARRAYLENGTH(percentrefinery), &status_readdb_refine);
+ sv_readdb(db_path, "job_db1.txt", ',', 5+MAX_WEAPON_TYPE, 5+MAX_WEAPON_TYPE, -1, &status_readdb_job1);
+ sv_readdb(db_path, "job_db2.txt", ',', 1, 1+MAX_LEVEL, -1, &status_readdb_job2);
+ sv_readdb(db_path, "size_fix.txt", ',', MAX_WEAPON_TYPE, MAX_WEAPON_TYPE, ARRAYLENGTH(atkmods), &status_readdb_sizefix);
+ sv_readdb(db_path, "refine_db.txt", ',', 3+MAX_REFINE+1, 3+MAX_REFINE+1, ARRAYLENGTH(percentrefinery), &status_readdb_refine);
+
+#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 033e7ca38..4bf0b627d 100644
--- a/src/map/status.h
+++ b/src/map/status.h
@@ -12,7 +12,7 @@ struct mercenary_data;
struct status_change;
//Use this to refer the max refinery level [Skotlex]
-#define MAX_REFINE 20
+#define MAX_REFINE 10
#define MAX_REFINE_BONUS 5
extern unsigned long StatusChangeFlagTable[];
@@ -326,38 +326,251 @@ typedef enum sc_type {
SC_SPL_MATK,
SC_FOOD_STR_CASH,
SC_FOOD_AGI_CASH,
- SC_FOOD_VIT_CASH, //305
+ SC_FOOD_VIT_CASH,
SC_FOOD_DEX_CASH,
SC_FOOD_INT_CASH,
- SC_FOOD_LUK_CASH,
- SC_PARTYFLEE,
-
- // Third Jobs - Maintaining SI order for SCs.
- SC_FEAR, // 310,
- SC_BURNING,
- SC_ENCHANTBLADE,
- SC_DEATHBOUND,
+ 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_GIANTGROWTH, //315
+ SC_REUSE_REFRESH,
+ SC_GIANTGROWTH,
SC_STONEHARDSKIN,
- SC_VITALITYACTIVATION,
+ SC_VITALITYACTIVATION,//320
+ SC_STORMBLAST,
SC_FIGHTINGSPIRIT,
SC_ABUNDANCE,
- SC_MILLENNIUMSHIELD, // 320
- //
- SC_EPICLESIS = 325,
+ /**
+ * Arch Bishop
+ **/
+ SC_ADORAMUS,
+ SC_EPICLESIS,//325
SC_ORATIO,
SC_LAUDAAGNUS,
SC_LAUDARAMUS,
- SC_RENOVATIO = 332,
- SC_EXPIATIO = 336,
+ SC_RENOVATIO,
+ SC_EXPIATIO,//330
SC_DUPLELIGHT,
- SC_ADORAMUS = 380,
- SC_AB_SECRAMENT = 451,
-
-// SC_ALL_RIDING = 472,
-
- SC_CRUSHSTRIKE = 599,
+ 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;
@@ -678,9 +891,10 @@ enum si_type {
// SI_REUSE_LIMIT_F = 310,
SI_INVINCIBLE = 311,
SI_CASH_PLUSONLYJOBEXP = 312,
- SI_PARTYFLEE = 313,
+// SI_PARTYFLEE = 313,
// SI_ANGEL_PROTECT = 314,
-// SI_ENDURE_MDEF = 315,
+
+ SI_ENDURE_MDEF = 315,
SI_ENCHANTBLADE = 316,
SI_DEATHBOUND = 317,
SI_REFRESH = 318,
@@ -689,24 +903,23 @@ enum si_type {
SI_VITALITYACTIVATION = 321,
SI_FIGHTINGSPIRIT = 322,
SI_ABUNDANCE = 323,
-// SI_REUSE_MILLENNIUMSHIELD = 324,
-// SI_REUSE_CRUSHSTRIKE = 325,
-// SI_REUSE_REFRESH = 326,
-// SI_REUSE_STORMBLAST = 327,
-// SI_VENOMIMPRESS = 328,
+ SI_REUSE_MILLENNIUMSHIELD = 324,
+ SI_REUSE_CRUSHSTRIKE = 325,
+ SI_REUSE_REFRESH = 326,
+ SI_REUSE_STORMBLAST = 327,
+ SI_VENOMIMPRESS = 328,
SI_EPICLESIS = 329,
SI_ORATIO = 330,
SI_LAUDAAGNUS = 331,
SI_LAUDARAMUS = 332,
-// SI_CLOAKINGEXCEED = 333,
-// SI_HALLUCINATIONWALK = 334,
-// SI_HALLUCINATIONWALK_POSTDELAY = 335,
+ SI_CLOAKINGEXCEED = 333,
+ SI_HALLUCINATIONWALK = 334,
+ SI_HALLUCINATIONWALK_POSTDELAY = 335,
SI_RENOVATIO = 336,
-// SI_WEAPONBLOCKING = 337,
-// SI_WEAPONBLOCKING_POSTDELAY = 338,
-// SI_ROLLINGCUTTER = 339,
+ SI_WEAPONBLOCKING = 337,
+ SI_WEAPONBLOCKING_POSTDELAY = 338,
+ SI_ROLLINGCUTTER = 339,
SI_EXPIATIO = 340,
-/*
SI_POISONINGWEAPON = 341,
SI_TOXIN = 342,
SI_PARALYSE = 343,
@@ -716,9 +929,7 @@ enum si_type {
SI_PYREXIA = 347,
SI_OBLIVIONCURSE = 348,
SI_LEECHESEND = 349,
-*/
SI_DUPLELIGHT = 350,
-/*
SI_FROSTMISTY = 351,
SI_FEARBREEZE = 352,
SI_ELECTRICSHOCKER = 353,
@@ -731,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,
@@ -749,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,
@@ -771,9 +982,7 @@ enum si_type {
SI_SHIELDSPELL_REF = 398,
SI_BODYPAINT = 399,
SI_EXEEDBREAK = 400,
-*/
SI_ADORAMUS = 401,
-/*
SI_PRESTIGE = 402,
SI_INVISIBILITY = 403,
SI_DEADLYINFECT = 404,
@@ -844,9 +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,
@@ -946,65 +1153,7 @@ enum si_type {
SI_WIND_INSIGNIA = 569,
SI_EARTH_INSIGNIA = 570,
SI_EQUIPED_FLOOR = 571,
- SI_GUARDIAN_RECALL = 572,
- SI_MORA_BUFF = 573,
- SI_REUSE_LIMIT_G = 574,
- SI_REUSE_LIMIT_H = 575,
- SI_NEEDLE_OF_PARALYZE = 576,
- SI_PAIN_KILLER = 577,
- SI_G_LIFEPOTION = 578,
- SI_VITALIZE_POTION = 579,
- SI_LIGHT_OF_REGENE = 580,
- SI_OVERED_BOOST = 581,
- SI_SILENT_BREEZE = 582,
- SI_ODINS_POWER = 583,
- SI_STYLE_CHANGE = 584,
- SI_SONIC_CLAW_POSTDELAY = 585,
-//--586-595 Unused
- SI_SILVERVEIN_RUSH_POSTDELAY = 596,
- SI_MIDNIGHT_FRENZY_POSTDELAY = 597,
- SI_GOLDENE_FERSE = 598,
- SI_ANGRIFFS_MODUS = 599,
- SI_TINDER_BREAKER = 600,
- SI_TINDER_BREAKER_POSTDELAY = 601,
- SI_CBC = 602,
- SI_CBC_POSTDELAY = 603,
- SI_EQC = 604,
- SI_MAGMA_FLOW = 605,
- SI_GRANITIC_ARMOR = 606,
- SI_PYROCLASTIC = 607,
- SI_VOLCANIC_ASH = 608,
- SI_SPIRITS_SAVEINFO1 = 609,
- SI_SPIRITS_SAVEINFO2 = 610,
- SI_MAGIC_CANDY = 611,
-//--612 skipped
- SI_ALL_RIDING = 613,
-//--614 skipped
- SI_MACRO = 615,
- SI_MACRO_POSTDELAY = 616,
- SI_BEER_BOTTLE_CAP = 617,
- SI_OVERLAPEXPUP = 618,
- SI_PC_IZ_DUN05 = 619,
-*/
- SI_CRUSHSTRIKE = 620,
-/*
- SI_MONSTER_TRANSFORM = 621,
- SI_SIT = 622,
- SI_ONAIR = 623,
- SI_MTF_ASPD = 624,
- SI_MTF_RANGEATK = 625,
- SI_MTF_MATK = 626,
- SI_MTF_MLEATKED = 627,
- SI_MTF_CRIDAMAGE = 628,
- SI_REUSE_LIMIT_MTF = 629,
- SI_MACRO_PERMIT = 630,
- SI_MACRO_PLAY = 631,
- SI_SKF_CAST = 632,
- SI_SKF_ASPD = 633,
- SI_SKF_ATK = 634,
- SI_SKF_MATK = 635,
- SI_REWARD_PLUSONLYJOBEXP = 636,
-*/
+ SI_ALL_RIDING = 613,//awesome 571-613 gap, we're missing quite a few stuff here.
};
// JOINTBEAT stackable ailments
@@ -1125,7 +1274,7 @@ enum {
OPTION_DRAGON3 = 0x01000000,
OPTION_DRAGON4 = 0x02000000,
OPTION_DRAGON5 = 0x04000000,
- OPTION_ALL_RIDING= 0x08000000,
+ 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,
@@ -1201,22 +1350,41 @@ struct weapon_atk {
//For holding basic status (which can be modified by status changes)
struct status_data {
unsigned int
- hp, sp,
+ hp, sp, // see status_cpy before adding members before hp and sp
max_hp, max_sp;
unsigned short
str, agi, vit, int_, dex, luk,
- batk, equipment_atk,
- matk_min, matk_max, status_matk,
+ batk,
+ matk_min, matk_max,
speed,
amotion, adelay, dmotion,
mode;
short
hit, flee, cri, flee2,
- def, mdef, def2, mdef2,
+ def2, mdef2,
+#if RRMODE
+ /**
+ * In RE def and mdef can go over 127 (signed char) limit, so in RE mode we use short
+ **/
+ def,mdef,
+#endif
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;
+#if RRMODE == 0
+ /**
+ * In NON-RE def and mdef are not required to be short, so we keep it signed char (ancient-default)
+ **/
+ signed char
+ def, mdef;
+#endif
struct weapon_atk rhw, lhw; //Right Hand/Left Hand Weapon.
};
@@ -1278,7 +1446,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];
};
@@ -1306,10 +1475,6 @@ int status_set_sp(struct block_list *bl, unsigned int sp, int flag);
int status_heal(struct block_list *bl,int hp,int sp, int flag);
int status_revive(struct block_list *bl, unsigned char per_hp, unsigned char per_sp);
-//Define for copying a status_data structure from b to a, without overwriting current Hp and Sp
-#define status_cpy(a, b) \
- memcpy(&((a)->max_hp), &((b)->max_hp), sizeof(struct status_data)-(sizeof((a)->hp)+sizeof((a)->sp)))
-
struct regen_data *status_get_regen_data(struct block_list *bl);
struct status_data *status_get_status_data(struct block_list *bl);
struct status_data *status_get_base_status(struct block_list *bl);
@@ -1329,7 +1494,7 @@ int status_get_lv(struct block_list *bl);
#define status_get_luk(bl) status_get_status_data(bl)->luk
#define status_get_hit(bl) status_get_status_data(bl)->hit
#define status_get_flee(bl) status_get_status_data(bl)->flee
-signed short status_get_def(struct block_list *bl);
+signed char status_get_def(struct block_list *bl);
#define status_get_mdef(bl) status_get_status_data(bl)->mdef
#define status_get_flee2(bl) status_get_status_data(bl)->flee2
#define status_get_def2(bl) status_get_status_data(bl)->def2
@@ -1355,6 +1520,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/storage.c b/src/map/storage.c
index 116ba18c9..4eb1beb32 100644
--- a/src/map/storage.c
+++ b/src/map/storage.c
@@ -138,11 +138,6 @@ static int storage_additem(struct map_session_data* sd, struct item* item_data,
data = itemdb_search(item_data->nameid);
- if( data->stack.storage && amount > data->stack.amount )
- {// item stack limitation
- return 1;
- }
-
if( !itemdb_canstore(item_data, pc_isGM(sd)) )
{ //Check if item is storable. [Skotlex]
clif_displaymessage (sd->fd, msg_txt(264));
@@ -155,7 +150,7 @@ static int storage_additem(struct map_session_data* sd, struct item* item_data,
{
if( compare_item(&stor->items[i], item_data) )
{// existing items found, stack them
- if( amount > MAX_AMOUNT - stor->items[i].amount || ( data->stack.storage && amount > data->stack.amount - stor->items[i].amount ) )
+ if( amount > MAX_AMOUNT - stor->items[i].amount )
return 1;
stor->items[i].amount += amount;
clif_storageitemadded(sd,&stor->items[i],i,amount);
@@ -404,11 +399,6 @@ int guild_storage_additem(struct map_session_data* sd, struct guild_storage* sto
data = itemdb_search(item_data->nameid);
- if( data->stack.guildstorage && amount > data->stack.amount )
- {// item stack limitation
- return 1;
- }
-
if( !itemdb_canguildstore(item_data, pc_isGM(sd)) || item_data->expire_time )
{ //Check if item is storable. [Skotlex]
clif_displaymessage (sd->fd, msg_txt(264));
@@ -418,7 +408,7 @@ int guild_storage_additem(struct map_session_data* sd, struct guild_storage* sto
if(itemdb_isstackable2(data)){ //Stackable
for(i=0;i<MAX_GUILD_STORAGE;i++){
if(compare_item(&stor->items[i], item_data)) {
- if( amount > MAX_AMOUNT - stor->items[i].amount || ( data->stack.guildstorage && amount > data->stack.amount - stor->items[i].amount ) )
+ if(stor->items[i].amount+amount > MAX_AMOUNT)
return 1;
stor->items[i].amount+=amount;
clif_storageitemadded(sd,&stor->items[i],i,amount);
diff --git a/src/map/unit.c b/src/map/unit.c
index b51e2602d..44296ca51 100644
--- a/src/map/unit.c
+++ b/src/map/unit.c
@@ -323,9 +323,13 @@ int unit_walktoxy( struct block_list *bl, short x, short y, int flag)
}
//To set Mob's CHASE/FOLLOW states (shouldn't be done if there's no path to reach)
-#define set_mobstate(bl, flag) \
- if((bl)->type == BL_MOB && (flag)) \
- ((TBL_MOB*)(bl))->state.skillstate = ((TBL_MOB*)(bl))->state.aggressive?MSS_FOLLOW:MSS_RUSH;
+static inline void set_mobstate(struct block_list* bl, int flag)
+{
+ struct mob_data* md = BL_CAST(BL_MOB,bl);
+
+ if( md && flag )
+ md->state.skillstate = md->state.aggressive ? MSS_FOLLOW : MSS_RUSH;
+}
static int unit_walktobl_sub(int tid, unsigned int tick, int id, intptr_t data)
{
@@ -440,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;
@@ -448,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))
@@ -460,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;
@@ -468,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;
@@ -837,8 +907,6 @@ int unit_can_move(struct block_list *bl)
sc->data[SC_CLOAKING]->val1 < 3 && !(sc->data[SC_CLOAKING]->val4&1))
|| sc->data[SC_MADNESSCANCEL]
|| (sc->data[SC_GRAVITATION] && sc->data[SC_GRAVITATION]->val3 == BCT_SELF)
- || (sc->data[SC_FEAR] && sc->data[SC_FEAR]->val3 > 0)
- || sc->data[SC_DEATHBOUND]
))
return 0;
}
@@ -990,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]
@@ -1101,10 +1169,18 @@ int unit_skilluse_id2(struct block_list *src, int target_id, short skill_num, sh
case SA_SPELLBREAKER:
temp = 1;
break;
+ case ST_CHASEWALK:
+ if (sc && sc->data[SC_CHASEWALK])
+ casttime = 0;
+ break;
case TK_RUN:
if (sc && sc->data[SC_RUN])
casttime = 0;
break;
+ case HP_BASILICA:
+ if( sc && sc->data[SC_BASILICA] )
+ casttime = 0; // No Casting time on basilica cancel
+ break;
case KN_CHARGEATK:
{
unsigned int k = (distance_bl(src,target)-1)/3; //+100% every 3 cells of distance
@@ -1118,17 +1194,9 @@ int unit_skilluse_id2(struct block_list *src, int target_id, short skill_num, sh
break;
}
- // Cancel status effects that lower cast time.
- if( !(skill_get_castnodex(skill_num, skill_lv)&2) && sc )
- {
- if( sc->data[SC_SUFFRAGIUM] )
- status_change_end(src, SC_SUFFRAGIUM, INVALID_TIMER);
- if( sc->data[SC_MEMORIZE] )
- {
- if ((--sc->data[SC_MEMORIZE]->val2) <= 0)
- status_change_end(src, SC_MEMORIZE, INVALID_TIMER);
- }
- }
+ // 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, skill_num, skill_lv);
if( casttime > 0 || temp )
{
@@ -1268,17 +1336,9 @@ int unit_skilluse_pos2( struct block_list *src, short skill_x, short skill_y, sh
unit_stop_attack(src);
- // Cancel status effects that lower cast time.
- if( !(skill_get_castnodex(skill_num, skill_lv)&2) && sc )
- {
- if( sc->data[SC_SUFFRAGIUM] )
- status_change_end(src, SC_SUFFRAGIUM, INVALID_TIMER);
- if( sc->data[SC_MEMORIZE] )
- {
- if ((--sc->data[SC_MEMORIZE]->val2) <= 0)
- status_change_end(src, SC_MEMORIZE, INVALID_TIMER);
- }
- }
+ // 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, 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) )
@@ -2079,7 +2139,6 @@ int unit_free(struct block_list *bl, clr_type clrtype)
guild_send_memberinfoshort(sd,0);
pc_cleareventtimer(sd);
pc_inventory_rental_clear(sd);
- if( sd->bg_id ) bg_team_leave(sd,1);
pc_delspiritball(sd,sd->spiritball,1);
if( sd->reg )
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];