/**********************************************************************
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 "g1_object.hh" #include "math/num_type.hh" #include "math/pi.hh" #include "saver.hh" #include "map.hh" #include "g1_render.hh" #include "object_definer.hh" #include "dll/dll.hh" #include "map_man.hh" #include "math/pi.hh" #include "objs/shockwave.hh" #include "objs/explosion1.hh" #include "objs/debris.hh" #include "map_vert.hh" #include "sound/sfx_id.hh" g1_object_definerg1_shockwave_def("shockwave", g1_object_definition_class::EDITOR_SELECTABLE); S1_SFX_DISTANCE(explode_sfx, "explosion/super_mortar.wav", S1_3D | S1_STREAMED, 100, 50); g1_shockwave_class::g1_shockwave_class(g1_object_type id, g1_loader_class *fp) : g1_object_class(id, fp), vert_map(0) { if (fp && fp->check_version(DATA_VERSION)) { fp->read_format("ff2", &strength, &focal_radius, &radius); alloc_vert_map(); fp->end_version(I4_LF); } else { radius=5; strength=1; focal_radius=0; alloc_vert_map(); } draw_params.setup("shockwave"); } void g1_shockwave_class::save(g1_saver_class *fp) { g1_object_class::save(fp); fp->start_version(DATA_VERSION); fp->write_format("ff2", &strength, &focal_radius, &radius); fp->end_version(); } g1_shockwave_class::~g1_shockwave_class() { if (vert_map) i4_free(vert_map); } void g1_shockwave_class::alloc_vert_map() { if (vert_map) i4_free(vert_map); int d=2*radius+1; vert_map=(vert_offset *)i4_malloc(sizeof(vert_offset) * d*d, ""); } void g1_shockwave_class::setup(const i4_3d_vector &pos, // starting position (center) float _strength, // maximum ground distortion w16 _radius) // maximum radius in game units { g1_map_class *map=g1_get_map(); x=lx=pos.x; y=ly=pos.y; h=lh=pos.z; strength=_strength; radius=_radius; focal_radius=0; alloc_vert_map(); red_intensity=1.0; green_intensity=1.0; blue_intensity=0; if (occupy_location()) { request_think(); g1_explosion1_class *explosion = NULL; explosion = (g1_explosion1_class *)g1_create_object(g1_get_object_type("explosion1")); if (explosion) explosion->setup(x,y,h, g1_explosion1_class::MAKE_SPHERE); g1_debris_class *debris = NULL; debris = (g1_debris_class *)g1_create_object(g1_get_object_type("debris")); if (debris) debris->setup(x,y,h, g1_debris_class::RING_CHUNKS); debris = (g1_debris_class *)g1_create_object(g1_get_object_type("debris")); if (debris) debris->setup(x,y,h, g1_debris_class::RING_CHUNKS); debris = (g1_debris_class *)g1_create_object(g1_get_object_type("debris")); if (debris) debris->setup(x,y,h, g1_debris_class::RING_CHUNKS); explode_sfx.play(x,y,h); } } i4_bool g1_shockwave_class::occupy_location() { if (get_flag(MAP_OCCUPIED) || !vert_map) return i4_T; if (g1_object_class::occupy_location()) { sw32 _ix = i4_f_to_i(x), _iy = i4_f_to_i(y); float oor = 1.f/(float)radius; vert_offset *vo = vert_map; sw32 x_left,x_right,y_top,y_bottom; sw32 wx = g1_get_map()->width(); sw32 wy = g1_get_map()->height(); x_left = _ix - radius; if (x_left<0) x_left=0; x_right = _ix + radius; if (x_right>wx-1) x_right=wx-1; y_top = _iy - radius; if (y_top<0) y_top=0; y_bottom = _iy + radius; if (y_bottom>wy-1) y_bottom=wy-1; sw32 ix,iy; for (iy=y_top; iy<=y_bottom; iy++) { g1_map_vertex_class *v = g1_get_map()->vertex(x_left, iy); for (ix=x_left; ix<=x_right; ix++, vo++, v++) { i4_3d_vector dir = i4_3d_vector(x-ix, y-iy, h - v->get_height()); i4_float dist = dir.length(); i4_float odist = 1.f/dist; // float t=dist * oor; float alpha=fabs((dist - focal_radius)*2.0); float multiplier=2 / (alpha*alpha+1); if (multiplier>1.0) multiplier=1.0; float new_height=multiplier*strength; sw32 new_height_value = i4_f_to_i(new_height/0.05); if (new_height_value>255) new_height_value=255; else if (new_height_value<0) new_height_value=0; vo->displacement=new_height_value; v->height+=vo->displacement; v->light_sum=0x80000000; v->normal=0x8000; w16 old_rgb=v->dynamic_light; sw32 r,g,b, or,og,ob; r=i4_f_to_i(red_intensity*multiplier*255); g=i4_f_to_i(green_intensity*multiplier*255); b=i4_f_to_i(blue_intensity*multiplier*255); or=(old_rgb>>16)&255; // grab the old light values og=(old_rgb>>8)&255; ob=(old_rgb)&255; if (r+or>255) r=255-or; // adjust for overflow if (g+og>255) g=255-og; if (b+ob>255) b=255-ob; vo->color = (r<<16) | (g<<8) | b; v->dynamic_light += vo->color; } } request_think(); return i4_T; } else return i4_F; } void g1_shockwave_class::unoccupy_location() { if (get_flag(MAP_OCCUPIED) && vert_map) { g1_object_class::unoccupy_location(); sw32 _ix = i4_f_to_i(x), _iy = i4_f_to_i(y); vert_offset *vo=vert_map; sw32 x_left,x_right,y_top,y_bottom; sw32 w = g1_get_map()->width(); sw32 h = g1_get_map()->height(); x_left = _ix - radius; if (x_left<0) x_left=0; x_right = _ix + radius; if (x_right>w-1) x_right=w-1; y_top = _iy - radius; if (y_top<0) y_top=0; y_bottom = _iy + radius; if (y_bottom>h-1) y_bottom=h-1; sw32 ix,iy; for (iy=y_top; iy<=y_bottom; iy++) { g1_map_vertex_class *v=g1_get_map()->vertex(x_left, iy); for (ix=x_left; ix<=x_right; ix++, vo++, v++) { v->height-=vo->displacement; v->dynamic_light-=vo->color; v->light_sum=0x80000000; v->normal=0x8000; } } } } void g1_shockwave_class::think() { grab_old(); unoccupy_location(); strength *= 0.92; focal_radius += 0.3; red_intensity *= 0.95; green_intensity *= 0.80; if (strength<0.05) request_remove(); else { occupy_location(); request_think(); } } void fast_transform(i4_transform_class *t,const i4_3d_vector &src, r1_3d_point_class &dst); void g1_shockwave_class::draw(g1_draw_context_class *context) { //g1_model_draw(this, draw_params, context); #if 0 sw32 frequency = 4; i4_float ratio = (1.f / (float)frequency) * i4_interpolate((g1_tick_counter & (frequency-1)), (g1_tick_counter & (frequency-1))+1, g1_render.frame_ratio); if (g1_tick_counter & frequency) ratio = 1-ratio; i4_float start_a,start_r,start_g,start_b; i4_float end_a, end_r, end_g, end_b; start_a = i4_interpolate(1,0.5,ratio); start_r = 1; start_g = i4_interpolate(0,1,ratio); start_b = 0; end_a = i4_interpolate(0.5,1,ratio); end_r = 1; end_g = i4_interpolate(1,0,ratio); end_b = 0; i4_3d_vector start_point = i4_3d_vector(x,y,h); i4_3d_vector end_point = i4_3d_vector(x,y,h+20); r1_3d_point_class t_start_point, t_end_point; fast_transform(context->transform, start_point, t_start_point); fast_transform(context->transform, end_point, t_end_point); t_start_point.x *= g1_render.scale_x; t_start_point.y *= g1_render.scale_y; t_end_point.x *= g1_render.scale_x; t_end_point.y *= g1_render.scale_y; i4_3d_vector v; v = i4_3d_vector(t_end_point.x - t_start_point.x, t_end_point.y - t_start_point.y, t_end_point.z - t_start_point.z); r1_vert points[4]; i4_3d_vector norm; norm.cross((i4_3d_vector &)t_start_point, v); norm.normalize(); norm *= 2; points[0].v.x = t_start_point.x + norm.x; points[0].v.y = t_start_point.y + norm.y; points[0].v.z = t_start_point.z + norm.z; points[0].a = start_a; points[0].r = start_r; points[0].g = start_g; points[0].b = start_b; points[1].v.x = t_start_point.x - norm.x; points[1].v.y = t_start_point.y - norm.y; points[1].v.z = t_start_point.z - norm.z; points[1].a = start_a; points[1].r = start_r; points[1].g = start_g; points[1].b = start_b; norm.cross((i4_3d_vector &)t_end_point, v); norm.normalize(); norm *= 2; points[2].v.x = t_end_point.x - norm.x; points[2].v.y = t_end_point.y - norm.y; points[2].v.z = t_end_point.z - norm.z; points[2].a = end_a; points[2].r = end_r; points[2].g = end_g; points[2].b = end_b; points[3].v.x = t_end_point.x + norm.x; points[3].v.y = t_end_point.y + norm.y; points[3].v.z = t_end_point.z + norm.z; points[3].a = end_a; points[3].r = end_r; points[3].g = end_g; points[3].b = end_b; g1_post_draw_quad_class p; p.vert_ref[0] = g1_render.add_post_draw_vert(points[0]); p.vert_ref[1] = g1_render.add_post_draw_vert(points[1]); p.vert_ref[2] = g1_render.add_post_draw_vert(points[2]); p.vert_ref[3] = g1_render.add_post_draw_vert(points[3]); g1_render.add_post_draw_quad(p); #endif }