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