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; }
/** * NPC quest/event icon check * @author [Kisuka] */ void questinfo_update_status(TBL_PC *sd) { unsigned short i = 0; #if PACKETVER >= 20090218 for( i = 0; i < map[sd->bl.m].qi_count; i++ ) { struct questinfo *qi = &map[sd->bl.m].qi_data[i]; int j = quest_check(sd, qi->id1, HAVEQUEST); int k = quest_check(sd, qi->id2, HAVEQUEST); j = j + (j < 1); k = k + (k < 1); if( qi->state1 == j ) { if( !qi->id2 ) { if( qi->hasJob ) { if( (qi->mask && ((qi->class_ == -1 && (sd->class_&qi->mask)) || (qi->class_ != -1 && (sd->class_&qi->mask) == qi->class_))) || (!qi->mask && qi->class_ != -1 && sd->status.class_ == qi->class_) ) clif_quest_show_event(sd, &qi->nd->bl, qi->icon, qi->color); } else clif_quest_show_event(sd, &qi->nd->bl, qi->icon, qi->color); } else { if( qi->state2 == k ) { if( qi->hasJob ) { if( (qi->mask && ((qi->class_ == -1 && (sd->class_&qi->mask)) || (qi->class_ != -1 && (sd->class_&qi->mask) == qi->class_))) || (!qi->mask && qi->class_ != -1 && sd->status.class_ == qi->class_) ) clif_quest_show_event(sd, &qi->nd->bl, qi->icon, qi->color); } else clif_quest_show_event(sd, &qi->nd->bl, qi->icon, qi->color); } else { #if PACKETVER >= 20120410 clif_quest_show_event(sd, &qi->nd->bl, 9999, 0); #else clif_quest_show_event(sd, &qi->nd->bl, 0, 0); #endif } } } else { #if PACKETVER >= 20120410 clif_quest_show_event(sd, &qi->nd->bl, 9999, 0); #else clif_quest_show_event(sd, &qi->nd->bl, 0, 0); #endif } } #endif }
/** * Handles the "death" of a monster. * * Disperses treasures carried by the monster centered at the monster location. * Note that objects dropped may disappear in crowded rooms. * * Checks for "Quest" completion when a quest monster is killed. * * Note that only the player can induce "monster_death()" on Uniques. * Thus (for now) all Quest monsters should be Uniques. * * If `stats` is true, then we skip updating the monster memory. This is * used by stats-generation code, for efficiency. */ void monster_death(struct monster *mon, bool stats) { int dump_item = 0; int dump_gold = 0; struct object *obj = mon->held_obj; bool visible = (mflag_has(mon->mflag, MFLAG_VISIBLE) || rf_has(mon->race->flags, RF_UNIQUE)); /* Delete any mimicked objects */ if (mon->mimicked_obj) object_delete(&mon->mimicked_obj); /* Drop objects being carried */ while (obj) { struct object *next = obj->next; /* Object no longer held */ obj->held_m_idx = 0; pile_excise(&mon->held_obj, obj); /* Count it and drop it - refactor once origin is a bitflag */ if (!stats) { if (tval_is_money(obj) && (obj->origin != ORIGIN_STOLEN)) dump_gold++; else if (!tval_is_money(obj) && ((obj->origin == ORIGIN_DROP) || (obj->origin == ORIGIN_DROP_PIT) || (obj->origin == ORIGIN_DROP_VAULT) || (obj->origin == ORIGIN_DROP_SUMMON) || (obj->origin == ORIGIN_DROP_SPECIAL) || (obj->origin == ORIGIN_DROP_BREED) || (obj->origin == ORIGIN_DROP_POLY) || (obj->origin == ORIGIN_DROP_WIZARD))) dump_item++; } /* Change origin if monster is invisible, unless we're in stats mode */ if (!visible && !stats) obj->origin = ORIGIN_DROP_UNKNOWN; drop_near(cave, obj, 0, mon->fy, mon->fx, true); obj = next; } /* Forget objects */ mon->held_obj = NULL; /* Take note of any dropped treasure */ if (visible && (dump_item || dump_gold)) lore_treasure(mon, dump_item, dump_gold); /* Update monster list window */ player->upkeep->redraw |= PR_MONLIST; /* Check if we finished a quest */ quest_check(mon); }
int quest_add(TBL_PC * sd, int quest_id) { int i, j; if( sd->num_quests >= MAX_QUEST_DB ) { ShowError("quest_add: Character %d has got all the quests.(max quests: %d)\n", sd->status.char_id, MAX_QUEST_DB); return 1; } if( quest_check(sd, quest_id, HAVEQUEST) >= 0 ) { ShowError("quest_add: Character %d already has quest %d.\n", sd->status.char_id, quest_id); return -1; } if( (j = quest_search_db(quest_id)) < 0 ) { ShowError("quest_add: quest %d not found in DB.\n", quest_id); return -1; } i = sd->avail_quests; memmove(&sd->quest_log[i+1], &sd->quest_log[i], sizeof(struct quest)*(sd->num_quests-sd->avail_quests)); memmove(sd->quest_index+i+1, sd->quest_index+i, sizeof(int)*(sd->num_quests-sd->avail_quests)); 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->num_quests++; sd->avail_quests++; sd->save_quest = true; clif_quest_add(sd, &sd->quest_log[i], sd->quest_index[i]); if( save_settings&64 ) chrif_save(sd,0); return 0; }
/** * Adds a quest to the player's list. * New quest will be added as Q_ACTIVE. * @param sd : Player's data * @param quest_id : ID of the quest to add. * @return 0 in case of success, nonzero otherwise */ int quest_add(TBL_PC *sd, int quest_id) { int n; struct quest_db *qi = quest_db(quest_id); if( qi == &quest_dummy ) { ShowError("quest_add: quest %d not found in DB.\n", quest_id); return -1; } if( quest_check(sd, quest_id, HAVEQUEST) >= 0 ) { ShowError("quest_add: Character %d already has quest %d.\n", sd->status.char_id, quest_id); return -1; } n = sd->avail_quests; //Insertion point sd->num_quests++; sd->avail_quests++; RECREATE(sd->quest_log, struct quest, sd->num_quests); //The character has some completed quests, make room before them so that they will stay at the end of the array if( sd->avail_quests != sd->num_quests ) memmove(&sd->quest_log[n + 1], &sd->quest_log[n], sizeof(struct quest) * (sd->num_quests-sd->avail_quests)); memset(&sd->quest_log[n], 0, sizeof(struct quest)); sd->quest_log[n].quest_id = qi->id; if( qi->time ) sd->quest_log[n].time = (unsigned int)(time(NULL) + qi->time); sd->quest_log[n].state = Q_ACTIVE; sd->save_quest = true; clif_quest_add(sd, &sd->quest_log[n]); clif_quest_update_objective(sd, &sd->quest_log[n]); if( save_settings&CHARSAVE_QUEST ) chrif_save(sd,0); return 0; }
/* * Note that "feeling" is set to zero unless some time has passed. * Note that this is done when the level is GENERATED, not entered. */ void do_cmd_feeling(void) { bool is_quest_level = quest_check(p_ptr->depth); /* No sensing things in Moria */ if (game_mode == GAME_NPPMORIA) return; /* No useful feeling in town */ if (!p_ptr->depth) { message(QString("Looks like a typical town.")); return; } /* No useful feelings until enough time has passed */ if (!do_feeling) { message(QString("You are still uncertain about this level...")); return; } if (p_ptr->dungeon_type == DUNGEON_TYPE_WILDERNESS) { if (is_quest_level) message(QString("You have entered a wilderness level on the verge of destruction!.")); else message(QString("You have entered an area of near pristine wilderness.")); } else if (p_ptr->dungeon_type == DUNGEON_TYPE_GREATER_VAULT) { message(QString("You have discovered a gigantic vault of great treasures guarded by dangerous creatures.")); } else if (p_ptr->dungeon_type == DUNGEON_TYPE_LABYRINTH) { if (is_quest_level) message(QString("You have entered a tiny, closely guarded labyrinth.")); else message(QString("You have entered a complex labyrinth of dungeon hallways.")); } else if (p_ptr->dungeon_type == DUNGEON_TYPE_ARENA) { message(QString("You are in an arena fighting for your life.")); } /* Verify the feeling */ else if (feeling >= LEV_THEME_HEAD) { /*print out a message about a themed level*/ QString note; QString mon_theme; note = (QString("You have entered ")); mon_theme = (QString(feeling_themed_level[feeling - LEV_THEME_HEAD])); if (begins_with_vowel(mon_theme)) note.append(QString("an ")); else note.append(QString("a ")); note.append(QString("%1 stronghold.") .arg(mon_theme)); message(note); } /* Display the feeling */ else message(QString(do_cmd_feeling_text[feeling])); /* Redraw the feeling indicator */ p_ptr->redraw |= (PR_SIDEBAR_PL); }