Commit 3fd459823e6ead702520e5bfffd049b21ba04783

Authored by dg
1 parent 930743c1

plop


git-svn-id: http://svn.net-core.org/repos/t-engine4@3243 51575b47-30f0-44d4-a5cc-537603b46e54

Too many changes to show.

To preserve performance only 17 of 17+ files are displayed.

1   --- TE4 - T-Engine 4
2   --- Copyright (C) 2009, 2010, 2011 Nicolas Casalini
3   ---
4   --- This program is free software: you can redistribute it and/or modify
5   --- it under the terms of the GNU General Public License as published by
6   --- the Free Software Foundation, either version 3 of the License, or
7   --- (at your option) any later version.
8   ---
9   --- This program is distributed in the hope that it will be useful,
10   --- but WITHOUT ANY WARRANTY; without even the implied warranty of
11   --- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12   --- GNU General Public License for more details.
13   ---
14   --- You should have received a copy of the GNU General Public License
15   --- along with this program. If not, see <http://www.gnu.org/licenses/>.
16   ---
17   --- Nicolas Casalini "DarkGod"
18   --- darkgod@te4.org
19   -
20   --- Defines AIs that can use talents, either smartly or "dumbly"
21   -
22   -newAI("angband", function(self)
23   - if self:runAI(self.ai_state.ai_target or "target_simple") then
24   - -- One in "talent_in" chance of using a talent
25   - if (not self.ai_state.no_talents or self.ai_state.no_talents == 0) and rng.chance(self.ai_state.talent_in or 6) and self:reactionToward(self.ai_target.actor) < 0 then
26   - self:runAI("dumb_talented")
27   - end
28   - if not self.energy.used then
29   - self:runAI(self.ai_state.ai_move or "move_simple")
30   - end
31   - return true
32   - end
1   --- ToME - Tales of Middle-Earth
2   --- Copyright (C) 2009, 2010, 2011 Nicolas Casalini
3   ---
4   --- This program is free software: you can redistribute it and/or modify
5   --- it under the terms of the GNU General Public License as published by
6   --- the Free Software Foundation, either version 3 of the License, or
7   --- (at your option) any later version.
8   ---
9   --- This program is distributed in the hope that it will be useful,
10   --- but WITHOUT ANY WARRANTY; without even the implied warranty of
11   --- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12   --- GNU General Public License for more details.
13   ---
14   --- You should have received a copy of the GNU General Public License
15   --- along with this program. If not, see <http://www.gnu.org/licenses/>.
16   ---
17   --- Nicolas Casalini "DarkGod"
18   --- darkgod@te4.org
19   -
20   -require "engine.class"
21   -require "engine.Actor"
22   -require "engine.Autolevel"
23   -require "engine.interface.ActorTemporaryEffects"
24   -require "engine.interface.ActorLife"
25   -require "engine.interface.ActorProject"
26   -require "engine.interface.ActorLevel"
27   -require "engine.interface.ActorStats"
28   -require "engine.interface.ActorTalents"
29   -require "engine.interface.ActorResource"
30   -require "engine.interface.ActorFOV"
31   -local Map = require "engine.Map"
32   -
33   -module(..., package.seeall, class.inherit(
34   - engine.Actor,
35   - engine.interface.ActorTemporaryEffects,
36   - engine.interface.ActorLife,
37   - engine.interface.ActorProject,
38   - engine.interface.ActorLevel,
39   - engine.interface.ActorStats,
40   - engine.interface.ActorTalents,
41   - engine.interface.ActorResource,
42   - engine.interface.ActorFOV
43   -))
44   -
45   -_M._noalpha = true
46   -
47   -function _M:init(t, no_default)
48   - -- Define some basic combat stats
49   - self.combat_armor = 0
50   -
51   - -- Default regen
52   - t.power_regen = t.power_regen or 1
53   - t.life_regen = t.life_regen or 0.25 -- Life regen real slow
54   -
55   - t.esp = {}
56   - t.speed = t.speed or 0
57   -
58   - -- Default melee barehanded damage
59   - self.combat = { dam=1 }
60   -
61   - engine.Actor.init(self, t, no_default)
62   - engine.interface.ActorTemporaryEffects.init(self, t)
63   - engine.interface.ActorLife.init(self, t)
64   - engine.interface.ActorProject.init(self, t)
65   - engine.interface.ActorTalents.init(self, t)
66   - engine.interface.ActorResource.init(self, t)
67   - engine.interface.ActorStats.init(self, t)
68   - engine.interface.ActorLevel.init(self, t)
69   - engine.interface.ActorFOV.init(self, t)
70   -
71   - self:computeEnergyMod()
72   -end
73   -
74   -function _M:act()
75   - if not engine.Actor.act(self) then return end
76   -
77   - self.changed = true
78   -
79   - -- Cooldown talents
80   - self:cooldownTalents()
81   - -- Regen resources
82   - self:regenLife()
83   - self:regenResources()
84   - -- Compute timed effects
85   - self:timedEffects()
86   -
87   - -- Still enough energy to act ?
88   - if self.energy.value < game.energy_to_act then return false end
89   -
90   - return true
91   -end
92   -
93   -function _M:move(x, y, force)
94   - local moved = false
95   - if force or self:enoughEnergy() then
96   - -- Never move but tries to attack ? ok
97   - if not force and self:attr("never_move") then
98   - -- A bit weird, but this simple asks the collision code to detect an attack
99   - if not game.level.map:checkAllEntities(x, y, "block_move", self, true) then
100   - game.logPlayer(self, "You are unable to move!")
101   - end
102   - else
103   - moved = engine.Actor.move(self, x, y, force)
104   - end
105   - if not force and moved and not self.did_energy then self:useEnergy() end
106   - end
107   - self.did_energy = nil
108   - return moved
109   -end
110   -
111   -local extract_energy =
112   -{
113   - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
114   - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
115   - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
116   - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
117   - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
118   - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
119   - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
120   - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
121   - 2, 2, 2, 2, 2, 2, 2, 3, 3, 3,
122   - 3, 3, 3, 3, 3, 4, 4, 4, 4, 4,
123   - 5, 5, 5, 5, 6, 6, 7, 7, 8, 9,
124   - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
125   - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
126   - 30, 31, 32, 33, 34, 35, 36, 36, 37, 37,
127   - 38, 38, 39, 39, 40, 40, 40, 41, 41, 41,
128   - 42, 42, 42, 43, 43, 43, 44, 44, 44, 44,
129   - 45, 45, 45, 45, 45, 46, 46, 46, 46, 46,
130   - 47, 47, 47, 47, 47, 48, 48, 48, 48, 48,
131   - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
132   - 49, 49, 49, 49, 49, 49, 49, 49, 49, 49,
133   -}
134   -
135   ---- Compute energy mod based on speed
136   -function _M:computeEnergyMod()
137   - self.energy.mod = extract_energy[self.speed + 111] / 10
138   -end
139   -
140   ---- Called when a temporary value changes (added or deleted)
141   --- Takes care to compute energy mod
142   --- @param prop the property changing
143   --- @param v the value of the change
144   --- @param base the base table of prop
145   -function _M:onTemporaryValueChange(prop, v, base)
146   - if prop == "speed" and base == self then
147   - self:computeEnergyMod()
148   - end
149   -end
150   -
151   ---- Reveals location surrounding the actor
152   -function _M:magicMap(radius, x, y)
153   - x = x or self.x
154   - y = y or self.y
155   - radius = math.floor(radius)
156   -
157   - local ox, oy
158   -
159   - self.x, self.y, ox, oy = x, y, self.x, self.y
160   - self:computeFOV(radius, "block_sense", function(x, y)
161   - game.level.map.remembers(x, y, true)
162   - game.level.map.has_seens(x, y, true)
163   - end, true, true, true)
164   -
165   - self.x, self.y = ox, oy
166   -end
167   -
168   -function _M:tooltip()
169   - return ([[%s%s
170   -#00ffff#Level: %d
171   -#ff0000#HP: %d (%d%%)
172   -Stats: %d / %d / %d
173   -%s]]):format(
174   - self:getDisplayString(),
175   - self.name,
176   - self.level,
177   - self.life, self.life * 100 / self.max_life,
178   - self:getStr(),
179   - self:getDex(),
180   - self:getCon(),
181   - self.desc or ""
182   - )
183   -end
184   -
185   -function _M:onTakeHit(value, src)
186   - return value
187   -end
188   -
189   -function _M:die(src)
190   - engine.interface.ActorLife.die(self, src)
191   -
192   - -- Gives the killer some exp for the kill
193   - if src and src.gainExp then
194   - src:gainExp(self:worthExp(src))
195   - end
196   -
197   - return true
198   -end
199   -
200   -function _M:levelup()
201   - self.max_life = self.max_life + 2
202   -
203   - self:incMaxPower(3)
204   -
205   - -- Healp up on new level
206   - self.life = self.max_life
207   - self.power = self.max_power
208   -end
209   -
210   ---- Notifies a change of stat value
211   -function _M:onStatChange(stat, v)
212   - if stat == self.STAT_CON then
213   - self.max_life = self.max_life + 2
214   - end
215   -end
216   -
217   -function _M:attack(target)
218   - self:bumpInto(target)
219   -end
220   -
221   -
222   ---- Called before a talent is used
223   --- Check the actor can cast it
224   --- @param ab the talent (not the id, the table)
225   --- @return true to continue, false to stop
226   -function _M:preUseTalent(ab, silent)
227   - if not self:enoughEnergy() then print("fail energy") return false end
228   -
229   - if ab.mode == "sustained" then
230   - if ab.sustain_power and self.max_power < ab.sustain_power and not self:isTalentActive(ab.id) then
231   - game.logPlayer(self, "You do not have enough power to activate %s.", ab.name)
232   - return false
233   - end
234   - else
235   - if ab.power and self:getPower() < ab.power then
236   - game.logPlayer(self, "You do not have enough power to cast %s.", ab.name)
237   - return false
238   - end
239   - end
240   -
241   - if not silent then
242   - -- Allow for silent talents
243   - if ab.message ~= nil then
244   - if ab.message then
245   - game.logSeen(self, "%s", self:useTalentMessage(ab))
246   - end
247   - elseif ab.mode == "sustained" and not self:isTalentActive(ab.id) then
248   - game.logSeen(self, "%s activates %s.", self.name:capitalize(), ab.name)
249   - elseif ab.mode == "sustained" and self:isTalentActive(ab.id) then
250   - game.logSeen(self, "%s deactivates %s.", self.name:capitalize(), ab.name)
251   - else
252   - game.logSeen(self, "%s uses %s.", self.name:capitalize(), ab.name)
253   - end
254   - end
255   - return true
256   -end
257   -
258   ---- Called before a talent is used
259   --- Check if it must use a turn, mana, stamina, ...
260   --- @param ab the talent (not the id, the table)
261   --- @param ret the return of the talent action
262   --- @return true to continue, false to stop
263   -function _M:postUseTalent(ab, ret)
264   - if not ret then return end
265   -
266   - self:useEnergy()
267   -
268   - if ab.mode == "sustained" then
269   - if not self:isTalentActive(ab.id) then
270   - if ab.sustain_power then
271   - self.max_power = self.max_power - ab.sustain_power
272   - end
273   - else
274   - if ab.sustain_power then
275   - self.max_power = self.max_power + ab.sustain_power
276   - end
277   - end
278   - else
279   - if ab.power then
280   - self:incPower(-ab.power)
281   - end
282   - end
283   -
284   - return true
285   -end
286   -
287   ---- Return the full description of a talent
288   --- You may overload it to add more data (like power usage, ...)
289   -function _M:getTalentFullDescription(t)
290   - local d = {}
291   -
292   - if t.mode == "passive" then d[#d+1] = "#6fff83#Use mode: #00FF00#Passive"
293   - elseif t.mode == "sustained" then d[#d+1] = "#6fff83#Use mode: #00FF00#Sustained"
294   - else d[#d+1] = "#6fff83#Use mode: #00FF00#Activated"
295   - end
296   -
297   - if t.power or t.sustain_power then d[#d+1] = "#6fff83#Power cost: #7fffd4#"..(t.power or t.sustain_power) end
298   - if self:getTalentRange(t) > 1 then d[#d+1] = "#6fff83#Range: #FFFFFF#"..self:getTalentRange(t)
299   - else d[#d+1] = "#6fff83#Range: #FFFFFF#melee/personal"
300   - end
301   - if t.cooldown then d[#d+1] = "#6fff83#Cooldown: #FFFFFF#"..t.cooldown end
302   -
303   - return table.concat(d, "\n").."\n#6fff83#Description: #FFFFFF#"..t.info(self, t)
304   -end
305   -
306   ---- How much experience is this actor worth
307   --- @param target to whom is the exp rewarded
308   --- @return the experience rewarded
309   -function _M:worthExp(target)
310   - return self.exp_worth * self.level / target.level
311   -end
312   -
313   ---- Can the actor see the target actor
314   --- This does not check LOS or such, only the actual ability to see it.<br/>
315   --- Check for telepathy, invisibility, stealth, ...
316   -function _M:canSee(actor, def, def_pct)
317   - if not actor then return false, 0 end
318   -
319   - -- Check for stealth. Checks against the target cunning and level
320   - if actor:attr("stealth") and actor ~= self then
321   - local def = self.level / 2 + self:getCun(25)
322   - local hit, chance = self:checkHit(def, actor:attr("stealth") + (actor:attr("inc_stealth") or 0), 0, 100)
323   - if not hit then
324   - return false, chance
325   - end
326   - end
327   -
328   - if def ~= nil then
329   - return def, def_pct
330   - else
331   - return true, 100
332   - end
333   -end
334   -
335   ---- Can the target be applied some effects
336   --- @param what a string describing what is being tried
337   -function _M:canBe(what)
338   - if what == "poison" and rng.percent(100 * (self:attr("poison_immune") or 0)) then return false end
339   - if what == "cut" and rng.percent(100 * (self:attr("cut_immune") or 0)) then return false end
340   - if what == "confusion" and rng.percent(100 * (self:attr("confusion_immune") or 0)) then return false end
341   - if what == "blind" and rng.percent(100 * (self:attr("blind_immune") or 0)) then return false end
342   - if what == "stun" and rng.percent(100 * (self:attr("stun_immune") or 0)) then return false end
343   - if what == "fear" and rng.percent(100 * (self:attr("fear_immune") or 0)) then return false end
344   - if what == "instakill" and rng.percent(100 * (self:attr("instakill_immune") or 0)) then return false end
345   - return true
1   --- ToME - Tales of Middle-Earth
2   --- Copyright (C) 2009, 2010, 2011 Nicolas Casalini
3   ---
4   --- This program is free software: you can redistribute it and/or modify
5   --- it under the terms of the GNU General Public License as published by
6   --- the Free Software Foundation, either version 3 of the License, or
7   --- (at your option) any later version.
8   ---
9   --- This program is distributed in the hope that it will be useful,
10   --- but WITHOUT ANY WARRANTY; without even the implied warranty of
11   --- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12   --- GNU General Public License for more details.
13   ---
14   --- You should have received a copy of the GNU General Public License
15   --- along with this program. If not, see <http://www.gnu.org/licenses/>.
16   ---
17   --- Nicolas Casalini "DarkGod"
18   --- darkgod@te4.org
19   -
20   -require "engine.class"
21   -require "engine.GameTurnBased"
22   -require "engine.interface.GameTargeting"
23   -require "engine.KeyBind"
24   -local Savefile = require "engine.Savefile"
25   -local DamageType = require "engine.DamageType"
26   -local Zone = require "engine.Zone"
27   -local Map = require "engine.Map"
28   -local Level = require "engine.Level"
29   -local Birther = require "engine.Birther"
30   -
31   -local Grid = require "mod.class.Grid"
32   -local Actor = require "mod.class.Actor"
33   -local Player = require "mod.class.Player"
34   -local NPC = require "mod.class.NPC"
35   -
36   -local PlayerDisplay = require "mod.class.PlayerDisplay"
37   -
38   -local HotkeysDisplay = require "engine.HotkeysDisplay"
39   -local ActorsSeenDisplay = require "engine.ActorsSeenDisplay"
40   -local LogDisplay = require "engine.LogDisplay"
41   -local LogFlasher = require "engine.LogFlasher"
42   -local DebugConsole = require "engine.DebugConsole"
43   -local FlyingText = require "engine.FlyingText"
44   -local Tooltip = require "engine.Tooltip"
45   -
46   -local QuitDialog = require "mod.dialogs.Quit"
47   -
48   -module(..., package.seeall, class.inherit(engine.GameTurnBased, engine.interface.GameTargeting))
49   -
50   -function _M:init()
51   - engine.GameTurnBased.init(self, engine.KeyBind.new(), 1000, 100)
52   -
53   - -- Pause at birth
54   - self.paused = true
55   -
56   - -- Same init as when loaded from a savefile
57   - self:loaded()
58   -end
59   -
60   -function _M:run()
61   - self.flash = LogFlasher.new(0, 0, self.w, 20, nil, nil, nil, {255,255,255}, {0,0,0})
62   - self.logdisplay = LogDisplay.new(0, self.h * 0.8, self.w * 0.5, self.h * 0.2, nil, nil, nil, {255,255,255}, "/data/gfx/ui/message-log.png")
63   - self.player_display = PlayerDisplay.new(0, 220, 200, self.h * 0.8 - 220, {30,30,0})
64   - self.hotkeys_display = HotkeysDisplay.new(nil, self.w * 0.5, self.h * 0.8, self.w * 0.5, self.h * 0.2, "/data/gfx/ui/talents-list.png")
65   - self.npcs_display = ActorsSeenDisplay.new(nil, self.w * 0.5, self.h * 0.8, self.w * 0.5, self.h * 0.2, "/data/gfx/ui/talents-list.png")
66   - self.tooltip = Tooltip.new(nil, nil, {255,255,255}, {30,30,30})
67   - self.flyers = FlyingText.new()
68   - self:setFlyingText(self.flyers)
69   - self.minimap_bg, self.minimap_bg_w, self.minimap_bg_h = core.display.loadImage("/data/gfx/ui/minimap.png"):glTexture()
70   - self:createSeparators()
71   -
72   - self.log = function(style, ...) if type(style) == "number" then self.logdisplay(...) self.flash(style, ...) else self.logdisplay(style, ...) self.flash(self.flash.NEUTRAL, style, ...) end end
73   - self.logSeen = function(e, style, ...) if e and self.level.map.seens(e.x, e.y) then self.log(style, ...) end end
74   - self.logPlayer = function(e, style, ...) if e == self.player then self.log(style, ...) end end
75   -
76   - self.log(self.flash.GOOD, "Welcome to #00FF00#the Pits of Angband!")
77   -
78   - -- Setup inputs
79   - self:setupCommands()
80   - self:setupMouse()
81   -
82   - -- Starting from here we create a new game
83   - if not self.player then self:newGame() end
84   -
85   - self.hotkeys_display.actor = self.player
86   - self.npcs_display.actor = self.player
87   -
88   - -- Setup the targetting system
89   - engine.interface.GameTargeting.init(self)
90   -
91   - -- Ok everything is good to go, activate the game in the engine!
92   - self:setCurrent()
93   -
94   - if self.level then self:setupDisplayMode() end
95   -end
96   -
97   -function _M:newGame()
98   - self.player = Player.new{name=self.player_name, game_ender=true}
99   - Map:setViewerActor(self.player)
100   - self:setupDisplayMode()
101   -
102   - self.creating_player = true
103   - local birth = Birther.new(nil, self.player, {"base", "race", "class" }, function()
104   - self:changeLevel(1, "dungeon")
105   - print("[PLAYER BIRTH] resolve...")
106   - self.player:resolve()
107   - self.player:resolve(nil, true)
108   - self.player.energy.value = self.energy_to_act
109   - self.paused = true
110   - self.creating_player = false
111   - print("[PLAYER BIRTH] resolved!")
112   - end)
113   - self:registerDialog(birth)
114   -end
115   -
116   -function _M:loaded()
117   - engine.GameTurnBased.loaded(self)
118   - Zone:setup{npc_class="mod.class.NPC", grid_class="mod.class.Grid", object_class="mod.class.Object", ood_factor=7}
119   - Map:setViewerActor(self.player)
120   - Map:setViewPort(200, 20, self.w - 200, math.floor(self.h * 0.80) - 20, 12, 16, "/data/font/FSEX300.ttf", 16, true)
121   - self.key = engine.KeyBind.new()
122   -end
123   -
124   -function _M:createSeparators()
125   - self.bottom_separator, self.bottom_separator_w, self.bottom_separator_h = self:createVisualSeparator("horizontal", self.w)
126   - self.split_separator, self.split_separator_w, self.split_separator_h = self:createVisualSeparator("vertical", math.floor(self.h * 0.2))
127   - self.player_separator, self.player_separator_w, self.player_separator_h = self:createVisualSeparator("vertical", math.floor(self.h * 0.8) - 20)
128   -end
129   -
130   -function _M:setupDisplayMode()
131   - Map:setViewPort(200, 20, self.w - 200, math.floor(self.h * 0.80) - 20, 12, 16, "/data/font/FSEX300.ttf", 16, true)
132   - Map:resetTiles()
133   - Map.tiles.use_images = false
134   -
135   - if self.level then
136   - self.level.map:recreate()
137   - engine.interface.GameTargeting.init(self)
138   - self.level.map:moveViewSurround(self.player.x, self.player.y, 8, 8)
139   - end
140   -end
141   -
142   -function _M:save()
143   - return class.save(self, self:defaultSavedFields{}, true)
144   -end
145   -
146   -function _M:getSaveDescription()
147   - return {
148   - name = self.player.name,
149   - description = ([[Exploring level %d of %s.]]):format(self.level.level, self.zone.name),
150   - }
151   -end
152   -
153   -function _M:leaveLevel(level, lev, old_lev)
154   - if level:hasEntity(self.player) then
155   - level.exited = level.exited or {}
156   - if lev > old_lev then
157   - level.exited.down = {x=self.player.x, y=self.player.y}
158   - else
159   - level.exited.up = {x=self.player.x, y=self.player.y}
160   - end
161   - level.last_turn = game.turn
162   - level:removeEntity(self.player)
163   - end
164   -end
165   -
166   -function _M:changeLevel(lev, zone)
167   - local old_lev = (self.level and not zone) and self.level.level or -1000
168   - if zone then
169   - if self.zone then
170   - self.zone:leaveLevel(false, lev, old_lev)
171   - self.zone:leave()
172   - end
173   - if type(zone) == "string" then
174   - self.zone = Zone.new(zone)
175   - else
176   - self.zone = zone
177   - end
178   - end
179   - self.zone:getLevel(self, lev, old_lev)
180   -
181   - if lev > old_lev then
182   - self.player:move(self.level.default_up.x, self.level.default_up.y, true)
183   - else
184   - self.player:move(self.level.default_down.x, self.level.default_down.y, true)
185   - end
186   - self.level:addEntity(self.player)
187   -
188   --- self.level.map:setZoom(1.2, self.player.x, self.player.y)
189   -end
190   -
191   -function _M:getPlayer()
192   - return self.player
193   -end
194   -
195   -function _M:tick()
196   - if self.level then
197   - self:targetOnTick()
198   -
199   - engine.GameTurnBased.tick(self)
200   - -- Fun stuff: this can make the game realtime, although callit it in display() will make it work better
201   - -- (since display is on a set FPS while tick() ticks as much as possible
202   - -- engine.GameEnergyBased.tick(self)
203   - end
204   - -- When paused (waiting for player input) we return true: this means we wont be called again until an event wakes us
205   - if self.paused and not savefile_pipe.saving then return true end
206   -end
207   -
208   ---- Called every game turns
209   --- Does nothing, you can override it
210   -function _M:onTurn()
211   - -- The following happens only every 10 game turns (once for every turn of 1 mod speed actors)
212   - if self.turn % 10 ~= 0 then return end
213   -
214   - -- Process overlay effects
215   - self.level.map:processEffects()
216   -end
217   -
218   -function _M:display(nb_keyframe)
219   - -- If switching resolution, blank everything but the dialog
220   - if self.change_res_dialog then engine.GameTurnBased.display(self, nb_keyframe) return end
221   -
222   - -- Now the map, if any
223   - if self.level and self.level.map and self.level.map.finished and self.player.x and self.player.y then
224   - -- Display the map and compute FOV for the player if needed
225   - if self.level.map.changed then
226   - self.player:playerFOV()
227   - end
228   -
229   - self.level.map:display(nil, nil, nb_keyframe)
230   -
231   - -- Display the targetting system if active
232   - self.target:display()
233   -
234   - -- Minimap display
235   - self.minimap_bg:toScreenFull(0, 20, 200, 200, self.minimap_bg_w, self.minimap_bg_h)
236   - self.level.map:minimapDisplay(0, 20, util.bound(self.player.x - 25, 0, self.level.map.w - 50), util.bound(self.player.y - 25, 0, self.level.map.h - 50), 50, 50, 1)
237   - end
238   -
239   - -- We display the player's interface
240   - self.flash:toScreen(nb_keyframe)
241   - self.logdisplay:toScreen()
242   - self.player_display:toScreen()
243   - if self.show_npc_list then
244   - self.npcs_display:toScreen()
245   - else
246   - self.hotkeys_display:toScreen()
247   - end
248   - if self.player then self.player.changed = false end
249   -
250   - -- Separators
251   - self.bottom_separator:toScreenFull(0, 20 - 3, self.w, 6, self.bottom_separator_w, self.bottom_separator_h)
252   - self.bottom_separator:toScreenFull(0, self.h * 0.8 - 3, self.w, 6, self.bottom_separator_w, self.bottom_separator_h)
253   - self.split_separator:toScreenFull(self.w * 0.5 - 3 - 15, self.h * 0.8, 6, self.h * 0.2, self.split_separator_w, self.split_separator_h)
254   - self.split_separator:toScreenFull(self.w * 0.5 - 3, self.h * 0.8, 6, self.h * 0.2, self.split_separator_w, self.split_separator_h)
255   - self.player_separator:toScreenFull(200 - 3, 20, 6, self.h * 0.8 - 20, self.player_separator_w, self.player_separator_h)
256   -
257   - -- Tooltip is displayed over all else
258   - self:targetDisplayTooltip()
259   -
260   - engine.GameTurnBased.display(self, nb_keyframe)
261   -end
262   -
263   ---- Setup the keybinds
264   -function _M:setupCommands()
265   - -- Make targeting work
266   - self.normal_key = self.key
267   - self:targetSetupKey()
268   -
269   - -- Debug mode
270   - self.key:addCommands{
271   - [{"_a","ctrl"}] = function() if config.settings.cheat then game:registerDialog(require("mod.dialogs.debug.DebugMain").new()) end end,
272   - }
273   -
274   - -- One key handled for normal function
275   - self.key:addBinds
276   - {
277   - -- Movements
278   - MOVE_LEFT = function() self.player:moveDir(4) end,
279   - MOVE_RIGHT = function() self.player:moveDir(6) end,
280   - MOVE_UP = function() self.player:moveDir(8) end,
281   - MOVE_DOWN = function() self.player:moveDir(2) end,
282   - MOVE_LEFT_UP = function() self.player:moveDir(7) end,
283   - MOVE_LEFT_DOWN = function() self.player:moveDir(1) end,
284   - MOVE_RIGHT_UP = function() self.player:moveDir(9) end,
285   - MOVE_RIGHT_DOWN = function() self.player:moveDir(3) end,
286   - MOVE_STAY = function() self.player:useEnergy() end,
287   -
288   - RUN_LEFT = function() self.player:runInit(4) end,
289   - RUN_RIGHT = function() self.player:runInit(6) end,
290   - RUN_UP = function() self.player:runInit(8) end,
291   - RUN_DOWN = function() self.player:runInit(2) end,
292   - RUN_LEFT_UP = function() self.player:runInit(7) end,
293   - RUN_LEFT_DOWN = function() self.player:runInit(1) end,
294   - RUN_RIGHT_UP = function() self.player:runInit(9) end,
295   - RUN_RIGHT_DOWN = function() self.player:runInit(3) end,
296   -
297   - -- Hotkeys
298   - HOTKEY_1 = function() self.player:activateHotkey(1) end,
299   - HOTKEY_2 = function() self.player:activateHotkey(2) end,
300   - HOTKEY_3 = function() self.player:activateHotkey(3) end,
301   - HOTKEY_4 = function() self.player:activateHotkey(4) end,
302   - HOTKEY_5 = function() self.player:activateHotkey(5) end,
303   - HOTKEY_6 = function() self.player:activateHotkey(6) end,
304   - HOTKEY_7 = function() self.player:activateHotkey(7) end,
305   - HOTKEY_8 = function() self.player:activateHotkey(8) end,
306   - HOTKEY_9 = function() self.player:activateHotkey(9) end,
307   - HOTKEY_10 = function() self.player:activateHotkey(10) end,
308   - HOTKEY_11 = function() self.player:activateHotkey(11) end,
309   - HOTKEY_12 = function() self.player:activateHotkey(12) end,
310   - HOTKEY_SECOND_1 = function() self.player:activateHotkey(13) end,
311   - HOTKEY_SECOND_2 = function() self.player:activateHotkey(14) end,
312   - HOTKEY_SECOND_3 = function() self.player:activateHotkey(15) end,
313   - HOTKEY_SECOND_4 = function() self.player:activateHotkey(16) end,
314   - HOTKEY_SECOND_5 = function() self.player:activateHotkey(17) end,
315   - HOTKEY_SECOND_6 = function() self.player:activateHotkey(18) end,
316   - HOTKEY_SECOND_7 = function() self.player:activateHotkey(19) end,
317   - HOTKEY_SECOND_8 = function() self.player:activateHotkey(20) end,
318   - HOTKEY_SECOND_9 = function() self.player:activateHotkey(21) end,
319   - HOTKEY_SECOND_10 = function() self.player:activateHotkey(22) end,
320   - HOTKEY_SECOND_11 = function() self.player:activateHotkey(23) end,
321   - HOTKEY_SECOND_12 = function() self.player:activateHotkey(24) end,
322   - HOTKEY_THIRD_1 = function() self.player:activateHotkey(25) end,
323   - HOTKEY_THIRD_2 = function() self.player:activateHotkey(26) end,
324   - HOTKEY_THIRD_3 = function() self.player:activateHotkey(27) end,
325   - HOTKEY_THIRD_4 = function() self.player:activateHotkey(28) end,
326   - HOTKEY_THIRD_5 = function() self.player:activateHotkey(29) end,
327   - HOTKEY_THIRD_6 = function() self.player:activateHotkey(30) end,
328   - HOTKEY_THIRD_7 = function() self.player:activateHotkey(31) end,
329   - HOTKEY_THIRD_8 = function() self.player:activateHotkey(31) end,
330   - HOTKEY_THIRD_9 = function() self.player:activateHotkey(33) end,
331   - HOTKEY_THIRD_10 = function() self.player:activateHotkey(34) end,
332   - HOTKEY_THIRD_11 = function() self.player:activateHotkey(35) end,
333   - HOTKEY_THIRD_12 = function() self.player:activateHotkey(36) end,
334   - HOTKEY_PREV_PAGE = function() self.player:prevHotkeyPage() end,
335   - HOTKEY_NEXT_PAGE = function() self.player:nextHotkeyPage() end,
336   -
337   - -- Actions
338   - CHANGE_LEVEL = function()
339   - local e = self.level.map(self.player.x, self.player.y, Map.TERRAIN)
340   - if self.player:enoughEnergy() and e.change_level then
341   - self:changeLevel(e.change_zone and e.change_level or self.level.level + e.change_level, e.change_zone)
342   - else
343   - self.log("There is no way out of this level here.")
344   - end
345   - end,
346   -
347   - REST = function()
348   - self.player:restInit()
349   - end,
350   -
351   - PICKUP_FLOOR = function()
352   - self.player:playerPickup()
353   - end,
354   - DROP_FLOOR = function()
355   - self.player:playerDrop()
356   - end,
357   - SHOW_INVENTORY = function()
358   - local d
359   - local titleupdator = self.player:getEncumberTitleUpdator("Inventory")
360   - d = self.player:showEquipInven(titleupdator(), nil, function(o, inven, item, button, event)
361   - if not o then return end
362   - local ud = require("mod.dialogs.UseItemDialog").new(event == "button", self.player, o, item, inven, function(_, _, _, stop)
363   - d:generateList()
364   - d.title = titleupdator()
365   - if stop then self:unregisterDialog(d) end
366   - end)
367   - self:registerDialog(ud)
368   - end)
369   - end,
370   - SHOW_EQUIPMENT = "SHOW_INVENTORY",
371   - WEAR_ITEM = function()
372   - self.player:playerWear()
373   - end,
374   - TAKEOFF_ITEM = function()
375   - self.player:playerTakeoff()
376   - end,
377   - USE_ITEM = function()
378   - self.player:playerUseItem()
379   - end,
380   -
381   - USE_TALENTS = function()
382   - self.player:useTalents()
383   - end,
384   -
385   - SAVE_GAME = function()
386   - self:saveGame()
387   - end,
388   -
389   - SHOW_CHARACTER_SHEET = function()
390   - self:registerDialog(require("mod.dialogs.CharacterSheet").new(self.player))
391   - end,
392   -
393   - -- Exit the game
394   - QUIT_GAME = function()
395   - self:onQuit()
396   - end,
397   -
398   - EXIT = function()
399   - local menu menu = require("engine.dialogs.GameMenu").new{
400   - "resume",
401   - "keybinds",
402   - "video",
403   - "save",
404   - "quit"
405   - }
406   - self:registerDialog(menu)
407   - end,
408   -
409   - -- Lua console, you probably want to disable it for releases
410   - LUA_CONSOLE = function()
411   - self:registerDialog(DebugConsole.new())
412   - end,
413   -
414   - -- Toggle monster list
415   - TOGGLE_NPC_LIST = function()
416   - self.show_npc_list = not self.show_npc_list
417   - self.player.changed = true
418   - end,
419   -
420   - TACTICAL_DISPLAY = function()
421   - if Map.view_faction then
422   - self.always_target = nil
423   - Map:setViewerFaction(nil)
424   - else
425   - self.always_target = true
426   - Map:setViewerFaction("players")
427   - end
428   - end,
429   -
430   - LOOK_AROUND = function()
431   - self.flash:empty(true)
432   - self.flash(self.flash.GOOD, "Looking around... (direction keys to select interresting things, shift+direction keys to move freely)")
433   - local co = coroutine.create(function() self.player:getTarget{type="hit", no_restrict=true, range=2000} end)
434   - local ok, err = coroutine.resume(co)
435   - if not ok and err then print(debug.traceback(co)) error(err) end
436   - end,
437   - }
438   - self.key:setCurrent()
439   -end
440   -
441   -function _M:setupMouse(reset)
442   - if reset then self.mouse:reset() end
443   - self.mouse:registerZone(Map.display_x, Map.display_y, Map.viewport.width, Map.viewport.height, function(button, mx, my, xrel, yrel, bx, by, event)
444   - -- Handle targeting
445   - if self:targetMouse(button, mx, my, xrel, yrel, event) then return end
446   -
447   - -- Handle the mouse movement/scrolling
448   - self.player:mouseHandleDefault(self.key, self.key == self.normal_key, button, mx, my, xrel, yrel, event)
449   - end)
450   - -- Scroll message log
451   - self.mouse:registerZone(self.logdisplay.display_x, self.logdisplay.display_y, self.w, self.h, function(button)
452   - if button == "wheelup" then self.logdisplay:scrollUp(1) end
453   - if button == "wheeldown" then self.logdisplay:scrollUp(-1) end
454   - end, {button=true})
455   - -- Tooltip over the player pane
456   - self.mouse:registerZone(self.player_display.display_x, self.player_display.display_y, self.player_display.w, self.player_display.h, function(button, mx, my, xrel, yrel, bx, by, event)
457   - self.player_display.mouse:delegate(button, mx, my, xrel, yrel, bx, by, event)
458   - end)
459   - -- Use hotkeys with mouse
460   - self.mouse:registerZone(self.hotkeys_display.display_x, self.hotkeys_display.display_y, self.w, self.h, function(button, mx, my, xrel, yrel, bx, by, event)
461   - self.hotkeys_display:onMouse(button, mx, my, event == "button", function(text) self.tooltip:displayAtMap(nil, nil, self.w, self.h, tostring(text)) end)
462   - end)
463   - self.mouse:setCurrent()
464   -end
465   -
466   ---- Ask if we realy want to close, if so, save the game first
467   -function _M:onQuit()
468   - self.player:restStop()
469   -
470   - if not self.quit_dialog then
471   - self.quit_dialog = QuitDialog.new()
472   - self:registerDialog(self.quit_dialog)
473   - end
474   -end
475   -
476   ---- Requests the game to save
477   -function _M:saveGame()
478   - -- savefile_pipe is created as a global by the engine
479   - savefile_pipe:push(self.save_name, "game", self)
480   - self.log("Saving game...")
481   -end
482   -
483   ---------------------------------------------------------------
484   --- UI stuff
485   ---------------------------------------------------------------
486   -
487   ---- Create a visual separator
488   -local _sep_left = core.display.loadImage("/data/gfx/ui/separator-left.png") _sep_left:alpha()
489   -local _sep_right = core.display.loadImage("/data/gfx/ui/separator-right.png") _sep_right:alpha()
490   -local _sep_horiz = core.display.loadImage("/data/gfx/ui/separator-hori.png") _sep_horiz:alpha()
491   -local _sep_top = core.display.loadImage("/data/gfx/ui/separator-top.png") _sep_top:alpha()
492   -local _sep_bottom = core.display.loadImage("/data/gfx/ui/separator-bottom.png") _sep_bottom:alpha()
493   -local _sep_vert = core.display.loadImage("/data/gfx/ui/separator-vert.png") _sep_vert:alpha()
494   -function _M:createVisualSeparator(dir, size)
495   - if dir == "horizontal" then
496   - local sep = core.display.newSurface(size, 6)
497   - sep:erase(0, 0, 0)
498   - sep:merge(_sep_left, 0, 0)
499   - for i = 7, size - 7, 9 do sep:merge(_sep_horiz, i, 0) end
500   - sep:merge(_sep_right, size - 6, 0)
501   - return sep:glTexture()
502   - else
503   - local sep = core.display.newSurface(6, size)
504   - sep:erase(0, 0, 0)
505   - sep:merge(_sep_top, 0, 0)
506   - for i = 7, size - 7, 9 do sep:merge(_sep_vert, 0, i) end
507   - sep:merge(_sep_bottom, 0, size - 6)
508   - return sep:glTexture()
509   - end
1   --- ToME - Tales of Middle-Earth
2   --- Copyright (C) 2009, 2010, 2011 Nicolas Casalini
3   ---
4   --- This program is free software: you can redistribute it and/or modify
5   --- it under the terms of the GNU General Public License as published by
6   --- the Free Software Foundation, either version 3 of the License, or
7   --- (at your option) any later version.
8   ---
9   --- This program is distributed in the hope that it will be useful,
10   --- but WITHOUT ANY WARRANTY; without even the implied warranty of
11   --- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12   --- GNU General Public License for more details.
13   ---
14   --- You should have received a copy of the GNU General Public License
15   --- along with this program. If not, see <http://www.gnu.org/licenses/>.
16   ---
17   --- Nicolas Casalini "DarkGod"
18   --- darkgod@te4.org
19   -
20   -require "engine.class"
21   -require "engine.Grid"
22   -local DamageType = require "engine.DamageType"
23   -
24   -module(..., package.seeall, class.inherit(engine.Grid))
25   -
26   -function _M:init(t, no_default)
27   - engine.Grid.init(self, t, no_default)
28   -end
29   -
30   -function _M:block_move(x, y, e, act, couldpass)
31   - -- Open doors
32   - if self.door_opened and act then
33   - game.level.map(x, y, engine.Map.TERRAIN, game.zone.grid_list[self.door_opened])
34   - return true
35   - elseif self.door_opened and not couldpass then
36   - return true
37   - end
38   -
39   - -- Pass walls
40   - if e and self.can_pass and e.can_pass then
41   - for what, check in pairs(e.can_pass) do
42   - if self.can_pass[what] and self.can_pass[what] <= check then return false end
43   - end
44   - end
45   -
46   - return self.does_block_move
47   -end
48   -
49   -function _M:on_move(x, y, who, forced)
50   - if forced then return end
51   - if who.move_project and next(who.move_project) then
52   - for typ, dam in pairs(who.move_project) do
53   - DamageType:get(typ).projector(who, x, y, typ, dam)
54   - end
55   - end
56   -end
57   -function _M:tooltip()
58   - if self.show_tooltip then
59   - local name = ((self.show_tooltip == true) and self.name or self.show_tooltip)
60   - if self.desc then
61   - return self:getDisplayString()..name.."\n"..self.desc
62   - else
63   - return self:getDisplayString()..name
64   - end
65   - else
66   - return self:getDisplayString()..self.name
67   - end
1   --- ToME - Tales of Middle-Earth
2   --- Copyright (C) 2009, 2010, 2011 Nicolas Casalini
3   ---
4   --- This program is free software: you can redistribute it and/or modify
5   --- it under the terms of the GNU General Public License as published by
6   --- the Free Software Foundation, either version 3 of the License, or
7   --- (at your option) any later version.
8   ---
9   --- This program is distributed in the hope that it will be useful,
10   --- but WITHOUT ANY WARRANTY; without even the implied warranty of
11   --- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12   --- GNU General Public License for more details.
13   ---
14   --- You should have received a copy of the GNU General Public License
15   --- along with this program. If not, see <http://www.gnu.org/licenses/>.
16   ---
17   --- Nicolas Casalini "DarkGod"
18   --- darkgod@te4.org
19   -
20   -require "engine.class"
21   -local ActorAI = require "engine.interface.ActorAI"
22   -local MonsterCombat = require "mod.class.interface.MonsterCombat"
23   -local Faction = require "engine.Faction"
24   -require "mod.class.Actor"
25   -
26   -module(..., package.seeall, class.inherit(mod.class.Actor, engine.interface.ActorAI, MonsterCombat))
27   -
28   -function _M:init(t, no_default)
29   - mod.class.Actor.init(self, t, no_default)
30   - ActorAI.init(self, t)
31   -end
32   -
33   -function _M:act()
34   - -- Do basic actor stuff
35   - if not mod.class.Actor.act(self) then return end
36   -
37   - -- Compute FOV, if needed
38   - self:computeFOV(self.sight or 20)
39   -
40   - -- Let the AI think .... beware of Shub !
41   - -- If AI did nothing, use energy anyway
42   - self:doAI()
43   - if not self.energy.used then self:useEnergy() end
44   -end
45   -
46   ---- Called by ActorLife interface
47   --- We use it to pass aggression values to the AIs
48   -function _M:onTakeHit(value, src)
49   - if not self.ai_target.actor and src.targetable then
50   - self.ai_target.actor = src
51   - end
52   -
53   - return mod.class.Actor.onTakeHit(self, value, src)
54   -end
55   -
56   -function _M:tooltip()
57   - local str = mod.class.Actor.tooltip(self)
58   - return str..([[
59   -
60   -Target: %s
61   -UID: %d]]):format(
62   - self.ai_target.actor and self.ai_target.actor.name or "none",
63   - self.uid)
1   --- ToME - Tales of Maj'Eyal
2   --- Copyright (C) 2009, 2010, 2011 Nicolas Casalini
3   ---
4   --- This program is free software: you can redistribute it and/or modify
5   --- it under the terms of the GNU General Public License as published by
6   --- the Free Software Foundation, either version 3 of the License, or
7   --- (at your option) any later version.
8   ---
9   --- This program is distributed in the hope that it will be useful,
10   --- but WITHOUT ANY WARRANTY; without even the implied warranty of
11   --- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12   --- GNU General Public License for more details.
13   ---
14   --- You should have received a copy of the GNU General Public License
15   --- along with this program. If not, see <http://www.gnu.org/licenses/>.
16   ---
17   --- Nicolas Casalini "DarkGod"
18   --- darkgod@te4.org
19   -
20   -require "engine.class"
21   -require "engine.Object"
22   -require "engine.interface.ObjectActivable"
23   -require "engine.interface.ObjectIdentify"
24   -
25   -local Stats = require("engine.interface.ActorStats")
26   -local Talents = require("engine.interface.ActorTalents")
27   -local DamageType = require("engine.DamageType")
28   -
29   -module(..., package.seeall, class.inherit(
30   - engine.Object,
31   - engine.interface.ObjectActivable,
32   - engine.interface.ObjectIdentify,
33   - engine.interface.ActorTalents
34   -))
35   -
36   -_M._noalpha = true
37   -
38   -function _M:init(t, no_default)
39   - t.encumber = t.encumber or 0
40   -
41   - engine.Object.init(self, t, no_default)
42   - engine.interface.ObjectActivable.init(self, t)
43   - engine.interface.ObjectIdentify.init(self, t)
44   - engine.interface.ActorTalents.init(self, t)
45   -end
46   -
47   ---- Can this object act at all
48   --- Most object will want to anwser false, only recharging and stuff needs them
49   -function _M:canAct()
50   - if self.power_regen or self.use_talent then return true end
51   - return false
52   -end
53   -
54   ---- Do something when its your turn
55   --- For objects this mostly is to recharge them
56   --- By default, does nothing at all
57   -function _M:act()
58   - self:regenPower()
59   - self:cooldownTalents()
60   - self:useEnergy()
61   -end
62   -
63   ---- Use the object (quaff, read, ...)
64   -function _M:use(who, typ, inven, item)
65   - inven = who:getInven(inven)
66   -
67   - if self.use_no_blind and who:attr("blind") then
68   - game.logPlayer(who, "You cannot see!")
69   - return
70   - end
71   - if self.use_no_silence and who:attr("silence") then
72   - game.logPlayer(who, "You are silenced!")
73   - return
74   - end
75   - if self:wornInven() and not self.wielded and not self.use_no_wear then
76   - game.logPlayer(who, "You must wear this object to use it!")
77   - return
78   - end
79   - if who:hasEffect(self.EFF_UNSTOPPABLE) then
80   - game.logPlayer(who, "You can not use items during a battle frenzy!")
81   - return
82   - end
83   -
84   - local types = {}
85   - if self:canUseObject() then types[#types+1] = "use" end
86   -
87   - if not typ and #types == 1 then typ = types[1] end
88   -
89   - if typ == "use" then
90   - who:useEnergy(game.energy_to_act * (inven.use_speed or 1))
91   - if self.use_sound then game:playSoundNear(who, self.use_sound) end
92   - return self:useObject(who, inven, item)
93   - end
94   -end
95   -
96   ---- Returns a tooltip for the object
97   -function _M:tooltip()
98   - return tostring(self:getDesc{do_color=true})
99   -end
100   -
101   ---- Describes an attribute, to expand object name
102   -function _M:descAttribute(attr)
103   - if attr == "MASTERY" then
104   - local tms = {}
105   - for ttn, i in pairs(self.wielder.talents_types_mastery) do
106   - local tt = Talents.talents_types_def[ttn]
107   - local cat = tt.type:gsub("/.*", "")
108   - local name = cat:capitalize().." / "..tt.name:capitalize()
109   - tms[#tms+1] = ("%0.2f %s"):format(i, name)
110   - end
111   - return table.concat(tms, ",")
112   - elseif attr == "STATBONUS" then
113   - local stat, i = next(self.wielder.inc_stats)
114   - return i > 0 and "+"..i or tostring(i)
115   - elseif attr == "DAMBONUS" then
116   - local stat, i = next(self.wielder.inc_damage)
117   - return (i > 0 and "+"..i or tostring(i)).."%"
118   - elseif attr == "RESIST" then
119   - local stat, i = next(self.wielder.resists)
120   - return (i > 0 and "+"..i or tostring(i)).."%"
121   - elseif attr == "REGEN" then
122   - local i = self.wielder.mana_regen or self.wielder.stamina_regen or self.wielder.life_regen
123   - return ("%s%0.2f/turn"):format(i > 0 and "+" or "-", math.abs(i))
124   - elseif attr == "COMBAT" then
125   - local c = self.combat
126   - return c.dam.."-"..(c.dam*(c.damrange or 1.1)).." power, "..(c.apr or 0).." apr"
127   - elseif attr == "COMBAT_DAMTYPE" then
128   - local c = self.combat
129   - return c.dam.."-"..(c.dam*(c.damrange or 1.1)).." power, "..(c.apr or 0).." apr, "..DamageType:get(c.damtype).name.." damage"
130   - elseif attr == "ARMOR" then
131   - return (self.wielder and self.wielder.combat_def or 0).." def, "..(self.wielder and self.wielder.combat_armor or 0).." armor"
132   - elseif attr == "ATTACK" then
133   - return (self.wielder and self.wielder.combat_atk or 0).." attack, "..(self.wielder and self.wielder.combat_apr or 0).." apr, "..(self.wielder and self.wielder.combat_dam or 0).." power"
134   - elseif attr == "MONEY" then
135   - return ("worth %0.2f"):format(self.money_value / 10)
136   - elseif attr == "USE_TALENT" then
137   - return self:getTalentFromId(self.use_talent.id).name:lower()
138   - elseif attr == "DIGSPEED" then
139   - return ("dig speed %d turns"):format(self.digspeed)
140   - elseif attr == "CHARGES" then
141   - if self.use_power then
142   - return (" (%d/%d)"):format(math.floor(self.power / self.use_power.power), math.floor(self.max_power / self.use_power.power))
143   - else
144   - return ""
145   - end
146   - end
147   -end
148   -
149   ---- Gets the "power rank" of an object
150   --- Possible values are 0 (normal, lore), 1 (ego), 2 (greater ego), 3 (artifact)
151   -function _M:getPowerRank()
152   - if self.unique then return 2 end
153   - if self.egoed then return 1 end
154   - return 0
155   -end
156   -
157   ---- Gets the color in which to display the object in lists
158   -function _M:getDisplayColor()
159   - if not self:isIdentified() then return {180, 180, 180}, "#B4B4B4#" end
160   - if self.egoed then
161   - return {0, 255, 128}, "#00FF80#"
162   - elseif self.unique then
163   - return {255, 215, 0}, "#FFD700#"
164   - else return {255, 255, 255}, "#FFFFFF#"
165   - end
166   -end
167   -
168   -_M.tval_table = {
169   - [1] = {"skeleton"},
170   - [2] = {"bottle"},
171   - [3] = {"junk"},
172   - [5] = {"spike"},
173   - [7] = {"chest"},
174   - [16] = {"shot", slot="QUIVER", show_weapon=true},
175   - [17] = {"arrow", slot="QUIVER", show_weapon=true},
176   - [18] = {"bolt", slot="QUIVER", show_weapon=true},
177   - [19] = {"bow", slot="SHOOTER"},
178   - [20] = {"digging"},
179   - [21] = {"hafted", slot="WEAPON", show_weapon=true},
180   - [22] = {"polearm", slot="WEAPON", show_weapon=true},
181   - [23] = {"sword", slot="WEAPON", show_weapon=true},
182   - [30] = {"boots", slot="FEET"},
183   - [31] = {"gloves", slot="HANDS"},
184   - [32] = {"helm", slot="HEAD"},
185   - [33] = {"crown", slot="HEAD"},
186   - [34] = {"shield", slot="SHIELD"},
187   - [35] = {"cloak", slot="CLOAK"},
188   - [36] = {"soft armor", slot="BODY"},
189   - [37] = {"hard armor", slot="BODY"},
190   - [38] = {"drag armor", slot="BODY"},
191   - [39] = {"light", slot="LITE", wielder={lite=2}},
192   - [40] = {"amulet", slot="NECK", name_gen=function(e) return "& Amulet~ of "..e.name end},
193   - [45] = {"ring", slot="FINGER", name_gen=function(e) return "& Ring~ of "..e.name end},
194   - [55] = {"staff", name_gen=function(e) return "& Staff~ of "..e.name end},
195   - [65] = {"wand", name_gen=function(e) return "& Wand~ of "..e.name end},
196   - [66] = {"rod", name_gen=function(e) return "& Rod~ of "..e.name end},
197   - [70] = {"scroll", name_gen=function(e) return "& Scroll~ of "..e.name end},
198   - [75] = {"potion", random_color=true, name_gen=function(e) return "& Potion~ of "..e.name end},
199   - [77] = {"flask"},
200   - [80] = {"food", random_color=true},
201   - [90] = {"magic book", name_gen=function(e) return "& Magic Book~ ["..e.name.."]" end},
202   - [91] = {"prayer book", name_gen=function(e) return "& Prayer Book~ ["..e.name.."]" end},
203   - [100] = {"gold"},
204   -}
205   -
206   ---- Gets the full name of the object
207   -function _M:getName(t)
208   - t = t or {}
209   - local qty = self:getNumber()
210   - local name = self.name
211   -
212   - if not self:isIdentified() and not t.force_id and self:getUnidentifiedName() then name = self:getUnidentifiedName() end
213   -
214   - -- To extend later
215   - name = name:gsub("~", ""):gsub("&", "a"):gsub("#([^#]+)#", function(attr)
216   - return self:descAttribute(attr)
217   - end)
218   -
219   - if not t.no_add_name and self.add_name and self:isIdentified() then
220   - name = name .. self.add_name:gsub("#([^#]+)#", function(attr)
221   - return self:descAttribute(attr)
222   - end)
223   - end
224   -
225   - local tval = self.tval_table[self.tval] or {"misc"}
226   - if tval.show_weapon and self.damage then
227   - name = name.." ("..self.damage[1].."d"..self.damage[2]..")"
228   - end
229