Skill_colldown

Move skillcooldown from ram saving to sql saving.
This will fix multimap skillcooldown and avoind increasing ram by
offline users.
This commit is contained in:
lighta 2013-10-08 16:54:03 -04:00
parent 9a5a6b9e6e
commit 69b28292cf
15 changed files with 312 additions and 148 deletions

View File

@ -1,3 +1,17 @@
--
-- Table structure for table `skillcooldown`
--
CREATE TABLE IF NOT EXISTS `skillcooldown` (
`account_id` int(11) unsigned NOT NULL,
`char_id` int(11) unsigned NOT NULL,
`skill` smallint(11) unsigned NOT NULL DEFAULT '0',
`tick` int(11) NOT NULL,
KEY `account_id` (`account_id`),
KEY `char_id` (`char_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
--
-- Table structure for table `auction`
--

View File

@ -0,0 +1,8 @@
CREATE TABLE IF NOT EXISTS `skillcooldown` (
`account_id` int(11) unsigned NOT NULL,
`char_id` int(11) unsigned NOT NULL,
`skill` smallint(11) unsigned NOT NULL DEFAULT '0',
`tick` int(11) NOT NULL,
KEY `account_id` (`account_id`),
KEY `char_id` (`char_id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

View File

@ -39,6 +39,7 @@ static char* msg_table[CHAR_MAX_MSG]; // Login Server messages_conf
char char_db[256] = "char";
char scdata_db[256] = "sc_data";
char skillcooldown_db[256] = "skillcooldown";
char cart_db[256] = "cart_inventory";
char inventory_db[256] = "inventory";
char charlog_db[256] = "charlog";
@ -2923,6 +2924,51 @@ int parse_frommap(int fd)
}
break;
case 0x2b0a: //Request skillcooldown data
if (RFIFOREST(fd) < 10)
return 0;
{
int aid, cid;
aid = RFIFOL(fd,2);
cid = RFIFOL(fd,6);
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT skill, tick FROM `%s` WHERE `account_id` = '%d' AND `char_id`='%d'",
skillcooldown_db, aid, cid) )
{
Sql_ShowDebug(sql_handle);
break;
}
if( Sql_NumRows(sql_handle) > 0 )
{
int count;
char* data;
struct skill_cooldown_data scd;
WFIFOHEAD(fd,14 + MAX_SKILLCOOLDOWN * sizeof(struct skill_cooldown_data));
WFIFOW(fd,0) = 0x2b0b;
WFIFOL(fd,4) = aid;
WFIFOL(fd,8) = cid;
for( count = 0; count < MAX_SKILLCOOLDOWN && SQL_SUCCESS == Sql_NextRow(sql_handle); ++count )
{
Sql_GetData(sql_handle, 0, &data, NULL); scd.skill_id = atoi(data);
Sql_GetData(sql_handle, 1, &data, NULL); scd.tick = atoi(data);
memcpy(WFIFOP(fd,14+count*sizeof(struct skill_cooldown_data)), &scd, sizeof(struct skill_cooldown_data));
}
if( count >= MAX_SKILLCOOLDOWN )
ShowWarning("Too many skillcooldowns for %d:%d, some of them were not loaded.\n", aid, cid);
if( count > 0 )
{
WFIFOW(fd,2) = 14 + count * sizeof(struct skill_cooldown_data);
WFIFOW(fd,12) = count;
WFIFOSET(fd,WFIFOW(fd,2));
//Clear the data once loaded.
if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", skillcooldown_db, aid, cid) )
Sql_ShowDebug(sql_handle);
}
}
Sql_FreeResult(sql_handle);
RFIFOSKIP(fd, 10);
}
break;
case 0x2afe: //set MAP user count
if (RFIFOREST(fd) < 4)
return 0;
@ -3398,6 +3444,37 @@ int parse_frommap(int fd)
}
break;
case 0x2b15: //Request to save skill cooldown data
if( RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2) )
return 0;
{
int count, aid, cid;
aid = RFIFOL(fd,4);
cid = RFIFOL(fd,8);
count = RFIFOW(fd,12);
if( count > 0 )
{
struct skill_cooldown_data data;
StringBuf buf;
int i;
StringBuf_Init(&buf);
StringBuf_Printf(&buf, "INSERT INTO `%s` (`account_id`, `char_id`, `skill`, `tick`) VALUES ", skillcooldown_db);
for( i = 0; i < count; ++i )
{
memcpy(&data,RFIFOP(fd,14+i*sizeof(struct skill_cooldown_data)),sizeof(struct skill_cooldown_data));
if( i > 0 )
StringBuf_AppendStr(&buf, ", ");
StringBuf_Printf(&buf, "('%d','%d','%d','%d')", aid, cid, data.skill_id, data.tick);
}
if( SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) )
Sql_ShowDebug(sql_handle);
StringBuf_Destroy(&buf);
}
RFIFOSKIP(fd, RFIFOW(fd, 2));
}
break;
case 0x2b23: // map-server alive packet
WFIFOHEAD(fd,2);
WFIFOW(fd,0) = 0x2b24;

