diff options
author | Andrei Karas <akaras@inbox.ru> | 2015-11-15 00:45:28 +0300 |
---|---|---|
committer | Andrei Karas <akaras@inbox.ru> | 2015-11-15 00:45:28 +0300 |
commit | 8ee5eafc741d581579efd696765fb0646b72a553 (patch) | |
tree | f2be1be92fc4bf5f16e5b8097dd13aaa0f4c3eec /src/map | |
parent | 45be44cc833bc47991218b90f1bbc1fc6dbd04f4 (diff) | |
parent | d8edfe7eb9e7d86da24c87198f03432b73e72284 (diff) | |
download | hercules-8ee5eafc741d581579efd696765fb0646b72a553.tar.gz hercules-8ee5eafc741d581579efd696765fb0646b72a553.tar.bz2 hercules-8ee5eafc741d581579efd696765fb0646b72a553.tar.xz hercules-8ee5eafc741d581579efd696765fb0646b72a553.zip |
Merge pull request #857 from HerculesWS/scriptqueue
Scriptqueue
Diffstat (limited to 'src/map')
-rw-r--r-- | src/map/battleground.c | 163 | ||||
-rw-r--r-- | src/map/clif.c | 8 | ||||
-rw-r--r-- | src/map/map.c | 14 | ||||
-rw-r--r-- | src/map/pc.c | 21 | ||||
-rw-r--r-- | src/map/pc.h | 3 | ||||
-rw-r--r-- | src/map/script.c | 613 | ||||
-rw-r--r-- | src/map/script.h | 55 | ||||
-rw-r--r-- | src/map/unit.c | 5 |
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; |