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
29 #define _USE_MATH_DEFINES
30 #include <math.h>
31 #include "object.h"
32 #include "registrar.h"
33 #include "resource_manager.h"
34 #include "alarm.h"
35 #include "config.h"
36 #include "trooper.h"
37 #include "game_monitor.h"
38 #include "rt_config.h"
39 #include <string.h>
40
get_impassability_penalty(const float impassability,float & base,float & base_value,float & penalty) const41 void Trooper::get_impassability_penalty(const float impassability, float &base, float &base_value, float &penalty) const {
42 if (impassability > 0.2f) {
43 base_value = 0.2f;
44 base = 0;
45 penalty = 0;
46 }
47 }
48
tick(const float dt)49 void Trooper::tick(const float dt) {
50 set_direction(_velocity.get_direction8() - 1);
51 Object::tick(dt);
52
53 if (!_state.fire) {
54 if (get_state() == "fire")
55 cancel_all();
56 }
57
58 if (_velocity.is0()) {
59 const std::string state = get_state();
60 if (state != "hold" && state != "fire" && state != "throw") {
61 cancel_all();
62 play("hold", true);
63 if (has("helmet")) {
64 Object *helmet = get("helmet");
65 helmet->cancel_all();
66 helmet->play("hold", true);
67 }
68 }
69 } else {
70 const std::string state = get_state();
71 if (state == "hold" || state.empty()) {
72 cancel_all();
73 play("run", true);
74 if (has("helmet")) {
75 Object *helmet = get("helmet");
76 helmet->cancel_all();
77 helmet->play("run", true);
78 }
79 }
80 }
81
82 if (!_object.empty() && _fire.tick(dt) && _state.fire && !_variants.has("nukeman")) {
83 _fire.reset();
84 if (disable_ai || validateFire(0)) {
85 if (get_state() != "fire") {
86 cancel_all();
87 play("fire", true);
88 }
89 spawn(_object, _object, v2<float>(), _direction);
90 }
91 }
92 if (_alt_fire.tick(dt) && _state.alt_fire) {
93 _alt_fire.reset();
94 if (_variants.has("nukeman")) {
95 //MUGGAGAGAGAGAG!!!
96 Object *o = spawn("nuke-explosion", "nuke-explosion");
97 emit("death", o);
98 } else if (!_variants.has("no-grenades")) {
99 if (get_state() != "throw")
100 play_now("throw");
101 spawn("grenade", "grenade", v2<float>(), _direction);
102 }
103 }
104 }
105
take(const BaseObject * obj,const std::string & type)106 const bool Trooper::take(const BaseObject *obj, const std::string &type) {
107 if (obj->classname == "missiles" && type == "nuke" && _variants.has("player") && !_variants.has("nukeman")) {
108 if (GameMonitor->getCampaign() != NULL || RTConfig->game_type == GameTypeCTF)
109 return Object::take(obj, type);
110
111 _variants.add("nukeman");
112 hp = max_hp = 999;
113 init("nukeman");
114 invalidate();
115 return true;
116 }
117 return Object::take(obj, type);
118 }
119
120 #include "world.h"
121
on_spawn()122 void Trooper::on_spawn() {
123 if (_variants.has("player")) {
124 speed *= 1.75f;
125 hp = max_hp *= 2;
126 }
127
128 int sid = get_summoner();
129 const Object *summoner = World->getObjectByID(sid);
130 if (summoner != NULL) {
131 const std::string &a = summoner->animation;
132 static const char *colors[4] = {"red-", "green-", "yellow-", "blue-"};
133 int i;
134 for(i = 0; i < 4; ++i) {
135 size_t l = strlen(colors[i]);
136 if (a.size() > l && a.compare(0, l, colors[i]) == 0)
137 break;
138 }
139 if (i < 4) {
140 std::string animation = colors[i] + registered_name + "-helmet";
141 //LOG_DEBUG(("helmet animation = %s", animation.c_str()));
142 if (ResourceManager->hasAnimation(animation)) {
143 add("helmet", "helmet", animation, v2<float>(), Centered);
144 }
145 }
146 }
147
148 if (_variants.has("disembark")) {
149 play_sound("disembark", false);
150 //add helmet if parent player detected.
151 }
152 GET_CONFIG_VALUE("objects.trooper.grenade-rate", float, gr, 1.2f);
153 _alt_fire.set(gr);
154
155 if (_object.empty()) {
156 //nothing to do
157 } else if (_object == "thrower-missile") {
158 GET_CONFIG_VALUE("objects.thrower.fire-rate", float, fr, 3);
159 _fire.set(fr);
160 } else if (_object == "machinegunner-bullet") {
161 GET_CONFIG_VALUE("objects.machinegunner.fire-rate", float, fr, 0.2);
162 _fire.set(fr);
163 } else throw_ex(("unsupported weapon %s", _object.c_str()));
164
165 play("hold", true);
166 _pose = "run";
167 }
168
can_attach(Object * vehicle) const169 bool Trooper::can_attach(Object *vehicle) const {
170 if (registered_name == "machinegunner-player")
171 return true;
172
173 if (!disable_ai)
174 return false;
175
176 v2<float> rel = get_relative_position(vehicle);
177 rel.normalize();
178 v2<float> dir = vehicle->get_direction_vector();
179 dir.normalize();
180 float c = - rel.x * dir.x - rel.y * dir.y;
181 //LOG_DEBUG(("cos = %g", c));
182 if (c > 0.8660254037844386468) //sqrt(3) / 2
183 return false;
184
185 return true;
186 }
187
emit(const std::string & event,Object * emitter)188 void Trooper::emit(const std::string &event, Object * emitter) {
189 if (event == "death") {
190 spawn("corpse(human-death)", "dead-" + animation, v2<float>(), v2<float>());
191 } else if (event == "collision" && emitter != NULL && emitter->classname == "vehicle" && !_variants.has("nukeman")) {
192 if (can_attach(emitter) && attachVehicle(emitter))
193 return;
194 }
195 Object::emit(event, emitter);
196 }
197
validateFire(const int idx)198 const bool Trooper::validateFire(const int idx) {
199 return true;
200 }
201
clone() const202 Object* Trooper::clone() const {
203 return new Trooper(*this);
204 }
205