Store.lua
7.87 KB
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
-- ToME - Tales of Maj'Eyal
-- Copyright (C) 2009, 2010, 2011 Nicolas Casalini
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
-- Nicolas Casalini "DarkGod"
-- darkgod@te4.org
require "engine.class"
local Store = require "engine.Store"
local Dialog = require "engine.ui.Dialog"
module(..., package.seeall, class.inherit(Store))
_M.stores_def = {}
function _M:loadStores(f)
self.stores_def = self:loadList(f)
end
function _M:init(t, no_default)
t.store.buy_percent = t.store.buy_percent or function(self, o) if o.type == "gem" then return 40 else return 5 end end
t.store.sell_percent = t.store.sell_percent or function(self, o) return 120 + 3 * (o.__store_level or 0) end -- Stores prices goes up with item level
t.store.nb_fill = t.store.nb_fill or 10
t.store.purse = t.store.purse or 20
Store.init(self, t, no_default)
self.name = self.name .. (" (Max buy %0.2f gold)"):format(self.store.purse)
if not self.store.actor_filter then
self.store.actor_filter = function(o)
return not o.quest and not o.lore and o.cost and o.cost > 0
end
end
end
--- Caleld when a new object is stocked
function _M:stocked_object(o)
o.__store_level = game.zone.base_level + game.level.level - 1
end
--- Restock based on player level
function _M:canRestock()
local s = self.store
if self.last_filled and self.last_filled >= game.state.stores_restock then
print("[STORE] not restocking yet [stores_restock]", game.state.stores_restock, s.restock_every, self.last_filled)
return false
end
return true
end
--- Fill the store with goods
-- @param level the level to generate for (instance of type engine.Level)
-- @param zone the zone to generate for
function _M:loadup(level, zone)
if Store.loadup(self, level, zone, self.store.nb_fill) then
self.last_filled = game.state.stores_restock
end
end
--- Called on object purchase try
-- @param who the actor buying
-- @param o the object trying to be purchased
-- @param item the index in the inventory
-- @param nb number of items (if stacked) to buy
-- @return true if allowed to buy
function _M:tryBuy(who, o, item, nb)
local price = self:getObjectPrice(o, "buy")
if who.money >= price * nb then
return nb, price * nb
else
Dialog:simplePopup("Not enough gold", "You do not have enough gold!")
end
end
--- Called on object sale try
-- @param who the actor selling
-- @param o the object trying to be sold
-- @param item the index in the inventory
-- @param nb number of items (if stacked) to sell
-- @return true if allowed to sell
function _M:trySell(who, o, item, nb)
local price = self:getObjectPrice(o, "sell")
if price <= 0 or nb <= 0 then return end
price = math.min(price * nb, self.store.purse * nb)
return nb, price
end
--- Called on object purchase
-- @param who the actor buying
-- @param o the object trying to be purchased
-- @param item the index in the inventory
-- @param nb number of items (if stacked) to buy
-- @param before true if this happens before removing the item
-- @return true if allowed to buy
function _M:onBuy(who, o, item, nb, before)
if before then return end
local price = self:getObjectPrice(o, "buy")
if who.money >= price * nb then
who:incMoney(- price * nb)
end
end
--- Called on object sale
-- @param who the actor selling
-- @param o the object trying to be sold
-- @param item the index in the inventory
-- @param nb number of items (if stacked) to sell
-- @param before true if this happens before removing the item
-- @return true if allowed to sell
function _M:onSell(who, o, item, nb, before)
if before then o:identify(true) return end
local price = self:getObjectPrice(o, "sell")
if price <= 0 or nb <= 0 then return end
price = math.min(price * nb, self.store.purse * nb)
who:incMoney(price)
o:forAllStack(function(so) so.__store_forget = true end) -- Make sure the store does never forget about it
end
--- Override the default
function _M:doBuy(who, o, item, nb, store_dialog)
nb = math.min(nb, o:getNumber())
local price
nb, price = self:tryBuy(who, o, item, nb)
if nb then
Dialog:yesnoPopup("Buy", ("Buy %d %s for %0.2f gold"):format(nb, o:getName{do_color=true, no_count=true}, price), function(ok) if ok then
self:onBuy(who, o, item, nb, true)
-- Learn lore ?
if who.player and o.lore then
self:removeObject(self:getInven("INVEN"), item)
who:learnLore(o.lore)
else
self:transfer(self, who, item, nb)
end
self:onBuy(who, o, item, nb, false)
if store_dialog then store_dialog:updateStore() end
end end, "Buy", "Cancel")
end
end
--- Override the default
function _M:doSell(who, o, item, nb, store_dialog)
nb = math.min(nb, o:getNumber())
local price
nb, price = self:trySell(who, o, item, nb)
if nb then
Dialog:yesnoPopup("Sell", ("Sell %d %s for %0.2f gold"):format(nb, o:getName{do_color=true, no_count=true}, price), function(ok) if ok then
self:onSell(who, o, item, nb, true)
self:transfer(who, self, item, nb)
self:onSell(who, o, item, nb, false)
if store_dialog then store_dialog:updateStore() end
end end, "Sell", "Cancel")
end
end
--- Called to describe an object, being to sell or to buy
-- @param who the actor
-- @param what either "sell" or "buy"
-- @param o the object
-- @return a string (possibly multiline) describing the object
function _M:descObject(who, what, o)
if what == "buy" then
local desc = tstring({"font", "bold"}, {"color", "GOLD"}, ("Buy for: %0.2f gold (You have %0.2f gold)"):format(self:getObjectPrice(o, "buy"), who.money), {"font", "normal"}, {"color", "LAST"}, true, true)
desc:merge(o:getDesc())
return desc
else
local desc = tstring({"font", "bold"}, {"color", "GOLD"}, ("Sell for: %0.2f gold (You have %0.2f gold)"):format(self:getObjectPrice(o, "sell"), who.money), {"font", "normal"}, {"color", "LAST"}, true, true)
desc:merge(o:getDesc())
return desc
end
end
function _M:getObjectPrice(o, what)
local v = o:getPrice() * util.getval(what == "buy" and self.store.sell_percent or self.store.buy_percent, self, o) / 100
return math.ceil(v * 10) / 10
end
--- Called to describe an object's price, being to sell or to buy
-- @param who the actor
-- @param what either "sell" or "buy"
-- @param o the object
-- @return a string describing the price
function _M:descObjectPrice(who, what, o)
return self:getObjectPrice(o, what), who.money
end
--- Actor interacts with the store
-- @param who the actor who interacts
function _M:interact(who, name)
who:sortInven()
Store.interact(self, who, name)
end
--- Display tooltips
function _M:on_select(item)
if item.last_display_x then
game.tooltip_x, game.tooltip_y = {}, 1
game.tooltip:displayAtMap(nil, nil, item.last_display_x, item.last_display_y, item.desc)
if not item.object or item.object.wielded then game.tooltip2_x = nil return end
local winven = item.object:wornInven()
winven = winven and game.player:getInven(winven)
if not winven then game.tooltip2_x = nil return end
local str = tstring{{"font", "bold"}, {"color", "GREY"}, "Currently equiped:", {"font", "normal"}, {"color", "LAST"}, true}
local ok = false
for i = 1, #winven do
str:merge(winven[i]:getDesc())
if i < #winven then str:add{true, "---", true} end
ok = true
end
if ok then
game.tooltip2_x, game.tooltip2_y = {}, 1
game.tooltip2:displayAtMap(nil, nil, 1, item.last_display_y, str)
game.tooltip2.last_display_x = game.tooltip.last_display_x - game.tooltip2.w
last = item
else
game.tooltip2_x = nil
end
end
end