From e0d592b0a5e032d7d35551907c4af69014e48b10 Mon Sep 17 00:00:00 2001 From: Matthew Cline Date: Mon, 7 Dec 2009 03:04:10 -0800 Subject: New monster props "speech_func" and "shout_func" MonPropsMarker can be used to set "speech_func" and "shout_func" on a monster, functions which return a string to be used as the monster's speech/shout message. --- crawl-ref/docs/develop/levels/advanced.txt | 15 ++++++++++++ crawl-ref/source/mon-speak.cc | 39 +++++++++++++++++++++++++++++- crawl-ref/source/mon-stuff.cc | 6 +++++ crawl-ref/source/shout.cc | 34 +++++++++++++++++++++++++- 4 files changed, 92 insertions(+), 2 deletions(-) (limited to 'crawl-ref') diff --git a/crawl-ref/docs/develop/levels/advanced.txt b/crawl-ref/docs/develop/levels/advanced.txt index f9cd653809..f5ffffe725 100644 --- a/crawl-ref/docs/develop/levels/advanced.txt +++ b/crawl-ref/docs/develop/levels/advanced.txt @@ -779,6 +779,18 @@ the marker is placed upon. The options currently available are: * monster_dies_lua_key: If this property is set to a function, that function will be executed upon the monster's death. +* shout_func: If this property is set to a function, that function will be + called if the monster shouts, and the string returned by the function + will be used as the text of the message. can return "__NONE" to + make the monster not shout, or "__NEXT" to proceed as if there was no + speech_func property. + +* speech_func: If this property is set to a function, that function will be + called if the monster speaks, and the string returned by the function + will be used as the text of the message. can return "__NONE" to + make the monster not talk, or "__NEXT" to proceed as if there was no + speech_func property. + * speech_key: This will override the initial key searched for in the speech database. Setting this to "Edmund", for example, will give the relevant monster Edmund's speech. @@ -792,6 +804,9 @@ An example of MonPropsMarker to replace the description and quote of a monster: MARKER: 8 = lua:MonPropsMarker:new {description="What a horrible sight!\n", \ quote='"They were filled with fear!'\n"} +Note that all of the speech related properties will be reset if the monster +polymorphs. + Lua API reference ----------------- a. The Map. diff --git a/crawl-ref/source/mon-speak.cc b/crawl-ref/source/mon-speak.cc index a5424f117b..9d2d8ecc85 100644 --- a/crawl-ref/source/mon-speak.cc +++ b/crawl-ref/source/mon-speak.cc @@ -15,8 +15,10 @@ #include "externs.h" #include "beam.h" +#include "cluautil.h" #include "database.h" #include "debug.h" +#include "dlua.h" #include "ghost.h" #include "message.h" #include "mon-stuff.h" @@ -558,8 +560,43 @@ bool mons_speaks(monsters *monster) } else { + if (monster->props.exists("speech_func")) + { +#ifdef DEBUG_MONSPEAK + mpr("Trying Lua function for monster speech", MSGCH_DIAGNOSTICS); +#endif + lua_stack_cleaner clean(dlua); + + dlua_chunk &chunk = monster->props["speech_func"]; + + if (!chunk.load(dlua)) + { + push_monster(dlua, monster); + dlua.callfn(NULL, 1, 1); + dlua.fnreturns(">s", &msg); + + // __NONE means to be silent, and __NEXT means to try the next + // method of getting a speech message. + if (msg == "__NONE") + { +#ifdef DEBUG_MONSPEAK + mpr("result: \"__NONE\"!", MSGCH_DIAGNOSTICS); +#endif + return (false); + } + if (msg == "__NEXT") + msg.clear(); + } + else + { + mprf(MSGCH_ERROR, + "Lua speech function for monster '%s' didn't load: %s", + monster->full_name(DESC_PLAIN).c_str(), + dlua.error.c_str()); + } + } - if (monster->props.exists("speech_key")) + if (msg.empty() && monster->props.exists("speech_key")) { msg = _get_speak_string(prefixes, monster->props["speech_key"].get_string(), diff --git a/crawl-ref/source/mon-stuff.cc b/crawl-ref/source/mon-stuff.cc index 0d4c374ce2..fc109c5aee 100644 --- a/crawl-ref/source/mon-stuff.cc +++ b/crawl-ref/source/mon-stuff.cc @@ -2509,6 +2509,12 @@ bool monster_polymorph(monsters *monster, monster_type targetc, monster->flags = flags; monster->god = god; + // Forget various speech/shout Lua functions. + monster->props.erase("speech_key"); + monster->props.erase("speech_prefix"); + monster->props.erase("speech_func"); + monster->props.erase("shout_func"); + // Keep spells for named monsters, but don't override innate ones // for dragons and the like. This means that Sigmund polymorphed // into a goblin will still cast spells, but if he ends up as a diff --git a/crawl-ref/source/shout.cc b/crawl-ref/source/shout.cc index e4167278ba..d7d21af7a4 100644 --- a/crawl-ref/source/shout.cc +++ b/crawl-ref/source/shout.cc @@ -7,8 +7,10 @@ #include "shout.h" +#include "cluautil.h" #include "coord.h" #include "database.h" +#include "dlua.h" #include "env.h" #include "ghost.h" #include "jobs.h" @@ -148,7 +150,37 @@ void handle_monster_shouts(monsters* monster, bool force) else suffix = " unseen"; - msg = getShoutString(key, suffix); + if (monster->props.exists("shout_func")) + { + lua_stack_cleaner clean(dlua); + + dlua_chunk &chunk = monster->props["shout_func"]; + + if (!chunk.load(dlua)) + { + push_monster(dlua, monster); + clua_pushcxxstring(dlua, suffix); + dlua.callfn(NULL, 2, 1); + dlua.fnreturns(">s", &msg); + + // __NONE means to be silent, and __NEXT or __DEFAULT means to try + // the next method of getting a shout message. + if (msg == "__NONE") + return; + if (msg == "__DEFAULT" || msg == "__NEXT") + msg.clear(); + } + else + { + mprf(MSGCH_ERROR, + "Lua shout function for monster '%s' didn't load: %s", + monster->full_name(DESC_PLAIN).c_str(), + dlua.error.c_str()); + } + } + + if (msg.empty()) + msg = getShoutString(key, suffix); if (msg == "__DEFAULT" || msg == "__NEXT") msg = getShoutString(default_msg_key, suffix); -- cgit v1.2.3-54-g00ecf