Fixed bugreport:5788 WL_READING_SB should now work like official behavior(save preserved spell on relog, proper skill fail message, maximum number of spell that a char can hold)
Fixed bugreport:5657 WL_EARTHSTRAIN should now work like official behavior(total number of range [15x4+lv], layout when casted, interval) Updated WL_IMPRISON duration, rate and proper skill fail message. Special thanks to Yommy and his amazing tool... git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@16365 54d463be-8e91-2dee-dedb-b68131a5f0ec
This commit is contained in:
parent
9d3e2c3021
commit
2e4022e97a
@ -1184,8 +1184,8 @@
|
||||
//==========================================
|
||||
|
||||
//===== Warlock ============================
|
||||
//-- WL_WHITEIMPRISON //CHECK Is reuse delay hard coded to work only if successful? Duration 1 may be incorrect. Is duration 2 for if casted on self?
|
||||
2201,0,0,0,10000:12000:14000:16000:18000,5000,0
|
||||
//-- WL_WHITEIMPRISON
|
||||
2201,0,0,0,6000:8000:10000:12000:14000,15000,0,0
|
||||
//-- WL_SOULEXPANSION
|
||||
2202,2000,500,0,0,0,0
|
||||
//-- WL_FROSTMISTY
|
||||
@ -1212,8 +1212,8 @@
|
||||
//-- WL_CHAINLIGHTNING //CHECK Whats duration 1 used for?
|
||||
2214,4500:5000:5500:6000:6500,3000,0,1000,0,0
|
||||
|
||||
//-- WL_EARTHSTRAIN //CHECK What is duration 2 used for?
|
||||
2216,3000:4000:5000:6000:7000,1000,0,500,60000,10000
|
||||
//-- WL_EARTHSTRAIN
|
||||
2216,2000:3000:4000:5000:6000,1000,0,150,0,10000,2000
|
||||
//-- WL_TETRAVORTEX //CHECK Duration 1 might be correct?
|
||||
2217,6000:7000:8000:9000:10000,2000,0,20000,0,15000
|
||||
|
||||
@ -1227,8 +1227,8 @@
|
||||
//-- WL_SUMMONSTONE
|
||||
2229,2000,0,0,30000:40000:50000:60000:70000,0,0
|
||||
|
||||
//-- WL_READING_SB //CHECK Is duration 1 how long the spell will be stored for?
|
||||
2231,4000,500,0,30000,0,5000
|
||||
//-- WL_READING_SB
|
||||
2231,4000,500,0,0,0,5000
|
||||
//==========================================
|
||||
|
||||
//===== Ranger =============================
|
||||
|
@ -101,7 +101,7 @@
|
||||
2032,0xe1, , 2, 0,1000,enemy, 0x018 //GC_POISONSMOKE
|
||||
|
||||
2214,0x86, , 0, 5, 100,enemy, 0x080 //WL_CHAINLIGHTNING
|
||||
2216,0xcb, , -1, 2,2000,enemy, 0x018 //WL_EARTHSTRAIN
|
||||
2216,0xcb, , -1, 0, 150,enemy, 0x018 //WL_EARTHSTRAIN
|
||||
|
||||
2238,0xd8, , 0, 1,1000,enemy, 0x006 //RA_ELECTRICSHOCKER
|
||||
2239,0xd9, , 0, 1,1000,enemy, 0x006 //RA_CLUSTERBOMB
|
||||
|
@ -1185,8 +1185,8 @@
|
||||
//==========================================
|
||||
|
||||
//===== Warlock ============================
|
||||
//-- WL_WHITEIMPRISON //CHECK Is reuse delay hard coded to work only if successful? Duration 1 may be incorrect. Is duration 2 for if casted on self?
|
||||
2201,0,0,0,10000:12000:14000:16000:18000,5000,0,0
|
||||
//-- WL_WHITEIMPRISON
|
||||
2201,0,0,0,6000:8000:10000:12000:14000,15000,0,0
|
||||
//-- WL_SOULEXPANSION
|
||||
2202,2000,500,0,0,0,0,0
|
||||
//-- WL_FROSTMISTY
|
||||
@ -1213,8 +1213,8 @@
|
||||
//-- WL_CHAINLIGHTNING //CHECK Whats duration 1 used for?
|
||||
2214,4500:5000:5500:6000:6500,3000,0,1000,0,0,0
|
||||
|
||||
//-- WL_EARTHSTRAIN //CHECK What is duration 2 used for?
|
||||
2216,3000:4000:5000:6000:7000,1000,0,500,60000,10000,0
|
||||
//-- WL_EARTHSTRAIN
|
||||
2216,2000:3000:4000:5000:6000,1000,0,150,0,10000,2000
|
||||
//-- WL_TETRAVORTEX //CHECK Duration 1 might be correct?
|
||||
2217,6000:7000:8000:9000:10000,2000,0,20000,0,15000,0
|
||||
|
||||
@ -1228,8 +1228,8 @@
|
||||
//-- WL_SUMMONSTONE
|
||||
2229,2000,0,0,30000:40000:50000:60000:70000,0,0,0
|
||||
|
||||
//-- WL_READING_SB //CHECK Is duration 1 how long the spell will be stored for?
|
||||
2231,4000,500,0,30000,0,5000,0
|
||||
//-- WL_READING_SB
|
||||
2231,4000,500,0,0,0,5000,0
|
||||
//==========================================
|
||||
|
||||
//===== Ranger =============================
|
||||
|
@ -101,7 +101,7 @@
|
||||
2032,0xe1, , 2, 0,1000,enemy, 0x018 //GC_POISONSMOKE
|
||||
|
||||
2214,0x86, , 0, 5, 100,enemy, 0x080 //WL_CHAINLIGHTNING
|
||||
2216,0xcb, , -1, 2,2000,enemy, 0x018 //WL_EARTHSTRAIN
|
||||
2216,0xcb, , -1, 0, 150,enemy, 0x018 //WL_EARTHSTRAIN
|
||||
|
||||
2238,0xd8, , 0, 1,1000,enemy, 0x006 //RA_ELECTRICSHOCKER
|
||||
2239,0xd9, , 0, 1,1000,enemy, 0x006 //RA_CLUSTERBOMB
|
||||
|
@ -15859,8 +15859,10 @@ int clif_spellbook_list(struct map_session_data *sd)
|
||||
sd->menuskill_id = WL_READING_SB;
|
||||
sd->menuskill_val = c;
|
||||
}
|
||||
else
|
||||
else{
|
||||
status_change_end(&sd->bl,SC_STOP,INVALID_TIMER);
|
||||
clif_skill_fail(sd, WL_READING_SB, USESKILL_FAIL_SPELLBOOK, 0);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
10
src/map/pc.h
10
src/map/pc.h
@ -23,9 +23,6 @@
|
||||
#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
|
||||
@ -422,13 +419,6 @@ 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;
|
||||
|
213
src/map/skill.c
213
src/map/skill.c
@ -97,7 +97,7 @@ bool skill_reproduce_db[MAX_SKILL_DB];
|
||||
struct s_skill_spellbook_db {
|
||||
int nameid;
|
||||
int skillid;
|
||||
int points;
|
||||
int point;
|
||||
};
|
||||
|
||||
struct s_skill_spellbook_db skill_spellbook_db[MAX_SKILL_SPELLBOOK_DB];
|
||||
@ -482,8 +482,10 @@ int skillnotok (int skillid, struct map_session_data *sd)
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (sd->blockskill[i] > 0)
|
||||
if (sd->blockskill[i] > 0){
|
||||
clif_skill_fail(sd, skillid, USESKILL_FAIL_SKILLINTERVAL, 0);
|
||||
return 1;
|
||||
}
|
||||
/**
|
||||
* It has been confirmed on a official server (thanks to Yommy) that item-cast skills bypass all the restrictions above
|
||||
* Also, without this check, an exploit where an item casting + healing (or any other kind buff) isn't deleted after used on a restricted map
|
||||
@ -4104,50 +4106,47 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int
|
||||
{
|
||||
int i;
|
||||
// Priority is to release SpellBook
|
||||
ARR_FIND(0,MAX_SPELLBOOK,i,sd->rsb[i].skillid != 0);
|
||||
if( i < MAX_SPELLBOOK )
|
||||
if( sc && sc->data[SC_READING_SB] )
|
||||
{ // SpellBook
|
||||
int rsb_skillid, rsb_skilllv;
|
||||
int skill_id, skill_lv, point, s = 0;
|
||||
int spell[SC_MAXSPELLBOOK-SC_SPELLBOOK1 + 1];
|
||||
|
||||
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
|
||||
}
|
||||
for(i = SC_MAXSPELLBOOK; i >= SC_SPELLBOOK1; i--) // List all available spell to be released
|
||||
if( sc->data[i] ) spell[s++] = i;
|
||||
|
||||
rsb_skillid = sd->rsb[i].skillid;
|
||||
rsb_skilllv = sd->rsb[i].level;
|
||||
|
||||
if( sc && sc->data[SC_READING_SB] && sc->data[SC_READING_SB]->val2 > 0 )
|
||||
sc->data[SC_READING_SB]->val2 -= sd->rsb[i].points;
|
||||
|
||||
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);
|
||||
|
||||
clif_skill_nodamage(src,bl,skillid,skilllv,1);
|
||||
if( !skill_check_condition_castbegin(sd,rsb_skillid,rsb_skilllv) )
|
||||
i = spell[s==1?0:rand()%s];// Random select of spell to be released.
|
||||
if( s && sc->data[i] ){// Now extract the data from the preserved spell
|
||||
skill_id = sc->data[i]->val1;
|
||||
skill_lv = sc->data[i]->val2;
|
||||
point = sc->data[i]->val3;
|
||||
status_change_end(src, (sc_type)i, INVALID_TIMER);
|
||||
}else //something went wrong :(
|
||||
break;
|
||||
|
||||
switch( skill_get_casttype(rsb_skillid) )
|
||||
if( sc->data[SC_READING_SB]->val2 > point )
|
||||
sc->data[SC_READING_SB]->val2 -= point;
|
||||
else // Last spell to be released
|
||||
status_change_end(src, SC_READING_SB, INVALID_TIMER);
|
||||
|
||||
clif_skill_nodamage(src, bl, skillid, skilllv, 1);
|
||||
if( !skill_check_condition_castbegin(sd, skill_id, skill_lv) )
|
||||
break;
|
||||
|
||||
switch( skill_get_casttype(skill_id) )
|
||||
{
|
||||
case CAST_GROUND:
|
||||
skill_castend_pos2(src,bl->x,bl->y,rsb_skillid,rsb_skilllv,tick,0);
|
||||
skill_castend_pos2(src, bl->x, bl->y, skill_id, skill_lv, tick, 0);
|
||||
break;
|
||||
case CAST_NODAMAGE:
|
||||
skill_castend_nodamage_id(src,bl,rsb_skillid,rsb_skilllv,tick,0);
|
||||
skill_castend_nodamage_id(src, bl, skill_id, skill_lv, tick, 0);
|
||||
break;
|
||||
case CAST_DAMAGE:
|
||||
skill_castend_damage_id(src,bl,rsb_skillid,rsb_skilllv,tick,0);
|
||||
skill_castend_damage_id(src, bl, skill_id, skill_lv, 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);
|
||||
sd->ud.canact_tick = tick + skill_delayfix(src, skill_id, skill_lv);
|
||||
clif_status_change(src, SI_ACTIONDELAY, 1, skill_delayfix(src, skill_id, skill_lv), 0, 0, 0);
|
||||
}
|
||||
else
|
||||
{ // Summon Balls
|
||||
@ -4166,7 +4165,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int
|
||||
|
||||
if( j == 0 )
|
||||
{ // No Spheres
|
||||
clif_skill_fail(sd,skillid,USESKILL_FAIL_LEVEL,0);
|
||||
clif_skill_fail(sd,skillid,USESKILL_FAIL_SUMMON_NONE,0);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -7600,16 +7599,25 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
|
||||
break;
|
||||
|
||||
case WL_WHITEIMPRISON:
|
||||
if( !(tsc && tsc->data[type]) && (src == bl || battle_check_target(src, bl, BCT_ENEMY)) && !is_boss(bl) )// Should not work with bosses.
|
||||
if( (src == bl || battle_check_target(src, bl, BCT_ENEMY)) && !is_boss(bl) )// Should not work with bosses.
|
||||
{
|
||||
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);
|
||||
int rate = ( sd? sd->status.job_level : 50 ) / 4;
|
||||
|
||||
if(src == bl ) rate = 100; // Success Chance: On self, 100%
|
||||
else if(bl->type == BL_PC) rate += 20 + 10 * skilllv; // On Players, (20 + 10 * Skill Level) %
|
||||
else rate += 40 + 10 * skilllv; // On Monsters, (40 + 10 * Skill Level) %
|
||||
|
||||
if( !(tsc && tsc->data[type]) ){
|
||||
i = sc_start2(bl,type,rate,skilllv,src->id,(src == bl)?5000:(bl->type == BL_PC)?skill_get_time(skillid,skilllv):skill_get_time2(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,USESKILL_FAIL_LEVEL,0);
|
||||
else if(sd)
|
||||
clif_skill_fail(sd,skillid,USESKILL_FAIL_LEVEL,0);
|
||||
}else if( sd )
|
||||
clif_skill_fail(sd,skillid,USESKILL_FAIL_TOTARGET,0);
|
||||
break;
|
||||
|
||||
case WL_FROSTMISTY:
|
||||
@ -7711,25 +7719,19 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
|
||||
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,USESKILL_FAIL_SKILLINTERVAL,0);
|
||||
break;
|
||||
}
|
||||
for( i = 0; i < MAX_SPELLBOOK && sd->rsb[i].skillid; i++ )
|
||||
preserved += sd->rsb[i].points;
|
||||
struct status_change *sc = status_get_sc(bl);
|
||||
int i, max_preserve = 4 * pc_checkskill(sd, WL_FREEZE_SP) + sstatus->int_ / 10 + sd->status.base_level / 10;
|
||||
|
||||
if( preserved >= max_preserve )
|
||||
{
|
||||
clif_skill_fail(sd,skillid,USESKILL_FAIL_SKILLINTERVAL,0);
|
||||
for(i=SC_SPELLBOOK1; i <= SC_MAXSPELLBOOK; i++) if( sc && !sc->data[i] ) break;
|
||||
if( i == SC_MAXSPELLBOOK )
|
||||
{
|
||||
clif_skill_fail(sd, WL_READING_SB, USESKILL_FAIL_SPELLBOOK_READING, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
sc_start(bl,SC_STOP,100,skilllv,-1); //Can't move while selecting a spellbook.
|
||||
sc_start(bl, SC_STOP, 100, skilllv, INVALID_TIMER); //Can't move while selecting a spellbook.
|
||||
clif_spellbook_list(sd);
|
||||
clif_skill_nodamage(src,bl,skillid,skilllv,1);
|
||||
clif_skill_nodamage(src, bl, skillid, skilllv, 1);
|
||||
}
|
||||
break;
|
||||
/**
|
||||
@ -9590,20 +9592,19 @@ int skill_castend_pos2(struct block_list* src, int x, int y, int skillid, int sk
|
||||
case WL_EARTHSTRAIN:
|
||||
{
|
||||
int i, wave = skilllv + 4, dir = map_calc_dir(src,x,y);
|
||||
int sx = x, sy = y;
|
||||
int sx = x = src->x, sy = y = src->y; // Store first caster's location to avoid glitch on unit setting
|
||||
|
||||
for( i = 0; i < wave; i++ )
|
||||
for( i = 1; 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;
|
||||
switch( dir ){
|
||||
case 0: case 1: case 7: sy = y + i; break;
|
||||
case 3: case 4: case 5: sy = y - i; break;
|
||||
case 2: sx = x - i; break;
|
||||
case 6: sx = 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.
|
||||
skill_addtimerskill(src,gettick() + (150 * i),0,sx,sy,skillid,skilllv,dir,flag&2);
|
||||
}
|
||||
if(sd) skill_blockpc_start(sd, skillid, skill_get_cooldown(skillid, skilllv));
|
||||
}
|
||||
break;
|
||||
/**
|
||||
@ -15738,57 +15739,52 @@ int skill_magicdecoy(struct map_session_data *sd, int nameid) {
|
||||
|
||||
// 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);
|
||||
int i, max_preserve, skill_id, point;
|
||||
struct status_change *sc;
|
||||
|
||||
if( sd->sc.data[SC_STOP] ) status_change_end(&sd->bl,SC_STOP,INVALID_TIMER);
|
||||
if( nameid <= 0 ) return 0;
|
||||
nullpo_ret(sd);
|
||||
|
||||
if( pc_search_inventory(sd,nameid) < 0 )
|
||||
{ // User with no item on inventory
|
||||
clif_skill_fail(sd,WL_READING_SB,USESKILL_FAIL_SKILLINTERVAL,0);
|
||||
return 0;
|
||||
}
|
||||
sc = status_get_sc(&sd->bl);
|
||||
status_change_end(&sd->bl, SC_STOP, INVALID_TIMER);
|
||||
|
||||
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,USESKILL_FAIL_SPELLBOOK_PRESERVATION_POINT,0);
|
||||
for(i=SC_SPELLBOOK1; i <= SC_MAXSPELLBOOK; i++) if( sc && !sc->data[i] ) break;
|
||||
if( i > SC_MAXSPELLBOOK )
|
||||
{
|
||||
clif_skill_fail(sd, WL_READING_SB, USESKILL_FAIL_SPELLBOOK_READING, 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,USESKILL_FAIL_SKILLINTERVAL,0);
|
||||
return 0;
|
||||
}
|
||||
if( i == MAX_SKILL_SPELLBOOK_DB ) return 0;
|
||||
|
||||
skillid = skill_spellbook_db[i].skillid;
|
||||
points = skill_spellbook_db[i].points;
|
||||
|
||||
if( !pc_checkskill(sd,skillid) )
|
||||
if( !pc_checkskill(sd, (skill_id = skill_spellbook_db[i].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,USESKILL_FAIL_SPELLBOOK_DIFFICULT_SLEEP,0);
|
||||
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, USESKILL_FAIL_SPELLBOOK_DIFFICULT_SLEEP, 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;
|
||||
max_preserve = 4 * pc_checkskill(sd, WL_FREEZE_SP) + status_get_int(&sd->bl) / 10 + sd->status.base_level / 10;
|
||||
point = skill_spellbook_db[i].point;
|
||||
|
||||
if( preserved + points >= max_preserve )
|
||||
{ // No more free points
|
||||
clif_skill_fail(sd,WL_READING_SB,USESKILL_FAIL_SKILLINTERVAL,0);
|
||||
return 0;
|
||||
if( sc && sc->data[SC_READING_SB] ){
|
||||
if( (sc->data[SC_READING_SB]->val2 + point) > max_preserve )
|
||||
{
|
||||
clif_skill_fail(sd, WL_READING_SB, USESKILL_FAIL_SPELLBOOK_PRESERVATION_POINT, 0);
|
||||
return 0;
|
||||
}
|
||||
for(i = SC_MAXSPELLBOOK; i >= SC_SPELLBOOK1; i--){ // This is how official saves spellbook. [malufett]
|
||||
if( !sc->data[i] ){
|
||||
sc->data[SC_READING_SB]->val2 += point; // increase points
|
||||
sc_start4(&sd->bl, (sc_type)i, 100, skill_id, pc_checkskill(sd,skill_id), point, 0, INVALID_TIMER);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
sc_start2(&sd->bl, SC_READING_SB, 100, 0, point, INVALID_TIMER);
|
||||
sc_start4(&sd->bl, SC_MAXSPELLBOOK, 100, skill_id, pc_checkskill(sd,skill_id), point, 0, INVALID_TIMER);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
int skill_select_menu(struct map_session_data *sd,int flag,int skill_id) {
|
||||
@ -16435,16 +16431,13 @@ void skill_init_unit_layout (void)
|
||||
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.
|
||||
skill_unit_layout[pos].count = 15;
|
||||
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};
|
||||
int dx[] = {-7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7};
|
||||
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));
|
||||
}
|
||||
@ -16452,10 +16445,8 @@ void skill_init_unit_layout (void)
|
||||
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};
|
||||
int dx[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
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));
|
||||
}
|
||||
@ -16847,7 +16838,7 @@ static bool skill_parse_row_spellbookdb(char* split[], int columns, int current)
|
||||
else
|
||||
{
|
||||
skill_spellbook_db[current].skillid = skillid;
|
||||
skill_spellbook_db[current].points = points;
|
||||
skill_spellbook_db[current].point = points;
|
||||
skill_spellbook_db[current].nameid = nameid;
|
||||
|
||||
return true;
|
||||
|
@ -785,6 +785,14 @@ void initChangeTables(void) {
|
||||
StatusIconChangeTable[SC_SPHERE_3] = SI_SPHERE_3;
|
||||
StatusIconChangeTable[SC_SPHERE_4] = SI_SPHERE_4;
|
||||
StatusIconChangeTable[SC_SPHERE_5] = SI_SPHERE_5;
|
||||
// Warlock Preserved spells
|
||||
StatusIconChangeTable[SC_SPELLBOOK1] = SI_SPELLBOOK1;
|
||||
StatusIconChangeTable[SC_SPELLBOOK2] = SI_SPELLBOOK2;
|
||||
StatusIconChangeTable[SC_SPELLBOOK3] = SI_SPELLBOOK3;
|
||||
StatusIconChangeTable[SC_SPELLBOOK4] = SI_SPELLBOOK4;
|
||||
StatusIconChangeTable[SC_SPELLBOOK5] = SI_SPELLBOOK5;
|
||||
StatusIconChangeTable[SC_SPELLBOOK6] = SI_SPELLBOOK6;
|
||||
StatusIconChangeTable[SC_MAXSPELLBOOK] = SI_SPELLBOOK7;
|
||||
|
||||
StatusIconChangeTable[SC_NEUTRALBARRIER_MASTER] = SI_NEUTRALBARRIER_MASTER;
|
||||
StatusIconChangeTable[SC_STEALTHFIELD_MASTER] = SI_STEALTHFIELD_MASTER;
|
||||
@ -5831,9 +5839,12 @@ 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).
|
||||
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_WHITEIMPRISON:
|
||||
rate -= (status_get_lv(bl) / 5 + status->vit / 4 + status->agi / 10)*100;
|
||||
if( tick != 5000) // not applied on caster
|
||||
tick -= (status->vit + status->luk) / 20 * 1000;
|
||||
break;
|
||||
case SC_BURNING:
|
||||
// From iROwiki : http://forums.irowiki.org/showpost.php?p=577240&postcount=583
|
||||
@ -7600,7 +7611,7 @@ int status_change_start(struct block_list* bl,enum sc_type type,int rate,int val
|
||||
break;
|
||||
case SC_READING_SB:
|
||||
// val2 = sp reduction per second
|
||||
tick_time = 1000; // [GodLesZ] tick time
|
||||
tick_time = 5000; // [GodLesZ] tick time
|
||||
break;
|
||||
case SC_SPHERE_1:
|
||||
case SC_SPHERE_2:
|
||||
@ -9644,9 +9655,13 @@ int status_change_timer(int tid, unsigned int tick, int id, intptr_t data)
|
||||
break;
|
||||
|
||||
case SC_READING_SB:
|
||||
if( !status_charge(bl, 0, sce->val2) )
|
||||
if( !status_charge(bl, 0, sce->val2) ){
|
||||
int i;
|
||||
for(i = SC_SPELLBOOK1; i <= SC_MAXSPELLBOOK; i++) // Also remove stored spell as well.
|
||||
status_change_end(bl, (sc_type)i, INVALID_TIMER);
|
||||
break;
|
||||
sc_timer_next(1000 + tick, status_change_timer, bl->id, data);
|
||||
}
|
||||
sc_timer_next(5000 + tick, status_change_timer, bl->id, data);
|
||||
return 0;
|
||||
|
||||
case SC_ELECTRICSHOCKER:
|
||||
|
@ -600,6 +600,18 @@ typedef enum sc_type {
|
||||
SC_EARTH_INSIGNIA,
|
||||
/* new pushcart */
|
||||
SC_PUSH_CART,
|
||||
/* Warlock Spell books */
|
||||
SC_SPELLBOOK1,
|
||||
SC_SPELLBOOK2,
|
||||
SC_SPELLBOOK3,
|
||||
SC_SPELLBOOK4,
|
||||
SC_SPELLBOOK5,
|
||||
SC_SPELLBOOK6,
|
||||
/**
|
||||
* In official server there are only 7 maximum number of spell books that can be memorized
|
||||
* To increase the maximum value just add another status type before SC_MAXSPELLBOOK (ex. SC_SPELLBOOK7, SC_SPELLBOOK8 and so on)
|
||||
**/
|
||||
SC_MAXSPELLBOOK,
|
||||
|
||||
SC_MAX, //Automatically updated max, used in for's to check we are within bounds.
|
||||
} sc_type;
|
||||
|
Loading…
x
Reference in New Issue
Block a user