1
2 /* Battle Tanks Game
3 * Copyright (C) 2006-2009 Battle Tanks team
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20 /*
21 * Additional rights can be granted beyond the GNU General Public License
22 * on the terms provided in the Exception. If you modify this file,
23 * you may extend this exception to your version of the file,
24 * but you are not obligated to do so. If you do not wish to provide this
25 * exception without modification, you must delete this exception statement
26 * from your version and license this file solely under the GPL without exception.
27 */
28 #include "special_zone.h"
29 #include "player_manager.h"
30 #include "player_slot.h"
31 #include "net/message.h"
32 #include "game_monitor.h"
33 #include "player_manager.h"
34 #include "config.h"
35 #include "menu/tooltip.h"
36 #include "object.h"
37 #include "rt_config.h"
38 #include "sound/mixer.h"
39 #include <set>
40
~SpecialZone()41 SpecialZone::~SpecialZone() {}
42
SpecialZone(const ZBox & zbox,const std::string & type,const std::string & name,const std::string & subname)43 SpecialZone::SpecialZone(const ZBox & zbox, const std::string &type, const std::string &name, const std::string &subname) :
44 ZBox(zbox), type(type), name(name), subname(subname) {
45 static std::set<std::string> allowed_types;
46 if (allowed_types.empty()) {
47 allowed_types.insert("checkpoint");
48 allowed_types.insert("hint");
49 allowed_types.insert("message");
50 allowed_types.insert("timer-lose");
51 allowed_types.insert("timer-win");
52 allowed_types.insert("reset-timer");
53 allowed_types.insert("disable-ai");
54 allowed_types.insert("enable-ai");
55 allowed_types.insert("play-tune");
56 allowed_types.insert("reset-tune");
57 allowed_types.insert("z-warp");
58 allowed_types.insert("script");
59 allowed_types.insert("local-script");
60 }
61
62 if (allowed_types.find(type) == allowed_types.end())
63 throw_ex(("unhanled type '%s'", type.c_str()));
64
65 _global = type == "timer-lose" || type == "timer-win" || type == "reset-timer" ||
66 type == "disable-ai" || type == "enable-ai" ||
67 type == "play-tune" || type == "reset-tune" || type == "script";
68
69 _final = type == "checkpoint" && name == "final";
70 _live = type == "z-warp";
71 }
72
onTimer(const int slot_id,const bool win)73 void SpecialZone::onTimer(const int slot_id, const bool win) {
74 float duration = (float)atof(subname.c_str());
75 LOG_DEBUG(("activating timer %s for %g seconds", name.c_str(), duration));
76
77 int spawn_limit = 0;
78 std::string key_name = "timer." + name + ".spawn-limit";
79 if (Config->has(key_name))
80 Config->get(key_name, spawn_limit, 1);
81
82 if (spawn_limit > 0)
83 for(size_t i = 0; i < PlayerManager->get_slots_count(); ++i) {
84 PlayerSlot &slot = PlayerManager->get_slot(i);
85 slot.spawn_limit = spawn_limit;
86 }
87
88 if (win) {
89 GameMonitor->setTimer("messages", "mission-accomplished", duration, true);
90 } else
91 GameMonitor->setTimer("messages", "game-over", duration, false);
92
93 GameMonitor->displayMessage(area, name, 3, global());
94 }
95
onExit(const int slot_id)96 void SpecialZone::onExit(const int slot_id) {
97 if (type == "z-warp") {
98 onWarp(slot_id, false);
99 } else if (_live)
100 throw_ex(("unhandled exit for type '%s'", type.c_str()));
101 }
102
onEnter(const int slot_id)103 void SpecialZone::onEnter(const int slot_id) {
104 if (type == "checkpoint")
105 onCheckpoint(slot_id);
106 else if (type == "hint")
107 onHint(slot_id);
108 else if (type == "message")
109 on_message(slot_id);
110 else if (type == "timer-lose")
111 onTimer(slot_id, false);
112 else if (type == "timer-win")
113 onTimer(slot_id, true);
114 else if (type == "reset-timer")
115 GameMonitor->resetTimer();
116 else if (type == "disable-ai")
117 GameMonitor->disable(name);
118 else if (type == "enable-ai")
119 GameMonitor->disable(name, false);
120 else if (type == "play-tune")
121 Mixer->play(name, true);
122 else if (type == "reset-tune")
123 Mixer->reset();
124 else if (type == "z-warp") {
125 onWarp(slot_id, true);
126 } else if (type == "script") {
127 GameMonitor->onScriptZone(slot_id, *this, true);
128 } else if (type == "local-script") {
129 GameMonitor->onScriptZone(slot_id, *this, false);
130 } else
131 throw_ex(("unhandled enter for type '%s'", type.c_str()));
132 }
133
on_message(const int slot_id)134 void SpecialZone::on_message(const int slot_id) {
135 GameMonitor->displayMessage(area, name, 3, global());
136 }
137
onHint(const int slot_id)138 void SpecialZone::onHint(const int slot_id) {
139 PlayerSlot &slot = PlayerManager->get_slot(slot_id);
140
141 //Game->pause();
142 if (slot.remote != -1 && !PlayerManager->is_client()) //useless but just for sure
143 PlayerManager->send_hint(slot_id, area, name);
144 else
145 slot.displayTooltip(area, name);
146 }
147
getPlayerPosition(const int slot_id) const148 const v3<int> SpecialZone::getPlayerPosition(const int slot_id) const {
149 int players = PlayerManager->get_slots_count();
150
151 int yn = (int) sqrt((double)size.y * players / size.x);
152 if (yn < 1)
153 yn = 1;
154
155 int xn = (players - 1) / yn + 1;
156 //int n = xn * yn;
157
158 int ysize = size.y / yn;
159 int xsize = size.x / xn;
160
161 //LOG_DEBUG(("position in checkpoint: %d %d of %d[%dx%d]. cell size: %dx%d.", slot_id % xn, slot_id / xn, n, xn, yn, xsize, ysize));
162 return v3<int>(
163 position.x + xsize * (slot_id % xn) + xsize / 2,
164 position.y + ysize * (slot_id / xn) + ysize / 2,
165 position.z
166 );
167 }
168
169
onCheckpoint(const int slot_id)170 void SpecialZone::onCheckpoint(const int slot_id) {
171 if (PlayerManager->is_client())
172 return; //no checkpoints on client
173
174 GameType game_type = RTConfig->game_type;
175
176 PlayerSlot &slot = PlayerManager->get_slot(slot_id);
177 slot.need_sync = true;
178
179 if (game_type == GameTypeRacing) {
180 const SpecialZone &zone = PlayerManager->get_next_checkpoint(slot);
181 if (zone.name != name) {
182 LOG_DEBUG(("wrong checkpoint, next checkpoint: %s", zone.name.c_str()));
183 GameMonitor->displayMessage("messages", "wrong-checkpoint", 3, false);
184 return;
185 }
186 PlayerManager->fix_checkpoints(slot, zone); //remove all wrong checkpoints from list
187 }
188 slot.position = getPlayerPosition(slot_id);
189
190 //v3<int> spawn_pos(_zones[c].position + checkpoint_size.convert2v3(0) / 2);
191 //slot.position = spawn_pos;
192 if (final()) {
193 GameMonitor->game_over("messages", "mission-accomplished", 5, true);
194 return;
195 }
196
197 if (slot.visible) {
198 if (game_type != GameTypeRacing)
199 GameMonitor->displayMessage("messages", "checkpoint-reached", 3, false);
200 } else {
201 if (slot.remote != -1 && PlayerManager->is_server() ) {
202 Message m(Message::TextMessage);
203 m.channel = slot_id;
204 m.set("hint", "0");
205 m.set("area", "messages");
206 m.set("message", "checkpoint-reached");
207 m.set("duration", "3");
208 PlayerManager->send(slot, m);
209 }
210 }
211 }
212
onWarp(const int slot_id,const bool enter)213 void SpecialZone::onWarp(const int slot_id, const bool enter) {
214 PlayerSlot &slot = PlayerManager->get_slot(slot_id);
215 Object *o = slot.getObject();
216 if (o == NULL)
217 return;
218 }
219
onTick(const int slot_id)220 void SpecialZone::onTick(const int slot_id) {
221 PlayerSlot &slot = PlayerManager->get_slot(slot_id);
222 Object *o = slot.getObject();
223 if (o == NULL)
224 return;
225
226 v2<float> pos, vel;
227 o->get_position(pos); o->get_velocity(vel);
228
229
230 v2<int> left_pos, right_pos;
231 o->get_position(left_pos);
232 o->get_position(right_pos);
233 right_pos += o->size.convert<int>();
234
235 v2<int> c_pos(position.x, position.y);
236 c_pos += size / 2;
237
238 int o_z = getBox(o->get_z());
239 //LOG_DEBUG(("zone zbox: %d, object zbox: %d", position.z, o_z));
240 if (name == "right") {
241 if (right_pos.x >= c_pos.x && o_z != (position.z + 1) && vel.x > 0)
242 o->set_zbox((position.z + 1) * 2000);
243 if (right_pos.x < c_pos.x && o_z != position.z && vel.x < 0)
244 o->set_zbox(position.z * 2000);
245 } else if (name == "left") {
246 if (left_pos.x < c_pos.x && o_z != (position.z + 1) && vel.x < 0)
247 o->set_zbox((position.z + 1) * 2000);
248 if (left_pos.x >= c_pos.x && o_z != position.z && vel.x > 0)
249 o->set_zbox(position.z * 2000);
250 }
251
252 //LOG_DEBUG(("delta left: %d, %d, delta right: %d, %d", left_pos.x - c_pos.x, left_pos.y - c_pos.y, right_pos.x - c_pos.x, right_pos.y - c_pos.y));
253 }
254