summaryrefslogtreecommitdiff
path: root/src/map
diff options
context:
space:
mode:
Diffstat (limited to 'src/map')
-rw-r--r--src/map/atcommand.c4
-rw-r--r--src/map/battle.c12
-rw-r--r--src/map/battle.h2
-rw-r--r--src/map/battleground.c163
-rw-r--r--src/map/clif.c8
-rw-r--r--src/map/map.c14
-rw-r--r--src/map/mob.c9
-rw-r--r--src/map/npc.c557
-rw-r--r--src/map/npc.h14
-rw-r--r--src/map/pc.c148
-rw-r--r--src/map/pc.h3
-rw-r--r--src/map/script.c613
-rw-r--r--src/map/script.h55
-rw-r--r--src/map/skill.c8
-rw-r--r--src/map/status.c18
-rw-r--r--src/map/status.h2
-rw-r--r--src/map/unit.c5
17 files changed, 954 insertions, 681 deletions
diff --git a/src/map/atcommand.c b/src/map/atcommand.c
index ff88f2c63..de71819de 100644
--- a/src/map/atcommand.c
+++ b/src/map/atcommand.c
@@ -77,7 +77,7 @@ struct atcmd_binding_data* get_atcommandbind_byname(const char* name) {
}
const char* atcommand_msgsd(struct map_session_data *sd, int msg_number) {
- Assert_retr("??", msg_number >= 0 && msg_number < MAX_MSG);
+ Assert_retr("??", msg_number >= 0 && msg_number < MAX_MSG && atcommand->msg_table[0][msg_number] != NULL);
if (!sd || sd->lang_id >= atcommand->max_message_table || !atcommand->msg_table[sd->lang_id][msg_number])
return atcommand->msg_table[0][msg_number];
return atcommand->msg_table[sd->lang_id][msg_number];
@@ -85,7 +85,7 @@ const char* atcommand_msgsd(struct map_session_data *sd, int msg_number) {
const char* atcommand_msgfd(int fd, int msg_number) {
struct map_session_data *sd = sockt->session_is_valid(fd) ? sockt->session[fd]->session_data : NULL;
- Assert_retr("??", msg_number >= 0 && msg_number < MAX_MSG);
+ Assert_retr("??", msg_number >= 0 && msg_number < MAX_MSG && atcommand->msg_table[0][msg_number] != NULL);
if (!sd || sd->lang_id >= atcommand->max_message_table || !atcommand->msg_table[sd->lang_id][msg_number])
return atcommand->msg_table[0][msg_number];
return atcommand->msg_table[sd->lang_id][msg_number];
diff --git a/src/map/battle.c b/src/map/battle.c
index ba640fedf..d1cdd19c4 100644
--- a/src/map/battle.c
+++ b/src/map/battle.c
@@ -229,10 +229,13 @@ int battle_delay_damage_sub(int tid, int64 tick, int id, intptr_t data) {
src = map->id2bl(dat->src_id);
//Check to see if you haven't teleported. [Skotlex]
- if( src
- && (target->type != BL_PC || ((TBL_PC*)target)->invincible_timer == INVALID_TIMER)
- && (dat->skill_id == MO_EXTREMITYFIST || (target->m == src->m && check_distance_bl(src, target, dat->distance)) )
- ) {
+ if (src && (
+ battle_config.fix_warp_hit_delay_abuse ?
+ (dat->skill_id == MO_EXTREMITYFIST || target->m != src->m || check_distance_bl(src, target, dat->distance))
+ :
+ ((target->type != BL_PC || ((TBL_PC*)target)->invincible_timer == INVALID_TIMER)
+ && (dat->skill_id == MO_EXTREMITYFIST || (target->m == src->m && check_distance_bl(src, target, dat->distance))))
+ )) {
map->freeblock_lock();
status_fix_damage(src, target, dat->damage, dat->delay);
if( dat->attack_type && !status->isdead(target) && dat->additional_effects )
@@ -7137,6 +7140,7 @@ static const struct battle_data {
{ "boss_icewall_walk_block", &battle_config.boss_icewall_walk_block, 0, 0, 255, },
{ "feature.roulette", &battle_config.feature_roulette, 1, 0, 1, },
{ "show_monster_hp_bar", &battle_config.show_monster_hp_bar, 1, 0, 1, },
+ { "fix_warp_hit_delay_abuse", &battle_config.fix_warp_hit_delay_abuse, 0, 0, 1, },
};
#ifndef STATS_OPT_OUT
/**
diff --git a/src/map/battle.h b/src/map/battle.h
index 55ddf3b9b..68a427e72 100644
--- a/src/map/battle.h
+++ b/src/map/battle.h
@@ -510,6 +510,8 @@ struct Battle_Config {
int feature_roulette;
int show_monster_hp_bar; // [Frost]
+
+ int fix_warp_hit_delay_abuse;
};
/* criteria for battle_config.idletime_critera */
diff --git a/src/map/battleground.c b/src/map/battleground.c
index cc5384d21..208b4b99f 100644
--- a/src/map/battleground.c
+++ b/src/map/battleground.c
@@ -471,24 +471,34 @@ struct bg_arena *bg_name2arena (char *name) {
}
return NULL;
}
-int bg_id2pos ( int queue_id, int account_id ) {
- struct hQueue *queue = script->queue(queue_id);
- if( queue ) {
- int i, pos = 1;
- for(i = 0; i < queue->size; i++ ) {
- if( queue->item[i] > 0 ) {
- if( queue->item[i] == account_id ) {
- return pos;
- }
- pos++;
- }
+
+/**
+ * Returns a character's position in a battleground's queue.
+ *
+ * @param queue_id The ID of the battleground's queue.
+ * @param account_id The character's account ID.
+ *
+ * @return the position (starting at 1).
+ * @retval 0 if the queue doesn't exist or the given account ID isn't present in it.
+ */
+int bg_id2pos(int queue_id, int account_id)
+{
+ struct script_queue *queue = script->queue(queue_id);
+ if (queue) {
+ int i;
+ ARR_FIND(0, VECTOR_LENGTH(queue->entries), i, VECTOR_INDEX(queue->entries, i) == account_id);
+ if (i != VECTOR_LENGTH(queue->entries)) {
+ return i+1;
}
}
return 0;
}
-void bg_queue_ready_ack (struct bg_arena *arena, struct map_session_data *sd, bool response) {
+
+void bg_queue_ready_ack(struct bg_arena *arena, struct map_session_data *sd, bool response)
+{
nullpo_retv(arena);
nullpo_retv(sd);
+
if( arena->begin_timer == INVALID_TIMER || !sd->bg_queue.arena || sd->bg_queue.arena != arena ) {
bg->queue_pc_cleanup(sd);
return;
@@ -496,18 +506,18 @@ void bg_queue_ready_ack (struct bg_arena *arena, struct map_session_data *sd, bo
if( !response )
bg->queue_pc_cleanup(sd);
else {
- struct hQueue *queue = &script->hq[arena->queue_id];
+ struct script_queue *queue = script->queue(arena->queue_id);
int i, count = 0;
sd->bg_queue.ready = 1;
- for( i = 0; i < queue->size; i++ ) {
- if (queue->item[i] > 0 && (sd = map->id2sd(queue->item[i])) != NULL) {
- if( sd->bg_queue.ready == 1 )
- count++;
- }
+ for (i = 0; i < VECTOR_LENGTH(queue->entries); i++) {
+ struct map_session_data *tsd = map->id2sd(VECTOR_INDEX(queue->entries, i));
+
+ if (tsd != NULL && tsd->bg_queue.ready == 1)
+ count++;
}
/* check if all are ready then cancel timer, and start game */
- if( count == queue->items ) {
+ if (count == VECTOR_LENGTH(queue->entries)) {
timer->delete(arena->begin_timer,bg->begin_timer);
arena->begin_timer = INVALID_TIMER;
bg->begin(arena);
@@ -531,7 +541,7 @@ void bg_queue_player_cleanup(struct map_session_data *sd) {
sd->bg_queue.type = 0;
}
void bg_match_over(struct bg_arena *arena, bool canceled) {
- struct hQueue *queue = &script->hq[arena->queue_id];
+ struct script_queue *queue = script->queue(arena->queue_id);
int i;
nullpo_retv(arena);
@@ -539,19 +549,20 @@ void bg_match_over(struct bg_arena *arena, bool canceled) {
return;
arena->ongoing = false;
- for( i = 0; i < queue->size; i++ ) {
- struct map_session_data * sd = NULL;
+ for (i = 0; i < VECTOR_LENGTH(queue->entries); i++) {
+ struct map_session_data *sd = map->id2sd(VECTOR_INDEX(queue->entries, i));
- if (queue->item[i] > 0 && (sd = map->id2sd(queue->item[i])) != NULL) {
- if( sd->bg_queue.arena ) {
- bg->team_leave(sd, 0);
- bg->queue_pc_cleanup(sd);
- }
- if (canceled)
- clif->messagecolor_self(sd->fd, COLOR_RED, "BG Match Canceled: not enough players");
- else
- pc_setglobalreg(sd, script->add_str(arena->delay_var), (unsigned int)time(NULL));
+ if (sd == NULL)
+ continue;
+
+ if (sd->bg_queue.arena) {
+ bg->team_leave(sd, 0);
+ bg->queue_pc_cleanup(sd);
}
+ if (canceled)
+ clif->messagecolor_self(sd->fd, COLOR_RED, "BG Match Canceled: not enough players");
+ else
+ pc_setglobalreg(sd, script->add_str(arena->delay_var), (unsigned int)time(NULL));
}
arena->begin_timer = INVALID_TIMER;
@@ -560,19 +571,20 @@ void bg_match_over(struct bg_arena *arena, bool canceled) {
script->queue_clear(arena->queue_id);
}
void bg_begin(struct bg_arena *arena) {
- struct hQueue *queue = &script->hq[arena->queue_id];
+ struct script_queue *queue = script->queue(arena->queue_id);
int i, count = 0;
nullpo_retv(arena);
- for( i = 0; i < queue->size; i++ ) {
- struct map_session_data * sd = NULL;
+ for (i = 0; i < VECTOR_LENGTH(queue->entries); i++) {
+ struct map_session_data *sd = map->id2sd(VECTOR_INDEX(queue->entries, i));
- if (queue->item[i] > 0 && (sd = map->id2sd(queue->item[i])) != NULL) {
- if( sd->bg_queue.ready == 1 )
- count++;
- else
- bg->queue_pc_cleanup(sd);
- }
+ if (sd == NULL)
+ continue;
+
+ if (sd->bg_queue.ready == 1)
+ count++;
+ else
+ bg->queue_pc_cleanup(sd);
}
/* TODO/FIXME? I *think* it should check what kind of queue the player used, then check if his party/guild
* (his team) still meet the join criteria (sort of what bg->can_queue does)
@@ -591,25 +603,24 @@ void bg_begin(struct bg_arena *arena) {
mapreg->setregstr(script->add_str("$@bg_delay_var$"),bg->gdelay_var);
count = 0;
- for( i = 0; i < queue->size; i++ ) {
- struct map_session_data * sd = NULL;
-
- if (queue->item[i] > 0 && (sd = map->id2sd(queue->item[i])) != NULL) {
- if( sd->bg_queue.ready == 1 ) {
- mapreg->setreg(reference_uid(script->add_str("$@bg_member"), count), sd->status.account_id);
- mapreg->setreg(reference_uid(script->add_str("$@bg_member_group"), count),
- sd->bg_queue.type == BGQT_GUILD ? sd->status.guild_id :
- sd->bg_queue.type == BGQT_PARTY ? sd->status.party_id :
- 0
- );
- mapreg->setreg(reference_uid(script->add_str("$@bg_member_type"), count),
- sd->bg_queue.type == BGQT_GUILD ? 1 :
- sd->bg_queue.type == BGQT_PARTY ? 2 :
- 0
- );
- count++;
- }
- }
+ for (i = 0; i < VECTOR_LENGTH(queue->entries); i++) {
+ struct map_session_data *sd = map->id2sd(VECTOR_INDEX(queue->entries, i));
+
+ if (sd == NULL || sd->bg_queue.ready != 1)
+ continue;
+
+ mapreg->setreg(reference_uid(script->add_str("$@bg_member"), count), sd->status.account_id);
+ mapreg->setreg(reference_uid(script->add_str("$@bg_member_group"), count),
+ sd->bg_queue.type == BGQT_GUILD ? sd->status.guild_id :
+ sd->bg_queue.type == BGQT_PARTY ? sd->status.party_id :
+ 0
+ );
+ mapreg->setreg(reference_uid(script->add_str("$@bg_member_type"), count),
+ sd->bg_queue.type == BGQT_GUILD ? 1 :
+ sd->bg_queue.type == BGQT_PARTY ? 2 :
+ 0
+ );
+ count++;
}
mapreg->setreg(script->add_str("$@bg_member_size"),count);
@@ -645,15 +656,15 @@ int bg_afk_timer(int tid, int64 tick, int id, intptr_t data) {
}
void bg_queue_pregame(struct bg_arena *arena) {
- struct hQueue *queue;
+ struct script_queue *queue;
int i;
-
nullpo_retv(arena);
- queue = &script->hq[arena->queue_id];
- for( i = 0; i < queue->size; i++ ) {
- struct map_session_data * sd = NULL;
- if (queue->item[i] > 0 && (sd = map->id2sd(queue->item[i])) != NULL) {
+ queue = script->queue(arena->queue_id);
+ for (i = 0; i < VECTOR_LENGTH(queue->entries); i++) {
+ struct map_session_data *sd = map->id2sd(VECTOR_INDEX(queue->entries, i));
+
+ if (sd != NULL) {
clif->bgqueue_battlebegins(sd,arena->id,SELF);
}
}
@@ -667,9 +678,11 @@ int bg_fillup_timer(int tid, int64 tick, int id, intptr_t data) {
void bg_queue_check(struct bg_arena *arena) {
int count;
-
+ struct script_queue *queue;
nullpo_retv(arena);
- count = script->hq[arena->queue_id].items;
+
+ queue = script->queue(arena->queue_id);
+ count = VECTOR_LENGTH(queue->entries);
if( count == arena->max_players ) {
if( arena->fillup_timer != INVALID_TIMER ) {
timer->delete(arena->fillup_timer,bg->fillup_timer);
@@ -682,7 +695,7 @@ void bg_queue_check(struct bg_arena *arena) {
}
void bg_queue_add(struct map_session_data *sd, struct bg_arena *arena, enum bg_queue_types type) {
enum BATTLEGROUNDS_QUEUE_ACK result = bg->can_queue(sd,arena,type);
- struct hQueue *queue;
+ struct script_queue *queue = NULL;
int i, count = 0;
nullpo_retv(sd);
@@ -718,7 +731,7 @@ void bg_queue_add(struct map_session_data *sd, struct bg_arena *arena, enum bg_q
break;
}
- if( !(queue = script->queue(arena->queue_id)) || (queue->items+count) > arena->max_players ) {
+ if( !(queue = script->queue(arena->queue_id)) || (VECTOR_LENGTH(queue->entries)+count) > arena->max_players ) {
clif->bgqueue_ack(sd,BGQA_FAIL_PPL_OVERAMOUNT,arena->id);
return;
}
@@ -729,8 +742,8 @@ void bg_queue_add(struct map_session_data *sd, struct bg_arena *arena, enum bg_q
sd->bg_queue.arena = arena;
sd->bg_queue.ready = 0;
script->queue_add(arena->queue_id,sd->status.account_id);
- clif->bgqueue_joined(sd,script->hq[arena->queue_id].items);
- clif->bgqueue_update_info(sd,arena->id,script->hq[arena->queue_id].items);
+ clif->bgqueue_joined(sd, VECTOR_LENGTH(queue->entries));
+ clif->bgqueue_update_info(sd,arena->id, VECTOR_LENGTH(queue->entries));
break;
case BGQT_PARTY: {
struct party_data *p = party->search(sd->status.party_id);
@@ -740,8 +753,8 @@ void bg_queue_add(struct map_session_data *sd, struct bg_arena *arena, enum bg_q
p->data[i].sd->bg_queue.arena = arena;
p->data[i].sd->bg_queue.ready = 0;
script->queue_add(arena->queue_id,p->data[i].sd->status.account_id);
- clif->bgqueue_joined(p->data[i].sd,script->hq[arena->queue_id].items);
- clif->bgqueue_update_info(p->data[i].sd,arena->id,script->hq[arena->queue_id].items);
+ clif->bgqueue_joined(p->data[i].sd, VECTOR_LENGTH(queue->entries));
+ clif->bgqueue_update_info(p->data[i].sd,arena->id, VECTOR_LENGTH(queue->entries));
}
}
break;
@@ -753,8 +766,8 @@ void bg_queue_add(struct map_session_data *sd, struct bg_arena *arena, enum bg_q
sd->guild->member[i].sd->bg_queue.arena = arena;
sd->guild->member[i].sd->bg_queue.ready = 0;
script->queue_add(arena->queue_id,sd->guild->member[i].sd->status.account_id);
- clif->bgqueue_joined(sd->guild->member[i].sd,script->hq[arena->queue_id].items);
- clif->bgqueue_update_info(sd->guild->member[i].sd,arena->id,script->hq[arena->queue_id].items);
+ clif->bgqueue_joined(sd->guild->member[i].sd, VECTOR_LENGTH(queue->entries));
+ clif->bgqueue_update_info(sd->guild->member[i].sd,arena->id, VECTOR_LENGTH(queue->entries));
}
break;
}
diff --git a/src/map/clif.c b/src/map/clif.c
index 80703fa12..621f0b44a 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -610,12 +610,12 @@ bool clif_send(const void* buf, int len, struct block_list* bl, enum send_target
case BG_QUEUE:
if( sd && sd->bg_queue.arena ) {
- struct hQueue *queue = &script->hq[sd->bg_queue.arena->queue_id];
+ struct script_queue *queue = script->queue(sd->bg_queue.arena->queue_id);
- for( i = 0; i < queue->size; i++ ) {
- struct map_session_data *qsd = NULL;
+ for (i = 0; i < VECTOR_LENGTH(queue->entries); i++) {
+ struct map_session_data *qsd = map->id2sd(VECTOR_INDEX(queue->entries, i));
- if (queue->item[i] > 0 && (qsd = map->id2sd(queue->item[i])) != NULL) {
+ if (qsd != NULL) {
WFIFOHEAD(qsd->fd,len);
memcpy(WFIFOP(qsd->fd,0), buf, len);
WFIFOSET(qsd->fd,len);
diff --git a/src/map/map.c b/src/map/map.c
index cd2ba17c2..fff1593a4 100644
--- a/src/map/map.c
+++ b/src/map/map.c
@@ -1802,16 +1802,16 @@ int map_quit(struct map_session_data *sd) {
skill->cooldown_save(sd);
pc->itemcd_do(sd,false);
- for( i = 0; i < sd->queues_count; i++ ) {
- struct hQueue *queue;
- if( (queue = script->queue(sd->queues[i])) && queue->onLogOut[0] != '\0' ) {
- npc->event(sd, queue->onLogOut, 0);
+ for (i = 0; i < VECTOR_LENGTH(sd->script_queues); i++) {
+ struct script_queue *queue = script->queue(VECTOR_INDEX(sd->script_queues, i));
+ if (queue && queue->event_logout[0] != '\0') {
+ npc->event(sd, queue->event_logout, 0);
}
}
/* two times, the npc event above may assign a new one or delete others */
- for( i = 0; i < sd->queues_count; i++ ) {
- if( sd->queues[i] != -1 )
- script->queue_remove(sd->queues[i],sd->status.account_id);
+ while (VECTOR_LENGTH(sd->script_queues)) {
+ int qid = VECTOR_LAST(sd->script_queues);
+ script->queue_remove(qid, sd->status.account_id);
}
npc->script_event(sd, NPCE_LOGOUT);
diff --git a/src/map/mob.c b/src/map/mob.c
index 2b519462d..6cbbd3a2a 100644
--- a/src/map/mob.c
+++ b/src/map/mob.c
@@ -142,17 +142,11 @@ void mvptomb_create(struct mob_data *md, char *killer, time_t time)
if ( md->tomb_nid )
mob->mvptomb_destroy(md);
- nd = npc->create_npc(md->bl.m, md->bl.x, md->bl.y);
+ nd = npc->create_npc(TOMB, md->bl.m, md->bl.x, md->bl.y, md->ud.dir, MOB_TOMB);
md->tomb_nid = nd->bl.id;
- nd->dir = md->ud.dir;
- nd->bl.type = BL_NPC;
safestrncpy(nd->name, msg_txt(856), sizeof(nd->name)); // "Tomb"
- nd->class_ = 565;
- nd->speed = 200;
- nd->subtype = TOMB;
-
nd->u.tomb.md = md;
nd->u.tomb.kill_time = time;
@@ -165,7 +159,6 @@ void mvptomb_create(struct mob_data *md, char *killer, time_t time)
map->addblock(&nd->bl);
status->set_viewdata(&nd->bl, nd->class_);
clif->spawn(&nd->bl);
-
}
void mvptomb_destroy(struct mob_data *md) {
diff --git a/src/map/npc.c b/src/map/npc.c
index 16fc07fe8..6ecc22282 100644
--- a/src/map/npc.c
+++ b/src/map/npc.c
@@ -53,8 +53,8 @@ static int npc_mob=0;
static int npc_delay_mob=0;
static int npc_cache_mob=0;
-static char *npc_last_path;
-static char *npc_last_ref;
+static const char *npc_last_path;
+static const char *npc_last_ref;
struct npc_path_data *npc_last_npd;
//For holding the view data of npc classes. [Skotlex]
@@ -2247,16 +2247,9 @@ int npc_unload(struct npc_data* nd, bool single)
npc_chat->finalize(nd); // deallocate npc PCRE data structures
#endif
- if( single && nd->path ) {
- struct npc_path_data* npd = NULL;
- if( nd->path && nd->path != npc_last_ref ) {
- npd = strdb_get(npc->path_db, nd->path);
- }
-
- if( npd && --npd->references == 0 ) {
- strdb_remove(npc->path_db, nd->path);/* remove from db */
- aFree(nd->path);/* remove now that no other instances exist */
- }
+ if (single && nd->path != NULL) {
+ npc->releasepathreference(nd->path);
+ nd->path = NULL;
}
if( single && nd->bl.m != -1 )
@@ -2407,6 +2400,64 @@ void npc_delsrcfile(const char* name)
}
}
+/**
+ * Retains a reference to filepath, for use in nd->path
+ *
+ * @param filepath The file path to retain.
+ * @return A retained reference to filepath.
+ */
+const char *npc_retainpathreference(const char *filepath)
+{
+ struct npc_path_data * npd = NULL;
+ nullpo_ret(filepath);
+
+ if (npc_last_path == filepath) {
+ if (npc_last_npd != NULL)
+ npc_last_npd->references++;
+ return npc_last_ref;
+ }
+
+ if ((npd = strdb_get(npc->path_db,filepath)) == NULL) {
+ CREATE(npd, struct npc_path_data, 1);
+ strdb_put(npc->path_db, filepath, npd);
+
+ CREATE(npd->path, char, strlen(filepath)+1);
+ safestrncpy(npd->path, filepath, strlen(filepath)+1);
+
+ npd->references = 0;
+ }
+
+ npd->references++;
+
+ npc_last_npd = npd;
+ npc_last_ref = npd->path;
+ npc_last_path = filepath;
+
+ return npd->path;
+}
+
+/**
+ * Releases a previously retained filepath.
+ *
+ * @param filepath The file path to release.
+ */
+void npc_releasepathreference(const char *filepath)
+{
+ struct npc_path_data* npd = NULL;
+
+ nullpo_retv(filepath);
+
+ if (filepath != npc_last_ref) {
+ npd = strdb_get(npc->path_db, filepath);
+ }
+
+ if (npd != NULL && --npd->references == 0) {
+ char *npcpath = npd->path;
+ strdb_remove(npc->path_db, filepath);/* remove from db */
+ aFree(npcpath);
+ }
+}
+
/// Parses and sets the name and exname of a npc.
/// Assumes that m, x and y are already set in nd.
void npc_parsename(struct npc_data* nd, const char* name, const char* start, const char* buffer, const char* filepath) {
@@ -2461,31 +2512,6 @@ void npc_parsename(struct npc_data* nd, const char* name, const char* start, con
ShowDebug("other npc in '%s' :\n display name '%s'\n unique name '%s'\n map=%s, x=%d, y=%d\n",dnd->path, dnd->name, dnd->exname, other_mapname, dnd->bl.x, dnd->bl.y);
safestrncpy(nd->exname, newname, sizeof(nd->exname));
}
-
- if( npc_last_path != filepath ) {
- struct npc_path_data * npd = NULL;
-
- if( !(npd = strdb_get(npc->path_db,filepath) ) ) {
- CREATE(npd, struct npc_path_data, 1);
- strdb_put(npc->path_db, filepath, npd);
-
- CREATE(npd->path, char, strlen(filepath)+1);
- safestrncpy(npd->path, filepath, strlen(filepath)+1);
-
- npd->references = 0;
- }
-
- nd->path = npd->path;
- npd->references++;
-
- npc_last_npd = npd;
- npc_last_ref = npd->path;
- npc_last_path = (char*) filepath;
- } else {
- nd->path = npc_last_ref;
- if( npc_last_npd )
- npc_last_npd->references++;
- }
}
// Parse View
@@ -2537,17 +2563,39 @@ bool npc_viewisid(const char * viewid)
return true;
}
-struct npc_data* npc_create_npc(int m, int x, int y)
+/**
+ * Creates a new NPC.
+ *
+ * @remark
+ * When creating a npc with subtype TOMB, no ID is assigned. The caller
+ * must assign the dead mob ID after the NPC is created.
+ *
+ * @param subtype The NPC subtype.
+ * @param m The map id.
+ * @param x The x coordinate on map.
+ * @param y The y coordinate on map.
+ * @param dir The facing direction.
+ * @param class_ The NPC view class.
+ * @return A pointer to the created NPC data (ownership passed to the caller).
+ */
+struct npc_data *npc_create_npc(enum npc_subtype subtype, int m, int x, int y, uint8 dir, int16 class_)
{
struct npc_data *nd;
CREATE(nd, struct npc_data, 1);
- nd->bl.id = npc->get_new_npc_id();
+ nd->subtype = subtype;
+ nd->bl.type = BL_NPC;
+ if (subtype != TOMB) {
+ nd->bl.id = npc->get_new_npc_id();
+ }
nd->bl.prev = nd->bl.next = NULL;
nd->bl.m = m;
nd->bl.x = x;
nd->bl.y = y;
+ nd->dir = dir;
nd->area_size = AREA_SIZE + 1;
+ nd->class_ = class_;
+ nd->speed = 200;
return nd;
}
@@ -2557,8 +2605,7 @@ struct npc_data* npc_add_warp(char* name, short from_mapid, short from_x, short
int i, flag = 0;
struct npc_data *nd;
- nd = npc->create_npc(from_mapid, from_x, from_y);
- map->addnpc(from_mapid, nd);
+ nd = npc->create_npc(WARP, from_mapid, from_x, from_y, 0, battle_config.warp_point_debug ? WARP_DEBUG_CLASS : WARP_CLASS);
safestrncpy(nd->exname, name, ARRAYLENGTH(nd->exname));
if (npc->name2id(nd->exname) != NULL)
@@ -2571,26 +2618,13 @@ struct npc_data* npc_add_warp(char* name, short from_mapid, short from_x, short
snprintf(nd->exname, ARRAYLENGTH(nd->exname), "warp%d_%d_%d_%d", i, from_mapid, from_x, from_y);
safestrncpy(nd->name, nd->exname, ARRAYLENGTH(nd->name));
- if( battle_config.warp_point_debug )
- nd->class_ = WARP_DEBUG_CLASS;
- else
- nd->class_ = WARP_CLASS;
- nd->speed = 200;
-
nd->u.warp.mapindex = to_mapindex;
nd->u.warp.x = to_x;
nd->u.warp.y = to_y;
nd->u.warp.xs = xs;
nd->u.warp.ys = xs;
- nd->bl.type = BL_NPC;
- nd->subtype = WARP;
- npc->setcells(nd);
- map->addblock(&nd->bl);
- status->set_viewdata(&nd->bl, nd->class_);
- nd->ud = &npc->base_ud;
- if( map->list[nd->bl.m].users )
- clif->spawn(&nd->bl);
- strdb_put(npc->name_db, nd->exname, nd);
+
+ npc->add_to_location(nd);
return nd;
}
@@ -2626,15 +2660,9 @@ const char* npc_parse_warp(char* w1, char* w2, char* w3, char* w4, const char* s
return strchr(start,'\n');;//try next
}
- nd = npc->create_npc(m, x, y);
- map->addnpc(m, nd);
+ nd = npc->create_npc(WARP, m, x, y, 0, battle_config.warp_point_debug ? WARP_DEBUG_CLASS : WARP_CLASS);
npc->parsename(nd, w3, start, buffer, filepath);
-
- if (!battle_config.warp_point_debug)
- nd->class_ = WARP_CLASS;
- else
- nd->class_ = WARP_DEBUG_CLASS;
- nd->speed = 200;
+ nd->path = npc->retainpathreference(filepath);
nd->u.warp.mapindex = i;
nd->u.warp.x = to_x;
@@ -2642,15 +2670,8 @@ const char* npc_parse_warp(char* w1, char* w2, char* w3, char* w4, const char* s
nd->u.warp.xs = xs;
nd->u.warp.ys = ys;
npc_warp++;
- nd->bl.type = BL_NPC;
- nd->subtype = WARP;
- npc->setcells(nd);
- map->addblock(&nd->bl);
- status->set_viewdata(&nd->bl, nd->class_);
- nd->ud = &npc->base_ud;
- if( map->list[nd->bl.m].users )
- clif->spawn(&nd->bl);
- strdb_put(npc->name_db, nd->exname, nd);
+
+ npc->add_to_location(nd);
return strchr(start,'\n');// continue
}
@@ -2669,7 +2690,7 @@ const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const char* s
size_t items_count = 40; // Starting items size
char *p;
- int x, y, dir, m, i;
+ int x, y, dir, m, i, class_;
struct npc_data *nd;
enum npc_subtype type;
@@ -2768,31 +2789,18 @@ const char* npc_parse_shop(char* w1, char* w2, char* w3, char* w4, const char* s
return strchr(start,'\n');// continue
}
- nd = npc->create_npc(m, x, y);
+ class_ = m == -1 ? -1 : npc->parseview(w4, start, buffer, filepath);
+ nd = npc->create_npc(type, m, x, y, dir, class_);
CREATE(nd->u.shop.shop_item, struct npc_item_list, i);
memcpy(nd->u.shop.shop_item, items, sizeof(items[0])*i);
aFree(items);
nd->u.shop.count = i;
npc->parsename(nd, w3, start, buffer, filepath);
- nd->class_ = m == -1 ? -1 : npc->parseview(w4, start, buffer, filepath);
- nd->speed = 200;
+ nd->path = npc->retainpathreference(filepath);
++npc_shop;
- nd->bl.type = BL_NPC;
- nd->subtype = type;
- if( m >= 0 ) {// normal shop npc
- map->addnpc(m,nd);
- map->addblock(&nd->bl);
- status->set_viewdata(&nd->bl, nd->class_);
- nd->ud = &npc->base_ud;
- nd->dir = dir;
- if( map->list[nd->bl.m].users )
- clif->spawn(&nd->bl);
- } else {// 'floating' shop
- map->addiddb(&nd->bl);
- }
- strdb_put(npc->name_db, nd->exname, nd);
+ npc->add_to_location(nd);
return strchr(start,'\n');// continue
}
@@ -2892,7 +2900,7 @@ const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, const char*
{
int x, y, dir = 0, m, xs = 0, ys = 0; // [Valaris] thanks to fov
struct script_code *scriptroot;
- int i;
+ int i, class_;
const char* end;
const char* script_start;
@@ -2949,39 +2957,74 @@ const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, const char*
npc->convertlabel_db(label_list,filepath);
}
- nd = npc->create_npc(m, x, y);
- if( sscanf(w4, "%*[^,],%d,%d", &xs, &ys) == 2 )
- {// OnTouch area defined
+ class_ = m == -1 ? -1 : npc->parseview(w4, start, buffer, filepath);
+ nd = npc->create_npc(SCRIPT, m, x, y, dir, class_);
+ if (sscanf(w4, "%*[^,],%d,%d", &xs, &ys) == 2) {
+ // OnTouch area defined
nd->u.scr.xs = xs;
nd->u.scr.ys = ys;
- }
- else
- {// no OnTouch area
+ } else {
+ // no OnTouch area
nd->u.scr.xs = -1;
nd->u.scr.ys = -1;
}
npc->parsename(nd, w3, start, buffer, filepath);
- nd->class_ = m == -1 ? -1 : npc->parseview(w4, start, buffer, filepath);
- nd->speed = 200;
+ nd->path = npc->retainpathreference(filepath);
nd->u.scr.script = scriptroot;
nd->u.scr.label_list = label_list;
nd->u.scr.label_list_num = label_list_num;
if( options&NPO_TRADER )
nd->u.scr.trader = true;
nd->u.scr.shop = NULL;
-
++npc_script;
- nd->bl.type = BL_NPC;
- nd->subtype = SCRIPT;
+ npc->add_to_location(nd);
- if( m >= 0 ) {
- map->addnpc(m, nd);
- nd->ud = &npc->base_ud;
- nd->dir = dir;
+ //-----------------------------------------
+ // Loop through labels to export them as necessary
+ for (i = 0; i < nd->u.scr.label_list_num; i++) {
+ if (npc->event_export(nd, i)) {
+ ShowWarning("npc_parse_script: duplicate event %s::%s in file '%s'.\n",
+ nd->exname, nd->u.scr.label_list[i].name, filepath);
+ if (retval) *retval = EXIT_FAILURE;
+ }
+ npc->timerevent_export(nd, i);
+ }
+
+ nd->u.scr.timerid = INVALID_TIMER;
+
+ if( options&NPO_ONINIT ) {
+ char evname[EVENT_NAME_LENGTH];
+ struct event_data *ev;
+
+ snprintf(evname, ARRAYLENGTH(evname), "%s::OnInit", nd->exname);
+
+ if( ( ev = (struct event_data*)strdb_get(npc->ev_db, evname) ) ) {
+
+ //Execute OnInit
+ script->run_npc(nd->u.scr.script,ev->pos,0,nd->bl.id);
+
+ }
+ }
+
+ return end;
+}
+
+/**
+ * Registers the NPC and adds it to its location (on map or floating).
+ *
+ * @param nd The NPC to register.
+ */
+void npc_add_to_location(struct npc_data *nd)
+{
+ nullpo_retv(nd);
+
+ if (nd->bl.m >= 0) {
+ map->addnpc(nd->bl.m, nd);
npc->setcells(nd);
map->addblock(&nd->bl);
- if( nd->class_ >= 0 ) {
+ nd->ud = &npc->base_ud;
+ if (nd->class_ >= 0) {
status->set_viewdata(&nd->bl, nd->class_);
if( map->list[nd->bl.m].users )
clif->spawn(&nd->bl);
@@ -2991,35 +3034,120 @@ const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, const char*
map->addiddb(&nd->bl);
}
strdb_put(npc->name_db, nd->exname, nd);
+}
+
+/**
+ * Duplicates a script (@see npc_duplicate_sub)
+ */
+bool npc_duplicate_script_sub(struct npc_data *nd, const struct npc_data *snd, int xs, int ys, int options)
+{
+ int i;
+ bool retval = true;
+
+ ++npc_script;
+ nd->u.scr.xs = xs;
+ nd->u.scr.ys = ys;
+ nd->u.scr.script = snd->u.scr.script;
+ nd->u.scr.label_list = snd->u.scr.label_list;
+ nd->u.scr.label_list_num = snd->u.scr.label_list_num;
+ nd->u.scr.shop = snd->u.scr.shop;
+ nd->u.scr.trader = snd->u.scr.trader;
+
+ //add the npc to its location
+ npc->add_to_location(nd);
- //-----------------------------------------
// Loop through labels to export them as necessary
for (i = 0; i < nd->u.scr.label_list_num; i++) {
if (npc->event_export(nd, i)) {
- ShowWarning("npc_parse_script: duplicate event %s::%s in file '%s'.\n",
- nd->exname, nd->u.scr.label_list[i].name, filepath);
- if (retval) *retval = EXIT_FAILURE;
+ ShowWarning("npc_parse_duplicate: duplicate event %s::%s in file '%s'.\n",
+ nd->exname, nd->u.scr.label_list[i].name, nd->path);
+ retval = false;
}
npc->timerevent_export(nd, i);
}
nd->u.scr.timerid = INVALID_TIMER;
- if( options&NPO_ONINIT ) {
+ if (options&NPO_ONINIT) {
+ // From npc_parse_script
char evname[EVENT_NAME_LENGTH];
struct event_data *ev;
snprintf(evname, ARRAYLENGTH(evname), "%s::OnInit", nd->exname);
- if( ( ev = (struct event_data*)strdb_get(npc->ev_db, evname) ) ) {
-
+ if ((ev = (struct event_data*)strdb_get(npc->ev_db, evname)) != NULL) {
//Execute OnInit
script->run_npc(nd->u.scr.script,ev->pos,0,nd->bl.id);
-
}
}
+ return retval;
+}
- return end;
+/**
+ * Duplicates a shop or cash shop (@see npc_duplicate_sub)
+ */
+bool npc_duplicate_shop_sub(struct npc_data *nd, const struct npc_data *snd, int xs, int ys, int options)
+{
+ ++npc_shop;
+ nd->u.shop.shop_item = snd->u.shop.shop_item;
+ nd->u.shop.count = snd->u.shop.count;
+
+ //add the npc to its location
+ npc->add_to_location(nd);
+
+ return true;
+}
+
+/**
+ * Duplicates a warp (@see npc_duplicate_sub)
+ */
+bool npc_duplicate_warp_sub(struct npc_data *nd, const struct npc_data *snd, int xs, int ys, int options)
+{
+ ++npc_warp;
+ nd->u.warp.xs = xs;
+ nd->u.warp.ys = ys;
+ nd->u.warp.mapindex = snd->u.warp.mapindex;
+ nd->u.warp.x = snd->u.warp.x;
+ nd->u.warp.y = snd->u.warp.y;
+
+ //Add the npc to its location
+ npc->add_to_location(nd);
+
+ return true;
+}
+
+/**
+ * Duplicates a warp, shop, cashshop or script.
+ *
+ * @param nd An already initialized NPC data. Expects bl->m, bl->x, bl->y,
+ * name, exname, path, dir, class_, speed, subtype to be already
+ * filled.
+ * @param snd The source NPC to duplicate.
+ * @param class_ The npc view class.
+ * @param dir The facing direction.
+ * @param xs The x-span, if any.
+ * @param ys The y-span, if any.
+ * @param options The NPC options.
+ * @retval false if there were any issues while creating and validating the NPC.
+ */
+bool npc_duplicate_sub(struct npc_data *nd, const struct npc_data *snd, int xs, int ys, int options)
+{
+ nd->src_id = snd->bl.id;
+ switch (nd->subtype) {
+ case SCRIPT:
+ return npc->duplicate_script_sub(nd, snd, xs, ys, options);
+
+ case SHOP:
+ case CASHSHOP:
+ return npc->duplicate_shop_sub(nd, snd, xs, ys, options);
+
+ case WARP:
+ return npc->duplicate_warp_sub(nd, snd, xs, ys, options);
+
+ case TOMB:
+ return false;
+ }
+ return false;
}
/// Duplicate a warp, shop, cashshop or script. [Orcao]
@@ -3032,12 +3160,10 @@ const char* npc_parse_script(char* w1, char* w2, char* w3, char* w4, const char*
const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath, int options, int *retval) {
int x, y, dir, m, xs = -1, ys = -1;
char srcname[128];
- int i;
- const char* end;
+ const char *end;
size_t length;
- int src_id;
- int type;
+ int class_;
struct npc_data* nd;
struct npc_data* dnd;
@@ -3059,18 +3185,16 @@ const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const ch
if (retval) *retval = EXIT_FAILURE;
return end;// next line, try to continue
}
- src_id = dnd->bl.id;
- type = dnd->subtype;
// get placement
- if ((type==SHOP || type==CASHSHOP || type==SCRIPT) && strcmp(w1, "-") == 0) {
+ if ((dnd->subtype==SHOP || dnd->subtype==CASHSHOP || dnd->subtype==SCRIPT) && strcmp(w1, "-") == 0) {
// floating shop/chashshop/script
x = y = dir = 0;
m = -1;
} else {
char mapname[32];
int fields = sscanf(w1, "%31[^,],%d,%d,%d", mapname, &x, &y, &dir);
- if (type == WARP && fields == 3) {
+ if (dnd->subtype == WARP && fields == 3) {
// <map name>,<x>,<y>
dir = 0;
} else if (fields != 4) {
@@ -3093,107 +3217,40 @@ const char* npc_parse_duplicate(char* w1, char* w2, char* w3, char* w4, const ch
return end;//try next
}
- if( type == WARP && sscanf(w4, "%d,%d", &xs, &ys) == 2 );// <spanx>,<spany>
- else if( type == SCRIPT && sscanf(w4, "%*[^,],%d,%d", &xs, &ys) == 2);// <sprite id>,<triggerX>,<triggerY>
- else if( type == WARP ) {
+ if (dnd->subtype == WARP && sscanf(w4, "%d,%d", &xs, &ys) == 2) { // <spanx>,<spany>
+ ;
+ } else if (dnd->subtype == SCRIPT && sscanf(w4, "%*[^,],%d,%d", &xs, &ys) == 2) { // <sprite id>,<triggerX>,<triggerY>
+ ;
+ } else if (dnd->subtype == WARP) {
ShowError("npc_parse_duplicate: Invalid span format for duplicate warp in file '%s', line '%d'. Skipping line...\n * w1=%s\n * w2=%s\n * w3=%s\n * w4=%s\n", filepath, strline(buffer,start-buffer), w1, w2, w3, w4);
if (retval) *retval = EXIT_FAILURE;
return end;// next line, try to continue
}
- nd = npc->create_npc(m, x, y);
+ class_ = m == -1 ? -1 : npc->parseview(w4, start, buffer, filepath);
+ nd = npc->create_npc(dnd->subtype, m, x, y, dir, class_);
npc->parsename(nd, w3, start, buffer, filepath);
- nd->class_ = m == -1 ? -1 : npc->parseview(w4, start, buffer, filepath);
- nd->speed = 200;
- nd->src_id = src_id;
- nd->bl.type = BL_NPC;
- nd->subtype = (enum npc_subtype)type;
- switch( type ) {
- case SCRIPT:
- ++npc_script;
- nd->u.scr.xs = xs;
- nd->u.scr.ys = ys;
- nd->u.scr.script = dnd->u.scr.script;
- nd->u.scr.label_list = dnd->u.scr.label_list;
- nd->u.scr.label_list_num = dnd->u.scr.label_list_num;
- nd->u.scr.shop = dnd->u.scr.shop;
- nd->u.scr.trader = dnd->u.scr.trader;
- break;
-
- case SHOP:
- case CASHSHOP:
- ++npc_shop;
- nd->u.shop.shop_item = dnd->u.shop.shop_item;
- nd->u.shop.count = dnd->u.shop.count;
- break;
-
- case WARP:
- ++npc_warp;
- if( !battle_config.warp_point_debug )
- nd->class_ = WARP_CLASS;
- else
- nd->class_ = WARP_DEBUG_CLASS;
- nd->u.warp.xs = xs;
- nd->u.warp.ys = ys;
- nd->u.warp.mapindex = dnd->u.warp.mapindex;
- nd->u.warp.x = dnd->u.warp.x;
- nd->u.warp.y = dnd->u.warp.y;
- break;
- }
-
- //Add the npc to its location
- if( m >= 0 ) {
- map->addnpc(m, nd);
- nd->ud = &npc->base_ud;
- nd->dir = dir;
- npc->setcells(nd);
- map->addblock(&nd->bl);
- if( nd->class_ >= 0 ) {
- status->set_viewdata(&nd->bl, nd->class_);
- if( map->list[nd->bl.m].users )
- clif->spawn(&nd->bl);
- }
- } else {
- // we skip map->addnpc, but still add it to the list of ID's
- map->addiddb(&nd->bl);
- }
- strdb_put(npc->name_db, nd->exname, nd);
-
- if( type != SCRIPT )
- return end;
-
- //-----------------------------------------
- // Loop through labels to export them as necessary
- for (i = 0; i < nd->u.scr.label_list_num; i++) {
- if (npc->event_export(nd, i)) {
- ShowWarning("npc_parse_duplicate: duplicate event %s::%s in file '%s'.\n",
- nd->exname, nd->u.scr.label_list[i].name, filepath);
- if (retval) *retval = EXIT_FAILURE;
- }
- npc->timerevent_export(nd, i);
+ nd->path = npc->retainpathreference(filepath);
+ if (!npc->duplicate_sub(nd, dnd, xs, ys, options)) {
+ if (retval) *retval = EXIT_FAILURE;
}
- nd->u.scr.timerid = INVALID_TIMER;
-
- if (options&NPO_ONINIT) {
- // From npc_parse_script
- char evname[EVENT_NAME_LENGTH];
- struct event_data *ev;
-
- snprintf(evname, ARRAYLENGTH(evname), "%s::OnInit", nd->exname);
-
- if( ( ev = (struct event_data*)strdb_get(npc->ev_db, evname) ) ) {
-
- //Execute OnInit
- script->run_npc(nd->u.scr.script,ev->pos,0,nd->bl.id);
-
- }
- }
return end;
}
-int npc_duplicate4instance(struct npc_data *snd, int16 m) {
+/**
+ * Duplicates an NPC for instancing purposes.
+ *
+ * @param snd The NPC to duplicate.
+ * @param m The instanced map ID.
+ * @return success state.
+ * @retval 0 in case of successful creation.
+ */
+int npc_duplicate4instance(struct npc_data *snd, int16 m)
+{
char newname[NAME_LENGTH];
+ int dm = -1, im = -1, xs = -1, ys = -1;
+ struct npc_data *nd = NULL;
if( m == -1 || map->list[m].instance_id == -1 )
return 1;
@@ -3204,50 +3261,35 @@ int npc_duplicate4instance(struct npc_data *snd, int16 m) {
return 1;
}
- if( snd->subtype == WARP ) { // Adjust destination, if instanced
- struct npc_data *wnd = NULL; // New NPC
- int dm = map->mapindex2mapid(snd->u.warp.mapindex), im;
- if( dm < 0 ) return 1;
-
- if( ( im = instance->mapid2imapid(dm, map->list[m].instance_id) ) == -1 ) {
+ switch (snd->subtype) {
+ case SCRIPT:
+ xs = snd->u.scr.xs;
+ ys = snd->u.scr.ys;
+ break;
+ case WARP:
+ xs = snd->u.warp.xs;
+ ys = snd->u.warp.ys;
+ // Adjust destination, if instanced
+ if ((dm = map->mapindex2mapid(snd->u.warp.mapindex)) < 0) {
+ return 1;
+ }
+ if ((im = instance->mapid2imapid(dm, map->list[m].instance_id)) == -1) {
ShowError("npc_duplicate4instance: warp (%s) leading to instanced map (%s), but instance map is not attached to current instance.\n", map->list[dm].name, snd->exname);
return 1;
}
+ break;
+ default: // Other types have no xs/ys
+ break;
+ }
- wnd = npc->create_npc(m, snd->bl.x, snd->bl.y);
- map->addnpc(m, wnd);
- safestrncpy(wnd->name, "", ARRAYLENGTH(wnd->name));
- safestrncpy(wnd->exname, newname, ARRAYLENGTH(wnd->exname));
- wnd->class_ = WARP_CLASS;
- wnd->speed = 200;
- wnd->u.warp.mapindex = map_id2index(im);
- wnd->u.warp.x = snd->u.warp.x;
- wnd->u.warp.y = snd->u.warp.y;
- wnd->u.warp.xs = snd->u.warp.xs;
- wnd->u.warp.ys = snd->u.warp.ys;
- wnd->bl.type = BL_NPC;
- wnd->subtype = WARP;
- npc->setcells(wnd);
- map->addblock(&wnd->bl);
- status->set_viewdata(&wnd->bl, wnd->class_);
- wnd->ud = &npc->base_ud;
- if( map->list[wnd->bl.m].users )
- clif->spawn(&wnd->bl);
- strdb_put(npc->name_db, wnd->exname, wnd);
- } else {
- static char w1[50], w2[50], w3[50], w4[50];
- const char* stat_buf = "- call from instancing subsystem -\n";
-
- snprintf(w1, sizeof(w1), "%s,%d,%d,%d", map->list[m].name, snd->bl.x, snd->bl.y, snd->dir);
- snprintf(w2, sizeof(w2), "duplicate(%s)", snd->exname);
- snprintf(w3, sizeof(w3), "%s::%s", snd->name, newname);
-
- if( snd->u.scr.xs >= 0 && snd->u.scr.ys >= 0 )
- snprintf(w4, sizeof(w4), "%d,%d,%d", snd->class_, snd->u.scr.xs, snd->u.scr.ys); // Touch Area
- else
- snprintf(w4, sizeof(w4), "%d", snd->class_);
-
- npc->parse_duplicate(w1, w2, w3, w4, stat_buf, stat_buf, "INSTANCING", NPO_NONE, NULL);
+ nd = npc->create_npc(snd->subtype, m, snd->bl.x, snd->bl.y, snd->dir, snd->class_);
+ safestrncpy(nd->name, snd->name, sizeof(nd->name));
+ safestrncpy(nd->exname, newname, sizeof(nd->exname));
+ nd->path = npc->retainpathreference("INSTANCING");
+ npc->duplicate_sub(nd, snd, xs, ys, NPO_NONE);
+ if (nd->subtype == WARP) {
+ // Adjust destination, if instanced
+ nd->u.warp.mapindex = map_id2index(im);
}
return 0;
@@ -4735,6 +4777,8 @@ void npc_defaults(void) {
npc->clearsrcfile = npc_clearsrcfile;
npc->addsrcfile = npc_addsrcfile;
npc->delsrcfile = npc_delsrcfile;
+ npc->retainpathreference = npc_retainpathreference;
+ npc->releasepathreference = npc_releasepathreference;
npc->parsename = npc_parsename;
npc->parseview = npc_parseview;
npc->viewisid = npc_viewisid;
@@ -4745,6 +4789,11 @@ void npc_defaults(void) {
npc->convertlabel_db = npc_convertlabel_db;
npc->skip_script = npc_skip_script;
npc->parse_script = npc_parse_script;
+ npc->add_to_location = npc_add_to_location;
+ npc->duplicate_script_sub = npc_duplicate_script_sub;
+ npc->duplicate_shop_sub = npc_duplicate_shop_sub;
+ npc->duplicate_warp_sub = npc_duplicate_warp_sub;
+ npc->duplicate_sub = npc_duplicate_sub;
npc->parse_duplicate = npc_parse_duplicate;
npc->duplicate4instance = npc_duplicate4instance;
npc->setcells = npc_setcells;
diff --git a/src/map/npc.h b/src/map/npc.h
index e12f942ae..e7fc16a21 100644
--- a/src/map/npc.h
+++ b/src/map/npc.h
@@ -70,7 +70,7 @@ struct npc_data {
unsigned short stat_point;
struct npc_parse *chatdb;
- char* path;/* path dir */
+ const char *path; ///< Source path reference
enum npc_subtype subtype;
int src_id;
union {
@@ -112,6 +112,7 @@ enum actor_classes {
FAKE_NPC = -1,
WARP_CLASS = 45,
HIDDEN_WARP_CLASS = 139,
+ MOB_TOMB = 565,
WARP_DEBUG_CLASS = 722,
FLAG_CLASS = 722,
INVISIBLE_CLASS = 32767,
@@ -121,7 +122,7 @@ enum actor_classes {
#define MAX_NPC_CLASS 1000
// New NPC range
#define MAX_NPC_CLASS2_START 10001
-#define MAX_NPC_CLASS2_END 10110
+#define MAX_NPC_CLASS2_END 10174
//Script NPC events.
enum npce_event {
@@ -226,10 +227,12 @@ struct npc_interface {
void (*clearsrcfile) (void);
void (*addsrcfile) (const char *name);
void (*delsrcfile) (const char *name);
+ const char *(*retainpathreference) (const char *filepath);
+ void (*releasepathreference) (const char *filepath);
void (*parsename) (struct npc_data *nd, const char *name, const char *start, const char *buffer, const char *filepath);
int (*parseview) (const char *w4, const char *start, const char *buffer, const char *filepath);
bool (*viewisid) (const char *viewid);
- struct npc_data* (*create_npc) (int m, int x, int y);
+ struct npc_data *(*create_npc) (enum npc_subtype subtype, int m, int x, int y, uint8 dir, int16 class_);
struct npc_data* (*add_warp) (char *name, short from_mapid, short from_x, short from_y, short xs, short ys, unsigned short to_mapindex, short to_x, short to_y);
const char* (*parse_warp) (char *w1, char *w2, char *w3, char *w4, const char *start, const char *buffer, const char *filepath, int *retval);
const char* (*parse_shop) (char *w1, char *w2, char *w3, char *w4, const char *start, const char *buffer, const char *filepath, int *retval);
@@ -237,6 +240,11 @@ struct npc_interface {
void (*convertlabel_db) (struct npc_label_list *label_list, const char *filepath);
const char* (*skip_script) (const char *start, const char *buffer, const char *filepath, int *retval);
const char* (*parse_script) (char *w1, char *w2, char *w3, char *w4, const char *start, const char *buffer, const char *filepath, int options, int *retval);
+ void (*add_to_location) (struct npc_data *nd);
+ bool (*duplicate_script_sub) (struct npc_data *nd, const struct npc_data *snd, int xs, int ys, int options);
+ bool (*duplicate_shop_sub) (struct npc_data *nd, const struct npc_data *snd, int xs, int ys, int options);
+ bool (*duplicate_warp_sub) (struct npc_data *nd, const struct npc_data *snd, int xs, int ys, int options);
+ bool (*duplicate_sub) (struct npc_data *nd, const struct npc_data *snd, int xs, int ys, int options);
const char* (*parse_duplicate) (char* w1, char* w2, char* w3, char* w4, const char* start, const char* buffer, const char* filepath, int options, int *retval);
int (*duplicate4instance) (struct npc_data *snd, int16 m);
void (*setcells) (struct npc_data *nd);
diff --git a/src/map/pc.c b/src/map/pc.c
index 4d4f41521..43adf331b 100644
--- a/src/map/pc.c
+++ b/src/map/pc.c
@@ -1126,8 +1126,7 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim
sd->bg_queue.client_has_bg_data = 0;
sd->bg_queue.type = 0;
- sd->queues = NULL;
- sd->queues_count = 0;
+ VECTOR_INIT(sd->script_queues);
sd->state.dialog = 0;
@@ -2186,6 +2185,7 @@ int pc_bonus_subele(struct map_session_data* sd, unsigned char ele, short rate,
int pc_bonus(struct map_session_data *sd,int type,int val) {
struct status_data *bst;
int bonus;
+ int i;
nullpo_ret(sd);
bst = &sd->base_status;
@@ -2436,20 +2436,48 @@ int pc_bonus(struct map_session_data *sd,int type,int val) {
sd->matk_rate += val;
break;
case SP_IGNORE_DEF_ELE:
- if(val >= ELE_MAX) {
+ if( (val >= ELE_MAX && val != ELE_ALL) || (val < ELE_NEUTRAL) ) {
ShowError("pc_bonus: SP_IGNORE_DEF_ELE: Invalid element %d\n", val);
break;
}
- if(!sd->state.lr_flag)
- sd->right_weapon.ignore_def_ele |= 1<<val;
- else if(sd->state.lr_flag == 1)
- sd->left_weapon.ignore_def_ele |= 1<<val;
+ if ( val == ELE_ALL ) {
+ for ( i = ELE_NEUTRAL; i < ELE_MAX; i++ ) {
+ if(!sd->state.lr_flag)
+ sd->right_weapon.ignore_def_ele |= 1<<i;
+ else if(sd->state.lr_flag == 1)
+ sd->left_weapon.ignore_def_ele |= 1<<i;
+ }
+ } else {
+ if(!sd->state.lr_flag)
+ sd->right_weapon.ignore_def_ele |= 1<<val;
+ else if(sd->state.lr_flag == 1)
+ sd->left_weapon.ignore_def_ele |= 1<<val;
+ }
break;
case SP_IGNORE_DEF_RACE:
- if(!sd->state.lr_flag)
- sd->right_weapon.ignore_def_race |= 1<<val;
- else if(sd->state.lr_flag == 1)
- sd->left_weapon.ignore_def_race |= 1<<val;
+ if (val == RC_MAX || (val > RC_NONDEMIPLAYER && val != RC_ALL) || val < RC_FORMLESS ) {
+ ShowWarning("pc_bonus: SP_IGNORE_DEF_RACE: Invalid Race(%d)\n",val);
+ break;
+ }
+ if ( val >= RC_MAX ) {
+ for ( i = RC_FORMLESS; i < RC_BOSS; i++ ) {
+ if ( (val == RC_NONPLAYER && i == RC_PLAYER) ||
+ (val == RC_NONDEMIHUMAN && i == RC_DEMIHUMAN) ||
+ (val == RC_DEMIPLAYER && (i != RC_PLAYER && i != RC_DEMIHUMAN)) ||
+ (val == RC_NONDEMIPLAYER && (i == RC_PLAYER || i == RC_DEMIHUMAN))
+ )
+ continue;
+ if(!sd->state.lr_flag)
+ sd->right_weapon.ignore_def_race |= 1<<i;
+ else if(sd->state.lr_flag == 1)
+ sd->left_weapon.ignore_def_race |= 1<<i;
+ }
+ } else {
+ if(!sd->state.lr_flag)
+ sd->right_weapon.ignore_def_race |= 1<<val;
+ else if(sd->state.lr_flag == 1)
+ sd->left_weapon.ignore_def_race |= 1<<val;
+ }
break;
case SP_ATK_RATE:
if(sd->state.lr_flag != 2)
@@ -2470,16 +2498,40 @@ int pc_bonus(struct map_session_data *sd,int type,int val) {
}
break;
case SP_IGNORE_MDEF_ELE:
- if(val >= ELE_MAX) {
+ if( (val >= ELE_MAX && val != ELE_ALL) || (val < ELE_NEUTRAL) ) {
ShowError("pc_bonus: SP_IGNORE_MDEF_ELE: Invalid element %d\n", val);
break;
}
- if(sd->state.lr_flag != 2)
- sd->bonus.ignore_mdef_ele |= 1<<val;
+ if (sd->state.lr_flag != 2) {
+ if ( val == ELE_ALL ) {
+ for ( i = ELE_NEUTRAL; i < ELE_MAX; i++ ) {
+ sd->bonus.ignore_mdef_ele |= 1<<i;
+ }
+ } else {
+ sd->bonus.ignore_mdef_ele |= 1<<val;
+ }
+ }
break;
case SP_IGNORE_MDEF_RACE:
- if(sd->state.lr_flag != 2)
- sd->bonus.ignore_mdef_race |= 1<<val;
+ if (val == RC_MAX || (val > RC_NONDEMIPLAYER && val != RC_ALL) || val < RC_FORMLESS ) {
+ ShowWarning("pc_bonus: SP_IGNORE_MDEF_RACE: Invalid Race(%d)\n",val);
+ break;
+ }
+ if(sd->state.lr_flag != 2) {
+ if ( val >= RC_MAX ) {
+ for ( i = RC_FORMLESS; i < RC_BOSS; i++ ) {
+ if ( (val == RC_NONPLAYER && i == RC_PLAYER) ||
+ (val == RC_NONDEMIHUMAN && i == RC_DEMIHUMAN) ||
+ (val == RC_DEMIPLAYER && (i != RC_PLAYER && i != RC_DEMIHUMAN)) ||
+ (val == RC_NONDEMIPLAYER && (i == RC_PLAYER || i == RC_DEMIHUMAN))
+ )
+ continue;
+ sd->bonus.ignore_mdef_race |= 1<<i;
+ }
+ } else {
+ sd->bonus.ignore_mdef_race |= 1<<val;
+ }
+ }
break;
case SP_PERFECT_HIT_RATE:
if(sd->state.lr_flag != 2 && sd->bonus.perfect_hit < val)
@@ -2494,24 +2546,48 @@ int pc_bonus(struct map_session_data *sd,int type,int val) {
sd->critical_rate+=val;
break;
case SP_DEF_RATIO_ATK_ELE:
- if(val >= ELE_MAX) {
+ if( (val >= ELE_MAX && val != ELE_ALL) || (val < ELE_NEUTRAL) ) {
ShowError("pc_bonus: SP_DEF_RATIO_ATK_ELE: Invalid element %d\n", val);
break;
}
- if(!sd->state.lr_flag)
- sd->right_weapon.def_ratio_atk_ele |= 1<<val;
- else if(sd->state.lr_flag == 1)
- sd->left_weapon.def_ratio_atk_ele |= 1<<val;
+ if ( val == ELE_ALL ) {
+ for ( i = ELE_NEUTRAL; i < ELE_MAX; i++ ) {
+ if(!sd->state.lr_flag)
+ sd->right_weapon.def_ratio_atk_ele |= 1<<i;
+ else if(sd->state.lr_flag == 1)
+ sd->left_weapon.def_ratio_atk_ele |= 1<<i;
+ }
+ } else {
+ if(!sd->state.lr_flag)
+ sd->right_weapon.def_ratio_atk_ele |= 1<<val;
+ else if(sd->state.lr_flag == 1)
+ sd->left_weapon.def_ratio_atk_ele |= 1<<val;
+ }
break;
case SP_DEF_RATIO_ATK_RACE:
- if(val >= RC_MAX) {
- ShowError("pc_bonus: SP_DEF_RATIO_ATK_RACE: Invalid race %d\n", val);
+ if (val == RC_MAX || (val > RC_NONDEMIPLAYER && val != RC_ALL) || val < RC_FORMLESS ) {
+ ShowWarning("pc_bonus: SP_DEF_RATIO_ATK_RACE: Invalid Race(%d)\n",val);
break;
}
- if(!sd->state.lr_flag)
- sd->right_weapon.def_ratio_atk_race |= 1<<val;
- else if(sd->state.lr_flag == 1)
- sd->left_weapon.def_ratio_atk_race |= 1<<val;
+ if ( val >= RC_MAX ) {
+ for ( i = RC_FORMLESS; i < RC_BOSS; i++ ) {
+ if ( (val == RC_NONPLAYER && i == RC_PLAYER) ||
+ (val == RC_NONDEMIHUMAN && i == RC_DEMIHUMAN) ||
+ (val == RC_DEMIPLAYER && (i != RC_PLAYER && i != RC_DEMIHUMAN)) ||
+ (val == RC_NONDEMIPLAYER && (i == RC_PLAYER || i == RC_DEMIHUMAN))
+ )
+ continue;
+ if(!sd->state.lr_flag)
+ sd->right_weapon.def_ratio_atk_race |= 1<<i;
+ else if(sd->state.lr_flag == 1)
+ sd->left_weapon.def_ratio_atk_race |= 1<<i;
+ }
+ } else {
+ if(!sd->state.lr_flag)
+ sd->right_weapon.def_ratio_atk_race |= 1<<val;
+ else if(sd->state.lr_flag == 1)
+ sd->left_weapon.def_ratio_atk_race |= 1<<val;
+ }
break;
case SP_HIT_RATE:
if(sd->state.lr_flag != 2)
@@ -5449,11 +5525,11 @@ int pc_setpos(struct map_session_data* sd, unsigned short map_index, int x, int
int i;
sd->state.pmap = sd->bl.m;
- for( i = 0; i < sd->queues_count; i++ ) {
- struct hQueue *queue;
- if( (queue = script->queue(sd->queues[i])) && queue->onMapChange[0] != '\0' ) {
- pc->setregstr(sd, script->add_str("QMapChangeTo"), map->list[m].name);
- npc->event(sd, queue->onMapChange, 0);
+ for (i = 0; i < VECTOR_LENGTH(sd->script_queues); i++) {
+ struct script_queue *queue = script->queue(VECTOR_INDEX(sd->script_queues, i));
+ if (queue && queue->event_mapchange[0] != '\0') {
+ pc->setregstr(sd, script->add_str("@Queue_Destination_Map$"), map->list[m].name);
+ npc->event(sd, queue->event_mapchange, 0);
}
}
@@ -7557,10 +7633,10 @@ int pc_dead(struct map_session_data *sd,struct block_list *src) {
npc->event(sd, bgd->die_event, 0);
}
- for( i = 0; i < sd->queues_count; i++ ) {
- struct hQueue *queue;
- if( (queue = script->queue(sd->queues[i])) && queue->onDeath[0] != '\0' )
- npc->event(sd, queue->onDeath, 0);
+ for (i = 0; i < VECTOR_LENGTH(sd->script_queues); i++ ) {
+ struct script_queue *queue = script->queue(VECTOR_INDEX(sd->script_queues, i));
+ if (queue && queue->event_death[0] != '\0')
+ npc->event(sd, queue->event_death, 0);
}
npc->script_event(sd,NPCE_DIE);
diff --git a/src/map/pc.h b/src/map/pc.h
index 2c8b24acf..62571f12a 100644
--- a/src/map/pc.h
+++ b/src/map/pc.h
@@ -531,8 +531,7 @@ END_ZEROED_BLOCK;
enum bg_queue_types type;
} bg_queue;
- int *queues;
- unsigned int queues_count;
+ VECTOR_DECL(int) script_queues;
/* Made Possible Thanks to Yommy~! */
unsigned int cryptKey; ///< Packet obfuscation key to be used for the next received packet
diff --git a/src/map/script.c b/src/map/script.c
index 54d8d338d..cfc7ed052 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -4627,22 +4627,16 @@ void do_final_script(void) {
aFree(script->buildin);
- if( script->hqs ) {
- for( i = 0; i < script->hqs; i++ ) {
- if( script->hq[i].item != NULL )
- aFree(script->hq[i].item);
- }
+ for (i = 0; i < VECTOR_LENGTH(script->hq); i++) {
+ VECTOR_CLEAR(VECTOR_INDEX(script->hq, i).entries);
}
- if (script->hqis && script->hqi) {
- for( i = 0; i < script->hqis; i++ ) {
- if( script->hqi[i].item != NULL )
- aFree(script->hqi[i].item);
- }
+ VECTOR_CLEAR(script->hq);
+
+ for (i = 0; i < VECTOR_LENGTH(script->hqi); i++) {
+ VECTOR_CLEAR(VECTOR_INDEX(script->hqi, i).entries);
}
- if( script->hq != NULL )
- aFree(script->hq);
- if( script->hqi != NULL )
- aFree(script->hqi);
+ VECTOR_CLEAR(script->hqi);
+
if( script->word_buf != NULL )
aFree(script->word_buf);
@@ -5020,6 +5014,9 @@ void do_init_script(bool minimal) {
ers_chunk_size(script->st_ers, 10);
ers_chunk_size(script->stack_ers, 10);
+ VECTOR_INIT(script->hq);
+ VECTOR_INIT(script->hqi);
+
script->parse_builtin();
script->read_constdb();
script->hardcoded_constants();
@@ -18789,329 +18786,434 @@ BUILDIN(montransform) {
return true;
}
-struct hQueue *script_hqueue_get(int idx) {
- if( idx < 0 || idx >= script->hqs || script->hq[idx].size == -1 )
+/**
+ * Returns the queue with he given index, if it exists.
+ *
+ * @param idx The queue index.
+ *
+ * @return The queue, or NULL if it doesn't exist.
+ */
+struct script_queue *script_hqueue_get(int idx)
+{
+ if (idx < 0 || idx >= VECTOR_LENGTH(script->hq) || !VECTOR_INDEX(script->hq, idx).valid)
return NULL;
- return &script->hq[idx];
+ return &VECTOR_INDEX(script->hq, idx);
}
-int script_hqueue_create(void) {
- int idx = script->hqs;
+
+/**
+ * Creates a new queue.
+ *
+ * @return The index of the created queue.
+ */
+int script_hqueue_create(void)
+{
+ struct script_queue *queue = NULL;
int i;
- for(i = 0; i < script->hqs; i++) {
- if( script->hq[i].size == -1 ) {
- break;
- }
+ ARR_FIND(0, VECTOR_LENGTH(script->hq), i, !VECTOR_INDEX(script->hq, i).valid);
+
+ if (i == VECTOR_LENGTH(script->hq)) {
+ VECTOR_ENSURE(script->hq, 1, 1);
+ VECTOR_PUSHZEROED(script->hq);
}
+ queue = &VECTOR_INDEX(script->hq, i);
- if( i == script->hqs ) {
- RECREATE(script->hq, struct hQueue, ++script->hqs);
- script->hq[ idx ].item = NULL;
- } else
- idx = i;
-
- script->hq[ idx ].id = idx;
- script->hq[ idx ].size = 0;
- script->hq[ idx ].items = 0;
- script->hq[ idx ].onDeath[0] = '\0';
- script->hq[ idx ].onLogOut[0] = '\0';
- script->hq[ idx ].onMapChange[0] = '\0';
- return idx;
-}
-/* set .@id,queue(); */
-/* creates queue, returns created queue id */
-BUILDIN(queue) {
+ memset(&VECTOR_INDEX(script->hq, i), 0, sizeof(VECTOR_INDEX(script->hq, i)));
+
+ queue->id = i;
+ queue->valid = true;
+ return i;
+}
+
+/**
+ * Script command queue: Creates a queue and returns its id.
+ *
+ * @code{.herc}
+ * .@queue_id = queue();
+ * @endcode
+ */
+BUILDIN(queue)
+{
script_pushint(st,script->queue_create());
return true;
}
-/* set .@length,queuesize(.@queue_id); */
-/* returns queue length */
-BUILDIN(queuesize) {
+
+/**
+ * Script command queuesize: Returns the length of the given queue.
+ *
+ * Returns 0 on error.
+ *
+ * \code{.herc}
+ * .@size = queuesize(<queue id>);
+ * \endcode
+ */
+BUILDIN(queuesize)
+{
int idx = script_getnum(st, 2);
- if( idx < 0 || idx >= script->hqs || script->hq[idx].size == -1 ) {
+ if (idx < 0 || idx >= VECTOR_LENGTH(script->hq) || !VECTOR_INDEX(script->hq, idx).valid) {
ShowWarning("buildin_queuesize: unknown queue id %d\n",idx);
script_pushint(st, 0);
- } else {
- script_pushint(st, script->hq[ idx ].items);
+ return true;
}
+ script_pushint(st, VECTOR_LENGTH(VECTOR_INDEX(script->hq, idx).entries));
return true;
}
+
+/**
+ * Adds an entry to the given queue.
+ *
+ * @param idx The queue index.
+ * @param var The entry to add.
+ * @retval false if the queue is invalid or the entry is already in the queue.
+ * @retval true in case of success.
+ */
bool script_hqueue_add(int idx, int var)
{
- if( idx < 0 || idx >= script->hqs || script->hq[idx].size == -1 ) {
- ShowWarning("script_hqueue_add: unknown queue id %d\n",idx);
- return true;
- } else {
- int i;
- for (i = 0; i < script->hq[idx].size; i++) {
- if (script->hq[idx].item[i] == var) {
- return true;
- }
- }
-
- if (i == script->hq[idx].size) {
- struct map_session_data *sd;
+ int i;
+ struct map_session_data *sd = NULL;
+ struct script_queue *queue = NULL;
- for (i = 0; i < script->hq[idx].size; i++) {
- if( script->hq[idx].item[i] == 0 ) {
- break;
- }
- }
+ if (idx < 0 || idx >= VECTOR_LENGTH(script->hq) || !VECTOR_INDEX(script->hq, idx).valid) {
+ ShowWarning("script_hqueue_add: unknown queue id %d\n",idx);
+ return false;
+ }
- if (i == script->hq[idx].size)
- RECREATE(script->hq[idx].item, int, ++script->hq[idx].size);
+ queue = &VECTOR_INDEX(script->hq, idx);
- script->hq[idx].item[i] = var;
- script->hq[idx].items++;
- if (var >= START_ACCOUNT_NUM && (sd = map->id2sd(var)) != NULL) {
- for (i = 0; i < sd->queues_count; i++) {
- if (sd->queues[i] == -1) {
- break;
- }
- }
+ ARR_FIND(0, VECTOR_LENGTH(queue->entries), i, VECTOR_INDEX(queue->entries, i) == var);
+ if (i != VECTOR_LENGTH(queue->entries)) {
+ return false; // Entry already exists
+ }
- if (i == sd->queues_count)
- RECREATE(sd->queues, int, ++sd->queues_count);
+ VECTOR_ENSURE(queue->entries, 1, 1);
+ VECTOR_PUSH(queue->entries, var);
- sd->queues[i] = idx;
- }
-
- }
+ if (var >= START_ACCOUNT_NUM && (sd = map->id2sd(var)) != NULL) {
+ VECTOR_ENSURE(sd->script_queues, 1, 1);
+ VECTOR_PUSH(sd->script_queues, idx);
}
- return false;
+ return true;
}
-/* queueadd(.@queue_id,.@var_id); */
-/* adds a new entry to the queue, returns 1 if already in queue, 0 otherwise */
-BUILDIN(queueadd) {
+
+/**
+ * Script command queueadd: Adds a new entry to the given queue.
+ *
+ * Returns 0 (false) if already in queue or in case of error, 1 (true)
+ * otherwise.
+ *
+ * @code{.herc}
+ * .@size = queuesize(.@queue_id);
+ * @endcode
+ */
+BUILDIN(queueadd)
+{
int idx = script_getnum(st, 2);
int var = script_getnum(st, 3);
- script_pushint(st,script->queue_add(idx,var)?1:0);
+ if (script->queue_add(idx, var))
+ script_pushint(st, 1);
+ else
+ script_pushint(st, 0);
return true;
}
-bool script_hqueue_remove(int idx, int var) {
- if( idx < 0 || idx >= script->hqs || script->hq[idx].size == -1 ) {
- ShowWarning("script_hqueue_remove: unknown queue id %d (used with var %d)\n",idx,var);
- return true;
- } else {
- int i;
- for(i = 0; i < script->hq[idx].size; i++) {
- if( script->hq[idx].item[i] == var ) {
- break;
- }
- }
+/**
+ * Removes an entry from the given queue.
+ *
+ * @param idx The queue index.
+ * @param var The entry to remove.
+ * @retval true if the entry was removed.
+ * @retval false if the entry wasn't in queue.
+ */
+bool script_hqueue_remove(int idx, int var)
+{
+ int i;
+ struct map_session_data *sd = NULL;
+ struct script_queue *queue = NULL;
- if( i != script->hq[idx].size ) {
- struct map_session_data *sd;
+ if (idx < 0 || idx >= VECTOR_LENGTH(script->hq) || !VECTOR_INDEX(script->hq, idx).valid) {
+ ShowWarning("script_hqueue_remove: unknown queue id %d (used with var %d)\n",idx,var);
+ return false;
+ }
- script->hq[idx].item[i] = -1;
- script->hq[idx].items--;
+ queue = &VECTOR_INDEX(script->hq, idx);
- if (var >= START_ACCOUNT_NUM && (sd = map->id2sd(var)) != NULL) {
- for(i = 0; i < sd->queues_count; i++) {
- if( sd->queues[i] == idx ) {
- break;
- }
- }
+ ARR_FIND(0, VECTOR_LENGTH(queue->entries), i, VECTOR_INDEX(queue->entries, i) == var);
+ if (i == VECTOR_LENGTH(queue->entries))
+ return false;
- if( i != sd->queues_count )
- sd->queues[i] = -1;
- }
+ VECTOR_ERASE(queue->entries, i);
- }
+ if (var >= START_ACCOUNT_NUM && (sd = map->id2sd(var)) != NULL) {
+ ARR_FIND(0, VECTOR_LENGTH(sd->script_queues), i, VECTOR_INDEX(sd->script_queues, i) == queue->id);
+
+ if (i != VECTOR_LENGTH(sd->script_queues))
+ VECTOR_ERASE(sd->script_queues, i);
}
- return false;
+ return true;
}
-/* queueremove(.@queue_id,.@var_id); */
-/* removes a entry from the queue, returns 1 if not in queue, 0 otherwise */
-BUILDIN(queueremove) {
+
+/**
+ * Script command queueremove: Removes an entry from a queue.
+ *
+ * Returns 1 (true) on success, 0 (false) if the item wasn't in queue.
+ *
+ * @code{.herc}
+ * queueremove(.@queue_id, .@value);
+ * @endcode
+ */
+BUILDIN(queueremove)
+{
int idx = script_getnum(st, 2);
int var = script_getnum(st, 3);
- script_pushint(st, script->queue_remove(idx,var)?1:0);
+ if (script->queue_remove(idx,var))
+ script_pushint(st, 1);
+ else
+ script_pushint(st, 0);
return true;
}
-/* queueopt(.@queue_id,optionType,<optional val>); */
-/* modifies the queue's options, when val is not provided the option is removed */
-/* when OnMapChange event is triggered, it sets a temp char var @QMapChangeTo$ with the destination map name */
-/* returns 1 when fails, 0 on success */
-BUILDIN(queueopt) {
+/**
+ * Script command queueopt: Modifies the options of a queue.
+ *
+ * When the option value isn't provided, the option is removed.
+ *
+ * Returns 1 (true) on success, 0 (false) on failure.
+ *
+ * The optionType is one of:
+ * - QUEUEOPT_DEATH
+ * - QUEUEOPT_LOGOUT
+ * - QUEUEOPT_MAPCHANGE
+ *
+ * When the QUEUEOPT_MAPCHANGE event is triggered, it sets a temporary
+ * character variable \c @Queue_Destination_Map$ with the destination map name.
+ *
+ * @code{.herc}
+ * queueopt(.@queue_id, optionType, <optional val>);
+ * @endcode
+ */
+BUILDIN(queueopt)
+{
int idx = script_getnum(st, 2);
int var = script_getnum(st, 3);
+ struct script_queue *queue = NULL;
- if( idx < 0 || idx >= script->hqs || script->hq[idx].size == -1 ) {
+ if (idx < 0 || idx >= VECTOR_LENGTH(script->hq) || !VECTOR_INDEX(script->hq, idx).valid) {
ShowWarning("buildin_queueopt: unknown queue id %d\n",idx);
- script_pushint(st, 1);
- } else if( var <= HQO_NONE || var >= HQO_MAX ) {
- ShowWarning("buildin_queueopt: unknown optionType %d\n",var);
- script_pushint(st, 1);
- } else {
- switch( (enum hQueueOpt)var ) {
- case HQO_OnDeath:
- if( script_hasdata(st, 4) )
- safestrncpy(script->hq[idx].onDeath, script_getstr(st, 4), EVENT_NAME_LENGTH);
- else
- script->hq[idx].onDeath[0] = '\0';
- break;
- case HQO_onLogOut:
- if( script_hasdata(st, 4) )
- safestrncpy(script->hq[idx].onLogOut, script_getstr(st, 4), EVENT_NAME_LENGTH);
- else
- script->hq[idx].onLogOut[0] = '\0';
- break;
- case HQO_OnMapChange:
- if( script_hasdata(st, 4) )
- safestrncpy(script->hq[idx].onMapChange, script_getstr(st, 4), EVENT_NAME_LENGTH);
- else
- script->hq[idx].onMapChange[0] = '\0';
- break;
- default:
- ShowWarning("buildin_queueopt: unsupported optionType %d\n",var);
- script_pushint(st, 1);
- break;
- }
+ script_pushint(st, 0);
+ return true;
}
+ queue = &VECTOR_INDEX(script->hq, idx);
+
+ switch (var) {
+ case SQO_ONDEATH:
+ if (script_hasdata(st, 4))
+ safestrncpy(queue->event_death, script_getstr(st, 4), EVENT_NAME_LENGTH);
+ else
+ queue->event_death[0] = '\0';
+ break;
+ case SQO_ONLOGOUT:
+ if (script_hasdata(st, 4))
+ safestrncpy(queue->event_logout, script_getstr(st, 4), EVENT_NAME_LENGTH);
+ else
+ queue->event_logout[0] = '\0';
+ break;
+ case SQO_ONMAPCHANGE:
+ if (script_hasdata(st, 4))
+ safestrncpy(queue->event_mapchange, script_getstr(st, 4), EVENT_NAME_LENGTH);
+ else
+ queue->event_mapchange[0] = '\0';
+ break;
+ default:
+ ShowWarning("buildin_queueopt: unsupported optionType %d\n",var);
+ script_pushint(st, 0);
+ return true;
+ }
+ script_pushint(st, 1);
return true;
}
+
+/**
+ * Deletes a queue.
+ *
+ * @param idx The queue index.
+ *
+ * @retval true if the queue was correctly deleted.
+ * @retval false if the queue didn't exist.
+ */
bool script_hqueue_del(int idx)
{
- if( idx < 0 || idx >= script->hqs || script->hq[idx].size == -1 ) {
- ShowWarning("script_queue_del: unknown queue id %d\n",idx);
- return true;
- } else {
- int i;
- for (i = 0; i < script->hq[idx].size; i++) {
- struct map_session_data *sd;
- if (script->hq[idx].item[i] >= START_ACCOUNT_NUM && (sd = map->id2sd(script->hq[idx].item[i])) != NULL) {
- int j;
- for(j = 0; j < sd->queues_count; j++) {
- if( sd->queues[j] == script->hq[idx].item[i] ) {
- break;
- }
- }
+ if (!script->queue_clear(idx))
+ return false;
- if( j != sd->queues_count )
- sd->queues[j] = -1;
- }
- script->hq[idx].item[i] = 0;
- }
+ VECTOR_INDEX(script->hq, idx).valid = false;
- script->hq[idx].size = -1;
- script->hq[idx].items = 0;
- }
- return false;
+ return true;
}
-/* queuedel(.@queue_id); */
-/* deletes queue of id .@queue_id, returns 1 if id not found, 0 otherwise */
-BUILDIN(queuedel) {
+
+/**
+ * Script command queuedel: Deletes a queue.
+ *
+ * Returns 1 (true) on success, 0 (false) if the queue doesn't exist.
+ *
+ * @code{.herc}
+ * queuedel(.@queue_id);
+ * @endcode
+ */
+BUILDIN(queuedel)
+{
int idx = script_getnum(st, 2);
- script_pushint(st,script->queue_del(idx)?1:0);
+ if (script->queue_del(idx))
+ script_pushint(st, 1);
+ else
+ script_pushint(st, 0);
return true;
}
-void script_hqueue_clear(int idx) {
- if( idx < 0 || idx >= script->hqs || script->hq[idx].size == -1 ) {
+
+/**
+ * Clears a queue.
+ *
+ * @param idx The queue index.
+ *
+ * @retval true if the queue was correctly cleared.
+ * @retval false if the queue didn't exist.
+ */
+bool script_hqueue_clear(int idx)
+{
+ struct script_queue *queue = NULL;
+
+ if (idx < 0 || idx >= VECTOR_LENGTH(script->hq) || !VECTOR_INDEX(script->hq, idx).valid) {
ShowWarning("script_hqueue_clear: unknown queue id %d\n",idx);
- return;
- } else {
- struct map_session_data *sd;
- int i, j;
+ return false;
+ }
- for(i = 0; i < script->hq[idx].size; i++) {
- if( script->hq[idx].item[i] > 0 ) {
+ queue = &VECTOR_INDEX(script->hq, idx);
- if (script->hq[idx].item[i] >= START_ACCOUNT_NUM && (sd = map->id2sd(script->hq[idx].item[i])) != NULL) {
- for(j = 0; j < sd->queues_count; j++) {
- if( sd->queues[j] == idx ) {
- break;
- }
- }
+ while (VECTOR_LENGTH(queue->entries) > 0) {
+ int entry = VECTOR_POP(queue->entries);
+ struct map_session_data *sd = NULL;
- if( j != sd->queues_count )
- sd->queues[j] = -1;
- }
- script->hq[idx].item[i] = 0;
- }
+ if (entry >= START_ACCOUNT_NUM && (sd = map->id2sd(entry)) != NULL) {
+ int i;
+ ARR_FIND(0, VECTOR_LENGTH(sd->script_queues), i, VECTOR_INDEX(sd->script_queues, i) == queue->id);
+
+ if (i != VECTOR_LENGTH(sd->script_queues))
+ VECTOR_ERASE(sd->script_queues, i);
}
- script->hq[idx].items = 0;
}
- return;
+ VECTOR_CLEAR(queue->entries);
+
+ return true;
}
-/* set .@id, queueiterator(.@queue_id); */
-/* creates a new queue iterator, returns its id */
-BUILDIN(queueiterator) {
+
+/**
+ * Script command queueiterator: Creates a new queue iterator.
+ *
+ * Returns the iterator's id or -1 in case of failure.
+ *
+ * @code{.herc}
+ * .@id = queueiterator(.@queue_id);
+ * @endcode
+ */
+BUILDIN(queueiterator)
+{
int qid = script_getnum(st, 2);
- struct hQueue *queue = NULL;
- int idx = script->hqis;
+ struct script_queue *queue = NULL;
+ struct script_queue_iterator *iter = NULL;
int i;
- if( qid < 0 || qid >= script->hqs || script->hq[qid].size == -1 || !(queue = script->queue(qid)) ) {
+ if (qid < 0 || qid >= VECTOR_LENGTH(script->hq) || !VECTOR_INDEX(script->hq, qid).valid || !(queue = script->queue(qid))) {
ShowWarning("queueiterator: invalid queue id %d\n",qid);
+ script_pushint(st, -1);
return true;
}
- /* what if queue->size is 0? (iterating a empty queue?) */
- if( queue->size <= 0 ) {
- ShowWarning("queueiterator: attempting to iterate on on empty queue id %d!\n",qid);
- return true;
- }
+ ARR_FIND(0, VECTOR_LENGTH(script->hqi), i, !VECTOR_INDEX(script->hqi, i).valid);
- for(i = 0; i < script->hqis; i++) {
- if( script->hqi[i].items == -1 ) {
- break;
- }
+ if (i == VECTOR_LENGTH(script->hqi)) {
+ VECTOR_ENSURE(script->hqi, 1, 1);
+ VECTOR_PUSHZEROED(script->hqi);
}
- if( i == script->hqis ) {
- RECREATE(script->hqi, struct hQueueIterator, ++script->hqis);
- script->hqi[ idx ].item = NULL;
- } else
- idx = i;
-
- RECREATE(script->hqi[ idx ].item, int, queue->size);
+ iter = &VECTOR_INDEX(script->hqi, i);
- memcpy(script->hqi[idx].item, queue->item, sizeof(int)*queue->size);
+ VECTOR_ENSURE(iter->entries, VECTOR_LENGTH(queue->entries), 1);
+ VECTOR_PUSHARRAY(iter->entries, VECTOR_DATA(queue->entries), VECTOR_LENGTH(queue->entries));
- script->hqi[ idx ].items = queue->size;
- script->hqi[ idx ].pos = 0;
+ iter->pos = 0;
+ iter->valid = true;
- script_pushint(st,idx);
+ script_pushint(st, i);
return true;
}
-/* Queue Iterator Get Next */
-/* returns next/first member in the iterator, 0 if none */
-BUILDIN(qiget) {
+
+/**
+ * Script command qiget: returns the next/first member in the iterator.
+ *
+ * Returns 0 if there's no next item.
+ *
+ * @code{.herc}
+ * for (.@i = qiget(.@iter); qicheck(.@iter); .@i = qiget(.@iter)) {
+ * // ...
+ * }
+ * @endcode
+ */
+BUILDIN(qiget)
+{
int idx = script_getnum(st, 2);
+ struct script_queue_iterator *it = NULL;
- if( idx < 0 || idx >= script->hqis ) {
+ if (idx < 0 || idx >= VECTOR_LENGTH(script->hqi) || !VECTOR_INDEX(script->hqi, idx).valid) {
ShowWarning("buildin_qiget: unknown queue iterator id %d\n",idx);
script_pushint(st, 0);
- } else if (script->hqi[idx].pos >= script->hqi[idx].items) {
- script_pushint(st, 0);
- } else {
- struct hQueueIterator *it = &script->hqi[idx];
- script_pushint(st, it->item[it->pos++]);
+ return true;
}
+ it = &VECTOR_INDEX(script->hqi, idx);
+
+ if (it->pos >= VECTOR_LENGTH(it->entries)) {
+ if (it->pos == VECTOR_LENGTH(it->entries))
+ ++it->pos; // Move beyond the last position to invalidate qicheck
+ script_pushint(st, 0);
+ return true;
+ }
+ script_pushint(st, VECTOR_INDEX(it->entries, it->pos++));
return true;
}
-/* Queue Iterator Check */
-/* returns 1:0 if there is a next member in the iterator */
-BUILDIN(qicheck) {
+
+/**
+ * Script command qicheck: Checks if the current member in the given iterator (from the last call to qiget) exists.
+ *
+ * Returns 1 if it exists, 0 otherwise.
+ *
+ * @code{.herc}
+ * for (.@i = qiget(.@iter); qicheck(.@iter); .@i = qiget(.@iter)) {
+ * // ...
+ * }
+ * @endcode
+ */
+BUILDIN(qicheck)
+{
int idx = script_getnum(st, 2);
+ struct script_queue_iterator *it = NULL;
- if( idx < 0 || idx >= script->hqis ) {
+ if (idx < 0 || idx >= VECTOR_LENGTH(script->hqi) || !VECTOR_INDEX(script->hqi, idx).valid) {
ShowWarning("buildin_qicheck: unknown queue iterator id %d\n",idx);
script_pushint(st, 0);
- } else if (script->hqi[idx].pos >= script->hqi[idx].items) {
+ return true;
+ }
+
+ it = &VECTOR_INDEX(script->hqi, idx);
+
+ if (it->pos <= 0 || it->pos > VECTOR_LENGTH(it->entries)) {
script_pushint(st, 0);
} else {
script_pushint(st, 1);
@@ -19119,20 +19221,37 @@ BUILDIN(qicheck) {
return true;
}
-/* Queue Iterator Check */
-BUILDIN(qiclear) {
+
+/**
+ * Script command qiclear: Destroys a queue iterator.
+ *
+ * Returns true (1) on success, false (0) on failure.
+ *
+ * @code{.herc}
+ * qiclear(.@iter);
+ * @endcode
+ */
+BUILDIN(qiclear)
+{
int idx = script_getnum(st, 2);
+ struct script_queue_iterator *it = NULL;
- if( idx < 0 || idx >= script->hqis ) {
+ if (idx < 0 || idx >= VECTOR_LENGTH(script->hqi) || !VECTOR_INDEX(script->hqi, idx).valid) {
ShowWarning("buildin_qiclear: unknown queue iterator id %d\n",idx);
- script_pushint(st, 1);
- } else {
- script->hqi[idx].items = -1;
script_pushint(st, 0);
+ return true;
}
+ it = &VECTOR_INDEX(script->hqi, idx);
+
+ VECTOR_CLEAR(it->entries);
+ it->pos = 0;
+ it->valid = false;
+
+ script_pushint(st, 1);
return true;
}
+
/**
* packageitem({<optional container_item_id>})
* when no item id is provided it tries to assume it comes from the current item id being processed (if any)
@@ -20366,7 +20485,7 @@ void script_parse_builtin(void) {
BUILDIN_DEF(showevent, "i?"),
/**
- * hQueue [Ind/Hercules]
+ * script_queue [Ind/Hercules]
**/
BUILDIN_DEF(queue,""),
BUILDIN_DEF(queuesize,"i"),
@@ -20573,10 +20692,6 @@ void script_defaults(void) {
script->stack_ers = NULL;
script->array_ers = NULL;
- script->hq = NULL;
- script->hqi = NULL;
- script->hqs = script->hqis = 0;
-
script->buildin = NULL;
script->buildin_count = 0;
diff --git a/src/map/script.h b/src/map/script.h
index ff660dec8..b153cf81a 100644
--- a/src/map/script.h
+++ b/src/map/script.h
@@ -223,12 +223,13 @@ typedef enum c_op {
#endif // PCRE_SUPPORT
} c_op;
-enum hQueueOpt {
- HQO_NONE,
- HQO_onLogOut,
- HQO_OnDeath,
- HQO_OnMapChange,
- HQO_MAX,
+/// Script queue options
+enum ScriptQueueOptions {
+ SQO_NONE, ///< No options set
+ SQO_ONLOGOUT, ///< Execute event on logout
+ SQO_ONDEATH, ///< Execute event on death
+ SQO_ONMAPCHANGE, ///< Execute event on map change
+ SQO_MAX,
};
enum e_script_state { RUN,STOP,END,RERUNLINE,GOTO,RETFUNC,CLOSE };
@@ -391,22 +392,27 @@ struct script_stack {
struct reg_db scope; ///< scope variables
};
-/* [Ind/Hercules] */
-struct hQueue {
- int id;
- int *item;
- int items;/* how many actual items are in the array */
- int size;/* size of the *item array, not the current amount of items in it since it can have empty slots */
- /* events */
- char onLogOut[EVENT_NAME_LENGTH];
- char onDeath[EVENT_NAME_LENGTH];
- char onMapChange[EVENT_NAME_LENGTH];
+/**
+ * Data structure to represent a script queue.
+ * @author Ind/Hercules
+ */
+struct script_queue {
+ int id; ///< Queue identifier
+ VECTOR_DECL(int) entries; ///< Items in the queue.
+ bool valid; ///< Whether the queue is valid.
+ /// Events
+ char event_logout[EVENT_NAME_LENGTH]; ///< Logout event
+ char event_death[EVENT_NAME_LENGTH]; ///< Death event
+ char event_mapchange[EVENT_NAME_LENGTH]; ///< Map change event
};
-struct hQueueIterator {
- int *item;
- int items;
- int pos;
+/**
+ * Iterator for a struct script_queue.
+ */
+struct script_queue_iterator {
+ VECTOR_DECL(int) entries; ///< Entries in the queue (iterator's cached copy)
+ bool valid; ///< Whether the queue is valid (initialized - not necessarily having entries available)
+ int pos; ///< Iterator's cursor
};
struct script_state {
@@ -515,9 +521,8 @@ struct script_interface {
struct eri *st_ers;
struct eri *stack_ers;
/* */
- struct hQueue *hq;
- struct hQueueIterator *hqi;
- int hqs, hqis;
+ VECTOR_DECL(struct script_queue) hq;
+ VECTOR_DECL(struct script_queue_iterator) hqi;
/* */
char **buildin;
unsigned int buildin_count;
@@ -667,12 +672,12 @@ struct script_interface {
void (*setd_sub) (struct script_state *st, struct map_session_data *sd, const char *varname, int elem, void *value, struct reg_db *ref);
void (*attach_state) (struct script_state* st);
/* */
- struct hQueue *(*queue) (int idx);
+ struct script_queue *(*queue) (int idx);
bool (*queue_add) (int idx, int var);
bool (*queue_del) (int idx);
bool (*queue_remove) (int idx, int var);
int (*queue_create) (void);
- void (*queue_clear) (int idx);
+ bool (*queue_clear) (int idx);
/* */
const char * (*parse_curly_close) (const char *p);
const char * (*parse_syntax_close) (const char *p);
diff --git a/src/map/skill.c b/src/map/skill.c
index cdf1c031f..8984bf0fa 100644
--- a/src/map/skill.c
+++ b/src/map/skill.c
@@ -11878,8 +11878,8 @@ int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *bl, int6
//Take into account these hit more times than the timer interval can handle.
do
skill->attack(BF_MAGIC,ss,&src->bl,bl,sg->skill_id,sg->skill_lv,tick+count*sg->interval,0);
- while(--src->val2 && x == bl->x && y == bl->y
- && ++count < SKILLUNITTIMER_INTERVAL/sg->interval && !status->isdead(bl));
+ while (src->alive != 0 && --src->val2 != 0 && x == bl->x && y == bl->y
+ && ++count < SKILLUNITTIMER_INTERVAL/sg->interval && !status->isdead(bl));
if (src->val2<=0)
skill->delunit(src);
@@ -11961,8 +11961,8 @@ int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *bl, int6
sg->limit = DIFF_TICK32(tick,sg->tick);
break;
}
- } while( x == bl->x && y == bl->y && sg->alive_count
- && ++count < SKILLUNITTIMER_INTERVAL/sg->interval && !status->isdead(bl) );
+ } while (src->alive != 0 && x == bl->x && y == bl->y && sg->alive_count != 0
+ && ++count < SKILLUNITTIMER_INTERVAL/sg->interval && !status->isdead(bl));
map->freeblock_unlock();
}
break;
diff --git a/src/map/status.c b/src/map/status.c
index 1a07f74dc..4cd73d3ac 100644
--- a/src/map/status.c
+++ b/src/map/status.c
@@ -823,6 +823,7 @@ void initChangeTables(void) {
status->dbs->IconChangeTable[SC_L_LIFEPOTION] = SI_L_LIFEPOTION;
status->dbs->IconChangeTable[SC_ATKER_BLOOD] = SI_ATKER_BLOOD;
status->dbs->IconChangeTable[SC_TARGET_BLOOD] = SI_TARGET_BLOOD;
+ status->dbs->IconChangeTable[SC_ACARAJE] = SI_ACARAJE;
// Mercenary Bonus Effects
status->dbs->IconChangeTable[SC_MER_FLEE] = SI_MER_FLEE;
status->dbs->IconChangeTable[SC_MER_ATK] = SI_MER_ATK;
@@ -1008,12 +1009,13 @@ void initChangeTables(void) {
status->dbs->ChangeFlagTable[SC_MUSTLE_M] |= SCB_MAXHP;
status->dbs->ChangeFlagTable[SC_LIFE_FORCE_F] |= SCB_MAXSP;
status->dbs->ChangeFlagTable[SC_EXTRACT_WHITE_POTION_Z] |= SCB_REGEN;
- status->dbs->ChangeFlagTable[SC_VITATA_500] |= SCB_REGEN;
+ status->dbs->ChangeFlagTable[SC_VITATA_500] |= SCB_REGEN | SCB_MAXSP;
status->dbs->ChangeFlagTable[SC_EXTRACT_SALAMINE_JUICE] |= SCB_ASPD;
status->dbs->ChangeFlagTable[SC_REBOUND] |= SCB_SPEED|SCB_REGEN;
status->dbs->ChangeFlagTable[SC_DEFSET] |= SCB_DEF|SCB_DEF2;
status->dbs->ChangeFlagTable[SC_MDEFSET] |= SCB_MDEF|SCB_MDEF2;
status->dbs->ChangeFlagTable[SC_MYSTERIOUS_POWDER] |= SCB_MAXHP;
+ status->dbs->ChangeFlagTable[SC_ACARAJE] |= SCB_HIT | SCB_ASPD;
status->dbs->ChangeFlagTable[SC_ALL_RIDING] = SCB_SPEED;
status->dbs->ChangeFlagTable[SC_WEDDING] = SCB_SPEED;
@@ -3328,8 +3330,8 @@ void status_calc_regen_rate(struct block_list *bl, struct regen_data *regen, str
regen->flag &=~RGN_SP;
if(sc->data[SC_EXTRACT_WHITE_POTION_Z])
regen->rate.hp += regen->rate.hp * sc->data[SC_EXTRACT_WHITE_POTION_Z]->val1/100;
- if(sc->data[SC_VITATA_500])
- regen->rate.sp += regen->rate.sp * sc->data[SC_VITATA_500]->val1/100;
+ if (sc->data[SC_VITATA_500])
+ regen->rate.sp += regen->rate.sp * sc->data[SC_VITATA_500]->val1 / 100;
}
/// Recalculates parts of an object's battle status according to the specified flags.
/// @param flag bitfield of values from enum scb_flag
@@ -4792,7 +4794,9 @@ signed short status_calc_hit(struct block_list *bl, struct status_change *sc, in
hit /= 2;
if(sc->data[SC_ILLUSIONDOPING])
hit -= hit * (5 + sc->data[SC_ILLUSIONDOPING]->val1) / 100; //custom
-
+ if (sc->data[SC_ACARAJE])
+ hit += sc->data[SC_ACARAJE]->val1;
+
return (short)cap_value(hit,1,SHRT_MAX);
}
@@ -5477,6 +5481,8 @@ short status_calc_aspd(struct block_list *bl, struct status_change *sc, short fl
bonus += sc->data[SC_GS_GATLINGFEVER]->val1;
if (sc->data[SC_STAR_COMFORT])
bonus += 3 * sc->data[SC_STAR_COMFORT]->val1;
+ if (sc->data[SC_ACARAJE])
+ bonus += sc->data[SC_ACARAJE]->val2;
}
return (bonus + pots);
@@ -5638,6 +5644,8 @@ short status_calc_aspd_rate(struct block_list *bl, struct status_change *sc, int
aspd_rate += sc->data[SC_PAIN_KILLER]->val2 * 10;
if( sc->data[SC_GOLDENE_FERSE])
aspd_rate -= sc->data[SC_GOLDENE_FERSE]->val3 * 10;
+ if (sc->data[SC_ACARAJE])
+ aspd_rate += sc->data[SC_ACARAJE]->val2 * 10;
return (short)cap_value(aspd_rate,0,SHRT_MAX);
}
@@ -5748,6 +5756,8 @@ unsigned int status_calc_maxsp(struct block_list *bl, struct status_change *sc,
maxsp += maxsp * sc->data[SC_LIFE_FORCE_F]->val1/100;
if(sc->data[SC_EARTH_INSIGNIA] && sc->data[SC_EARTH_INSIGNIA]->val1 == 3)
maxsp += 50;
+ if (sc->data[SC_VITATA_500])
+ maxsp += maxsp * sc->data[SC_VITATA_500]->val2 / 100;
return cap_value(maxsp,1,UINT_MAX);
}
diff --git a/src/map/status.h b/src/map/status.h
index 800e3de9f..7635248d0 100644
--- a/src/map/status.h
+++ b/src/map/status.h
@@ -745,6 +745,8 @@ typedef enum sc_type {
SC_LJOSALFAR,
SC_MERMAID_LONGING,
+
+ SC_ACARAJE, // 590
SC_MAX, //Automatically updated max, used in for's to check we are within bounds.
} sc_type;
diff --git a/src/map/unit.c b/src/map/unit.c
index 7c253c5c2..3046db9e1 100644
--- a/src/map/unit.c
+++ b/src/map/unit.c
@@ -2645,10 +2645,7 @@ int unit_free(struct block_list *bl, clr_type clrtype) {
aFree(sd->instance);
sd->instance = NULL;
}
- if( sd->queues != NULL ) {
- aFree(sd->queues);
- sd->queues = NULL;
- }
+ VECTOR_CLEAR(sd->script_queues);
if( sd->quest_log != NULL ) {
aFree(sd->quest_log);
sd->quest_log = NULL;