summaryrefslogtreecommitdiff
path: root/src/map
diff options
context:
space:
mode:
Diffstat (limited to 'src/map')
-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/pc.c21
-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/unit.c5
8 files changed, 505 insertions, 377 deletions
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/pc.c b/src/map/pc.c
index 351d77b26..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;
@@ -5526,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);
}
}
@@ -7634,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/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;