/** * Map iterator to ensures a player has no invalid quest log entries. * * Any entries that are no longer in the db are removed. * * @see map_foreachpc * @param ap Ignored */ int quest_reload_check_sub(struct map_session_data *sd, va_list ap) { int i, j; nullpo_ret(sd); j = 0; for( i = 0; i < sd->num_quests; i++ ) { struct quest_db *qi = quest_search(sd->quest_log[i].quest_id); if( qi == &quest_dummy ) { //Remove no longer existing entries if( sd->quest_log[i].state != Q_COMPLETE ) //And inform the client if necessary clif_quest_delete(sd, sd->quest_log[i].quest_id); continue; } if( i != j ) { //Move entries if there's a gap to fill memcpy(&sd->quest_log[j], &sd->quest_log[i], sizeof(struct quest)); } j++; } sd->num_quests = j; ARR_FIND(0, sd->num_quests, i, sd->quest_log[i].state == Q_COMPLETE); sd->avail_quests = i; return 1; }
/** * Updates a quest's state. * * Only status of active and inactive quests can be updated. Completed quests can't (for now). [Inkfish] * * @param sd Character's data * @param quest_id Quest ID to update * @param qs New quest state * @return 0 in case of success, nonzero otherwise */ int quest_update_status(TBL_PC *sd, int quest_id, enum quest_state status) { int i; ARR_FIND(0, sd->avail_quests, i, sd->quest_log[i].quest_id == quest_id); if( i == sd->avail_quests ) { ShowError("quest_update_status: Character %d doesn't have quest %d.\n", sd->status.char_id, quest_id); return -1; } sd->quest_log[i].state = status; sd->save_quest = true; if( status < Q_COMPLETE ) { clif_quest_update_status(sd, quest_id, status == Q_ACTIVE ? true : false); return 0; } // The quest is complete, so it needs to be moved to the completed quests block at the end of the array if( i < (--sd->avail_quests) ) { struct quest tmp_quest; memcpy(&tmp_quest, &sd->quest_log[i], sizeof(struct quest)); memcpy(&sd->quest_log[i], &sd->quest_log[sd->avail_quests], sizeof(struct quest)); memcpy(&sd->quest_log[sd->avail_quests], &tmp_quest, sizeof(struct quest)); } clif_quest_delete(sd, quest_id); if( save_settings&64 ) chrif_save(sd,0); return 0; }
/** * Removes a quest from a player's list * * @param sd Player's data * @param quest_id ID of the quest to remove * @return 0 in case of success, nonzero otherwise */ int quest_delete(TBL_PC *sd, int quest_id) { int i; //Search for quest ARR_FIND(0, sd->num_quests, i, sd->quest_log[i].quest_id == quest_id); if( i == sd->num_quests ) { ShowError("quest_delete: Character %d doesn't have quest %d.\n", sd->status.char_id, quest_id); return -1; } if( sd->quest_log[i].state != Q_COMPLETE ) sd->avail_quests--; if( i < --sd->num_quests ) //Compact the array memmove(&sd->quest_log[i], &sd->quest_log[i + 1], sizeof(struct quest) * (sd->num_quests - i)); if( sd->num_quests == 0 ) { aFree(sd->quest_log); sd->quest_log = NULL; } else RECREATE(sd->quest_log, struct quest, sd->num_quests); sd->save_quest = true; clif_quest_delete(sd, quest_id); if( save_settings&64 ) chrif_save(sd,0); return 0; }
int quest_delete(TBL_PC * sd, int quest_id) { int i; //Search for quest ARR_FIND(0, sd->num_quests, i, sd->quest_log[i].quest_id == quest_id); if(i == sd->num_quests) { ShowError("quest_delete: Character %d doesn't have quest %d.\n", sd->status.char_id, quest_id); return -1; } if( sd->quest_log[i].state != Q_COMPLETE ) sd->avail_quests--; if( sd->num_quests-- < MAX_QUEST_DB && sd->quest_log[i+1].quest_id ) { memmove(&sd->quest_log[i], &sd->quest_log[i+1], sizeof(struct quest)*(sd->num_quests-i)); memmove(sd->quest_index+i, sd->quest_index+i+1, sizeof(int)*(sd->num_quests-i)); } memset(&sd->quest_log[sd->num_quests], 0, sizeof(struct quest)); sd->quest_index[sd->num_quests] = 0; sd->save_quest = true; clif_quest_delete(sd, quest_id); if( save_settings&64 ) chrif_save(sd,0); return 0; }
int quest_update_status(TBL_PC *sd, int quest_id, quest_state status) { int i; //Only status of active and inactive quests can be updated. Completed quests can't (for now). [Inkfish] ARR_FIND(0, sd->avail_quests, i, sd->quest_log[i].quest_id == quest_id); if(i == sd->avail_quests) { ShowError("quest_update_status: Character %d doesn't have quest %d.\n", sd->status.char_id, quest_id); return -1; } sd->quest_log[i].state = status; sd->save_quest = true; if(status < Q_COMPLETE) { clif_quest_update_status(sd, quest_id, (bool)status); return 0; } achievement_validate_quest(sd,quest_id); if( i != (--sd->avail_quests) ) { struct quest tmp_quest; memcpy(&tmp_quest, &sd->quest_log[i],sizeof(struct quest)); memcpy(&sd->quest_log[i], &sd->quest_log[sd->avail_quests],sizeof(struct quest)); memcpy(&sd->quest_log[sd->avail_quests], &tmp_quest,sizeof(struct quest)); } clif_quest_delete(sd, quest_id); if(save_settings&64) chrif_save(sd,0); return 0; }
int quest_change(TBL_PC * sd, int qid1, int qid2) { int i, j; if( quest_check(sd, qid2, HAVEQUEST) >= 0 ) { ShowError("quest_change: Character %d already has quest %d.\n", sd->status.char_id, qid2); return -1; } if( quest_check(sd, qid1, HAVEQUEST) < 0 ) { ShowError("quest_change: Character %d doesn't have quest %d.\n", sd->status.char_id, qid1); return -1; } if( (j = quest_search_db(qid2)) < 0 ) { ShowError("quest_change: quest %d not found in DB.\n",qid2); return -1; } ARR_FIND(0, sd->avail_quests, i, sd->quest_log[i].quest_id == qid1); if(i == sd->avail_quests) { ShowError("quest_change: Character %d has completed quests %d.\n", sd->status.char_id, qid1); return -1; } memset(&sd->quest_log[i], 0, sizeof(struct quest)); sd->quest_log[i].quest_id = quest_db[j].id; if( quest_db[j].time ) sd->quest_log[i].time = (unsigned int)(time(NULL) + quest_db[j].time); sd->quest_log[i].state = Q_ACTIVE; sd->quest_index[i] = j; sd->save_quest = true; clif_quest_delete(sd, qid1); clif_quest_add(sd, &sd->quest_log[i], sd->quest_index[i]); if( save_settings&64 ) chrif_save(sd,0); return 0; }