summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/lua/kills.lua
blob: b84b1f93c0a7d59393f7bcf52ddd4e7f6986097d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
------------------------------------------------------------------
-- kills.lua:
-- Generates fancier vanquished creatures lists.
--
-- List ideas courtesy Jukka Kuusisto and Erik Piper.
--
-- To use this, add this line to your init.txt:
--   lua_file = lua/kills.lua
--
-- Take a look at the c_kill_list function - that's where to start if you
-- want to customize things.
------------------------------------------------------------------

function kill_filter(a, condition)
    local t = { }
    for i, k in ipairs(a) do
        if condition(k) then
            table.insert(t, k)
        end
    end
    return t
end

function show_sorted_list(list, baseindent, sortfn)
    baseindent = baseindent or "    "
    sortfn = sortfn or 
               function (x, y)
                   return kills.exp(x) > kills.exp(y) or
                   (kills.exp(x) == kills.exp(y) and
                        kills.base_name(x) < kills.base_name(y))
               end
    table.sort(list, sortfn)
    for i, k in ipairs(list) do
        kills.rawwrite(baseindent .. "  " .. kills.desc(k))
    end
    kills.rawwrite(baseindent .. kills.summary(list))
end

function group_kills(a, namemap, keys, selector)
    local count = 0
    for i, key in ipairs(keys) do
        local selected = kill_filter(a, 
            function (k)
                return selector(key, k)
            end
        )
        if table.getn(selected) > 0 then
            if count > 0 then
                kills.rawwrite("")
            end
            count = count + 1
            kills.rawwrite("    " .. namemap[key])
            show_sorted_list(selected)
        end
    end
end

function holiness_list(a)
    local holies = {
        strange = "Strange Monsters",
        unique  = "Uniques",
        holy    = "Holy Monsters",
        natural = "Natural Monsters",
        undead  = "Undead Monsters",
        demonic = "Demonic Monsters",
        nonliving = "Non-Living Monsters",
        plant   = "Plants",
    }
    local holysort = { "strange", "unique", 
                       "natural", "nonliving",
                       "undead", "demonic", "plant" }
    kills.rawwrite("  Monster Nature")
    group_kills( a, holies, holysort, 
        function ( key, kill )
            return (kills.holiness(kill) == key and not kills.isunique(kill)) 
                or 
                   (key == "unique" and kills.isunique(kill))
        end 
    )
    kills.rawwrite("  " .. kills.summary(a))
end

function count_list(a, ascending)
    kills.rawwrite("  Ascending Order")
    show_sorted_list(a,
        "  ",
        function (x, y)
            if ascending then
                return kills.nkills(x) < kills.nkills(y)
                    or (kills.nkills(x) == kills.nkills(y) and
                        kills.exp(x) > kills.exp(y))
            else
                return kills.nkill(x) > kills.nkills(y)
                    or (kills.nkills(x) == kills.nkills(y) and
                        kills.exp(x) > kills.exp(y))
            end
        end
    )
end

function symbol_list(a)
    -- Create a list of monster characters and sort it
    local allsyms = { }
    for i, k in ipairs(a) do
        local ksym = kills.symbol(k)
        allsyms[ kills.symbol(k) ] = true
    end

    local sortedsyms = { }
    for sym, dud in pairs(allsyms) do table.insert(sortedsyms, sym) end
    table.sort(sortedsyms)

    kills.rawwrite("  Monster Symbol")
    for i, sym in ipairs(sortedsyms) do
        if i > 1 then
            kills.rawwrite("")
        end
        
        local symlist = kill_filter(a, 
                function (k)
                    return kills.symbol(k) == sym
                end
        )
        kills.rawwrite("    All '" .. sym .. "'")
        show_sorted_list(symlist)
    end

    kills.rawwrite("  " .. kills.summary(a))
end

function classic_list(title, a, suffix)
    if table.getn(a) == 0 then return end
    kills.rawwrite(title)
    for i, k in ipairs(a) do
        kills.rawwrite("    " .. kills.desc(k))
    end
    kills.rawwrite("  " .. kills.summary(a))
    if suffix then
        kills.rawwrite(suffix)
    end
end

function separator()
    kills.rawwrite("----------------------------------------\n")
end

function newline()
    kills.rawwrite("")
end

-----------------------------------------------------------------------------
-- This is the function that Crawl calls when it wants to dump the kill list
-- The parameter "a" is the list (Lua table) of kills, initially sorted in
-- descending order of experience. Kill entries must be inspected using 
-- kills.foo(ke).
--
-- NOTE: Comment out the kill lists that you don't like!
--
-- As of 20060224, the kill list is divided into three:
--  * Direct player kills
--  * Monsters killed by friendlies
--  * Monsters killed by other things (traps, etc.)
--  
-- For each category, the game calls c_kill_list, with a table of killed
-- monsters, and the killer (who). The killer will be nil for direct player
-- kills, and a string ("collateral kills", "others") otherwise.
--
-- c_kill_list will not be called for a category if the category contains no
-- kills.
--
-- After all categories, c_kill_list will be called with no arguments to
-- indicate the end of the kill listing.

function c_kill_list(a, who, needsep)
    -- If there aren't any kills yet, bail out
    if not a or table.getn(a) == 0 then
        if not a and who and who ~= "" then
            -- This is the grand total
            separator()
            kills.rawwrite(who)
        end
        return
    end

    if needsep then
        separator()
    end

    local title = "Vanquished Creatures"
    if who then
        title = title .. " (" .. who .. ")"
    end

    kills.rawwrite(title)

    -- Group kills by monster symbol
    symbol_list(a)
    newline()

    -- Group by holiness
    holiness_list(a)
    newline()

    -- Sort by kill count (ascending).
    count_list(a, true)
    newline()

    -- Classic list without zombies and skeletons
    -- Commented-out - this is a boring list.
    --[[
    -- First re-sort into descending order of exp, since
    -- count_list has re-sorted the array.
    table.sort(a, function (x, y)
                      return kills.exp(x) > kills.exp(y)
                  end);

    -- Filter out zombies and skeletons and display the rest
    classic_list(
        "  Kills minus zombies and skeletons",
        kill_filter(a, 
            function (k)
                return kills.modifier(k) ~= "zombie" and
                       kills.modifier(k) ~= "skeleton"
            end
        ))

    separator()
    --]]

    -- Show only monsters with 3 digit kill count
    classic_list(
        "  The 3-digit Club",
        kill_filter(a, 
            function (k)
                return kills.nkills(k) > 99
            end
        ),
        "")

end