diff options
Diffstat (limited to 'crawl-ref/source')
-rw-r--r-- | crawl-ref/source/abl-show.cc | 1 | ||||
-rw-r--r-- | crawl-ref/source/acr.cc | 11 | ||||
-rw-r--r-- | crawl-ref/source/command.cc | 5 | ||||
-rw-r--r-- | crawl-ref/source/delay.cc | 8 | ||||
-rw-r--r-- | crawl-ref/source/describe.cc | 14 | ||||
-rw-r--r-- | crawl-ref/source/direct.cc | 9 | ||||
-rw-r--r-- | crawl-ref/source/enum.h | 61 | ||||
-rw-r--r-- | crawl-ref/source/itemprop.h | 2 | ||||
-rw-r--r-- | crawl-ref/source/items.cc | 3 | ||||
-rw-r--r-- | crawl-ref/source/misc.cc | 2 | ||||
-rw-r--r-- | crawl-ref/source/tutorial.cc | 548 | ||||
-rw-r--r-- | crawl-ref/source/tutorial.h | 3 | ||||
-rw-r--r-- | crawl-ref/source/view.cc | 2 | ||||
-rw-r--r-- | crawl-ref/source/view.h | 1 |
14 files changed, 594 insertions, 76 deletions
diff --git a/crawl-ref/source/abl-show.cc b/crawl-ref/source/abl-show.cc index ed75ea325c..3dfe627c57 100644 --- a/crawl-ref/source/abl-show.cc +++ b/crawl-ref/source/abl-show.cc @@ -1839,7 +1839,6 @@ static void add_talent(std::vector<talent>& vec, const ability_type ability, if ( t.which != ABIL_NON_ABILITY ) { vec.push_back(t); - learned_something_new(TUT_NEW_ABILITY); } } diff --git a/crawl-ref/source/acr.cc b/crawl-ref/source/acr.cc index f340b0c206..86672702ac 100644 --- a/crawl-ref/source/acr.cc +++ b/crawl-ref/source/acr.cc @@ -890,9 +890,6 @@ static void input() if (Options.tut_just_triggered) Options.tut_just_triggered = false; - if (Options.tutorial_events[TUT_RUN_AWAY] && 2*you.hp < you.hp_max ) - learned_something_new(TUT_RUN_AWAY); - if ( i_feel_safe() ) { if (Options.tutorial_left) @@ -916,6 +913,14 @@ static void input() } } } + else + { + if (2*you.hp < you.hp_max) + learned_something_new(TUT_RUN_AWAY); + + if (Options.tutorial_type == TUT_MAGIC_CHAR && you.magic_points < 1) + learned_something_new(TUT_RETREAT_CASTER); + } if ( you.duration[DUR_PARALYSIS] ) { diff --git a/crawl-ref/source/command.cc b/crawl-ref/source/command.cc index 8a4a6ef884..447b740ee2 100644 --- a/crawl-ref/source/command.cc +++ b/crawl-ref/source/command.cc @@ -115,6 +115,11 @@ void swap_inv_slots(int from_slot, int to_slot, bool verbose) item_def tmp = you.inv[to_slot]; you.inv[to_slot] = you.inv[from_slot]; you.inv[from_slot] = tmp; + + // slot switching + tmp.slot = you.inv[to_slot].slot; + you.inv[to_slot].slot = you.inv[from_slot].slot; + you.inv[from_slot].slot = tmp.slot; you.inv[from_slot].link = from_slot; you.inv[to_slot].link = to_slot; diff --git a/crawl-ref/source/delay.cc b/crawl-ref/source/delay.cc index ea9be8acf5..abbeadd299 100644 --- a/crawl-ref/source/delay.cc +++ b/crawl-ref/source/delay.cc @@ -996,6 +996,14 @@ inline static void monster_warning(activity_interrupt_type ai, if (at.context != "uncharm") mprf(MSGCH_WARN, "%s comes into view.", mon->name(DESC_CAP_A).c_str()); + + if (Options.tutorial_left) + { + // enforce that this message comes first + tutorial_first_monster(*mon); + if (get_mons_colour(mon) != mon->colour) + learned_something_new(TUT_MONSTER_BRAND); + } #else formatted_string fs( channel_to_colour(MSGCH_WARN) ); fs.cprintf("%s (", mon->name(DESC_PLAIN, true).c_str()); diff --git a/crawl-ref/source/describe.cc b/crawl-ref/source/describe.cc index 8d081759a9..d1d2401f9d 100644 --- a/crawl-ref/source/describe.cc +++ b/crawl-ref/source/describe.cc @@ -50,6 +50,7 @@ #include "spl-book.h" #include "stuff.h" #include "spl-util.h" +#include "tutorial.h" // ======================================================================== @@ -3310,6 +3311,13 @@ void describe_feature_wide(int x, int y) clrscr(); print_description(desc); + + if (Options.tutorial_left) + { + gotoxy(1, wherey() + 2); + tutorial_describe_feature(grd[x][y]); + } + if ( getch() == 0 ) getch(); } @@ -3378,6 +3386,12 @@ void describe_item( item_def &item ) break; } + if (Options.tutorial_left) + { + gotoxy(1, wherey() + 2); + tutorial_describe_item(item); + } + gotoxy(1, wherey() + 2); formatted_string::parse_string("<cyan>Do you wish to inscribe this item? ").display(); diff --git a/crawl-ref/source/direct.cc b/crawl-ref/source/direct.cc index 11acd1c91f..36ab799592 100644 --- a/crawl-ref/source/direct.cc +++ b/crawl-ref/source/direct.cc @@ -47,6 +47,7 @@ #include "spells4.h" #include "stash.h" #include "travel.h" +#include "tutorial.h" #include "view.h" #include "macro.h" @@ -1763,7 +1764,13 @@ static void describe_cell(int mx, int my) marker.c_str(), traveldest.c_str()); #else - mpr(feature_desc.c_str()); + if (Options.tutorial_left && tutorial_feat_interesting(grd[mx][my])) + { + feature_desc += " (Press <w>v<lightgray> for more information.)"; + print_formatted_paragraph(feature_desc, 80); + } + else + mpr(feature_desc.c_str()); #endif } diff --git a/crawl-ref/source/enum.h b/crawl-ref/source/enum.h index 238de7b1c3..bea9e7d856 100644 --- a/crawl-ref/source/enum.h +++ b/crawl-ref/source/enum.h @@ -3768,54 +3768,59 @@ enum tutorial_event_type { TUT_SEEN_FIRST_OBJECT, // 0 // seen certain items - TUT_SEEN_POTION, + TUT_SEEN_POTION, TUT_SEEN_SCROLL, TUT_SEEN_WAND, TUT_SEEN_SPBOOK, - TUT_SEEN_JEWELLERY, // 5 - TUT_SEEN_MISC, + TUT_SEEN_JEWELLERY, // 5 + TUT_SEEN_MISC, TUT_SEEN_STAFF, TUT_SEEN_WEAPON, TUT_SEEN_MISSILES, TUT_SEEN_ARMOUR, // 10 - TUT_SEEN_RANDART, - TUT_SEEN_FOOD, + TUT_SEEN_RANDART, + TUT_SEEN_FOOD, TUT_SEEN_CARRION, // encountered dungeon features - TUT_SEEN_STAIRS, - TUT_SEEN_ESCAPE_HATCH, // 15 - TUT_SEEN_TRAPS, + TUT_SEEN_STAIRS, // 14 + TUT_SEEN_ESCAPE_HATCH, + TUT_SEEN_TRAP, TUT_SEEN_ALTAR, TUT_SEEN_SHOP, TUT_SEEN_DOOR, // other 'first events' TUT_SEEN_MONSTER, // 20 - TUT_KILLED_MONSTER, + TUT_MONSTER_BRAND, + TUT_KILLED_MONSTER, TUT_NEW_LEVEL, TUT_SKILL_RAISE, - TUT_YOU_ENCHANTED, - TUT_YOU_SICK, // 25 - TUT_YOU_POISON, - TUT_YOU_CURSED, - TUT_YOU_HUNGRY, - TUT_YOU_STARVING, - TUT_MULTI_PICKUP, // 30 - TUT_HEAVY_LOAD, + TUT_MAKE_CHUNKS, // 25 + TUT_OFFER_CORPSE, + TUT_NEW_ABILITY, + TUT_FLEEING_MONSTER, TUT_ROTTEN_FOOD, - TUT_NEED_HEALING, + // status changes + TUT_YOU_ENCHANTED, // 30 + TUT_YOU_SICK, + TUT_YOU_POISON, + TUT_YOU_CURSED, + TUT_YOU_HUNGRY, + TUT_YOU_STARVING, // 35 + TUT_YOU_MUTATED, + TUT_POSTBERSERK, + // warning + TUT_RUN_AWAY, // 38 + TUT_RETREAT_CASTER, + TUT_WIELD_WEAPON, + TUT_NEED_HEALING, TUT_NEED_POISON_HEALING, - TUT_RUN_AWAY, // 35 - TUT_MAKE_CHUNKS, - TUT_OFFER_CORPSE, - TUT_POSTBERSERK, + // interface + TUT_MULTI_PICKUP, // 43 + TUT_HEAVY_LOAD, TUT_SHIFT_RUN, - TUT_MAP_VIEW, // 40 + TUT_MAP_VIEW, TUT_DONE_EXPLORE, - TUT_YOU_MUTATED, - TUT_NEW_ABILITY, - TUT_WIELD_WEAPON, - TUT_FLEEING_MONSTER, - TUT_EVENTS_NUM // 46 + TUT_EVENTS_NUM // 48 }; // for numbers higher than 48 change size of tutorial_events in externs.h enum tutorial_types diff --git a/crawl-ref/source/itemprop.h b/crawl-ref/source/itemprop.h index 5904722a4a..49e64b20c0 100644 --- a/crawl-ref/source/itemprop.h +++ b/crawl-ref/source/itemprop.h @@ -1,5 +1,5 @@ /* - * File: itemname.cc + * File: itemprop.h * Summary: Misc functions. * Written by: Brent Ross * diff --git a/crawl-ref/source/items.cc b/crawl-ref/source/items.cc index 67cd67a401..7b1f6f46eb 100644 --- a/crawl-ref/source/items.cc +++ b/crawl-ref/source/items.cc @@ -1388,6 +1388,9 @@ int move_item_to_player( int obj, int quant_got, bool quiet ) item.y = -1; item.link = freeslot; + if (!item.slot) + item.slot = index_to_letter(item.link); + autoinscribe_item( item ); origin_freeze(item, you.x_pos, you.y_pos); diff --git a/crawl-ref/source/misc.cc b/crawl-ref/source/misc.cc index ef24bd534f..0749ec3637 100644 --- a/crawl-ref/source/misc.cc +++ b/crawl-ref/source/misc.cc @@ -1663,7 +1663,7 @@ void handle_traps(char trt, int i, bool trap_known) 75 + random2(100), 3, "a Zot trap" ); break; } - learned_something_new(TUT_SEEN_TRAPS, you.x_pos, you.y_pos); + learned_something_new(TUT_SEEN_TRAP, you.x_pos, you.y_pos); } // end handle_traps() void disarm_trap( struct dist &disa ) diff --git a/crawl-ref/source/tutorial.cc b/crawl-ref/source/tutorial.cc index 2e12854dff..fd5642bcb0 100644 --- a/crawl-ref/source/tutorial.cc +++ b/crawl-ref/source/tutorial.cc @@ -2,14 +2,15 @@ * Created for Crawl Reference by JPEG on $Date: 2007-01-11$ */ +#include "tutorial.h" #include <cstring> #include <sstream> -#include "tutorial.h" #include "cio.h" #include "command.h" #include "files.h" #include "initfile.h" +#include "itemname.h" #include "itemprop.h" #include "menu.h" #include "message.h" @@ -17,7 +18,9 @@ #include "newgame.h" #include "output.h" #include "player.h" +#include "randart.h" #include "religion.h" +#include "skills2.h" #include "spl-util.h" #include "stuff.h" #include "view.h" @@ -27,7 +30,7 @@ static job_type get_tutorial_job(unsigned int type); //#define TUTORIAL_DEBUG -#define TUTORIAL_VERSION 110 +#define TUTORIAL_VERSION 111 static int get_tutorial_cols() { @@ -39,7 +42,7 @@ void save_tutorial( FILE* fp ) { writeLong( fp, TUTORIAL_VERSION); writeShort( fp, Options.tutorial_type); - for ( unsigned i = 0; i < TUT_EVENTS_NUM; ++i ) + for ( long i = 0; i < TUT_EVENTS_NUM; ++i ) writeShort( fp, Options.tutorial_events[i] ); } @@ -48,9 +51,10 @@ void load_tutorial( FILE* fp ) Options.tutorial_left = 0; int version = readLong(fp); - Options.tutorial_type = readShort(fp); if (version != TUTORIAL_VERSION) return; + + Options.tutorial_type = readShort(fp); for ( long i = 0; i < TUT_EVENTS_NUM; ++i ) { Options.tutorial_events[i] = readShort(fp); @@ -232,7 +236,7 @@ static formatted_string tut_starting_info(unsigned int width) " <white>?</white> - shows the items and the commands" EOL " <white>S</white> - saves the game, to be resumed later " "(but note that death is permanent)" EOL - " <white>x</white> - examine something in your vicinity" EOL EOL + " <white>x</white> - examines something in your vicinity" EOL EOL "This tutorial will help you play Crawl without reading any " "documentation. If you feel intrigued, there is more information " "available in these files (all of which can also be read in-game):" @@ -290,7 +294,7 @@ static std::string tut_debug_list(int event) return "seen first stairs"; case TUT_SEEN_ESCAPE_HATCH: return "seen first escape hatch"; - case TUT_SEEN_TRAPS: + case TUT_SEEN_TRAP: return "encountered a trap"; case TUT_SEEN_ALTAR: return "seen an altar"; @@ -334,6 +338,8 @@ static std::string tut_debug_list(int event) return "learned about Berserk aftereffects"; case TUT_RUN_AWAY: return "were told to run away"; + case TUT_RETREAT_CASTER: + return "were told to retreat as a caster"; case TUT_SHIFT_RUN: return "learned about shift-run"; case TUT_MAP_VIEW: @@ -348,6 +354,8 @@ static std::string tut_debug_list(int event) return "wielded an unsuitable weapon"; case TUT_FLEEING_MONSTER: return "made a monster flee"; + case TUT_MONSTER_BRAND: + return "learned about colour brandings"; default: return "faced a bug"; } @@ -407,7 +415,7 @@ static formatted_string tutorial_map_intro() result = "<magenta>" "What you see here is the typical Crawl screen. The upper left map " "shows your hero as the <white>@<magenta> in the center. The parts " - "of the map you remember but cannot currently see, will be greyed " + "of the map you remember but cannot currently see will be greyed " "out." "</magenta>" EOL; result += " --more-- Press <white>Escape</white> to skip the basics"; @@ -552,8 +560,10 @@ void tutorial_death_screen() if (Options.tutorial_type == TUT_MAGIC_CHAR && Options.tut_spell_counter < Options.tut_melee_counter ) + { text = "As a Conjurer your main weapon should be offensive magic. Cast " - "spells more often! Remember to rest when your Magic is low."; + "spells more often! Remember to rest when your Magic is low."; + } else if (Options.tutorial_type == TUT_BERSERK_CHAR && Options.tut_berserk_counter < 1 ) { @@ -828,39 +838,35 @@ void tutorial_first_monster(const monsters& mon) text += ch; text += "<magenta> is a monster, usually depicted by a letter. Some typical " "early monsters look like <brown>r<magenta>, <w>g<magenta>, " - "<lightgray>b<magenta> or <brown>K<magenta>. You can gain " - "information about it by pressing <w>x<magenta>, moving the cursor " - "on the monster and then pressing <w>v<magenta>. To attack it with " - "your wielded weapon, just move into it."; + "<lightgray>b<magenta> or <brown>K<magenta>. "; + + if (get_mons_colour(&mon) != (&mon)->colour) + learned_something_new(TUT_MONSTER_BRAND); + else + { + text += "You can gain information about it by pressing <w>x<magenta> " + "and moving the cursor on the monster."; + } + text += "\nTo attack this monster with your wielded weapon, just move into " + "it."; + print_formatted_paragraph(text, get_tutorial_cols(), MSGCH_TUTORIAL); - more(); - if (Options.tutorial_type == TUT_RANGER_CHAR) { + more(); text = "However, as a hunter you will want to deal with it using your " - "bow. Do this as follows: <w>wbff<magenta> where <w>wb<magenta> " - "wields the bow, and <w>ff<magenta> fires appropriate ammunition " - "(your arrows) at the nearest hostile monster. If you'd like to " - "choose a new monster you can type <w>f<magenta> followed by " - "<w>+<magenta> or <w>-<magenta> instead to cycle through the " - "available targets. Then press <w>Enter<magenta>, <w>f<magenta> " - "or <w>.<magenta> to fire. If you miss, <w>ff<magenta> fires at " - "the previous target again."; + "bow. If you have a look at your bow with <w>v<magenta>, you'll " + "find an explanation of how to do this. First <w>w<magenta>ield " + "it, then follow the instructions."; print_formatted_paragraph(text, get_tutorial_cols(), MSGCH_TUTORIAL); } else if (Options.tutorial_type == TUT_MAGIC_CHAR) { + more(); text = "However, as a conjurer you will want to deal with it using magic. " - "Do this as follows: <w>Za.<magenta> where <w>Za<magenta> zaps " - "the first spell you know, "; - text += spell_title(get_spell_by_letter('a')); - text += ", and <w>.<magenta> shoots at the targetted monster (the closest " - "hostile monster). To target a different monster, use <w>+<magenta> " - "or <w>-<magenta> to cycle through the available targets. " - "<w>Enter<magenta>, <w>f<magenta> or <w>.<magenta> will fire. If you " - "miss, <w>Za<magenta> followed by any of the aforementioned keys " - "will fire at it again."; + "If you have a look at your spellbook with <w>v<magenta>, you'll " + "find an explanation of how to do this."; print_formatted_paragraph(text, get_tutorial_cols(), MSGCH_TUTORIAL); } @@ -986,7 +992,7 @@ void learned_something_new(tutorial_event_type seen_what, int x, int y) if (you.species == SP_CENTAUR || you.species == SP_MINOTAUR) { text << "\nNote that as a " << species_name(you.species, 1) - << "you will be unable to wear " + << " you will be unable to wear " << (you.species == SP_CENTAUR ? "boots" : "helmets"); } break; @@ -1030,7 +1036,7 @@ void learned_something_new(tutorial_event_type seen_what, int x, int y) text << "You have picked up a magic staff or a rod, both of which are " "represented by '<w>" << static_cast<char>(ch) - << "<magenta>'. Both must be <w>i<magenta>elded to be of use. " + << "<magenta>'. Both must be <w>w<magenta>ielded to be of use. " "Magicians use staves to increase their power in certain spell " "schools. By contrast, a rod allows the casting of certain " "spells even without magic knowledge simply by " @@ -1053,6 +1059,9 @@ void learned_something_new(tutorial_event_type seen_what, int x, int y) break; case TUT_SEEN_ESCAPE_HATCH: + if (you.num_turns < 1) + return; + object = env.show[ex][ey]; colour = env.show_col[ex][ey]; get_item_symbol( object, &ch, &colour ); @@ -1064,15 +1073,15 @@ void learned_something_new(tutorial_event_type seen_what, int x, int y) "quickly leave a level with <w><<<magenta> and <w>><magenta>, " "respectively, but will usually be unable to return right away."; break; - case TUT_SEEN_TRAPS: + case TUT_SEEN_TRAP: object = env.show[ex][ey]; colour = env.show_col[ex][ey]; get_item_symbol( object, &ch, &colour ); text << "Oops... you just triggered a trap. An unwary adventurer will " "occasionally stumble into one of these nasty constructions " - "depicted by <w>^<magenta>. They can do physical damage (with " - "darts or needles, for example) or have other, more magical " - "effects, like teleportation."; + "depicted by " << colour_to_tag(colour) << "^<magenta>. They " + "can do physical damage (with darts or needles, for example) " + "or have other, more magical effects, like teleportation."; break; case TUT_SEEN_ALTAR: object = env.show[ex][ey]; @@ -1131,8 +1140,8 @@ void learned_something_new(tutorial_event_type seen_what, int x, int y) } break; case TUT_SKILL_RAISE: - text << "One of your skills just got raised. Type <w>m<magenta> to take " - "a look at your skills screen."; + text << "One of your skills just got raised. To view or manage your " + "skill set, type <w>m<magenta>."; break; case TUT_YOU_ENCHANTED: text << "Enchantments of all types can befall you temporarily. " @@ -1291,6 +1300,11 @@ void learned_something_new(tutorial_event_type seen_what, int x, int y) "to temporarily gain more hitpoints and greater strength. "; } break; + case TUT_RETREAT_CASTER: + text << "Without magical power you're unable to cast spells. While " + "melee is a possibility, that's not where your strengths lie, " + "so retreat (if possible) might be the better option."; + break; case TUT_YOU_MUTATED: text << "Mutations can be obtained from several sources, among them " "potions, spell miscasts, and overuse of strong enchantments " @@ -1301,7 +1315,7 @@ void learned_something_new(tutorial_event_type seen_what, int x, int y) break; case TUT_NEW_ABILITY: text << "You just gained a new ability. Press <w>a<magenta> to take a " - "look at your abilities or to use one of them."; + "look at your abilities or to use one of them."; break; case TUT_WIELD_WEAPON: if (Options.tutorial_type == TUT_RANGER_CHAR @@ -1325,6 +1339,11 @@ void learned_something_new(tutorial_event_type seen_what, int x, int y) "<w>f+.<magenta> instead; the game will pick the first weapon " "that fits the option."; break; + case TUT_MONSTER_BRAND: + text << "That monster looks a bit unusual. You might wish to examine " + "it a bit more closely by pressing <w>x<magenta> and moving " + "the cursor onto its square."; + break; case TUT_SEEN_MONSTER: case TUT_SEEN_FIRST_OBJECT: break; @@ -1366,3 +1385,452 @@ formatted_string tut_abilities_info() } return formatted_string::parse_string(text.str(), false); } + +// a short explanation of Crawl's target mode +// and the most important commands +static std::string tut_target_mode(bool spells = false) +{ + std::string result; + result = "You'll then find yourself in target mode with the nearest monster " + "or previous target already targetted. You can also cycle through " + "all hostile monsters in sight with <w>+<magenta> or <w>-<magenta>. " + "Once you're aiming at the correct monster, simply hit " + "<w>f<magenta>, <w>Enter<magenta> or <w>.<magenta> to shoot at it. " + "If you miss, <w> "; + + if (spells) + result += "Zap"; + else + result += "ff"; + + result += "<magenta> fires at the same target again."; + + return (result); +} + +static std::string tut_throw_stuff(item_def &item) +{ + std::string result; + + result = "To do this, type <w>t<magenta> to throw, then <w>"; + result += item.slot; + result += "<magenta> for "; + result += (item.quantity > 1 ? "these" : "this"); + result += " "; + result += item_base_name(item); + result += (item.quantity > 1? "s" : ""); + result += ". "; + result += tut_target_mode(); + + return (result); +} + +void tutorial_describe_item(item_def &item) +{ + std::ostringstream ostr; + ostr << "<magenta>"; + switch (item.base_type) + { + case OBJ_WEAPONS: + { + // for identified artefacts don't give all this information + // (The screen is likely to overflow.) + if (is_artefact(item) && item_type_known(item)) + return; + + item_def *weap = you.slot_item(EQ_WEAPON); + bool wielded = (*weap).slot == item.slot; + bool long_text = false; + + if (!wielded) + { + ostr << "You can wield this weapon with <w>w<magenta>, or use " + "<w>'<magenta> to switch between the weapons in slot " + "a and b. (Use <w>=<magenta> to adjust item slots.)"; + + // weapon skill used by this weapon and the best weapon skill + int curr_wpskill, best_wpskill; + + // maybe this is a launching weapon + if (is_range_weapon(item)) + { + // then only compare with other launcher skills + curr_wpskill = range_skill(item); + best_wpskill = best_skill(SK_SLINGS, SK_DARTS, 99); + } + else + { + // compare with other melee weapons + curr_wpskill = weapon_skill(item); + best_wpskill = best_skill(SK_SHORT_BLADES, SK_STAVES, 99); + // maybe unarmed is better + if (you.skills[SK_UNARMED_COMBAT] > you.skills[best_wpskill]) + best_wpskill = SK_UNARMED_COMBAT; + } + + if (you.skills[curr_wpskill] + 2 < you.skills[best_wpskill]) + { + ostr << "\nOn second look you've been training in <w>" + << skill_name(best_wpskill) + << "<magenta> for a while, so maybe you should " + "continue training that rather than <w>" + << skill_name(curr_wpskill) + << "<magenta>. (Type <w>m<magenta> to see the skill " + "management screen for the actual numbers.)"; + long_text = true; + } + } + else // wielded weapon + { + if (is_range_weapon(item)) + { + ostr << "To attack a monster, you only need to " + "<w>f<magenta>ire the appropriate type of ammunition. "; + ostr << tut_target_mode(); + } + else + { + ostr << "To attack a monster, you can simply walk into it."; + } + } + if (is_throwable(item, you.body_size()) && !long_text) + { + ostr << "\n\nSome weapons (including this one), can also be used " + "for ranged combat. "; + ostr << tut_throw_stuff(item); + long_text = true; + } + if (!item_type_known(item) && + (is_artefact(item) || get_equip_desc( item ) != ISFLAG_NO_DESC)) + { + ostr << "\n\nWeapons and armour that have unusual descriptions " + << "like this are much more likely to be of higher " + << "enchantment or have special properties, good or bad. " + << "The rarer the description, the greater the potential " + << "value of an item."; + + Options.tutorial_events[TUT_SEEN_RANDART] = 0; + } + if (item_known_cursed( item ) && !long_text) + { + ostr << "\n\nOnce wielded, a cursed weapon won't leave your hands " + "again until the curse has been lifted by reading a " + "scroll of remove curse."; + if (!wielded && is_throwable(item, you.body_size())) + ostr << " (Throwing it is safe, though.)"; + + Options.tutorial_events[TUT_YOU_CURSED] = 0; + } + Options.tutorial_events[TUT_SEEN_WEAPON] = 0; + break; + } + case OBJ_MISSILES: + if (item.sub_type == MI_JAVELIN || item.sub_type == MI_SLING_BULLET + || item.sub_type == MI_DART || item.sub_type == MI_STONE) + { + ostr << item.name(DESC_CAP_YOUR) + << " can be thrown without the use of a launcher. "; + ostr << tut_throw_stuff(item); + } + else if (is_launched(&you, you.weapon(), item)) + { + ostr << "As you're already wielding the appropriate launcher, " + "you can simply <w>f<magenta>ire " + << (item.quantity > 1 ? "these" : "this") + << " " << item.name(DESC_BASENAME) + << (item.quantity > 1? "s" : "") + << ". "; + ostr << tut_target_mode(); + } + else + { + ostr << "To shoot " + << (item.quantity > 1 ? "these" : "this") + << " " << item.name(DESC_BASENAME) + << (item.quantity > 1? "s" : "") + << ", first you need to <w>w<magenta>ield an appropriate " + "launcher."; + } + Options.tutorial_events[TUT_SEEN_MISSILES] = 0; + break; + + case OBJ_ARMOUR: + ostr << "You can wear pieces of armour with <w>W<magenta> and take " + "them off again with <w>T<magenta>. "; + + if (!item_type_known(item) && + (is_artefact(item) || get_equip_desc( item ) != ISFLAG_NO_DESC)) + { + ostr << "\n\nWeapons and armour that have unusual descriptions " + << "like this are much more likely to be of higher " + << "enchantment or have special properties, good or bad. " + << "The rarer the description, the greater the potential " + << "value of an item."; + + Options.tutorial_events[TUT_SEEN_RANDART] = 0; + } + if (item_known_cursed( item )) + { + ostr << "\nA cursed piece of armour, once worn, cannot be removed " + "again until the curse has been lifted by reading a " + "scroll of remove curse."; + } + Options.tutorial_events[TUT_SEEN_ARMOUR] = 0; + break; + + case OBJ_WANDS: + ostr << "The magic within can be unleashed by <w>z<magenta>apping it."; + Options.tutorial_events[TUT_SEEN_WAND] = 0; + break; + + case OBJ_FOOD: + ostr << "Food can simply be <w>e<magenta>aten. "; + if (item.sub_type == FOOD_CHUNK) + { + ostr << "Note that most species refuse to eat raw meat unless " + "really hungry. "; + if (item.special < 100) + { + ostr << "Even fewer can safely digest rotten meat, and you're " + "probably not part of this group."; + } + } + Options.tutorial_events[TUT_SEEN_FOOD] = 0; + break; + + case OBJ_SCROLLS: + ostr << "Type <w>r<magenta> to read this scroll. "; + Options.tutorial_events[TUT_SEEN_SCROLL] = 0; + break; + + case OBJ_JEWELLERY: + ostr << "Jewellery can be <w>P<magenta>ut on or <w>R<magenta>emoved " + "again. "; + + if (item_known_cursed( item )) + { + ostr << "\nA cursed piece of jewellery will cling to its " + "unfortunate wearer's neck or fingers until the curse is " + "finally lifted when he or she reads a scroll of remove " + "curse."; + } + Options.tutorial_events[TUT_SEEN_JEWELLERY] = 0; + break; + + case OBJ_POTIONS: + ostr << "Use <w>q<magenta> to quaff this potion. "; + Options.tutorial_events[TUT_SEEN_POTION] = 0; + break; + + case OBJ_BOOKS: + if (!item_ident(item, ISFLAG_KNOW_TYPE)) + { + ostr << "It's a book, you can <w>r<magenta>ead it. "; + } + else + { + if (item.sub_type == BOOK_MANUAL) + { + ostr << "A manual can greatly help you in training a skill. " + "To use it, <w>r<magenta>ead it while your experience " + "pool (the number in brackets) is full. Note that " + "this will drain said pool, so only use this manual " + "if you think you need the skill in question."; + } + else + { + ostr << "A spellbook! You could <w>M<magenta>emorize some " + "spells and then cast them with <w>Z<magenta>. "; + if (you.religion == GOD_TROG) + { + ostr << "\nAs a worshipper of " + << god_name(GOD_TROG) + << ", though, you might instead wish to burn this " + "tome of hated magic, by using the corresponding " + "<w>a<magenta>bility. " + "Note that this only works on books that are " + "lying on the floor and not on your current " + "square. "; + } + else if (!you.skills[SK_SPELLCASTING]) + { + ostr << "\nFor now, however, that will have to wait " + "until you've learned the basics of Spellcasting " + "by reading lots of scrolls."; + } + else + { + ostr << "Do this as follows: Type <w>Z<magenta>, then " + "choose the spell you want to cast (with " + "<w>?<magenta>), for example <w>a<magenta>, " + "which is the first spell you know, " + << spell_title(get_spell_by_letter('a')) + << ". "; + ostr << tut_target_mode(true); + } + } + } + Options.tutorial_events[TUT_SEEN_SPBOOK] = 0; + break; + + case OBJ_CORPSES: + ostr << "Corpses lying on the floor can be <w>D<magenta>issected " + "with a sharp implement to produce chunks for food " + "(though they may not be healthy)"; + + if (god_likes_butchery(you.religion)) + { + ostr << ", or as a sacrifice to " + << god_name(you.religion) + << " (while <w>p<magenta>raying)"; + } + + ostr << ". "; + if (item.special < 100) + ostr << "Rotten corpses won't be of any use to you, though, so " + "you might just as well <w>d<magenta>rop this."; + Options.tutorial_events[TUT_SEEN_CARRION] = 0; + break; + + case OBJ_STAVES: + ostr << "Staffs have to be <w>w<magenta>ielded to be of use. " + "There are staves that help spellcasters, and others that " + "allow you to harness spells hidden within."; + if (!item_ident(item, ISFLAG_KNOW_TYPE)) + { + ostr << "\n\nTo find out what this staff might do, you have to " + "wield it, then <w>E<magenta>voke it to see if anything " + "interesting happens. If nothing happens, it's probably " + "an ancient staff capable of enhancing certain spell " + "schools while suppressing others. "; + if (you.spell_no) + { + ostr << "You can find out which one, by casting spells while " + "wielding this staff. Eventually, the staff might " + "react to a spell of its school and identify itself."; + } + } + Options.tutorial_events[TUT_SEEN_STAFF] = 0; + break; + + case OBJ_MISCELLANY: + ostr << "Miscellanous items sometimes harbour magical powers. Try " + "<w>w<magenta>ielding and <w>E<magenta>voking it."; + Options.tutorial_events[TUT_SEEN_MISC] = 0; + break; + + default: + return; + } + + std::string broken = ostr.str(); + linebreak_string2(broken, get_tutorial_cols()); + formatted_string::parse_block(broken, false).display(); +} + +bool tutorial_feat_interesting(int feat) +{ + switch (feat) + { + case DNGN_CLOSED_DOOR: + case DNGN_OPEN_DOOR: + case DNGN_ORCISH_IDOL: + case DNGN_GRANITE_STATUE: + case DNGN_SILVER_STATUE: + case DNGN_ORANGE_CRYSTAL_STATUE: + case DNGN_TRAP_MAGICAL: + case DNGN_TRAP_MECHANICAL: + case DNGN_STONE_STAIRS_DOWN_I: + case DNGN_STONE_STAIRS_DOWN_II: + case DNGN_STONE_STAIRS_DOWN_III: + case DNGN_STONE_STAIRS_UP_I: + case DNGN_STONE_STAIRS_UP_II: + case DNGN_STONE_STAIRS_UP_III: + case DNGN_ROCK_STAIRS_DOWN: + case DNGN_ROCK_STAIRS_UP: + return true; + default: + return false; + } +} + +void tutorial_describe_feature(int feat) +{ + std::ostringstream ostr; + ostr << "<magenta>"; + + switch (feat) + { + case DNGN_CLOSED_DOOR: + ostr << "You can open it by walking into it."; + Options.tutorial_events[TUT_SEEN_DOOR]; + break; + case DNGN_OPEN_DOOR: + ostr << "You can close an open door if you stand next to it while " + "the doorway's empty, and then press <w>c<magenta> followed " + "by the direction of the door."; + Options.tutorial_events[TUT_SEEN_DOOR]; + break; + case DNGN_ORCISH_IDOL: + case DNGN_GRANITE_STATUE: + case DNGN_SILVER_STATUE: + case DNGN_ORANGE_CRYSTAL_STATUE: + ostr << "Beware! Sometimes such a statue actually has a mind of its own."; + break; + case DNGN_TRAP_MAGICAL: + case DNGN_TRAP_MECHANICAL: + ostr << "These nasty constructions can do physical damage (with " + "darts or needles, for example) or have other, more magical " + "effects. "; + if (feat == DNGN_TRAP_MECHANICAL) + { + ostr << "You can attempt to deactivate the mechanical type by " + "standing next to it and then pressing <w>Shift<magenta> " + "and the direction of the trap. Note that this usually " + "causes the trap to go off, so it can be quite a " + "dangerous task."; + } + Options.tutorial_events[TUT_SEEN_TRAP]; + break; + case DNGN_STONE_STAIRS_DOWN_I: + case DNGN_STONE_STAIRS_DOWN_II: + case DNGN_STONE_STAIRS_DOWN_III: + ostr << "You can enter the next (deeper) level by following them " + "down (<w>><magenta>). To get back to this level again, " + "press <w><<<magenta> while standing on the upstairs."; + Options.tutorial_events[TUT_SEEN_STAIRS]; + break; + case DNGN_STONE_STAIRS_UP_I: + case DNGN_STONE_STAIRS_UP_II: + case DNGN_STONE_STAIRS_UP_III: + if (you.your_level < 1) + { + ostr << "These stairs lead out of the dungeon. Following them " + "will end the game. The only way to win is to transport " + "the fabled orb of Zot outside."; + } + else + { + ostr << "You can enter the previous (lower) level by following " + "these down (<w><<<magenta>). To get back to this level " + "again, press <w>><magenta> while standing on the " + "downstairs."; + } + Options.tutorial_events[TUT_SEEN_STAIRS]; + break; + + case DNGN_ROCK_STAIRS_DOWN: + case DNGN_ROCK_STAIRS_UP: + ostr << "Escape hatches can be used to quickly leave a level with " + "<w><<<magenta> and <w>><magenta>, respectively. Note that " + "you will usually be unable to return right away."; + Options.tutorial_events[TUT_SEEN_ESCAPE_HATCH]; + break; + default: + return; + } + + std::string broken = ostr.str(); + linebreak_string2(broken, get_tutorial_cols()); + formatted_string::parse_block(broken, false).display(); +} diff --git a/crawl-ref/source/tutorial.h b/crawl-ref/source/tutorial.h index 3c93228cc7..2763b08650 100644 --- a/crawl-ref/source/tutorial.h +++ b/crawl-ref/source/tutorial.h @@ -37,5 +37,8 @@ void tutorial_first_monster(const monsters& mon); void tutorial_first_item(const item_def& item); void learned_something_new(tutorial_event_type seen_what, int x=0, int y=0); formatted_string tut_abilities_info(); +void tutorial_describe_item(item_def& item); +bool tutorial_feat_interesting(int feat); +void tutorial_describe_feature(int feat); #endif diff --git a/crawl-ref/source/view.cc b/crawl-ref/source/view.cc index 28b32242ca..09ef72e530 100644 --- a/crawl-ref/source/view.cc +++ b/crawl-ref/source/view.cc @@ -584,7 +584,7 @@ void clear_map(bool clear_detected_items, bool clear_detected_monsters) } } -static int get_mons_colour(const monsters *mons) +int get_mons_colour(const monsters *mons) { int col = mons->colour; diff --git a/crawl-ref/source/view.h b/crawl-ref/source/view.h index a3965502aa..1cb1553d56 100644 --- a/crawl-ref/source/view.h +++ b/crawl-ref/source/view.h @@ -107,6 +107,7 @@ void get_item_symbol(unsigned int object, unsigned *ch, // Applies EC_ colour substitutions and brands. unsigned real_colour(unsigned raw_colour); +int get_mons_colour(const monsters *mons); void set_envmap_obj( int x, int y, int object ); unsigned get_envmap_char(int x, int y); |