1 /* Copyright (C) 2013-2014 Michal Brzozowski (rusolis@poczta.fm)
2
3 This file is part of KeeperRL.
4
5 KeeperRL is free software; you can redistribute it and/or modify it under the terms of the
6 GNU General Public License as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 KeeperRL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
10 even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License along with this program.
14 If not, see http://www.gnu.org/licenses/ . */
15
16 #include "stdafx.h"
17
18 #include "square.h"
19 #include "level.h"
20 #include "creature.h"
21 #include "item.h"
22 #include "view_object.h"
23 #include "progress_meter.h"
24 #include "game.h"
25 #include "vision.h"
26 #include "view_index.h"
27 #include "inventory.h"
28 #include "poison_gas.h"
29 #include "tribe.h"
30 #include "view.h"
31 #include "event_listener.h"
32
33 template <class Archive>
serialize(Archive & ar,const unsigned int version)34 void Square::serialize(Archive& ar, const unsigned int version) {
35 ar & SUBCLASS(OwnedObject<Square>);
36 ar(inventory, onFire);
37 ar(creature, landingLink, poisonGas);
38 ar(lastViewer, viewIndex);
39 ar(forbiddenTribe);
40 if (progressMeter)
41 progressMeter->addProgress();
42 }
43
44 ProgressMeter* Square::progressMeter = nullptr;
45
46 SERIALIZABLE(Square);
47
Square()48 Square::Square() : viewIndex(new ViewIndex()) {
49 }
50
~Square()51 Square::~Square() {
52 }
53
putCreature(WCreature c)54 void Square::putCreature(WCreature c) {
55 //CHECK(canEnter(c)) << c->getName().bare() << " " << getName();
56 setCreature(c);
57 onEnter(c);
58 if (WGame game = c->getGame())
59 game->addEvent(EventInfo::CreatureMoved{c});
60 }
61
setLandingLink(StairKey key)62 void Square::setLandingLink(StairKey key) {
63 landingLink = key;
64 }
65
getLandingLink() const66 optional<StairKey> Square::getLandingLink() const {
67 return landingLink;
68 }
69
setCreature(WCreature c)70 void Square::setCreature(WCreature c) {
71 creature = c;
72 }
73
onAddedToLevel(Position pos) const74 void Square::onAddedToLevel(Position pos) const {
75 if (!inventory->isEmpty())
76 pos.getLevel()->addTickingSquare(pos.getCoord());
77 }
78
tick(Position pos)79 void Square::tick(Position pos) {
80 setDirty(pos);
81 if (!inventory->isEmpty()) {
82 vector<WItem> discarded;
83 for (auto item : copyOf(inventory->getItems())) {
84 item->tick(pos);
85 if (item->isDiscarded())
86 discarded.push_back(item);
87 }
88 for (auto item : discarded)
89 inventory->removeItem(item);
90 }
91 poisonGas->tick(pos);
92 if (creature && poisonGas->getAmount() > 0.2) {
93 creature->poisonWithGas(min(1.0, poisonGas->getAmount()));
94 }
95 }
96
itemLands(vector<WItem> item,const Attack & attack) const97 bool Square::itemLands(vector<WItem> item, const Attack& attack) const {
98 if (creature) {
99 if (item.size() > 1)
100 creature->you(MsgType::MISS_THROWN_ITEM_PLURAL, item[0]->getPluralTheName(item.size()));
101 else
102 creature->you(MsgType::MISS_THROWN_ITEM, item[0]->getTheName());
103 }
104 return false;
105 }
106
onItemLands(Position pos,vector<PItem> item,const Attack & attack,int remainingDist,Vec2 dir,VisionId vision)107 void Square::onItemLands(Position pos, vector<PItem> item, const Attack& attack, int remainingDist, Vec2 dir,
108 VisionId vision) {
109 setDirty(pos);
110 if (creature) {
111 item[0]->onHitCreature(creature, attack, item.size());
112 if (!item[0]->isDiscarded())
113 dropItems(pos, std::move(item));
114 return;
115 }
116 item[0]->onHitSquareMessage(pos, item.size());
117 if (!item[0]->isDiscarded())
118 pos.dropItems(std::move(item));
119 }
120
addPoisonGas(Position pos,double amount)121 void Square::addPoisonGas(Position pos, double amount) {
122 setDirty(pos);
123 if (pos.canSeeThru(VisionId::NORMAL)) {
124 poisonGas->addAmount(amount);
125 pos.getLevel()->addTickingSquare(pos.getCoord());
126 }
127 }
128
getPoisonGasAmount() const129 double Square::getPoisonGasAmount() const {
130 return poisonGas->getAmount();
131 }
132
getViewIndex(ViewIndex & ret,WConstCreature viewer) const133 void Square::getViewIndex(ViewIndex& ret, WConstCreature viewer) const {
134 if ((!viewer && lastViewer) || (viewer && lastViewer == viewer->getUniqueId())) {
135 ret = *viewIndex;
136 return;
137 }
138 // viewer is null only in Spectator mode, so setting a random id to lastViewer is ok
139 lastViewer = viewer ? viewer->getUniqueId() : Creature::Id();
140 double fireSize = 0;
141 if (!inventory->isEmpty())
142 for (WItem it : getInventory().getItems())
143 fireSize = max(fireSize, it->getFireSize());
144 if (WItem it = getTopItem())
145 ret.insert(copyOf(it->getViewObject()).setAttribute(ViewObject::Attribute::BURNING, fireSize));
146 if (poisonGas->getAmount() > 0)
147 ret.setHighlight(HighlightType::POISON_GAS, min(1.0, poisonGas->getAmount()));
148 *viewIndex = ret;
149 }
150
onEnter(WCreature c)151 void Square::onEnter(WCreature c) {
152 setDirty(c->getPosition());
153 }
154
dropItem(Position pos,PItem item)155 void Square::dropItem(Position pos, PItem item) {
156 dropItems(pos, makeVec(std::move(item)));
157 }
158
dropItemsLevelGen(vector<PItem> items)159 void Square::dropItemsLevelGen(vector<PItem> items) {
160 getInventory().addItems(std::move(items));
161 }
162
dropItems(Position pos,vector<PItem> items)163 void Square::dropItems(Position pos, vector<PItem> items) {
164 setDirty(pos);
165 pos.getLevel()->addTickingSquare(pos.getCoord());
166 dropItemsLevelGen(std::move(items));
167 }
168
getCreature() const169 WCreature Square::getCreature() const {
170 return creature;
171 }
172
isOnFire() const173 bool Square::isOnFire() const {
174 return onFire;
175 }
176
setOnFire(bool state)177 void Square::setOnFire(bool state) {
178 onFire = state;
179 }
180
removeCreature(Position pos)181 void Square::removeCreature(Position pos) {
182 setDirty(pos);
183 CHECK(creature);
184 WCreature tmp = creature;
185 creature = nullptr;
186 }
187
getTopItem() const188 WItem Square::getTopItem() const {
189 if (inventory->isEmpty())
190 return nullptr;
191 else
192 return inventory->getItems().back();
193 }
194
removeItem(Position pos,WItem it)195 PItem Square::removeItem(Position pos, WItem it) {
196 setDirty(pos);
197 return getInventory().removeItem(it);
198 }
199
removeItems(Position pos,vector<WItem> it)200 vector<PItem> Square::removeItems(Position pos, vector<WItem> it) {
201 setDirty(pos);
202 return getInventory().removeItems(it);
203 }
204
setDirty(Position pos)205 void Square::setDirty(Position pos) {
206 pos.getLevel()->setNeedsMemoryUpdate(pos.getCoord(), true);
207 pos.getLevel()->setNeedsRenderUpdate(pos.getCoord(), true);
208 lastViewer.reset();
209 }
210
forbidMovementForTribe(Position pos,TribeId tribe)211 void Square::forbidMovementForTribe(Position pos, TribeId tribe) {
212 CHECK(!forbiddenTribe || forbiddenTribe == tribe);
213 forbiddenTribe = tribe;
214 pos.updateConnectivity();
215 setDirty(pos);
216 }
217
allowMovementForTribe(Position pos,TribeId tribe)218 void Square::allowMovementForTribe(Position pos, TribeId tribe) {
219 CHECK(!forbiddenTribe || forbiddenTribe == tribe);
220 forbiddenTribe = none;
221 pos.updateConnectivity();
222 setDirty(pos);
223 }
224
isTribeForbidden(TribeId tribe) const225 bool Square::isTribeForbidden(TribeId tribe) const {
226 return forbiddenTribe == tribe;
227 }
228
getForbiddenTribe() const229 optional<TribeId> Square::getForbiddenTribe() const {
230 return forbiddenTribe;
231 }
232
getInventory()233 Inventory& Square::getInventory() {
234 return *inventory;
235 }
236
getInventory() const237 const Inventory& Square::getInventory() const {
238 return *inventory;
239 }
240
clearItemIndex(ItemIndex index)241 void Square::clearItemIndex(ItemIndex index) {
242 inventory->clearIndex(index);
243 }
244