OSDN Git Service

961e3107b6f473427f7b82595479c27669ca97c7
[nazghul-jp/nazghul-jp.git] / src / vehicle.cpp
1 //
2 // nazghul - an old-school RPG engine
3 // Copyright (C) 2002, 2003 Gordon McNutt
4 //
5 // This program is free software; you can redistribute it and/or modify it
6 // under the terms of the GNU General Public License as published by the Free
7 // Software Foundation; either version 2 of the License, or (at your option)
8 // any later version.
9 //
10 // This program is distributed in the hope that it will be useful, but WITHOUT
11 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13 // more details.
14 //
15 // You should have received a copy of the GNU General Public License along with
16 // this program; if not, write to the Free Foundation, Inc., 59 Temple Place,
17 // Suite 330, Boston, MA 02111-1307 USA
18 //
19 // Gordon McNutt
20 // gmcnutt@users.sourceforge.net
21 //
22
23 #include "vehicle.h"
24 #include "sprite.h"
25 #include "common.h"
26 #include "sound.h"
27 #include "place.h"
28 #include "map.h"
29 #include "console.h"
30 #include "wind.h"
31 #include "player.h"
32 #include "session.h"
33 #include "log.h"
34
35 /* This is the number of wilderness turns an unnamed vehicle will hang around
36  * before being garbage collected. Note that wilderness turns only pass when
37  * the player is actually walking around in the wilderness. Kamping, loitering
38  * and combat don't count. */
39 #define VEHICLE_DEF_TTL 256
40
41 #include <unistd.h>
42
43 // ----------------------------------------------------------------------------
44 //
45 // VehicleType
46 //
47 // ----------------------------------------------------------------------------
48
49
50 VehicleType::VehicleType(const char *tag, const char *name, struct sprite *sprite,
51                          struct terrain_map *_map,
52                          ArmsType *_ordnance,
53                          bool _vulnerable,
54                          bool _killsOccupants,
55                          bool _mustTurn,
56                          char *_mv_desc,
57                          sound_t *_mv_sound,
58                          int _tailwind_penalty,
59                          int _headwind_penalty,
60                          int _crosswind_penalty,
61                          int _max_hp,
62                          int _speed
63         )
64         : ObjectType(tag, name, sprite, vehicle_layer)
65 {
66         map = _map;
67         formation = NULL;
68         ordnance = _ordnance;
69         is_vulnerable = _vulnerable;
70         kills_occupants = _killsOccupants;
71         must_turn = _mustTurn;
72         mv_desc = strdup(_mv_desc);
73         assert(mv_desc);
74         mv_sound = _mv_sound;
75         tailwind_penalty = _tailwind_penalty;
76         headwind_penalty = _headwind_penalty;
77         crosswind_penalty = _crosswind_penalty;
78
79         max_hp = _max_hp; // override base class default
80         speed  = _speed;  // override base class default
81 }
82
83 VehicleType::~ VehicleType() 
84 {
85         if (mv_desc)
86                 free(mv_desc);
87 }
88
89 class Object *VehicleType::createInstance()
90 {
91         class Vehicle *obj = new Vehicle(this);
92         assert(obj);
93         return obj;
94 }
95
96 int VehicleType::getWindPenalty(int facing)
97 {
98         int vdx, vdy, wdx, wdy, base_speed;
99
100         base_speed = getSpeed();
101
102         if (!mustTurn())
103                 return 1;
104
105         vdx = directionToDx(facing);
106         vdy = directionToDy(facing);
107         wdx = directionToDx(windGetDirection());
108         wdy = directionToDy(windGetDirection());
109
110         // take the vector dot product
111         int dotprod = (vdx * wdx + vdy * wdy);
112         if (dotprod < 0) {
113             // with the wind
114             return tailwind_penalty;
115         } else if (0 == dotprod) {
116             // tacking across the wind
117             return crosswind_penalty;
118         } else {
119             // against the wind
120             return headwind_penalty;
121         }
122 }
123
124 bool VehicleType::mustTurn()
125 {
126         return must_turn;
127 }
128
129 bool VehicleType::isVulnerable()
130 {
131         return is_vulnerable;
132 }
133
134 bool VehicleType::killsOccupants()
135 {
136         return kills_occupants;
137 }
138
139 int VehicleType::getType() 
140 {
141         return VEHICLE_TYPE_ID;
142 }
143
144 bool VehicleType::isType(int classID) 
145
146         if (classID == VEHICLE_TYPE_ID)
147                 return true;
148         return ObjectType::isType(classID);
149 }
150
151 class ArmsType *VehicleType::getOrdnance() 
152 {
153         return ordnance;
154 }
155
156 char *VehicleType::getMvDesc() 
157 {
158         return mv_desc;
159 }
160
161 sound_t *VehicleType::get_movement_sound() 
162 {
163         return mv_sound;
164 }
165
166 // ----------------------------------------------------------------------------
167 //
168 // Vehicle
169 //
170 // ----------------------------------------------------------------------------
171
172 // ----------------------------------------------------------------------------
173 // The constructor used by VehicleType::createInstance()
174 // ----------------------------------------------------------------------------
175 Vehicle::Vehicle(VehicleType *type)
176         : Object(type), name(0)
177 {
178         setFacing(NORTH);
179         hp = type->getMaxHp();
180 }
181
182
183 // ----------------------------------------------------------------------------
184 // The constructor used by kern_mk_vehicle()
185 // ----------------------------------------------------------------------------
186 Vehicle::Vehicle(VehicleType *type, int _facing, int _hp)
187         : Object(type), name(0)
188 {
189         occupant = NULL;
190         setFacing(_facing);
191         hp = _hp;
192 }
193
194 Vehicle::~Vehicle()
195 {
196         if (name)
197                 free(name);
198 }
199
200 int Vehicle::get_facing_to_fire_weapon(int dx, int dy)
201 {
202         if (dx)
203                 return NORTH;
204         if (dy)
205                 return EAST;
206         return -1;
207 }
208
209 bool Vehicle::fire_weapon(int dx, int dy, class Object *user)
210 {
211         class ArmsType *ordnance;
212
213         ordnance = getOrdnance();
214         assert(ordnance);
215
216         // check facing
217         int vdir = getFacing();
218         if (((vdir == NORTH || vdir == SOUTH) && dy) ||
219             ((vdir == EAST || vdir == WEST) && dx)) {
220                 return false;
221         }
222
223         ordnance->fireInDirection(getPlace(), getX(), getY(), dx, dy, user);
224         return true;
225 }
226
227 bool Vehicle::turn(int dx, int dy, int *cost)
228 {
229         *cost = 0;
230
231         if (getFacing() == vector_to_facing(dx, dy))
232                 return false;
233
234         if (!setFacing(vector_to_facing(dx, dy)))
235                 return false;
236
237         *cost = getObjectType()->getSpeed();
238         return true;
239 }
240
241 int Vehicle::getMovementCostMultiplier()
242 {
243         return getObjectType()->getWindPenalty(getFacing());
244 }
245
246 void Vehicle::damage(int amount)
247 {
248         Object::damage(amount);
249         hp -= amount;
250         hp = max(0, hp);
251         hp = min(hp, getObjectType()->getMaxHp());
252
253         if (hp == 0)
254                 destroy();
255 }
256
257 struct formation *Vehicle::get_formation()
258 {
259         return getObjectType()->formation;
260 }
261
262 struct place *Vehicle::getPlace()
263 {
264         if (occupant)
265                 return occupant->getPlace();
266         return Object::getPlace();
267 }
268
269 int Vehicle::getX()
270 {
271         if (occupant != NULL)
272                 return occupant->getX();
273         return Object::getX();
274 }
275
276 int Vehicle::getY()
277 {
278         if (occupant != NULL)
279                 return occupant->getY();
280         return Object::getY();
281 }
282
283 bool Vehicle::mustTurn()
284 {
285         return getObjectType()->mustTurn();   
286 }
287
288 bool Vehicle::isVulnerable()
289 {
290         return getObjectType()->isVulnerable();       
291 }
292
293 void Vehicle::destroy()
294 {
295         Object::destroy();
296
297         if (occupant != NULL &&
298             getObjectType()->killsOccupants()) {                
299                 occupant->destroy();
300                 setOccupant(0);
301         }
302 }
303
304 bool Vehicle::isType(int classID) 
305
306         if (classID == VEHICLE_ID)
307                 return true;
308         return Object::isType(classID);
309 }
310
311 int Vehicle::getType() 
312 {
313         return VEHICLE_ID;
314 }
315
316 class VehicleType *Vehicle::getObjectType() 
317
318         return (class VehicleType *) Object::getObjectType();
319 }
320
321 class ArmsType *Vehicle::getOrdnance() 
322
323         return getObjectType()->getOrdnance();
324 }
325
326 char *Vehicle::getMvDesc() 
327 {
328         return getObjectType()->getMvDesc();
329 }
330
331 sound_t *Vehicle::get_movement_sound()
332 {
333         return getObjectType()->get_movement_sound();
334 }
335
336 void Vehicle::save(struct save *save)
337 {
338         save->enter(save, "(let ((kveh (kern-mk-vehicle %s %d %d)))\n",
339                     getObjectType()->getTag(), getFacing(), getHp());
340         if (name) {
341                 save->write(save, "(kern-vehicle-set-name kveh \"%s\")\n", name);
342         }
343         if (getTTL() != -1) {
344                 save->write(save, "(kern-obj-set-ttl kveh %d)\n", getTTL());
345         }
346         save->exit(save, "kveh) ;; vehicle \n");
347 }
348
349 struct mmode *Vehicle::getMovementMode()
350 {
351         return getObjectType()->mmode;
352 }
353
354 const char *Vehicle::getName()
355 {
356         if (name)
357                 return name;
358         return Object::getName();
359 }
360
361 void Vehicle::setName(char *val)
362 {
363         name = strdup(val);
364         assert(name);
365 }
366
367 class Object *Vehicle::getOccupant()
368 {
369         return occupant;
370 }
371
372 void Vehicle::setOccupant(class Object *val)
373 {
374         if (val) {
375                 assert(!occupant);
376                 occupant = val;
377                 obj_inc_ref(occupant);
378                 Object::setTTL(this, -1);
379         } else if (occupant) {
380                 obj_dec_ref(occupant);
381                 occupant = 0;
382
383                 /* Unnamed vehicles will expire after a while. */
384                 if (!name) {
385                         Object::setTTL(this, VEHICLE_DEF_TTL);
386                 }
387         }
388 }
389
390 bool Vehicle::isNamed()
391 {
392         return name != 0;
393 }
394
395 void Vehicle::describe()
396 {
397         if (name) {
398                 log_continue("the %s", name);
399         } else {
400                 Object::describe();
401         }
402 }