/**********************************************************************
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 "objs/bullet.hh"
#include "input.hh"
#include "map.hh"
#include "math/pi.hh"
#include "math/trig.hh"
#include "math/random.hh"
#include "resources.hh"
#include "objs/model_draw.hh"
#include "objs/explosion1.hh"
#include "saver.hh"
#include "tile.hh"
#include "sfx_id.hh"
#include "sound_man.hh"
#include "objs/map_piece.hh"
#include "objs/explosion1.hh"
#include "objs/flak.hh"
#include "objs/shrapnel.hh"
#include "object_definer.hh"
#include "math/pi.hh"
#include "g1_texture_id.hh"
#include "r1_api.hh"
#include "g1_tint.hh"
#include "map_man.hh"
#include "flare.hh"
#include "objs/light_o.hh"
#include "objs/particle_emitter.hh"
#include "lisp/li_class.hh"
#include "li_objref.hh"
#include "camera.hh"
#include "time/profile.hh"
static i4_profile_class pf_bullet("bullet_think");
static li_symbol_ref explosion_type("explosion1"),
flak_type("flak"),
shrapnel_type("shrapnel"),
light_type("lightbulb"),
particle_emitter_type("particle_emitter"),
damager_type("damager");
g1_object_definer g1_b120mm_def("b120mm");
g1_object_definer g1_b90mm_def("b90mm");
g1_object_definer g1_acid_def("acid", g1_object_definition_class::HAS_ALPHA);
g1_object_definer g1_napalm_def("napalm", g1_object_definition_class::HAS_ALPHA);
g1_object_definer g1_chain_gun_def("chain_gun", g1_object_definition_class::HAS_ALPHA);
static li_float_class_member start_size("start_size"),
grow_speed("grow_speed"), max_speed("max_speed");
static li_object_class_member texture_name("texture_name");
static r1_texture_ref bullet_particle("bullet_particle");
void g1_bullet_class::think()
{
pf_bullet.start();
move();
pf_bullet.stop();
}
void g1_bright_ambient(i4_transform_class *object_to_world,
i4_float &ar, i4_float &ag, i4_float &ab)
{
ar=ag=ab=1;
}
g1_bullet_class::g1_bullet_class(g1_object_type id,
g1_loader_class *fp)
: g1_object_class(id,fp)
{
range=10;
if (fp && fp->check_version(DATA_VERSION))
{
x=-1;
// fp->read_reference(who_fired_me);
// fp->read_format("fffff4",
// &vel.x, &vel.y, &vel.z,
// &range, &range_decrement,
// &bullet_flags);
// fp->end_version(I4_LF);
}
else
{
bullet_flags=0;
vel=i4_3d_vector(0,0,0);
range=0;
range_decrement=1;
}
if (fp)
flags|=THINKING;
}
void g1_bullet_class::move_forward()
{
grab_old();
x += vel.x; y += vel.y; h += vel.z;
if (bullet_flags & SPINS)
roll+=0.9;
range -= range_decrement;
if (light.get())
light->move(x,y,h);
if (particle_emitter.get())
particle_emitter->move(x,y,h);
}
void g1_bullet_class::setup(const i4_3d_vector &start_pos,
const i4_3d_vector &_vel,
g1_object_class *this_guy_fired_me,
i4_float _range,
w32 flags,
r1_texture_handle sprite_texture,
g1_light_object_class *_light)
{
bullet_flags = flags;
range = _range;
x=start_pos.x;
y=start_pos.y;
h=start_pos.z;
lx=start_pos.x;
ly=start_pos.y;
lh=start_pos.z;
vel=_vel;
range_decrement=vel.length()/range;
ltheta=theta = i4_atan2(vel.y, vel.x);
pitch=lpitch = i4_atan2(-vel.z, sqrt(vel.x * vel.x +
vel.y * vel.y));
lroll=roll = 0;
player_num = this_guy_fired_me->player_num;
who_fired_me = this_guy_fired_me;
if (bullet_flags & IS_SPRITE)
tex=sprite_texture;
else
draw_params.setup(name());
if (!get_flag(MAP_OCCUPIED))
{
if (!occupy_location())
return;
request_think();
}
i4_bool possible_visible;
float r=g1_resources.visual_radius();
if (g1_current_view_state()->dist_sqrd(i4_3d_vector(x,y,h))setup(x,y,h, p);
}
}
light=_light;
move();
}
void g1_bullet_class::save(g1_saver_class *fp)
{
// tell direived classes to save themselves
g1_object_class::save(fp);
fp->start_version(DATA_VERSION);
fp->write_reference(who_fired_me);
fp->write_format("fffff44",
&vel.x, &vel.y, &vel.z,
&range, &range_decrement,
&bullet_flags);
fp->end_version();
}
void g1_bullet_class::draw(g1_draw_context_class *context)
{
if ((bullet_flags & IS_SPRITE)==0)
{
g1_get_ambient_function_type old_ambient=g1_render.get_ambient;
g1_render.get_ambient=g1_bright_ambient;
g1_render.r_api->set_filter_mode(R1_BILINEAR_FILTERING);
g1_model_draw(this, draw_params, context);
g1_render.r_api->set_filter_mode(R1_NO_FILTERING);
g1_render.get_ambient=old_ambient;
}
else
{
i4_3d_vector pos(i4_interpolate(lx,x, g1_render.frame_ratio),
i4_interpolate(ly,y, g1_render.frame_ratio),
i4_interpolate(lh,h, g1_render.frame_ratio)), t_pos;
context->transform->transform(pos, t_pos);
g1_render.render_sprite(t_pos, tex, 0.05, 0.05);
}
}
void g1_bullet_class::done(i4_bool hit, g1_object_class *hit_object)
{
unoccupy_location();
request_remove();
if (hit_object)
{
g1_shrapnel_class *shrap =
(g1_shrapnel_class *)g1_create_object(g1_get_object_type(shrapnel_type.get()));
if (shrap)
shrap->setup(x,y,h,5,1);
g1_apply_damage(this, who_fired_me.get(), hit_object, vel);
}
else if (hit)
{
g1_flak_class *flak = (g1_flak_class *)g1_create_object(g1_get_object_type(flak_type.get()));
if (flak)
flak->setup(i4_3d_vector(x,y,h), 0.1);
}
if (light.get())
{
light->unoccupy_location();
light->request_remove();
}
if (particle_emitter.get())
particle_emitter->stop();
}
i4_bool g1_bullet_class::move()
{
// we traveled to far already, let's go away
if (range<0)
{
done();
return i4_F;
}
g1_object_class *hit = 0;
i4_3d_vector pos(x,y,h);
if (!g1_get_map()->check_non_player_collision(player_num,pos,vel,hit))
{
unoccupy_location();
move_forward();
occupy_location();
request_think();
return i4_T;
}
else
{
#ifdef TEST_COLLIDE
x += vel.x;
y += vel.y;
h += vel.z;
vel.set(0,0,0);
grab_old();
#else
if (hit)
{
float v_len=vel.length();
if (v_len>0.05)
{
i4_3d_vector dir=vel; // scoot the bullet back so smoke & stuff show up in front
dir/=v_len; // of the vehicle
dir*=0.05;
vel-=dir;
}
else
vel.set(0,0,0);
x+=vel.x;
y+=vel.y;
h+=vel.z;
}
done(i4_T, hit); //we've hit something or the ground
#endif
}
return i4_F;
}