View File

@ -128,6 +128,7 @@
#define MAX_FRIENDS 40
#define MAX_MEMOPOINTS 3
#define MAX_SKILLCOOLDOWN 20
//Size of the fame list arrays.
#define MAX_FAME_LIST 10
@ -248,6 +249,11 @@ struct status_change_data {
long val1, val2, val3, val4, tick; //Remaining duration.
};
struct skill_cooldown_data {
unsigned short skill_id;
long tick;
};
struct storage_data {
int storage_amount;
struct item items[MAX_STORAGE];

View File

@ -2021,9 +2021,10 @@ static int is_attack_piercing(struct Damage wd, struct block_list *src, struct b
sd->left_weapon.def_ratio_atk_race & (1<<tstatus->race) ||
sd->left_weapon.def_ratio_atk_race & (1<<(is_boss(target)?RC_BOSS:RC_NONBOSS))) )
{ //Pass effect onto right hand if configured so. [Skotlex]
if (battle_config.left_cardfix_to_right && is_attack_right_handed(src, skill_id))
if (battle_config.left_cardfix_to_right && is_attack_right_handed(src, skill_id)){
if (weapon_position == EQI_HAND_R)
return 1;
}
else if (weapon_position == EQI_HAND_L)
return 1;
}

View File

@ -41,8 +41,8 @@ static DBMap* auth_db; // int id -> struct auth_node*
static const int packet_len_table[0x3d] = { // U - used, F - free
60, 3,-1,27,10,-1, 6,-1, // 2af8-2aff: U->2af8, U->2af9, U->2afa, U->2afb, U->2afc, U->2afd, U->2afe, U->2aff
6,-1,18, 7,-1,39,30, 10, // 2b00-2b07: U->2b00, U->2b01, U->2b02, U->2b03, U->2b04, U->2b05, U->2b06, U->2b07
6,30, 0, 0,86, 7,44,34, // 2b08-2b0f: U->2b08, U->2b09, F->2b0a, F->2b0b, U->2b0c, U->2b0d, U->2b0e, U->2b0f
11,10,10, 0,11, 0,266,10, // 2b10-2b17: U->2b10, U->2b11, U->2b12, F->2b13, U->2b14, F->2b15, U->2b16, U->2b17
6,30, 10, -1,86, 7,44,34, // 2b08-2b0f: U->2b08, U->2b09, U->2b0a, U->2b0b, U->2b0c, U->2b0d, U->2b0e, U->2b0f
11,10,10, 0,11, -1,266,10, // 2b10-2b17: U->2b10, U->2b11, U->2b12, F->2b13, U->2b14, U->2b15, U->2b16, U->2b17
2,10, 2,-1,-1,-1, 2, 7, // 2b18-2b1f: U->2b18, U->2b19, U->2b1a, U->2b1b, U->2b1c, U->2b1d, U->2b1e, U->2b1f
-1,10, 8, 2, 2,14,19,19, // 2b20-2b27: U->2b20, U->2b21, U->2b22, U->2b23, U->2b24, U->2b25, U->2b26, U->2b27
};
@ -275,8 +275,10 @@ int chrif_save(struct map_session_data *sd, int flag) {
if (flag && sd->state.active) { //Store player data which is quitting
//FIXME: SC are lost if there's no connection at save-time because of the way its related data is cleared immediately after this function. [Skotlex]
if ( chrif_isconnected() )
chrif_save_scdata(sd);
if (chrif_isconnected()) {
chrif_save_scdata(sd);
chrif_skillcooldown_save(sd);
}
if ( !chrif_auth_logout(sd,flag == 1 ? ST_LOGOUT : ST_MAPCHANGE) )
ShowError("chrif_save: Failed to set up player %d:%d for proper quitting!\n", sd->status.account_id, sd->status.char_id);
}
@ -575,8 +577,20 @@ int chrif_scdata_request(int account_id, int char_id) {
WFIFOL(char_fd,6) = char_id;
WFIFOSET(char_fd,10);
#endif
return 0;
}
return 0;
/*==========================================
* Request skillcooldown from charserver
*------------------------------------------*/
int chrif_skillcooldown_request(int account_id, int char_id) {
chrif_check(-1);
WFIFOHEAD(char_fd, 10);
WFIFOW(char_fd, 0) = 0x2b0a;
WFIFOL(char_fd, 2) = account_id;
WFIFOL(char_fd, 6) = char_id;
WFIFOSET(char_fd, 10);
return 0;
}
/*==========================================
@ -1214,6 +1228,44 @@ int chrif_save_scdata(struct map_session_data *sd) { //parses the sc_data of the
WFIFOW(char_fd,2) = 14 +count*sizeof(struct status_change_data); //Total packet size
WFIFOSET(char_fd,WFIFOW(char_fd,2));
#endif
return 0;
}
int chrif_skillcooldown_save(struct map_session_data *sd) {
int i, count = 0;
struct skill_cooldown_data data;
unsigned int tick;
const struct TimerData *timer;
chrif_check(-1);
tick = gettick();
WFIFOHEAD(char_fd, 14 + MAX_SKILLCOOLDOWN * sizeof (struct skill_cooldown_data));
WFIFOW(char_fd, 0) = 0x2b15;
WFIFOL(char_fd, 4) = sd->status.account_id;
WFIFOL(char_fd, 8) = sd->status.char_id;
for (i = 0; i < MAX_SKILLCOOLDOWN; i++) {
if (!sd->scd[i])
continue;
if (!battle_config.guild_skill_relog_delay && (sd->scd[i]->skill_id >= GD_BATTLEORDER && sd->scd[i]->skill_id <= GD_EMERGENCYCALL))
continue;
timer = get_timer(sd->scd[i]->timer);
if (timer == NULL || timer->func != skill_blockpc_end || DIFF_TICK(timer->tick, tick) < 0)
continue;
data.tick = DIFF_TICK(timer->tick, tick);
data.skill_id = sd->scd[i]->skill_id;
memcpy(WFIFOP(char_fd, 14 + count * sizeof (struct skill_cooldown_data)), &data, sizeof (struct skill_cooldown_data));
count++;
}
if (count == 0)
return 0;
WFIFOW(char_fd, 12) = count;
WFIFOW(char_fd, 2) = 14 + count * sizeof (struct skill_cooldown_data);
WFIFOSET(char_fd, WFIFOW(char_fd, 2));
return 0;
}
@ -1248,8 +1300,35 @@ int chrif_load_scdata(int fd) {
status_change_start(NULL,&sd->bl, (sc_type)data->type, 10000, data->val1, data->val2, data->val3, data->val4, data->tick, 1|2|4|8);
}
#endif
return 0;
}
return 0;
//Retrieve and load skillcooldown for a player
int chrif_skillcooldown_load(int fd) {
struct map_session_data *sd;
struct skill_cooldown_data *data;
int aid, cid, i, count;
aid = RFIFOL(fd, 4);
cid = RFIFOL(fd, 8);
sd = map_id2sd(aid);
if (!sd) {
ShowError("chrif_skillcooldown_load: Player of AID %d not found!\n", aid);
return -1;
}
if (sd->status.char_id != cid) {
ShowError("chrif_skillcooldown_load: Receiving data for account %d, char id does not matches (%d != %d)!\n", aid, sd->status.char_id, cid);
return -1;
}
count = RFIFOW(fd, 12); //sc_count
for (i = 0; i < count; i++) {
data = (struct skill_cooldown_data*) RFIFOP(fd, 14 + i * sizeof (struct skill_cooldown_data));
skill_blockpc_start(sd, data->skill_id, data->tick);
}
return 0;
}
/*==========================================
@ -1443,6 +1522,7 @@ int chrif_parse(int fd) {
case 0x2b04: chrif_recvmap(fd); break;
case 0x2b06: chrif_changemapserverack(RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOL(fd,14), RFIFOW(fd,18), RFIFOW(fd,20), RFIFOW(fd,22), RFIFOL(fd,24), RFIFOW(fd,28)); break;
case 0x2b09: map_addnickdb(RFIFOL(fd,2), (char*)RFIFOP(fd,6)); break;
case 0x2b0b: chrif_skillcooldown_load(fd); break;
case 0x2b0d: chrif_changedsex(fd); break;
case 0x2b0f: chrif_char_ask_name_answer(RFIFOL(fd,2), (char*)RFIFOP(fd,6), RFIFOW(fd,30), RFIFOW(fd,32)); break;
case 0x2b12: chrif_divorceack(RFIFOL(fd,2), RFIFOL(fd,6)); break;

View File

@ -38,6 +38,9 @@ bool chrif_auth_finished(struct map_session_data* sd);
void chrif_authreq(struct map_session_data* sd);
void chrif_authok(int fd);
int chrif_scdata_request(int account_id, int char_id);
int chrif_skillcooldown_request(int account_id, int char_id);
int chrif_skillcooldown_save(struct map_session_data *sd);
int chrif_skillcooldown_load(int fd);
int chrif_save(struct map_session_data* sd, int flag);
int chrif_charselectreq(struct map_session_data* sd, uint32 s_ip);
int chrif_changemapserver(struct map_session_data* sd, uint32 ip, uint16 port);

View File

@ -856,15 +856,16 @@ int guild_member_withdraw(int guild_id, int account_id, int char_id, int flag, c
if( i == -1 )
return 0; // not a member (inconsistency!)
online_member_sd = guild_getavailablesd(g);
if(online_member_sd == NULL)
return 0; // noone online to inform
#ifdef BOUND_ITEMS
//Guild bound item check
guild_retrieveitembound(char_id,account_id,guild_id);
#endif
online_member_sd = guild_getavailablesd(g);
if(online_member_sd == NULL)
return 0; // noone online to inform
if(!flag)
clif_guild_leave(online_member_sd, name, mes);
else
@ -912,15 +913,15 @@ void guild_retrieveitembound(int char_id,int aid,int guild_id)
}
else { //Character is offline, ask char server to do the job
struct guild_storage* stor = guild2storage2(guild_id);
struct guild *g = guild_search(guild_id);
int i;
nullpo_retv(g);
if(stor && stor->storage_status == 1) { //Someone is in guild storage, close them
struct s_mapiterator* iter = mapit_getallusers();
for( sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC*)mapit_next(iter) ) {
if(sd->status.guild_id == guild_id && sd->state.storage_flag == 2) {
for(i=0; i<g->max_member; i++){
TBL_PC *pl_sd = g->member[i].sd;
if(pl_sd && pl_sd->state.storage_flag == 2)
storage_guild_storageclose(sd);
break;
}
}
mapit_free(iter);
}
intif_itembound_req(char_id,aid,guild_id);
}
@ -1398,7 +1399,7 @@ void guild_block_skill(struct map_session_data *sd, int time)
uint16 skill_id[] = { GD_BATTLEORDER, GD_REGENERATION, GD_RESTORE, GD_EMERGENCYCALL };
int i;
for (i = 0; i < 4; i++)
skill_blockpc_start_(sd, skill_id[i], time , true);
skill_blockpc_start(sd, skill_id[i], time);
}
/*====================================================

View File

@ -2182,16 +2182,13 @@ void intif_itembound_req(int char_id,int aid,int guild_id) {
WFIFOL(inter_fd,6) = aid;
WFIFOW(inter_fd,10) = guild_id;
WFIFOSET(inter_fd,12);
if(gstor)
gstor->lock = 1; //Lock for retrieval process
if(gstor) gstor->lock = 1; //Lock for retrieval process
}
//3856
void intif_parse_itembound_ack(int fd) {
struct guild_storage *gstor;
int guild_id = RFIFOW(char_fd,6);
gstor = guild2storage2(guild_id);
int guild_id = RFIFOW(fd,6);
struct guild_storage *gstor = guild2storage2(guild_id);
if(gstor) gstor->lock = 0; //Unlock now that operation is completed
}
#endif

View File

@ -963,7 +963,7 @@ int npc_touch_areanpc(struct map_session_data* sd, int16 m, int16 x, int16 y)
}
switch(map[m].npc[i]->subtype) {
case WARP:
if (pc_ishiding(sd) || sd->sc.count && sd->sc.data[SC_CAMOUFLAGE] || pc_isdead(sd))
if (pc_ishiding(sd) || (sd->sc.count && sd->sc.data[SC_CAMOUFLAGE]) || pc_isdead(sd))
break; // hidden or dead chars cannot use warps
pc_setpos(sd,map[m].npc[i]->u.warp.mapindex,map[m].npc[i]->u.warp.x,map[m].npc[i]->u.warp.y,CLR_OUTSIGHT);
break;
@ -2725,7 +2725,7 @@ int npc_duplicate4instance(struct npc_data *snd, int16 m) {
if(!imap)
imap = map_mapname2mapid(map[dm].name);
if( imap == -1 ) {
ShowError("npc_duplicate4instance: warp (%s) leading to instanced map (%s), but instance map is not attached to current instance.\n", map[dm].name, snd->exname);
return 1;

View File

@ -1147,11 +1147,6 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim
clif_changemap(sd,sd->bl.m,sd->bl.x,sd->bl.y);
}
/**
* Check if player have any cool downs on
**/
skill_cooldown_load(sd);
/**
* Check if player have any item cooldowns on
**/
@ -1296,7 +1291,7 @@ int pc_reg_received(struct map_session_data *sd)
status_calc_pc(sd,1);
chrif_scdata_request(sd->status.account_id, sd->status.char_id);
chrif_skillcooldown_request(sd->status.account_id, sd->status.char_id);
intif_Mail_requestinbox(sd->status.char_id, 0); // MAIL SYSTEM - Request Mail Inbox
intif_request_questlog(sd);

View File

@ -115,6 +115,11 @@ struct s_autobonus {
unsigned short pos;
};
struct skill_cooldown_entry {
unsigned short skill_id;
int timer;
};
enum npc_timeout_type {
NPCT_INPUT = 0,
NPCT_MENU = 1,
@ -244,7 +249,7 @@ struct map_session_data {
uint16 skill_id_old,skill_lv_old;
uint16 skill_id_dance,skill_lv_dance;
short cook_mastery; // range: [0,1999] [Inkfish]
unsigned char blockskill[MAX_SKILL];
struct skill_cooldown_entry * scd[MAX_SKILLCOOLDOWN]; // Skill Cooldown
int cloneskill_id, reproduceskill_id;
int menuskill_id, menuskill_val, menuskill_val2;
@ -321,6 +326,10 @@ struct map_session_data {
short flag, rate;
unsigned char ele;
} subele2[MAX_PC_BONUS];
struct {
int id;
int val;
} cooldown[MAX_PC_BONUS];
struct {
short value;
int rate, tick;

View File

@ -63,20 +63,6 @@ static DBMap* bowling_db = NULL; // int mob_id -> struct mob_data*
DBMap* skillunit_db = NULL; // int id -> struct skill_unit*
/**
* Skill Cool Down Delay Saving
* Struct skill_cd is not a member of struct map_session_data
* to keep cooldowns in memory between player log-ins.
* All cooldowns are reset when server is restarted.
**/
DBMap* skillcd_db = NULL; // char_id -> struct skill_cd
struct skill_cd {
int duration[MAX_SKILL_TREE];//milliseconds
short skidx[MAX_SKILL_TREE];//the skill index entries belong to
short nameid[MAX_SKILL_TREE];//skill id
unsigned char cursor;
};
/**
* Skill Unit Persistency during endack routes (mostly for songs see bugreport:4574)
**/
@ -257,6 +243,27 @@ int skill_tree_get_max(uint16 skill_id, int b_class)
return skill_get_max(skill_id);
}
int skill_get_cooldown_(struct map_session_data *sd, int id, int lv) {
int i, cooldown;
int idx = skill_get_index (id);
if (!idx) return 0;
cooldown = 0;
if (skill_db[idx].cooldown[lv - 1])
cooldown = skill_db[idx].cooldown[lv - 1];
for (i = 0; i < ARRAYLENGTH(sd->cooldown) && sd->cooldown[i].id; i++) {
if (sd->cooldown[i].id == id) {
cooldown += sd->cooldown[i].val;
if (cooldown < 0)
cooldown = 0;
break;
}
}
return cooldown;
}
int skill_frostjoke_scream(struct block_list *bl,va_list ap);
int skill_attack_area(struct block_list *bl,va_list ap);
struct skill_unit_group *skill_locate_element_field(struct block_list *bl); // [Skotlex]
@ -446,7 +453,7 @@ static short skill_isCopyable (struct map_session_data *sd, uint16 skill_id, str
// Only copy skill that player doesn't have or the skill is old clone
if (sd->status.skill[skill_id].id != 0 && sd->status.skill[skill_id].flag != SKILL_FLAG_PLAGIARIZED)
return 0;
// Never copy NPC/Wedding Skills
if (skill_get_inf2(skill_id)&(INF2_NPC_SKILL|INF2_WEDDING_SKILL))
return 0;
@ -510,7 +517,7 @@ bool skill_isNotOk(uint16 skill_id, struct map_session_data *sd)
return true;
}
if (sd->blockskill[idx] > 0) {
if (skill_blockpc_get(sd, skill_id) != -1){
clif_skill_fail(sd,skill_id,USESKILL_FAIL_SKILLINTERVAL,0);
return true;
}
@ -711,7 +718,7 @@ bool skill_isNotOk_npcRange(struct block_list *src, struct block_list *target, u
if (src->type == BL_PC && pc_has_permission(BL_CAST(BL_PC,src),PC_PERM_SKILL_UNCONDITIONAL))
return false;
inf = skill_get_inf(skill_id);
//if self skill
if (inf&INF_SELF_SKILL) {
@ -9650,15 +9657,8 @@ int skill_castend_id(int tid, unsigned int tick, int id, intptr_t data)
if( !sd || sd->skillitem != ud->skill_id || skill_get_delay(ud->skill_id,ud->skill_lv) )
ud->canact_tick = tick + skill_delayfix(src, ud->skill_id, ud->skill_lv); //Tests show wings don't overwrite the delay but skill scrolls do. [Inkfish]
if (sd) { //Cooldown application
int i, cooldown = skill_get_cooldown(ud->skill_id, ud->skill_lv);
for (i = 0; i < ARRAYLENGTH(sd->skillcooldown) && sd->skillcooldown[i].id; i++) { // Increases/Decreases cooldown of a skill by item/card bonuses.
if (sd->skillcooldown[i].id == ud->skill_id){
cooldown += sd->skillcooldown[i].val;
break;
}
}
if(cooldown)
skill_blockpc_start(sd, ud->skill_id, cooldown);
int cooldown = skill_get_cooldown_(sd,ud->skill_id, ud->skill_lv); // Increases/Decreases cooldown of a skill by item/card bonuses.
if(cooldown) skill_blockpc_start(sd, ud->skill_id, cooldown);
}
if( battle_config.display_status_timers && sd )
clif_status_change(src, SI_ACTIONDELAY, 1, skill_delayfix(src, ud->skill_id, ud->skill_lv), 0, 0, 0);
@ -17337,86 +17337,81 @@ static int skill_destroy_trap( struct block_list *bl, va_list ap ) {
return 0;
}
/*==========================================
*
*------------------------------------------*/
*
*------------------------------------------*/
int skill_blockpc_get(struct map_session_data *sd, int skillid) {
int i;
nullpo_retr(-1, sd);
ARR_FIND(0, MAX_SKILLCOOLDOWN, i, sd->scd[i] && sd->scd[i]->skill_id == skillid);
return (i >= MAX_SKILLCOOLDOWN) ? -1 : i;
}
int skill_blockpc_end(int tid, unsigned int tick, int id, intptr_t data) {
struct map_session_data *sd = map_id2sd(id);
struct skill_cd * cd = NULL;
int i = (int) data;
if (data <= 0 || data >= MAX_SKILL)
if (!sd || data < 0 || data >= MAX_SKILLCOOLDOWN)
return 0;
if (!sd) return 0;
if (sd->blockskill[data] != (0x1|(tid&0xFE))) return 0;
if( ( cd = idb_get(skillcd_db,sd->status.char_id) ) ) {
int i,cursor;
ARR_FIND( 0, cd->cursor+1, cursor, cd->skidx[cursor] == data );
cd->duration[cursor] = 0;
cd->skidx[cursor] = 0;
cd->nameid[cursor] = 0;
// compact the cool down list
for( i = 0, cursor = 0; i < cd->cursor; i++ ) {
if( cd->duration[i] == 0 )
continue;
if( cursor != i ) {
cd->duration[cursor] = cd->duration[i];
cd->skidx[cursor] = cd->skidx[i];
cd->nameid[cursor] = cd->nameid[i];
}
cursor++;
}
if( cursor == 0 )
idb_remove(skillcd_db,sd->status.char_id);
else
cd->cursor = cursor;
if (!sd->scd[i] || sd->scd[i]->timer != tid) {
ShowWarning("skill_blockpc_end: Invalid Timer or not Skill Cooldown.\n");
return 0;
}
sd->blockskill[data] = 0;
return 1;
aFree(sd->scd[i]);
sd->scd[i] = NULL;
return 1;
}
/**
* flags a singular skill as being blocked from persistent usage.
* @param sd the player the skill delay affects
* @param skill_id the skill which should be delayed
* @param tick the length of time the delay should last
* @param load whether this assignment is being loaded upon player login
* @return 0 if successful, -1 otherwise
*/
int skill_blockpc_start_(struct map_session_data *sd, uint16 skill_id, int tick, bool load)
{
int oskill_id = skill_id;
struct skill_cd* cd = NULL;
uint16 idx = skill_get_index(skill_id);
nullpo_retr (-1, sd);
if (idx == 0)
* flags a singular skill as being blocked from persistent usage.
* @param sd the player the skill delay affects
* @param skill_id the skill which should be delayed
* @param tick the length of time the delay should last
* @param load whether this assignment is being loaded upon player login
* @return 0 if successful, -1 otherwise
*/
int skill_blockpc_start(struct map_session_data *sd, int skillid, int tick) {
int i;
nullpo_retr(-1, sd);
if (skillid == 0 || tick < 1)
return -1;
if (tick < 1) {
sd->blockskill[idx] = 0;
return -1;
ARR_FIND(0, MAX_SKILLCOOLDOWN, i, sd->scd[i] && sd->scd[i]->skill_id == skillid);
if (i < MAX_SKILLCOOLDOWN) { // Skill already with cooldown
delete_timer(sd->scd[i]->timer, skill_blockpc_end);
aFree(sd->scd[i]);
sd->scd[i] = NULL;
}
if( battle_config.display_status_timers )
clif_skill_cooldown(sd, idx, tick);
ARR_FIND(0, MAX_SKILLCOOLDOWN, i, !sd->scd[i]);
if (i < MAX_SKILLCOOLDOWN) { // Free Slot found
CREATE(sd->scd[i], struct skill_cooldown_entry, 1);
sd->scd[i]->skill_id = skillid;
sd->scd[i]->timer = add_timer(gettick() + tick, skill_blockpc_end, sd->bl.id, i);
if( !load ) {// not being loaded initially so ensure the skill delay is recorded
if( !(cd = idb_get(skillcd_db,sd->status.char_id)) ) {// create a new skill cooldown object for map storage
CREATE( cd, struct skill_cd, 1 );
idb_put( skillcd_db, sd->status.char_id, cd );
}
if (battle_config.display_status_timers && tick > 0)
clif_skill_cooldown(sd, skillid, tick);
// record the skill duration in the database map
cd->duration[cd->cursor] = tick;
cd->skidx[cd->cursor] = idx;
cd->nameid[cd->cursor] = oskill_id;
cd->cursor++;
return 1;
} else {
ShowWarning("skill_blockpc_start: Too many skillcooldowns, increase MAX_SKILLCOOLDOWN.\n");
return 0;
}
}
sd->blockskill[idx] = 0x1|(0xFE&add_timer(gettick()+tick,skill_blockpc_end,sd->bl.id,idx));
return 0;
int skill_blockpc_clear(struct map_session_data *sd) {
int i;
nullpo_ret(sd);
for (i = 0; i < MAX_SKILLCOOLDOWN; i++) {
if (!sd->scd[i])
continue;
delete_timer(sd->scd[i]->timer, skill_blockpc_end);
aFree(sd->scd[i]);
sd->scd[i] = NULL;
}
return 1;
}
int skill_blockhomun_end(int tid, unsigned int tick, int id, intptr_t data) //[orn]
@ -17938,29 +17933,6 @@ int skill_get_elemental_type( uint16 skill_id , uint16 skill_lv ) {
return type;
}
/**
* reload stored skill cooldowns when a player logs in.
* @param sd the affected player structure
*/
void skill_cooldown_load(struct map_session_data * sd)
{
int i;
struct skill_cd* cd = NULL;
// always check to make sure the session properly exists
nullpo_retv(sd);
if( !(cd = idb_get(skillcd_db, sd->status.char_id)) ) {// no skill cooldown is associated with this character
return;
}
// process each individual cooldown associated with the character
for( i = 0; i < cd->cursor; i++ ) {
// block the skill from usage but ensure it is not recorded (load = true)
skill_blockpc_start_( sd, cd->nameid[i], cd->duration[i], true );
}
}
/*==========================================
* sub-function of DB reading.
* skill_db.txt
@ -18492,7 +18464,6 @@ int do_init_skill (void)
group_db = idb_alloc(DB_OPT_BASE);
skillunit_db = idb_alloc(DB_OPT_BASE);
skillcd_db = idb_alloc(DB_OPT_RELEASE_DATA);
skillusave_db = idb_alloc(DB_OPT_RELEASE_DATA);
bowling_db = idb_alloc(DB_OPT_BASE);
skill_unit_ers = ers_new(sizeof(struct skill_unit_group),"skill.c::skill_unit_ers",ERS_OPT_NONE);
@ -18514,7 +18485,6 @@ int do_final_skill(void)
db_destroy(skilldb_name2id);
db_destroy(group_db);
db_destroy(skillunit_db);
db_destroy(skillcd_db);
db_destroy(skillusave_db);
db_destroy(bowling_db);
ers_destroy(skill_unit_ers);

View File

@ -429,11 +429,13 @@ int skill_castend_nodamage_id( struct block_list *src, struct block_list *bl,uin
int skill_castend_damage_id( struct block_list* src, struct block_list *bl,uint16 skill_id,uint16 skill_lv,unsigned int tick,int flag );
int skill_castend_pos2( struct block_list *src, int x,int y,uint16 skill_id,uint16 skill_lv,unsigned int tick,int flag);
int skill_blockpc_start_(struct map_session_data*, uint16 skill_id, int, bool);
int skill_blockpc_start(struct map_session_data*, int, int);
int skill_blockpc_get(struct map_session_data *sd, int skillid);
int skill_blockpc_clear(struct map_session_data *sd);
int skill_blockpc_end(int tid, unsigned int tick, int id, intptr_t data);
int skill_blockhomun_start (struct homun_data*,uint16 skill_id,int);
int skill_blockmerc_start (struct mercenary_data*,uint16 skill_id,int);
#define skill_blockpc_start(sd, skill_id, tick) skill_blockpc_start_( sd, skill_id, tick, false )
// (Epoque:) To-do: replace this macro with some sort of skill tree check (rather than hard-coded skill names)
#define skill_ischangesex(id) ( \

View File

@ -2370,6 +2370,7 @@ int unit_free(struct block_list *bl, clr_type clrtype)
duel_reject(sd->duel_invite, sd);
channel_pcquit(sd,0xF); //leave all chan
skill_blockpc_clear(sd); //clear all skill cooldown related
// Notify friends that this char logged out. [Skotlex]
map_foreachpc(clif_friendslist_toggle_sub, sd->status.account_id, sd->status.char_id, 0);