summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source
diff options
context:
space:
mode:
authorj-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573>2007-08-15 21:32:33 +0000
committerj-p-e-g <j-p-e-g@c06c8d41-db1a-0410-9941-cceddc491573>2007-08-15 21:32:33 +0000
commit054c713cec71c3010b1ac3eb0848f2b601db982f (patch)
treeda7a575a718b842b7ea15bb8ffc59efdccc2ff95 /crawl-ref/source
parent54f595ca30391a4e95ae1f46706d9c7cc5a6b6a8 (diff)
downloadcrawl-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')
-rw-r--r--crawl-ref/source/describe.cc12
-rw-r--r--crawl-ref/source/direct.cc5
-rw-r--r--crawl-ref/source/item_use.cc19
-rw-r--r--crawl-ref/source/itemprop.cc76
-rw-r--r--crawl-ref/source/itemprop.h1
-rw-r--r--crawl-ref/source/output.cc13
-rw-r--r--crawl-ref/source/spl-book.cc37
-rw-r--r--crawl-ref/source/spl-book.h1
-rw-r--r--crawl-ref/source/tutorial.cc301
-rw-r--r--crawl-ref/source/tutorial.h10
10 files changed, 422 insertions, 53 deletions
diff --git a/crawl-ref/source/describe.cc b/crawl-ref/source/describe.cc
index 9adc69245b..61d04151fc 100644
--- a/crawl-ref/source/describe.cc
+++ b/crawl-ref/source/describe.cc
@@ -3388,10 +3388,10 @@ void describe_item( item_def &item, bool allow_inscribe )
if (Options.tutorial_left)
{
- gotoxy(1, wherey() + 2);
tutorial_describe_item(item);
}
- if (allow_inscribe)
+ // Don't ask if there aren't enough rows left
+ if (allow_inscribe && wherey() <= get_number_of_lines() - 3)
{
gotoxy(1, wherey() + 2);
formatted_string::parse_string("<cyan>Do you wish to inscribe this item? ").display();
@@ -3606,7 +3606,7 @@ void describe_monsters(monsters& mons)
case MONS_GUARDIAN_NAGA:
description << getLongDescription("naga")
<< "$These nagas are often used as guardians "
- "by powerful creatures.$";
+ "by powerful creatures.$";
break;
case MONS_GREATER_NAGA:
description << getLongDescription("naga")
@@ -3731,6 +3731,12 @@ void describe_monsters(monsters& mons)
clrscr();
print_description(description.str());
+ if (Options.tutorial_left)
+ {
+ gotoxy(1, wherey() + 2);
+ tutorial_describe_monster(static_cast<const monsters*>(&mons));
+ }
+
if (getch() == 0)
getch();
} // end describe_monsters
diff --git a/crawl-ref/source/direct.cc b/crawl-ref/source/direct.cc
index 36ab799592..9521b7f6ea 100644
--- a/crawl-ref/source/direct.cc
+++ b/crawl-ref/source/direct.cc
@@ -1708,6 +1708,11 @@ static void describe_cell(int mx, int my)
#if DEBUG_DIAGNOSTICS
stethoscope(i);
#endif
+ if (Options.tutorial_left && tutorial_monster_interesting(&menv[i]))
+ {
+ std::string msg = "(Press <w>v<lightgray> for more information.)";
+ print_formatted_paragraph(msg, 80);
+ }
}
#if (!DEBUG_DIAGNOSTICS)
diff --git a/crawl-ref/source/item_use.cc b/crawl-ref/source/item_use.cc
index eeab91d2cc..73a9300e2d 100644
--- a/crawl-ref/source/item_use.cc
+++ b/crawl-ref/source/item_use.cc
@@ -2232,7 +2232,6 @@ void jewellery_wear_effects(item_def &item)
case RING_SUSTENANCE:
case RING_SLAYING:
case RING_SEE_INVISIBLE:
- case RING_TELEPORTATION:
case RING_WIZARDRY:
case RING_REGENERATION:
case RING_TELEPORT_CONTROL:
@@ -2286,6 +2285,15 @@ void jewellery_wear_effects(item_def &item)
ident = ID_KNOWN_TYPE;
break;
+ case RING_TELEPORTATION:
+ if (!scan_randarts( RAP_CAN_TELEPORT ))
+ {
+ mpr("You feel slightly jumpy.");
+ ident = ID_KNOWN_TYPE;
+ break;
+ }
+ break;
+
case AMU_RAGE:
mpr("You feel a brief urge to hack something to bits.");
ident = ID_KNOWN_TYPE;
@@ -2899,6 +2907,15 @@ void inscribe_item()
mpr( "Inscribe with what? ", MSGCH_PROMPT );
if (!cancelable_get_line(buf, sizeof buf))
{
+ // strip spaces from the end
+ for (int i = strlen(buf) - 1; i >= 0; i--)
+ {
+ if (isspace( buf[i] ))
+ buf[i] = 0;
+ else
+ break;
+ }
+
you.inv[item_slot].inscription = std::string(buf);
you.wield_change = true;
}
diff --git a/crawl-ref/source/itemprop.cc b/crawl-ref/source/itemprop.cc
index 65f87c3a50..46dea61357 100644
--- a/crawl-ref/source/itemprop.cc
+++ b/crawl-ref/source/itemprop.cc
@@ -1918,6 +1918,82 @@ int property( const item_def &item, int prop_type )
return (0);
}
+bool gives_ability( const item_def &item )
+{
+ if (!item_type_known(item))
+ return false;
+
+ switch (item.base_type)
+ {
+ case OBJ_WEAPONS:
+ {
+ // unwielded weapon
+ item_def *weap = you.slot_item(EQ_WEAPON);
+ if (!weap || (*weap).slot != item.slot)
+ return false;
+ break;
+ }
+ case OBJ_JEWELLERY:
+ {
+ if (item.sub_type < NUM_RINGS)
+ {
+ // unworn ring
+ item_def *lring = you.slot_item(EQ_LEFT_RING);
+ item_def *rring = you.slot_item(EQ_RIGHT_RING);
+ if ((!lring || (*lring).slot != item.slot)
+ && (!rring || (*rring).slot != item.slot))
+ {
+ return false;
+ }
+
+ if (item.sub_type == RING_TELEPORTATION
+ || item.sub_type == RING_LEVITATION
+ || item.sub_type == RING_INVISIBILITY)
+ {
+ return true;
+ }
+ }
+ else
+ {
+ // unworn amulet
+ item_def *amul = you.slot_item(EQ_AMULET);
+ if (!amul || (*amul).slot != item.slot)
+ return false;
+
+ if (item.sub_type == AMU_RAGE)
+ return true;
+ }
+ break;
+ }
+ case OBJ_ARMOUR:
+ {
+ const equipment_type eq = get_armour_slot(item);
+ if (eq == EQ_NONE)
+ return false;
+
+ // unworn armour
+ item_def *arm = you.slot_item(eq);
+ if (!arm || (*arm).slot != item.slot)
+ return false;
+ break;
+ }
+ default:
+ return false;
+ }
+
+ if (!is_random_artefact(item))
+ return false;
+
+ // check for evokable randart properties
+ for (int rap = RAP_INVISIBLE; rap <= RAP_MAPPING; rap++)
+ {
+ if (randart_wpn_property( item, rap ))
+ return true;
+ }
+
+ return false;
+}
+
int item_mass( const item_def &item )
{
int unit_mass = 0;
diff --git a/crawl-ref/source/itemprop.h b/crawl-ref/source/itemprop.h
index 49e64b20c0..eb12110809 100644
--- a/crawl-ref/source/itemprop.h
+++ b/crawl-ref/source/itemprop.h
@@ -146,6 +146,7 @@ bool can_cut_meat( const item_def &item );
// generic item property functions:
bool is_tool( const item_def &item );
int property( const item_def &item, int prop_type );
+bool gives_ability( const item_def &item );
int item_mass( const item_def &item );
size_type item_size( const item_def &item );
diff --git a/crawl-ref/source/output.cc b/crawl-ref/source/output.cc
index db0d566a9d..decafc3ccd 100644
--- a/crawl-ref/source/output.cc
+++ b/crawl-ref/source/output.cc
@@ -1274,8 +1274,17 @@ void print_overview_screen()
{
if (e_order[i] == EQ_BODY_ARMOUR || e_order[i] == EQ_HELMET)
{
- snprintf(buf, sizeof buf,
- "%-7s: <lightgray>(ill-fitting)</lightgray>", slot);
+ if (!you_tran_can_wear(e_order[i]))
+ {
+ snprintf(buf, sizeof buf, "%-7s: "
+ "<darkgray>(currently unavailable)</darkgray>",
+ slot);
+ }
+ else
+ { snprintf(buf, sizeof buf,
+ "%-7s: <lightgray>(ill-fitting)</lightgray>",
+ slot);
+ }
}
else
{
diff --git a/crawl-ref/source/spl-book.cc b/crawl-ref/source/spl-book.cc
index 0d4309d7cf..f4734d2f79 100644
--- a/crawl-ref/source/spl-book.cc
+++ b/crawl-ref/source/spl-book.cc
@@ -1131,6 +1131,43 @@ bool undead_cannot_memorise(spell_type spell, char being)
return false;
} // end undead_cannot_memorise()
+bool player_can_memorize(item_def &book)
+{
+ if (book.base_type != OBJ_BOOKS || book.sub_type == BOOK_MANUAL)
+ return false;
+
+ if (!player_spell_levels())
+ return false;
+
+ for (int j = 0; j < SPELLBOOK_SIZE; j++)
+ {
+ const spell_type stype = which_spell_in_book(book.book_number(), j);
+
+ if (stype == SPELL_NO_SPELL)
+ continue;
+
+ // easiest spell already too difficult
+ if (spell_difficulty(stype) > you.experience_level
+ || player_spell_levels() < spell_levels_required(stype))
+ {
+ return false;
+ }
+
+ bool knowsSpell = false;
+ for (int i = 0; i < 25 && !knowsSpell; i++)
+ {
+ knowsSpell = (you.spells[i] == stype);
+ }
+
+ // don't already know this spell
+ if (!knowsSpell)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
bool learn_spell(void)
{
int chance = 0;
diff --git a/crawl-ref/source/spl-book.h b/crawl-ref/source/spl-book.h
index edcb8a89f9..54eb3fa0b8 100644
--- a/crawl-ref/source/spl-book.h
+++ b/crawl-ref/source/spl-book.h
@@ -40,6 +40,7 @@ int read_book( item_def &item, read_book_action_type action );
/* ***********************************************************************
* called from: acr
* *********************************************************************** */
+bool player_can_memorize(item_def &book);
bool learn_spell(void);
spell_type which_spell_in_book(int sbook_type, int spl);
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
diff --git a/crawl-ref/source/tutorial.h b/crawl-ref/source/tutorial.h
index 2763b08650..a4824ab89b 100644
--- a/crawl-ref/source/tutorial.h
+++ b/crawl-ref/source/tutorial.h
@@ -37,8 +37,12 @@ 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);
+
+// additional information for tutorial players
+void tutorial_describe_item(item_def &item);
+bool tutorial_feat_interesting(dungeon_feature_type feat);
+void tutorial_describe_feature(dungeon_feature_type feat);
+bool tutorial_monster_interesting(const monsters *mons);
+void tutorial_describe_monster(const monsters *mons);
#endif