summaryrefslogtreecommitdiffstats
path: root/stone_soup/crawl-ref/source/Kills.cc
diff options
context:
space:
mode:
Diffstat (limited to 'stone_soup/crawl-ref/source/Kills.cc')
-rw-r--r--stone_soup/crawl-ref/source/Kills.cc1098
1 files changed, 0 insertions, 1098 deletions
diff --git a/stone_soup/crawl-ref/source/Kills.cc b/stone_soup/crawl-ref/source/Kills.cc
deleted file mode 100644
index 06f465bb70..0000000000
--- a/stone_soup/crawl-ref/source/Kills.cc
+++ /dev/null
@@ -1,1098 +0,0 @@
-/*
- * File: Kills.cc
- * Summary: Player kill tracking
- * Written by: Darshan Shaligram
- */
-#include "AppHdr.h"
-#include "chardump.h"
-#include "describe.h"
-#include "mon-util.h"
-#include "files.h"
-#include "itemname.h"
-#include "travel.h"
-#include "tags.h"
-#include "Kills.h"
-#include "clua.h"
-#include <algorithm>
-
-#define KILLS_MAJOR_VERSION 4
-#define KILLS_MINOR_VERSION 1
-
-#ifdef CLUA_BINDINGS
-static void kill_lua_filltable(std::vector<kill_exp> &v);
-#endif
-
-
-unsigned short get_packed_place( unsigned char branch, int subdepth,
- char level_type )
-{
- unsigned short place = (unsigned short)
- ( (branch << 8) | subdepth );
- if (level_type == LEVEL_ABYSS || level_type == LEVEL_PANDEMONIUM
- || level_type == LEVEL_LABYRINTH)
- place = (unsigned short) ( (level_type << 8) | 0xFF );
- return place;
-}
-
-unsigned short get_packed_place()
-{
- return get_packed_place( you.where_are_you,
- subdungeon_depth(you.where_are_you, you.your_level),
- you.level_type );
-}
-
-///////////////////////////////////////////////////////////////////////////
-// KillMaster
-//
-
-const char *kill_category_names[] =
-{
- "you",
- "collateral kills",
- "others",
-};
-
-const char *KillMaster::category_name(kill_category kc) const
-{
- if (kc >= KC_YOU && kc < KC_NCATEGORIES)
- return (kill_category_names[kc]);
- return (NULL);
-}
-
-bool KillMaster::empty() const
-{
- for (int i = 0; i < KC_NCATEGORIES; ++i)
- if (!categorized_kills[i].empty())
- return (false);
- return (true);
-}
-
-void KillMaster::save(FILE *file) const
-{
- // Write the version of the kills file
- writeByte(file, KILLS_MAJOR_VERSION);
- writeByte(file, KILLS_MINOR_VERSION);
-
- for (int i = 0; i < KC_NCATEGORIES; ++i)
- categorized_kills[i].save(file);
-}
-
-void KillMaster::load(FILE *file)
-{
- unsigned char major = readByte(file),
- minor = readByte(file);
- if (major != KILLS_MAJOR_VERSION ||
- (minor != KILLS_MINOR_VERSION && minor > 0))
- return ;
-
- for (int i = 0; i < KC_NCATEGORIES; ++i)
- {
- categorized_kills[i].load(file);
- if (!minor)
- break;
- }
-}
-
-void KillMaster::record_kill(const monsters *mon, int killer, bool ispet)
-{
- kill_category kc =
- (killer == KILL_YOU || killer == KILL_YOU_MISSILE)? KC_YOU :
- (ispet)? KC_FRIENDLY :
- KC_OTHER;
- categorized_kills[kc].record_kill(mon);
-}
-
-std::string KillMaster::kill_info() const
-{
- if (empty())
- return ("");
-
- std::string killtext;
-
- bool needseparator = false;
- int categories = 0;
- long grandtotal = 0L;
-
- Kills catkills[KC_NCATEGORIES];
- for (int i = 0; i < KC_NCATEGORIES; ++i)
- {
- int targ = Options.kill_map[i];
- catkills[targ].merge( categorized_kills[i] );
- }
-
- for (int i = KC_YOU; i < KC_NCATEGORIES; ++i)
- {
- if (catkills[i].empty())
- continue;
-
- categories++;
- std::vector<kill_exp> kills;
- long count = catkills[i].get_kills(kills);
- grandtotal += count;
-
- add_kill_info( killtext,
- kills,
- count,
- i == KC_YOU? NULL :
- category_name((kill_category) i),
- needseparator );
- needseparator = true;
- }
-
- std::string grandt;
- if (categories > 1)
- {
- char buf[200];
- snprintf(buf, sizeof buf,
- "Grand Total: %ld creatures vanquished",
- grandtotal);
- grandt = buf;
- }
-
-#ifdef CLUA_BINDINGS
- // Call the kill dump Lua function with null a, to tell it we're done.
- if (!clua.callfn("c_kill_list", "ss", NULL, grandt.c_str()))
-#endif
- {
- // We can sum up ourselves, if Lua doesn't want to.
- // FIXME: I'm not happy with the looks/wording of the grand total
- // count.
- if (categories > 1)
- {
- // Give ourselves a newline first
- killtext += EOL;
- killtext += grandt + EOL;
- }
- }
-
- return killtext;
-}
-
-void KillMaster::add_kill_info(std::string &killtext,
- std::vector<kill_exp> &kills,
- long count,
- const char *category,
- bool separator) const
-{
-#ifdef CLUA_BINDINGS
- // Set a pointer to killtext as a Lua global
- lua_pushlightuserdata(clua.state(), &killtext);
- clua.setregistry("cr_skill");
-
- // Populate a Lua table with kill_exp structs, in the default order,
- // and leave the table on the top of the Lua stack.
- kill_lua_filltable(kills);
-
- if (category)
- lua_pushstring(clua, category);
- else
- lua_pushnil(clua);
-
- lua_pushboolean(clua, separator);
-
- if (!clua.callfn("c_kill_list", 3, 0))
-#endif
- {
-#ifdef CLUA_BINDINGS
- if (clua.error.length())
- {
- killtext += "Lua error:\n";
- killtext += clua.error + "\n\n";
- }
-#endif
- if (separator)
- killtext += EOL;
-
- killtext += "Vanquished Creatures";
- if (category)
- killtext += std::string(" (") + category + ")";
-
- killtext += EOL;
-
- for (int i = 0, sz = kills.size(); i < sz; ++i)
- {
- killtext += " " + kills[i].desc;
- killtext += EOL;
- }
- {
- char numbuf[100];
- snprintf(numbuf, sizeof numbuf,
- "%ld creature%s vanquished." EOL, count,
- count > 1? "s" : "");
- killtext += numbuf;
- }
- }
-}
-
-///////////////////////////////////////////////////////////////////////////
-
-bool Kills::empty() const
-{
- return kills.empty() && ghosts.empty();
-}
-
-void Kills::merge(const Kills &k)
-{
- ghosts.insert( ghosts.end(), k.ghosts.begin(), k.ghosts.end() );
-
- // Regular kills are messier to merge.
- for (kill_map::const_iterator i = k.kills.begin();
- i != k.kills.end(); ++i)
- {
- const kill_monster_desc &kmd = i->first;
- kill_def &k = kills[kmd];
- const kill_def &ko = i->second;
- bool uniq = mons_is_unique(kmd.monnum);
- k.merge(ko, uniq);
- }
-}
-
-void Kills::record_kill(const struct monsters *mon)
-{
- // Handle player ghosts separately.
- if (mon->type == MONS_PLAYER_GHOST || mon->type == MONS_PANDEMONIUM_DEMON)
- {
- record_ghost_kill(mon);
- return ;
- }
-
- // Normal monsters
- // Create a descriptor
- kill_monster_desc descriptor = mon;
-
- kill_def &k = kills[descriptor];
- if (k.kills)
- k.add_kill(mon, get_packed_place());
- else
- k = kill_def(mon);
-}
-
-long Kills::get_kills(std::vector<kill_exp> &all_kills) const
-{
- long count = 0;
- kill_map::const_iterator iter = kills.begin();
- for (; iter != kills.end(); ++iter)
- {
- const kill_monster_desc &md = iter->first;
- const kill_def &k = iter->second;
- all_kills.push_back( kill_exp(k, md) );
- count += k.kills;
- }
-
- ghost_vec::const_iterator gi = ghosts.begin();
- for (; gi != ghosts.end(); ++gi)
- {
- all_kills.push_back( kill_exp(*gi) );
- }
- count += ghosts.size();
-
- std::sort(all_kills.begin(), all_kills.end());
- return (count);
-}
-
-// Takes a packed 'place' and returns a compact stringified place name.
-// XXX: This is done in several other places; a unified function to
-// describe places would be nice.
-std::string short_place_name(unsigned short place)
-{
- unsigned char branch = (unsigned char) ((place >> 8) & 0xFF);
- int lev = place & 0xFF;
-
- const char *s;
- bool level_num = false;
- if (lev == 0xFF)
- {
- switch (branch)
- {
- case LEVEL_ABYSS:
- s = "Abyss";
- break;
- case LEVEL_PANDEMONIUM:
- s = "Pan";
- break;
- case LEVEL_LABYRINTH:
- s = "Lab";
- break;
- default:
- s = "Buggy Badlands";
- break;
- }
- }
- else
- {
- switch (branch)
- {
- case BRANCH_VESTIBULE_OF_HELL:
- s = "Hell";
- break;
- case BRANCH_HALL_OF_BLADES:
- s = "Blade";
- break;
- case BRANCH_ECUMENICAL_TEMPLE:
- s = "Temple";
- break;
- default:
- level_num = true;
- s = (branch == BRANCH_DIS) ? "Dis:" :
- (branch == BRANCH_GEHENNA) ? "Geh:" :
- (branch == BRANCH_COCYTUS) ? "Coc:" :
- (branch == BRANCH_TARTARUS) ? "Tar:" :
- (branch == BRANCH_ORCISH_MINES) ? "Orc:" :
- (branch == BRANCH_HIVE) ? "Hive:" :
- (branch == BRANCH_LAIR) ? "Lair:" :
- (branch == BRANCH_SLIME_PITS) ? "Slime:" :
- (branch == BRANCH_VAULTS) ? "Vault:" :
- (branch == BRANCH_CRYPT) ? "Crypt:" :
- (branch == BRANCH_HALL_OF_ZOT) ? "Zot:" :
- (branch == BRANCH_SNAKE_PIT) ? "Snake:" :
- (branch == BRANCH_ELVEN_HALLS) ? "Elf:" :
- (branch == BRANCH_TOMB) ? "Tomb:" :
- (branch == BRANCH_SWAMP) ? "Swamp:" : "D:";
- break;
- }
- }
-
- std::string pl = s;
- if (level_num)
- {
- char buf[20];
- snprintf(buf, sizeof buf, "%d", lev);
- pl += buf;
- }
- return pl;
-}
-
-void Kills::save(FILE *file) const
-{
- // How many kill records do we have?
- writeLong(file, kills.size());
-
- kill_map::const_iterator iter = kills.begin();
- for ( ; iter != kills.end(); ++iter)
- {
- iter->first.save(file);
- iter->second.save(file);
- }
-
- // How many ghosts do we have?
- writeShort(file, ghosts.size());
- for (ghost_vec::const_iterator iter = ghosts.begin();
- iter != ghosts.end(); ++iter)
- {
- iter->save(file);
- }
-}
-
-void Kills::load(FILE *file)
-{
- // How many kill records?
- long kill_count = readLong(file);
- kills.clear();
- for (long i = 0; i < kill_count; ++i)
- {
- kill_monster_desc md;
- md.load(file);
- kills[md].load(file);
- }
-
- short ghost_count = readShort(file);
- ghosts.clear();
- for (short i = 0; i < ghost_count; ++i)
- {
- kill_ghost kg;
- kg.load(file);
- ghosts.push_back(kg);
- }
-}
-
-void Kills::record_ghost_kill(const struct monsters *mon)
-{
- kill_ghost ghost(mon);
- ghosts.push_back(ghost);
-}
-
-kill_def::kill_def(const struct monsters *mon) : kills(0), exp(0)
-{
- exp = exper_value( (struct monsters *) mon);
- add_kill(mon, get_packed_place());
-}
-
-static bool ends_with(const std::string &s, const char *suffix)
-{
- std::string other = suffix;
- if (s.length() < other.length()) return false;
- return (s.substr(s.length() - other.length()) == other);
-}
-
-static bool ends_with(const std::string &s, const char *suffixes[])
-{
- if (!suffixes) return false;
- for ( ; *suffixes; suffixes++)
- {
- if (ends_with(s, *suffixes))
- return true;
- }
- return false;
-}
-
-// For monster names ending with these suffixes, we pluralize directly without
-// attempting to use the "of" rule. For instance:
-//
-// moth of wrath => moths of wrath but
-// moth of wrath zombie => moth of wrath zombies.
-//
-// This is not necessary right now, since there are currently no monsters that
-// require this special treatment (no monster with 'of' in its name is eligible
-// for zombies or skeletons).
-static const char *modifier_suffixes[] =
-{
- "zombie", "skeleton", "simulacrum", NULL,
-};
-
-// Pluralizes a monster name. This'll need to be updated for correctness
-// whenever new monsters are added.
-static std::string pluralize(const std::string &name,
- const char *no_of[] = NULL)
-{
- std::string::size_type pos;
-
- // Pluralize first word of names like 'eye of draining', but only if the
- // whole name is not suffixed by a modifier, such as 'zombie' or 'skeleton'
- if ( (pos = name.find(" of ")) != std::string::npos
- && !ends_with(name, no_of) )
- {
- return pluralize(name.substr(0, pos)) + name.substr(pos);
- }
- else if (ends_with(name, "us"))
- // Fungus, ufetubus, for instance.
- return name.substr(0, name.length() - 2) + "i";
- else if (ends_with(name, "larva") || ends_with(name, "amoeba"))
- // Giant amoebae sounds a little weird, to tell the truth.
- return name + "e";
- else if (ends_with(name, "ex"))
- // Vortex; vortexes is legal, but the classic plural is cooler.
- return name.substr(0, name.length() - 2) + "ices";
- else if (ends_with(name, "cyclops"))
- return name.substr(0, name.length() - 1) + "es";
- else if (ends_with(name, "y"))
- return name.substr(0, name.length() - 1) + "ies";
- else if (ends_with(name, "lf"))
- // Elf, wolf. Dwarfs can stay dwarfs, if there were dwarfs.
- return name.substr(0, name.length() - 1) + "ves";
- else if (ends_with(name, "mage"))
- // mage -> magi
- return name.substr(0, name.length() - 1) + "i";
- else if ( ends_with(name, "sheep") || ends_with(name, "manes")
- || ends_with(name, "fish") )
- // Maybe we should generalise 'manes' to ends_with("es")?
- return name;
- else if (ends_with(name, "ch") || ends_with(name, "sh")
- || ends_with(name, "x"))
- // To handle cockroaches, fish and sphinxes. Fish will be netted by
- // the previous check anyway.
- return name + "es";
- else if (ends_with(name, "um"))
- // simulacrum -> simulacra
- return name.substr(0, name.length() - 2) + "a";
- else if (ends_with(name, "efreet"))
- // efreet -> efreeti. Not sure this is correct.
- return name + "i";
-
- return name + "s";
-}
-
-// Naively prefix A/an to a monster name. At the moment, we don't have monster
-// names that demand more sophistication (maybe ynoxinul - don't know how
-// that's pronounced).
-static std::string article_a(const std::string &name)
-{
- if (!name.length()) return name;
- switch (name[0])
- {
- case 'a': case 'e': case 'i': case 'o': case 'u':
- case 'A': case 'E': case 'I': case 'O': case 'U':
- return "An " + name;
- default:
- return "A " + name;
- }
-}
-
-// For a non-unique monster, prefixes a suitable article if we have only one
-// kill, else prefixes a kill count and pluralizes the monster name.
-static std::string n_names(const std::string &name, int n)
-{
- if (n > 1)
- {
- char buf[20];
- snprintf(buf, sizeof buf, "%d ", n);
- return buf + pluralize(name, modifier_suffixes);
- }
- else
- return article_a(name);
-}
-
-// Returns a string describing the number of times a unique has been killed.
-// Currently required only for Boris.
-//
-static std::string kill_times(int kills)
-{
- char buf[50];
- switch (kills)
- {
- case 1:
- strcpy(buf, " (once)");
- break;
- case 2:
- strcpy(buf, " (twice)");
- break;
- case 3:
- strcpy(buf, " (thrice)");
- break;
- default:
- snprintf(buf, sizeof buf, " (%d times)", kills);
- break;
- }
- return std::string(buf);
-}
-
-void kill_def::merge(const kill_def &k, bool uniq)
-{
- if (!kills)
- {
- *this = k;
- }
- else
- {
- kills += k.kills;
- for (int i = 0, size = k.places.size(); i < size; ++i)
- add_place(k.places[i], uniq);
- }
-}
-
-void kill_def::add_kill(const struct monsters *mon, unsigned short place)
-{
- kills++;
- add_place(place, mons_is_unique(mon->type));
-}
-
-void kill_def::add_place(unsigned short place, bool force)
-{
- for (unsigned i = 0; i < places.size(); ++i)
- if (places[i] == place) return;
-
- if (force || places.size() < PLACE_LIMIT)
- places.push_back(place);
-}
-
-std::string kill_def::base_name(const kill_monster_desc &md) const
-{
- char monnamebuf[ITEMNAME_SIZE]; // Le sigh.
- moname(md.monnum, true, DESC_PLAIN, monnamebuf);
-
- std::string name = monnamebuf;
- switch (md.modifier)
- {
- case kill_monster_desc::M_ZOMBIE:
- name += " zombie";
- break;
- case kill_monster_desc::M_SKELETON:
- name += " skeleton";
- break;
- case kill_monster_desc::M_SIMULACRUM:
- name += " simulacrum";
- break;
- case kill_monster_desc::M_SPECTRE:
- name = "spectral " + name;
- break;
- default:
- // Silence compiler warning about not handling M_NORMAL and
- // M_SHAPESHIFTER
- break;
- }
-
- switch (md.monnum)
- {
- case MONS_ABOMINATION_LARGE:
- name = "large " + name;
- break;
- case MONS_ABOMINATION_SMALL:
- // Do nothing
- break;
- case MONS_RAKSHASA_FAKE:
- name = "illusory " + name;
- break;
- }
- return name;
-}
-
-std::string kill_def::info(const kill_monster_desc &md) const
-{
- std::string name = base_name(md);
-
- if (!mons_is_unique(md.monnum))
- {
- // Pluralize as needed
- name = n_names(name, kills);
-
- // We brand shapeshifters with the (shapeshifter) qualifier. This
- // has to be done after doing pluralize(), else we get very odd plurals
- // :)
- if (md.modifier == kill_monster_desc::M_SHAPESHIFTER &&
- md.monnum != MONS_SHAPESHIFTER &&
- md.monnum != MONS_GLOWING_SHAPESHIFTER)
- name += " (shapeshifter)";
- }
- else if (kills > 1)
- {
- // Aha! A resurrected unique
- name += kill_times(kills);
- }
-
- // What places we killed this type of monster
- return append_places(md, name);
-}
-
-std::string kill_def::append_places(const kill_monster_desc &md,
- const std::string &name) const
-{
- if (Options.dump_kill_places == KDO_NO_PLACES) return name;
-
- int nplaces = places.size();
- if ( nplaces == 1 || mons_is_unique(md.monnum)
- || Options.dump_kill_places == KDO_ALL_PLACES )
- {
- std::string augmented = name;
- augmented += " (";
- for (std::vector<unsigned short>::const_iterator iter = places.begin();
- iter != places.end(); ++iter)
- {
- if (iter != places.begin())
- augmented += " ";
- augmented += short_place_name(*iter);
- }
- augmented += ")";
- return augmented;
- }
- return name;
-}
-
-void kill_def::save(FILE *file) const
-{
- writeShort(file, kills);
- writeShort(file, exp);
-
- writeShort(file, places.size());
- for (std::vector<unsigned short>::const_iterator iter = places.begin();
- iter != places.end(); ++iter)
- {
- writeShort(file, *iter);
- }
-}
-
-void kill_def::load(FILE *file)
-{
- kills = (unsigned short) readShort(file);
- exp = readShort(file);
-
- places.clear();
- short place_count = readShort(file);
- for (short i = 0; i < place_count; ++i)
- {
- places.push_back((unsigned short) readShort(file));
- }
-}
-
-kill_ghost::kill_ghost(const struct monsters *mon)
-{
- exp = exper_value( (struct monsters *) mon);
- place = get_packed_place();
- ghost_name = ghost.name;
-
- // Check whether this is really a ghost, since we also have to handle
- // the Pandemonic demons.
- if (mon->type == MONS_PLAYER_GHOST)
- ghost_name = "The ghost of " + ghost_description(true);
-}
-
-std::string kill_ghost::info() const
-{
- return ghost_name +
- (Options.dump_kill_places != KDO_NO_PLACES?
- " (" + short_place_name(place) + ")" : std::string(""));
-}
-
-void kill_ghost::save(FILE *file) const
-{
- writeString(file, ghost_name);
- writeShort(file, (unsigned short) exp);
- writeShort(file, place);
-}
-
-void kill_ghost::load(FILE *file)
-{
- ghost_name = readString(file);
- exp = readShort(file);
- place = (unsigned short) readShort(file);
-}
-
-kill_monster_desc::kill_monster_desc(const monsters *mon)
-{
-
- // TODO: We need to understand how shapeshifters are handled.
- monnum = mon->type;
- modifier = M_NORMAL;
- switch (mon->type)
- {
- case MONS_ZOMBIE_LARGE: case MONS_ZOMBIE_SMALL:
- modifier = M_ZOMBIE;
- break;
- case MONS_SKELETON_LARGE: case MONS_SKELETON_SMALL:
- modifier = M_SKELETON;
- break;
- case MONS_SIMULACRUM_LARGE: case MONS_SIMULACRUM_SMALL:
- modifier = M_SIMULACRUM;
- break;
- case MONS_SPECTRAL_THING:
- modifier = M_SPECTRE;
- break;
- }
- if (modifier != M_NORMAL) monnum = mon->number;
-
- if (mons_has_ench((struct monsters *) mon, ENCH_SHAPESHIFTER) ||
- mons_has_ench((struct monsters *) mon, ENCH_GLOWING_SHAPESHIFTER))
- modifier = M_SHAPESHIFTER;
-
- // XXX: Ugly hack - merge all mimics into one mimic record.
- if (monnum >= MONS_GOLD_MIMIC && monnum <= MONS_POTION_MIMIC)
- monnum = MONS_WEAPON_MIMIC;
-}
-
-void kill_monster_desc::save(FILE *file) const
-{
- writeShort(file, (short) monnum);
- writeShort(file, (short) modifier);
-}
-
-void kill_monster_desc::load(FILE *file)
-{
- monnum = (int) readShort(file);
- modifier = (name_modifier) readShort(file);
-}
-
-#ifdef CLUA_BINDINGS
-///////////////////////////////////////////////////////////////////////////
-// Kill Lua interface
-//
-
-#define KILLEXP_ACCESS(name, type, field) \
- static int kill_lualc_##name(lua_State *ls) { \
- if (!lua_islightuserdata(ls, 1)) { \
- luaL_argerror(ls, 1, "Unexpected argument type"); \
- return 0; \
- } \
- \
- kill_exp *ke = static_cast<kill_exp*>( lua_touserdata(ls, 1) ); \
- if (ke) { \
- lua_push##type(ls, ke->field); \
- return 1; \
- } \
- return 0; \
- }
-
-KILLEXP_ACCESS(nkills, number, nkills)
-KILLEXP_ACCESS(exp, number, exp)
-KILLEXP_ACCESS(base_name, string, base_name.c_str())
-KILLEXP_ACCESS(desc, string, desc.c_str())
-KILLEXP_ACCESS(monnum, number, monnum)
-KILLEXP_ACCESS(isghost, boolean,
- monnum == -1 &&
- ke->desc.find("The ghost of") != std::string::npos)
-KILLEXP_ACCESS(ispandemon, boolean,
- monnum == -1 &&
- ke->desc.find("The ghost of") == std::string::npos)
-KILLEXP_ACCESS(isunique, boolean,
- monnum != -1 && mons_is_unique(ke->monnum))
-
-
-static int kill_lualc_modifier(lua_State *ls)
-{
- if (!lua_islightuserdata(ls, 1))
- {
- luaL_argerror(ls, 1, "Unexpected argument type");
- return 0;
- }
-
- kill_exp *ke = static_cast<kill_exp*>( lua_touserdata(ls, 1) );
- if (ke)
- {
- const char *modifier;
- switch (ke->modifier)
- {
- case kill_monster_desc::M_ZOMBIE:
- modifier = "zombie";
- break;
- case kill_monster_desc::M_SKELETON:
- modifier = "skeleton";
- break;
- case kill_monster_desc::M_SIMULACRUM:
- modifier = "simulacrum";
- break;
- case kill_monster_desc::M_SPECTRE:
- modifier = "spectre";
- break;
- case kill_monster_desc::M_SHAPESHIFTER:
- modifier = "shapeshifter";
- break;
- default:
- modifier = "";
- break;
- }
- lua_pushstring(ls, modifier);
- return 1;
- }
- return 0;
-}
-
-static int kill_lualc_places(lua_State *ls)
-{
- if (!lua_islightuserdata(ls, 1))
- {
- luaL_argerror(ls, 1, "Unexpected argument type");
- return 0;
- }
-
- kill_exp *ke = static_cast<kill_exp*>( lua_touserdata(ls, 1) );
- if (ke)
- {
- lua_newtable(ls);
- for (int i = 0, count = ke->places.size(); i < count; ++i)
- {
- lua_pushnumber(ls, ke->places[i]);
- lua_rawseti(ls, -2, i + 1);
- }
- return 1;
- }
- return 0;
-}
-
-static int kill_lualc_place_name(lua_State *ls)
-{
- int num = luaL_checkint(ls, 1);
- std::string plname = short_place_name(num);
- lua_pushstring(ls, plname.c_str());
- return 1;
-}
-
-static bool is_ghost(const kill_exp *ke)
-{
- return ke->monnum == -1
- && ke->desc.find("The ghost of") != std::string::npos;
-}
-
-static int kill_lualc_holiness(lua_State *ls)
-{
- if (!lua_islightuserdata(ls, 1))
- {
- luaL_argerror(ls, 1, "Unexpected argument type");
- return 0;
- }
-
- kill_exp *ke = static_cast<kill_exp*>( lua_touserdata(ls, 1) );
- if (ke)
- {
- const char *verdict = "strange";
- if (ke->monnum == -1)
- {
- verdict = is_ghost(ke)? "undead" : "demonic";
- }
- else
- {
- switch (mons_class_holiness(ke->monnum))
- {
- case MH_HOLY: verdict = "holy"; break;
- case MH_NATURAL: verdict = "natural"; break;
- case MH_UNDEAD: verdict = "undead"; break;
- case MH_DEMONIC: verdict = "demonic"; break;
- case MH_NONLIVING: verdict = "nonliving"; break;
- case MH_PLANT: verdict = "plant"; break;
- }
- if (ke->modifier != kill_monster_desc::M_NORMAL
- && ke->modifier != kill_monster_desc::M_SHAPESHIFTER)
- verdict = "undead";
- }
- lua_pushstring(ls, verdict);
- return 1;
- }
- return 0;
-}
-
-static int kill_lualc_symbol(lua_State *ls)
-{
- if (!lua_islightuserdata(ls, 1))
- {
- luaL_argerror(ls, 1, "Unexpected argument type");
- return 0;
- }
-
- kill_exp *ke = static_cast<kill_exp*>( lua_touserdata(ls, 1) );
- if (ke)
- {
- unsigned char ch = ke->monnum != -1?
- mons_char(ke->monnum) :
- is_ghost(ke)? 'p' : '&';
-
- if (ke->monnum == MONS_PROGRAM_BUG)
- ch = ' ';
-
- switch (ke->modifier)
- {
- case kill_monster_desc::M_ZOMBIE:
- case kill_monster_desc::M_SKELETON:
- case kill_monster_desc::M_SIMULACRUM:
- ch = mons_zombie_size(ke->monnum) == Z_SMALL? 'z' : 'Z';
- break;
- case kill_monster_desc::M_SPECTRE:
- ch = 'W';
- break;
- default:
- break;
- }
-
- char s[2];
- s[0] = (char) ch;
- s[1] = 0;
- lua_pushstring(ls, s);
- return 1;
- }
- return 0;
-}
-
-static int kill_lualc_rawwrite(lua_State *ls)
-{
- const char *s = luaL_checkstring(ls, 1);
- lua_pushstring(ls, "cr_skill");
- lua_gettable(ls, LUA_REGISTRYINDEX);
- if (!lua_islightuserdata(ls, -1))
- {
- lua_settop(ls, -2);
- fprintf(stderr, "Can't find kill string?\n");
- return 0;
- }
-
- std::string *skill = static_cast<std::string *>( lua_touserdata(ls, -1) );
- // Pop the userdata off the stack.
- lua_settop(ls, -2);
-
- *skill += s;
- *skill += "\n";
-
- return 0;
-}
-
-static int kill_lualc_write(lua_State *ls)
-{
- if (!lua_islightuserdata(ls, 1))
- {
- luaL_argerror(ls, 1, "Unexpected argument type");
- return 0;
- }
-
- kill_exp *ke = static_cast<kill_exp*>( lua_touserdata(ls, 1) );
- if (ke)
- {
- lua_pushstring(ls, "cr_skill");
- lua_gettable(ls, LUA_REGISTRYINDEX);
- if (!lua_islightuserdata(ls, -1))
- {
- lua_settop(ls,-2);
- fprintf(stderr, "Can't find kill string?\n");
- return 0;
- }
-
- std::string *skill = static_cast<std::string *>(
- lua_touserdata(ls, -1) );
- // Pop the userdata off the stack.
- lua_settop(ls, -2);
-
- // Write kill description and a newline.
- *skill += ke->desc + "\n";
- }
- return 0;
-}
-
-static int kill_lualc_summary(lua_State *ls)
-{
- if (!lua_istable(ls, 1))
- {
- luaL_argerror(ls, 1, "Unexpected argument type, wanted table");
- return 0;
- }
-
- unsigned long count = 0;
- for (int i = 1; ; ++i)
- {
- lua_rawgeti(ls, 1, i);
- if (lua_isnil(ls, -1))
- {
- lua_settop(ls, -2);
- break;
- }
-
- if (!lua_islightuserdata(ls, -1))
- {
- luaL_argerror(ls, 1, "Unexpected argument type");
- return 0;
- }
-
- kill_exp *ke = static_cast<kill_exp*>( lua_touserdata(ls, -1) );
- lua_settop(ls, -2);
- if (ke)
- count += ke->nkills;
- }
- char buf[120];
- *buf = 0;
- if (count)
- snprintf(buf, sizeof buf, "%lu creature%s vanquished.",
- count, count > 1? "s" : "");
- lua_pushstring(ls, buf);
- return 1;
-}
-
-static const struct luaL_reg kill_lib[] =
-{
- { "nkills", kill_lualc_nkills },
- { "exp" , kill_lualc_exp },
- { "base_name", kill_lualc_base_name },
- { "desc", kill_lualc_desc },
- { "monnum", kill_lualc_monnum },
- { "modifier", kill_lualc_modifier },
- { "places", kill_lualc_places },
- { "place_name", kill_lualc_place_name },
- { "holiness", kill_lualc_holiness },
- { "symbol", kill_lualc_symbol },
- { "isghost", kill_lualc_isghost },
- { "ispandemon", kill_lualc_ispandemon },
- { "isunique", kill_lualc_isunique },
- { "rawwrite", kill_lualc_rawwrite },
- { "write", kill_lualc_write },
- { "summary", kill_lualc_summary },
- { NULL, NULL }
-};
-
-void lua_open_kills(lua_State *ls)
-{
- luaL_openlib(ls, "kills", kill_lib, 0);
-}
-
-static void kill_lua_filltable(std::vector<kill_exp> &v)
-{
- lua_State *ls = clua.state();
- lua_newtable(ls);
- for (int i = 0, count = v.size(); i < count; ++i)
- {
- lua_pushlightuserdata(ls, &v[i]);
- lua_rawseti(ls, -2, i + 1);
- }
-}
-
-#endif