diff options
author | j-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573> | 2007-08-15 21:32:33 +0000 |
---|---|---|
committer | j-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573> | 2007-08-15 21:32:33 +0000 |
commit | 054c713cec71c3010b1ac3eb0848f2b601db982f (patch) | |
tree | da7a575a718b842b7ea15bb8ffc59efdccc2ff95 /crawl-ref/source/tutorial.cc | |
parent | 54f595ca30391a4e95ae1f46706d9c7cc5a6b6a8 (diff) | |
download | crawl-ref-054c713cec71c3010b1ac3eb0848f2b601db982f.tar.gz crawl-ref-054c713cec71c3010b1ac3eb0848f2b601db982f.zip |
More stuff for the tutorial:
- Enhanced handling of spellbooks and artefacts.
- Feature descriptions now cover altars.
- Added monster descriptions (out of depth and brands).
Also:
- space-only inscription counts as no inscription
- ring of teleportation autoID's if no teleport randart
In my last commit I forgot to mention that the
descriptions were suggested by Richard Gould, and
I'd like to give credit where credit is due. :)
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@2005 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref/source/tutorial.cc')
-rw-r--r-- | crawl-ref/source/tutorial.cc | 301 |
1 files changed, 257 insertions, 44 deletions
diff --git a/crawl-ref/source/tutorial.cc b/crawl-ref/source/tutorial.cc index fd5642bcb0..a9df4e5746 100644 --- a/crawl-ref/source/tutorial.cc +++ b/crawl-ref/source/tutorial.cc @@ -15,12 +15,16 @@ #include "menu.h" #include "message.h" #include "misc.h" +#include "mon-pick.h" +#include "mon-util.h" +#include "monstuff.h" #include "newgame.h" #include "output.h" #include "player.h" #include "randart.h" #include "religion.h" #include "skills2.h" +#include "spl-book.h" #include "spl-util.h" #include "stuff.h" #include "view.h" @@ -821,40 +825,39 @@ static std::string colour_to_tag(int col, bool closed = false) return tag; } -void tutorial_first_monster(const monsters& mon) +void tutorial_first_monster(const monsters &mon) { if (!Options.tutorial_events[TUT_SEEN_MONSTER]) return; + // crude hack: + // if the first monster is sleeping wake it + // (highlighting is an unnecessary complication) + if (get_mons_colour(&mon) != (&mon)->colour) + { + noisy(1, mon.x, mon.y); + viewwindow(true, false); + } + unsigned ch; unsigned short col; get_mons_glyph(&mon, &ch, &col); - if (ch == ' ') // happens if monster standing on dropped corpse or item - return; - std::string text = "<magenta>That "; text += colour_to_tag(col); 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>. "; - - 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 " + "<lightgray>b<magenta> or <brown>K<magenta>. You can gain information " + "about it by pressing <w>x<magenta> and moving the cursor on the " + "monster." + "\nTo attack this monster with your wielded weapon, just move into " "it."; print_formatted_paragraph(text, get_tutorial_cols(), MSGCH_TUTORIAL); if (Options.tutorial_type == TUT_RANGER_CHAR) { - more(); text = "However, as a hunter you will want to deal with it using your " "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 " @@ -863,7 +866,6 @@ void tutorial_first_monster(const monsters& mon) } else if (Options.tutorial_type == TUT_MAGIC_CHAR) { - more(); text = "However, as a conjurer you will want to deal with it using magic. " "If you have a look at your spellbook with <w>v<magenta>, you'll " "find an explanation of how to do this."; @@ -875,7 +877,7 @@ void tutorial_first_monster(const monsters& mon) Options.tut_just_triggered = 1; } -void tutorial_first_item(const item_def& item) +void tutorial_first_item(const item_def &item) { if (!Options.tutorial_events[TUT_SEEN_FIRST_OBJECT] || Options.tut_just_triggered) @@ -887,6 +889,9 @@ void tutorial_first_item(const item_def& item) unsigned short col; get_item_glyph(&item, &ch, &col); + if (ch == ' ') // happens if monster standing on dropped corpse or item + return; + std::string text = "<magenta>That "; text += colour_to_tag(col); text += ch; @@ -1077,6 +1082,9 @@ void learned_something_new(tutorial_event_type seen_what, int x, int y) object = env.show[ex][ey]; colour = env.show_col[ex][ey]; get_item_symbol( object, &ch, &colour ); + if (ch == ' ' || colour == BLACK) + colour = LIGHTCYAN; + text << "Oops... you just triggered a trap. An unwary adventurer will " "occasionally stumble into one of these nasty constructions " "depicted by " << colour_to_tag(colour) << "^<magenta>. They " @@ -1391,12 +1399,12 @@ formatted_string tut_abilities_info() 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>. " + result = "then be taken to 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 you miss, <w>"; if (spells) result += "Zap"; @@ -1408,6 +1416,13 @@ static std::string tut_target_mode(bool spells = false) return (result); } +static std::string tut_abilities() +{ + return ("To do this enter the ability menu with <w>a<magenta>, and then " + "choose the corresponding ability. Note that such an attempt of " + "activation, especially by the untrained, is likely to fail."); +} + static std::string tut_throw_stuff(item_def &item) { std::string result; @@ -1419,7 +1434,7 @@ static std::string tut_throw_stuff(item_def &item) result += " "; result += item_base_name(item); result += (item.quantity > 1? "s" : ""); - result += ". "; + result += ". You'll "; result += tut_target_mode(); return (result); @@ -1436,10 +1451,20 @@ void tutorial_describe_item(item_def &item) // for identified artefacts don't give all this information // (The screen is likely to overflow.) if (is_artefact(item) && item_type_known(item)) + { + // exception: you can activate it + if (gives_ability(item)) + { + ostr << "When wielded, some weapons (such as this one) " + "offer abilities that can be evoked. "; + ostr << tut_abilities(); + break; + } return; + } item_def *weap = you.slot_item(EQ_WEAPON); - bool wielded = (*weap).slot == item.slot; + bool wielded = (weap && (*weap).slot == item.slot); bool long_text = false; if (!wielded) @@ -1485,7 +1510,8 @@ void tutorial_describe_item(item_def &item) if (is_range_weapon(item)) { ostr << "To attack a monster, you only need to " - "<w>f<magenta>ire the appropriate type of ammunition. "; + "<w>f<magenta>ire the appropriate type of ammunition. " + "You'll "; ostr << tut_target_mode(); } else @@ -1539,7 +1565,7 @@ void tutorial_describe_item(item_def &item) << (item.quantity > 1 ? "these" : "this") << " " << item.name(DESC_BASENAME) << (item.quantity > 1? "s" : "") - << ". "; + << ". You'll "; ostr << tut_target_mode(); } else @@ -1555,8 +1581,25 @@ void tutorial_describe_item(item_def &item) break; case OBJ_ARMOUR: - ostr << "You can wear pieces of armour with <w>W<magenta> and take " - "them off again with <w>T<magenta>. "; + { + bool wearable = true; + if (you.species == SP_CENTAUR && item.sub_type == ARM_BOOTS) + { + ostr << "As a Centaur you cannot wear boots."; + wearable = false; + } + else if (you.species == SP_MINOTAUR && item.sub_type == ARM_HELMET + && get_helmet_type(item) != THELM_CAP + && get_helmet_type(item) != THELM_WIZARD_HAT) + { + ostr << "As a Minotaur you cannot wear helmets."; + wearable = false; + } + else + { + 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)) @@ -1569,15 +1612,21 @@ void tutorial_describe_item(item_def &item) Options.tutorial_events[TUT_SEEN_RANDART] = 0; } - if (item_known_cursed( item )) + if (item_known_cursed( item ) && wearable) { 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."; } + if (is_artefact(item) && gives_ability(item)) + { + ostr << "\nWhen worn, some types of armour (such as this one) " + "offer abilities that can be evoked. "; + ostr << tut_abilities(); + } 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; @@ -1604,6 +1653,7 @@ void tutorial_describe_item(item_def &item) break; case OBJ_JEWELLERY: + { ostr << "Jewellery can be <w>P<magenta>ut on or <w>R<magenta>emoved " "again. "; @@ -1614,9 +1664,15 @@ void tutorial_describe_item(item_def &item) "finally lifted when he or she reads a scroll of remove " "curse."; } + if (gives_ability(item)) + { + ostr << "\nWhen worn, some types of jewellery (such as this one) " + "offer abilities that can be evoked. "; + ostr << tut_abilities(); + } 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; @@ -1637,12 +1693,12 @@ void tutorial_describe_item(item_def &item) "this will drain said pool, so only use this manual " "if you think you need the skill in question."; } - else + else // it's a spellbook { - 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 << "A spellbook! You could <w>M<magenta>emorize some " + "spells and then cast them with <w>Z<magenta>. "; ostr << "\nAs a worshipper of " << god_name(GOD_TROG) << ", though, you might instead wish to burn this " @@ -1654,19 +1710,34 @@ void tutorial_describe_item(item_def &item) } else if (!you.skills[SK_SPELLCASTING]) { + ostr << "A spellbook! You could <w>M<magenta>emorize some " + "spells and then cast them with <w>Z<magenta>. "; ostr << "\nFor now, however, that will have to wait " "until you've learned the basics of Spellcasting " "by reading lots of scrolls."; } - else + else // actually can cast spells { - 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); + if (player_can_memorize(item)) + { + ostr << "Such a <lightblue>highlighted spell<magenta> " + "can be <w>M<magenta>emorized right away. "; + } + else + { + ostr << "You cannot memorize any " + << (you.spell_no ? "more " : "") + << "spells right now. This will change as you " + "grow in levels and Spellcasting proficiency. "; + } + + if (you.spell_no) + { + ostr << "\n\nTo do magic, type <w>Z<magenta> and " + "choose a spell (check with <w>?<magenta>). " + "For attack spells you'll "; + ostr << tut_target_mode(true); + } } } } @@ -1725,11 +1796,17 @@ void tutorial_describe_item(item_def &item) std::string broken = ostr.str(); linebreak_string2(broken, get_tutorial_cols()); + gotoxy(1, wherey() + 2); formatted_string::parse_block(broken, false).display(); -} +} // tutorial_describe_item -bool tutorial_feat_interesting(int feat) +bool tutorial_feat_interesting(dungeon_feature_type feat) { + if (feat >= DNGN_ALTAR_ZIN && feat <= DNGN_ALTAR_BEOGH) + return true; + if (feat >= DNGN_ENTER_ORCISH_MINES && feat <= DNGN_ENTER_SHOALS) + return true; + switch (feat) { case DNGN_CLOSED_DOOR: @@ -1754,7 +1831,7 @@ bool tutorial_feat_interesting(int feat) } } -void tutorial_describe_feature(int feat) +void tutorial_describe_feature(dungeon_feature_type feat) { std::ostringstream ostr; ostr << "<magenta>"; @@ -1826,6 +1903,86 @@ void tutorial_describe_feature(int feat) "you will usually be unable to return right away."; Options.tutorial_events[TUT_SEEN_ESCAPE_HATCH]; break; + + case DNGN_ALTAR_ZIN: + case DNGN_ALTAR_SHINING_ONE: + case DNGN_ALTAR_KIKUBAAQUDGHA: + case DNGN_ALTAR_YREDELEMNUL: + case DNGN_ALTAR_XOM: + case DNGN_ALTAR_VEHUMET: + case DNGN_ALTAR_OKAWARU: + case DNGN_ALTAR_MAKHLEB: + case DNGN_ALTAR_SIF_MUNA: + case DNGN_ALTAR_TROG: + case DNGN_ALTAR_NEMELEX_XOBEH: + case DNGN_ALTAR_ELYVILON: + case DNGN_ALTAR_LUGONU: + case DNGN_ALTAR_BEOGH: + { + god_type altar_god = grid_altar_god(feat); + + if (you.religion == GOD_NO_GOD) + { + ostr << "This is your chance to join a religion! In general, the " + "gods will help their followers, bestowing powers of all " + "sorts upon them, but many of them demand a life of " + "dedication, constant tributes or entertainment in return. " + "\nYou can get information about <w>" + << god_name(altar_god) + << "<magenta> by pressing <w>p<magenta> while standing on " + "the altar. Before taking up the responding faith you'll " + "be asked for confirmation."; + } + else + { + if (you.religion == altar_god) + { + ostr << "If " + << god_name(you.religion) + << " likes to have items or corpses sacrificed on altars, " + "here you can do this by <w>d<magenta>ropping them, " + "then <w>p<magenta>raying. As a follower, pressing " + "<w>^<magenta> allows you to check " + << god_name(you.religion) + << "'s likes and dislikes at any time."; + } + else + { + ostr << god_name(you.religion) + << " probably won't like it if you switch allegiance, " + "but having a look won't hurt: to get information on <w>"; + ostr << god_name(altar_god); + ostr << "<magenta>, press <w>p<magenta> while standing on the " + "altar. Before taking up the responding faith (and " + "abandoning your current one!) you'll be asked for " + "confirmation." + "\nTo see your current standing with " + << god_name(you.religion) + << " press <w>^<magenta>."; + } + } + Options.tutorial_events[TUT_SEEN_ALTAR]; + break; + } + case DNGN_ENTER_ORCISH_MINES: + case DNGN_ENTER_HIVE: + case DNGN_ENTER_LAIR: + case DNGN_ENTER_SLIME_PITS: + case DNGN_ENTER_VAULTS: + case DNGN_ENTER_CRYPT: + case DNGN_ENTER_HALL_OF_BLADES: + case DNGN_ENTER_ZOT: + case DNGN_ENTER_TEMPLE: + case DNGN_ENTER_SNAKE_PIT: + case DNGN_ENTER_ELVEN_HALLS: + case DNGN_ENTER_TOMB: + case DNGN_ENTER_SWAMP: + case DNGN_ENTER_SHOALS: + ostr << "An entryway into one of the many dungeon branches in Crawl. "; + if (feat != DNGN_ENTER_TEMPLE) + ostr << "Beware, sometimes these can be deadly!"; + break; + default: return; } @@ -1833,4 +1990,60 @@ void tutorial_describe_feature(int feat) std::string broken = ostr.str(); linebreak_string2(broken, get_tutorial_cols()); formatted_string::parse_block(broken, false).display(); +} // tutorial_describe_feature + +bool tutorial_monster_interesting(const monsters *mons) +{ + // highlighted in some way + if (get_mons_colour(mons) != mons->colour) + return true; + + // monster is (seriously) out of depth + if (you.level_type == LEVEL_DUNGEON && + mons_level(mons->type) >= you.your_level + Options.ood_interesting) + { + return true; + } + return false; } + +void tutorial_describe_monster(const monsters *mons) +{ + std::ostringstream ostr; + ostr << "<magenta>"; + + int level_diff + = mons_level(mons->type) - (you.your_level + Options.ood_interesting); + + if (you.level_type == LEVEL_DUNGEON && level_diff >= 0) + { + ostr << "This kind of monster is usually only encountered " + << (level_diff > 5 ? "much " : "") + << "deeper in the dungeon, so it's probably " + << (level_diff > 5 ? "extremely" : "very") + << " dangerous!\n\n"; + } + + if (mons->has_ench(ENCH_BERSERK)) + ostr << "A berserking monster is bloodthirsty and fighting madly.\n"; + + if (mons_friendly(mons)) + { + ostr << "Friendly monsters will follow you around and attempt to aid " + "you in battle."; + } + else if (Options.stab_brand != CHATTR_NORMAL + && mons_looks_stabbable(mons)) + { + ostr << "Apparently it has not noticed you - yet."; + } + else if (Options.may_stab_brand != CHATTR_NORMAL + && mons_looks_distracted(mons)) + { + ostr << "Apparently it has been distracted by something."; + } + + std::string broken = ostr.str(); + linebreak_string2(broken, get_tutorial_cols()); + formatted_string::parse_block(broken, false).display(); +} // tutorial_describe_monster |