/**********************************************************************
This file is part of Crack dot Com's free source code release of
Golgotha.
for
information about compiling & licensing issues visit this URL
If that doesn't help, contact Jonathan Clark at
golgotha_source@usa.net (Subject should have "GOLG" in it)
***********************************************************************/
#include "sound_man.hh"
#include "objs/model_id.hh"
#include "objs/model_draw.hh"
#include "objs/rocktank.hh"
#include "input.hh"
#include "math/pi.hh"
#include "math/trig.hh"
#include "math/angle.hh"
#include "g1_rand.hh"
#include "resources.hh"
#include "saver.hh"
#include "map_cell.hh"
#include "map.hh"
#include "objs/vehic_sounds.hh"
#include "sound/sfx_id.hh"
#include "object_definer.hh"
#include "objs/fire.hh"
S1_SFX(rumble, "rumble/missile_truck_lp.wav", S1_3D, 1);
S1_SFX(raising, "misc/missile_truck_raise.wav", S1_3D, 5);
S1_SFX(lowering, "misc/missile_truck_lower.wav", S1_3D, 5);
enum { DATA_VERSION=1 };
enum eRackState
{
LOWERED,
RAISE,
RAISING,
RAISED,
LOWER,
LOWERING,
};
static g1_model_ref model_ref("rocket_truck"),
shadow_ref("rocket_truck_shadow"),
rack_ref("rocket_truck_top"),
base_lod("rocket_truck_lod"),
top_lod("rocket_truck_top_lod");
static i4_3d_vector rack_attach, rack_offset;
static void g1_rocket_tank_init()
{
rack_attach.set(0,0,0);
model_ref()->get_mount_point("Rack", rack_attach);
rack_offset.set(0,0,0);
rack_ref()->get_mount_point("Rack", rack_offset);
rack_offset.reverse();
}
g1_object_definer
g1_rocket_tank_def("rocket_tank",
g1_object_definition_class::TO_MAP_PIECE |
g1_object_definition_class::MOVABLE |
g1_object_definition_class::EDITOR_SELECTABLE,
g1_rocket_tank_init);
static char *chunk_list[3]={"chunk_missiletruck_body", "chunk_missiletruck_launcher",
"chunk_missiletruck_tread"};
int g1_rocket_tank_class::get_chunk_names(char **&list) { list=chunk_list; return 3; }
g1_rocket_tank_class::g1_rocket_tank_class(g1_object_type id,
g1_loader_class *fp)
: g1_map_piece_class(id, fp)
{
draw_params.setup(model_ref.id(), shadow_ref.id(), base_lod.id());
allocate_mini_objects(2,"Rocket Tank Mini-objects");
missile_rack = &mini_objects[0];
missile_rack->defmodeltype = rack_ref.id();
missile_rack->lod_model = top_lod.id();
missile_rack->position(rack_attach);
missile_rack->offset = rack_offset;
w16 ver,data_size;
if (fp)
{
fp->get_version(ver,data_size);
switch (ver)
{
case DATA_VERSION:
fp->read_8();
fp->read_format("fff",
&missile_rack->rotation.x,
&missile_rack->rotation.y,
&missile_rack->rotation.z);
missile_rack->grab_old();
break;
case 0:
fp->read_8();
fp->read_8();
fp->read_8();
fp->read_8();
fp->read_16();
missile_rack->rotation.x = fp->read_float();
missile_rack->rotation.y = fp->read_float();
missile_rack->rotation.z = fp->read_float();
missile_rack->lrotation.x = fp->read_float();
missile_rack->lrotation.y = fp->read_float();
missile_rack->lrotation.z = fp->read_float();
break;
default:
fp->seek(fp->tell() + data_size);
missile_rack->rotation.x = 0;
missile_rack->rotation.y = 0;
missile_rack->rotation.z = 0;
missile_rack->lrotation = missile_rack->rotation;
fire_delay = 15;
break;
}
fp->end_version(I4_LF);
}
else
{
missile_rack->rotation.x = 0;
missile_rack->rotation.y = 0;
missile_rack->rotation.z = 0;
missile_rack->lrotation = missile_rack->rotation;
fire_delay = 15;
}
init_rumble_sound(G1_RUMBLE_GROUND);
guard_angle = 0;
guard_pitch = 0;
guard_time = 0;
radar_type=G1_RADAR_VEHICLE;
set_flag(BLOCKING |
SELECTABLE |
TARGETABLE |
GROUND |
HIT_AERIAL |
HIT_GROUND |
DANGEROUS, 1);
}
void g1_rocket_tank_class::save(g1_saver_class *fp)
{
g1_map_piece_class::save(fp);
fp->start_version(DATA_VERSION);
fp->write_8(0);
fp->write_format("fff",
&missile_rack->rotation.x,
&missile_rack->rotation.y,
&missile_rack->rotation.z);
fp->end_version();
}
void g1_rocket_tank_class::fire()
{
g1_object_class *target=attack_target.get();
if (target)
{
i4_float bx,by,bz;
i4_3d_vector pos, dir;
i4_transform_class btrans,tmp1;
btrans.translate(x,y,h);
tmp1.rotate_x(groundroll);
btrans.multiply(tmp1);
tmp1.rotate_y(groundpitch);
btrans.multiply(tmp1);
tmp1.rotate_z(theta);
btrans.multiply(tmp1);
tmp1.translate(missile_rack->x, missile_rack->y, missile_rack->h);
btrans.multiply(tmp1);
tmp1.rotate_z(missile_rack->rotation.z);
btrans.multiply(tmp1);
tmp1.rotate_y(missile_rack->rotation.y);
btrans.multiply(tmp1);
btrans.transform(i4_3d_vector(0.1, 0, 0), pos);
btrans.transform(i4_3d_vector(1.0, 0, 0), dir);
dir-=pos;
g1_fire(defaults->fire_type, this, target, pos, dir);
fire_delay = defaults->fire_delay;
}
}
void g1_rocket_tank_class::think()
{
g1_map_piece_class::think();
if (!alive())
return;
//aim the missile rack
if (attack_target.valid())
{
request_think();
i4_float dx,dy,dangle;
//this will obviously only be true if attack_target.ref != NULL
dx = ((x+missile_rack->x) - attack_target->x);
dy = ((y+missile_rack->y) - attack_target->y);
//aim the vehicle
guard_angle = i4_atan2(dy,dx) + i4_pi() - theta;
i4_normalize_angle(guard_angle);
i4_float dist = dx*dx+dy*dy;
if (dist>25.0)
guard_pitch = -i4_pi()/8;
else if (dist>9.0)
guard_pitch = -(dist - 9.0)*i4_pi()/8/(25.0-9.0);
else
guard_pitch = 0;
i4_normalize_angle(guard_pitch);
i4_bool aimed = i4_F;
dangle = i4_rotate_to(missile_rack->rotation.z, guard_angle, 0.1);
aimed = (dangle<0.1 && dangle>-0.1);
dangle = i4_rotate_to(missile_rack->rotation.y, guard_pitch, 0.1);
aimed &= (dangle<0.1 && dangle>-0.1);
if (aimed && !fire_delay)
fire();
guard_time = 40;
}
else
{
guard_pitch = 0;
guard_angle = 0;
request_think(); // move this to draw function
i4_rotate_to(missile_rack->rotation.z, guard_angle, 0.1);
i4_rotate_to(missile_rack->rotation.y, guard_pitch, 0.1);
}
}