From 4a3c2e2c8c3a8dee5828258f920f1c175e952cb0 Mon Sep 17 00:00:00 2001 From: Magnus Auvinen Date: Sun, 16 Mar 2008 22:32:17 +0000 Subject: [PATCH] loads of fixes, skidding, velocity ramping and other stuff --- datasrc/teewars.ds | 7 ++ src/game/client/gc_client.cpp | 28 +++++++- src/game/client/gc_client.h | 1 + src/game/client/gc_effects.cpp | 54 +++++++++++--- src/game/client/gc_particles.cpp | 1 + src/game/client/gc_render_obj.cpp | 45 ++++++++++-- src/game/g_game.cpp | 19 ++++- src/game/g_game.h | 7 +- src/game/g_protocol.def | 4 +- src/game/g_tuning.h | 15 ++-- src/game/server/gs_common.h | 2 +- src/game/server/gs_server.cpp | 114 +++++++++++++++++++----------- 12 files changed, 223 insertions(+), 74 deletions(-) diff --git a/datasrc/teewars.ds b/datasrc/teewars.ds index bcc21edf7..c3fd93531 100644 --- a/datasrc/teewars.ds +++ b/datasrc/teewars.ds @@ -118,6 +118,13 @@ sounds { "data/audio/vo_teefault_spawn-06.wv" "data/audio/vo_teefault_spawn-07.wv" } + + player_skid { + "data/audio/sfx_skid-01.wv" + "data/audio/sfx_skid-02.wv" + "data/audio/sfx_skid-03.wv" + "data/audio/sfx_skid-04.wv" + } tee_cry { "data/audio/vo_teefault_cry-01.wv" diff --git a/src/game/client/gc_client.cpp b/src/game/client/gc_client.cpp index 7b191fbfa..2526ab834 100644 --- a/src/game/client/gc_client.cpp +++ b/src/game/client/gc_client.cpp @@ -1373,11 +1373,15 @@ void render_game() { gfx_mapscreen(0, 0, 300*gfx_screenaspect(), 300); - float speed = distance(vec2(netobjects.local_prev_character->x, netobjects.local_prev_character->y), - vec2(netobjects.local_character->x, netobjects.local_character->y)); + /*float speed = distance(vec2(netobjects.local_prev_character->x, netobjects.local_prev_character->y), + vec2(netobjects.local_character->x, netobjects.local_character->y));*/ + + float velspeed = length(vec2(netobjects.local_character->vx/256.0f, netobjects.local_character->vy/256.0f))*50; + + float ramp = velocity_ramp(velspeed, tuning.velramp_start, tuning.velramp_range, tuning.velramp_curvature); char buf[512]; - str_format(buf, sizeof(buf), "%.2f %d", speed/2, netobj_num_corrections()); + str_format(buf, sizeof(buf), "%.0f\n%.0f\n%.2f\n%d", velspeed, velspeed*ramp, ramp, netobj_num_corrections()); gfx_text(0, 150, 50, 12, buf, -1); } @@ -1481,6 +1485,24 @@ void render_game() count++; } + + y = y+count*6; + + gfx_texture_set(-1); + gfx_blend_normal(); + gfx_lines_begin(); + float height = 50.0f; + float pv = 1; + for(int i = 0; i < 100; i++) + { + float speed = i/100.0f * 3000; + float ramp = velocity_ramp(speed, tuning.velramp_start, tuning.velramp_range, tuning.velramp_curvature); + float rampedspeed = (speed * ramp)/1000.0f; + gfx_lines_draw((i-1)*2, y+height-pv*height, i*2, y+height-rampedspeed*height); + //gfx_lines_draw((i-1)*2, 200, i*2, 200); + pv = rampedspeed; + } + gfx_lines_end(); } gfx_text_color(1,1,1,1); diff --git a/src/game/client/gc_client.h b/src/game/client/gc_client.h index e61459546..55a880ed4 100644 --- a/src/game/client/gc_client.h +++ b/src/game/client/gc_client.h @@ -142,6 +142,7 @@ void effects_update(); void effect_bullettrail(vec2 pos); void effect_smoketrail(vec2 pos, vec2 vel); +void effect_skidtrail(vec2 pos, vec2 vel); void effect_explosion(vec2 pos); void effect_air_jump(vec2 pos); void effect_damage_indicator(vec2 pos, vec2 dir); diff --git a/src/game/client/gc_effects.cpp b/src/game/client/gc_effects.cpp index fcf7ac931..094392e58 100644 --- a/src/game/client/gc_effects.cpp +++ b/src/game/client/gc_effects.cpp @@ -2,7 +2,8 @@ #include "gc_client.h" #include "../generated/gc_data.h" -static bool add_trail = false; +static bool add_50hz = false; +static bool add_100hz = false; void effect_air_jump(vec2 pos) { @@ -27,7 +28,7 @@ void effect_air_jump(vec2 pos) void effect_powerupshine(vec2 pos, vec2 size) { - if(!add_trail) + if(!add_50hz) return; particle p; @@ -48,7 +49,7 @@ void effect_powerupshine(vec2 pos, vec2 size) void effect_smoketrail(vec2 pos, vec2 vel) { - if(!add_trail) + if(!add_50hz) return; particle p; @@ -65,9 +66,28 @@ void effect_smoketrail(vec2 pos, vec2 vel) } +void effect_skidtrail(vec2 pos, vec2 vel) +{ + if(!add_100hz) + return; + + particle p; + p.set_default(); + p.spr = SPRITE_PART_SMOKE; + p.pos = pos; + p.vel = vel + random_dir()*50.0f; + p.life_span = 0.5f + frandom()*0.5f; + p.start_size = 24.0f + frandom()*12; + p.end_size = 0; + p.friction = 0.7f; + p.gravity = frandom()*-500.0f; + p.color = vec4(0.75f,0.75f,0.75f,1.0f); + particle_add(PARTGROUP_GENERAL, &p); +} + void effect_bullettrail(vec2 pos) { - if(!add_trail) + if(!add_100hz) return; particle p; @@ -77,7 +97,7 @@ void effect_bullettrail(vec2 pos) p.life_span = 0.25f + frandom()*0.25f; p.start_size = 8.0f; p.end_size = 0; - p.friction = 0.7; + p.friction = 0.7f; particle_add(PARTGROUP_PROJECTILE_TRAIL, &p); } @@ -170,14 +190,26 @@ void effect_explosion(vec2 pos) void effects_update() { - static float last_update = 0; - if(client_localtime()-last_update > 0.02f) + static float last_update_100hz = 0; + static float last_update_50hz = 0; + + if(client_localtime()-last_update_100hz > 0.01f) { - add_trail = true; - last_update = client_localtime(); - flow_update(); + add_100hz = true; + last_update_100hz = client_localtime(); } else - add_trail = false; + add_100hz = false; + + if(client_localtime()-last_update_50hz > 0.02f) + { + add_50hz = true; + last_update_50hz = client_localtime(); + } + else + add_50hz = false; + + if(add_50hz) + flow_update(); } diff --git a/src/game/client/gc_particles.cpp b/src/game/client/gc_particles.cpp index bdeb26fd0..a0b1ff927 100644 --- a/src/game/client/gc_particles.cpp +++ b/src/game/client/gc_particles.cpp @@ -107,6 +107,7 @@ void particle_update(float time_passed) particles[first_free].prev_part = i; particles[i].prev_part = -1; particles[i].next_part = first_free; + first_free = i; } i = next; diff --git a/src/game/client/gc_render_obj.cpp b/src/game/client/gc_render_obj.cpp index 73f58a859..839a52610 100644 --- a/src/game/client/gc_render_obj.cpp +++ b/src/game/client/gc_render_obj.cpp @@ -25,15 +25,29 @@ void render_projectile(const NETOBJ_PROJECTILE *current, int itemid) gfx_quads_begin(); // get positions - float gravity = -400; - if(current->type != WEAPON_GRENADE) - gravity = -100; + float curvature = 0; + float speed = 0; + if(current->type == WEAPON_GRENADE) + { + curvature = tuning.grenade_curvature; + speed = tuning.grenade_speed; + } + else if(current->type == WEAPON_SHOTGUN) + { + curvature = tuning.shotgun_curvature; + speed = tuning.shotgun_speed; + } + else if(current->type == WEAPON_GUN) + { + curvature = tuning.gun_curvature; + speed = tuning.gun_speed; + } float ct = (client_tick()-current->start_tick)/(float)SERVER_TICK_SPEED + client_ticktime()*1/(float)SERVER_TICK_SPEED; vec2 startpos(current->x, current->y); - vec2 startvel(current->vx, current->vy); - vec2 pos = calc_pos(startpos, startvel, gravity, ct); - vec2 prevpos = calc_pos(startpos, startvel, gravity, ct-0.001f); + vec2 startvel(current->vx/100.0f, current->vy/100.0f); + vec2 pos = calc_pos(startpos, startvel, curvature, speed, ct); + vec2 prevpos = calc_pos(startpos, startvel, curvature, speed, ct-0.001f); select_sprite(data->weapons[clamp(current->type, 0, NUM_WEAPONS-1)].sprite_proj); vec2 vel = pos-prevpos; @@ -295,6 +309,7 @@ void render_player( bool stationary = player.vx < 1 && player.vx > -1; bool inair = col_check_point(player.x, player.y+16) == 0; + bool want_other_dir = (player.wanted_direction == -1 && vel.x > 0) || (player.wanted_direction == 1 && vel.x < 0); // evaluate animation float walk_time = fmod(position.x, 100.0f)/100.0f; @@ -305,7 +320,7 @@ void render_player( anim_eval_add(&state, &data->animations[ANIM_INAIR], 0, 1.0f); // TODO: some sort of time here else if(stationary) anim_eval_add(&state, &data->animations[ANIM_IDLE], 0, 1.0f); // TODO: some sort of time here - else + else if(!want_other_dir) anim_eval_add(&state, &data->animations[ANIM_WALK], walk_time, 1.0f); if (player.weapon == WEAPON_HAMMER) @@ -318,6 +333,22 @@ void render_player( float a = clamp((client_tick()-player.attacktick+ticktime)/40.0f, 0.0f, 1.0f); anim_eval_add(&state, &data->animations[ANIM_NINJA_SWING], a, 1.0f); } + + // do skidding + if(!inair && want_other_dir && length(vec2(prev.vx/256.0f, prev.vy/256.0f)*50) > 500.0f) + { + static int64 skid_sound_time = 0; + if(time_get()-skid_sound_time > time_freq()/10) + { + snd_play_random(CHN_WORLD, SOUND_PLAYER_SKID, 0.25f, position); + skid_sound_time = time_get(); + } + + effect_skidtrail( + position+vec2(-player.wanted_direction*6,12), + vec2(-player.wanted_direction*100*length(vel),-50) + ); + } // draw hook if (prev.hook_state>0 && player.hook_state>0) diff --git a/src/game/g_game.cpp b/src/game/g_game.cpp index c87da2d46..f2ebadee3 100644 --- a/src/game/g_game.cpp +++ b/src/game/g_game.cpp @@ -154,6 +154,17 @@ void move_box(vec2 *inout_pos, vec2 *inout_vel, vec2 size, float elasticity) *inout_vel = vel; } +float hermite_basis1(float v) +{ + return 2*v*v*v - 3*v*v+1; +} + +float velocity_ramp(float value, float start, float range, float curvature) +{ + if(value < start) + return 1.0f; + return 1.0f/pow(curvature, (value-start)/range); +} void player_core::reset() { @@ -405,13 +416,17 @@ void player_core::tick() } // clamp the velocity to something sane - if(length(vel) > world->tuning.terminal_velocity) - vel = normalize(vel) * world->tuning.terminal_velocity; + if(length(vel) > 6000) + vel = normalize(vel) * 6000; } void player_core::move() { + float rampvalue = velocity_ramp(length(vel)*50, world->tuning.velramp_start, world->tuning.velramp_range, world->tuning.velramp_curvature); + + vel.x = vel.x*rampvalue; move_box(&pos, &vel, vec2(28.0f, 28.0f), 0); + vel.x = vel.x*(1.0f/rampvalue); } void player_core::write(NETOBJ_PLAYER_CORE *obj_core) diff --git a/src/game/g_game.h b/src/game/g_game.h index 3cb6639b3..6b13fb7bd 100644 --- a/src/game/g_game.h +++ b/src/game/g_game.h @@ -53,11 +53,12 @@ inline float get_angle(vec2 dir) } -inline vec2 calc_pos(vec2 p, vec2 v, float gravity, float t) +inline vec2 calc_pos(vec2 p, vec2 v, float curvature, float speed, float t) { vec2 n; + t *= speed; n.x = p.x + v.x*t; - n.y = p.y + v.y*t - gravity*(t*t); + n.y = p.y + v.y*t + curvature/10000*(t*t); return n; } @@ -88,7 +89,7 @@ inline T saturated_add(T min, T max, T current, T modifier) void move_point(vec2 *inout_pos, vec2 *inout_vel, float elasticity, int *bounces); void move_box(vec2 *inout_pos, vec2 *inout_vel, vec2 size, float elasticity); bool test_box(vec2 pos, vec2 size); - +float velocity_ramp(float value, float start, float range, float curvature); // hooking stuff enum diff --git a/src/game/g_protocol.def b/src/game/g_protocol.def index 75ae4012d..53753d655 100644 --- a/src/game/g_protocol.def +++ b/src/game/g_protocol.def @@ -151,14 +151,16 @@ end object player_character extends player_core range(0, NUM_PLAYERSTATES-1) player_state + range(-1, 1) wanted_direction + range(0, 10) health range(0, 10) armor range(0, 10) ammocount - range(0, 10) weaponstage range(0, NUM_WEAPONS-1) weapon range(0, NUM_EMOTES-1) emote + range(0, 10) weaponstage range(0, max_int) attacktick end diff --git a/src/game/g_tuning.h b/src/game/g_tuning.h index c22018894..b80398d47 100644 --- a/src/game/g_tuning.h +++ b/src/game/g_tuning.h @@ -12,15 +12,20 @@ MACRO_TUNING_PARAM(hook_fire_speed, 45.0f) MACRO_TUNING_PARAM(hook_drag_accel, 3.0f) MACRO_TUNING_PARAM(hook_drag_speed, 15.0f) MACRO_TUNING_PARAM(gravity, 0.5f) -MACRO_TUNING_PARAM(terminal_velocity, 1000.0f / ticks_per_second) + +MACRO_TUNING_PARAM(velramp_start, 500) +MACRO_TUNING_PARAM(velramp_range, 2000) +MACRO_TUNING_PARAM(velramp_curvature, 1.5f) /* weapon tuning */ -MACRO_TUNING_PARAM(gun_speed, 30.0f) +MACRO_TUNING_PARAM(gun_curvature, 1.5f) +MACRO_TUNING_PARAM(gun_speed, 2200.0f) -MACRO_TUNING_PARAM(shotgun_speed_center, 40.0f) -MACRO_TUNING_PARAM(shotgun_speed_wide, 30.0f) +MACRO_TUNING_PARAM(shotgun_curvature, 1.5f) +MACRO_TUNING_PARAM(shotgun_speed, 2200.0f) -MACRO_TUNING_PARAM(grenade_speed, 15.0f) +MACRO_TUNING_PARAM(grenade_curvature, 7.0f) +MACRO_TUNING_PARAM(grenade_speed, 900.0f) MACRO_TUNING_PARAM(laser_reach, 800.0f) MACRO_TUNING_PARAM(laser_bounce_delay, 150) diff --git a/src/game/server/gs_common.h b/src/game/server/gs_common.h index ffeadecfe..0de813183 100644 --- a/src/game/server/gs_common.h +++ b/src/game/server/gs_common.h @@ -188,7 +188,7 @@ public: PROJECTILE_FLAGS_EXPLODE = 1 << 0, }; - vec2 vel; + vec2 direction; entity *powner; // this is nasty, could be removed when client quits int lifespan; int owner; diff --git a/src/game/server/gs_server.cpp b/src/game/server/gs_server.cpp index f674ecfd9..fa3f99250 100644 --- a/src/game/server/gs_server.cpp +++ b/src/game/server/gs_server.cpp @@ -24,6 +24,7 @@ void create_playerspawn(vec2 p); void create_death(vec2 p); void create_sound(vec2 pos, int sound, int mask=-1); class player *intersect_player(vec2 pos0, vec2 pos1, vec2 &new_pos, class entity *notthis = 0); +class player *closest_player(vec2 pos, float radius, entity *notthis); game_world *world; @@ -380,13 +381,13 @@ static input_count count_input(int prev, int cur) ////////////////////////////////////////////////// // projectile ////////////////////////////////////////////////// -projectile::projectile(int type, int owner, vec2 pos, vec2 vel, int span, entity* powner, +projectile::projectile(int type, int owner, vec2 pos, vec2 dir, int span, entity* powner, int damage, int flags, float force, int sound_impact, int weapon) : entity(NETOBJTYPE_PROJECTILE) { this->type = type; this->pos = pos; - this->vel = vel * server_tickspeed(); // TODO: remove this + this->direction = normalize(dir); this->lifespan = span; this->owner = owner; this->powner = powner; @@ -407,14 +408,28 @@ void projectile::reset() void projectile::tick() { - float gravity = -400; - if(type != WEAPON_GRENADE) - gravity = -100; + float curvature = 0; + float speed = 0; + if(type == WEAPON_GRENADE) + { + curvature = tuning.grenade_curvature; + speed = tuning.grenade_speed; + } + else if(type == WEAPON_SHOTGUN) + { + curvature = tuning.shotgun_curvature; + speed = tuning.shotgun_speed; + } + else if(type == WEAPON_GUN) + { + curvature = tuning.gun_curvature; + speed = tuning.gun_speed; + } float pt = (server_tick()-start_tick-1)/(float)server_tickspeed(); float ct = (server_tick()-start_tick)/(float)server_tickspeed(); - vec2 prevpos = calc_pos(pos, vel, gravity, pt); - vec2 curpos = calc_pos(pos, vel, gravity, ct); + vec2 prevpos = calc_pos(pos, direction, curvature, speed, pt); + vec2 curpos = calc_pos(pos, direction, curvature, speed, ct); lifespan--; @@ -432,7 +447,7 @@ void projectile::tick() create_explosion(prevpos, owner, weapon, false); else if (targetplayer) { - targetplayer->take_damage(normalize(vel) * max(0.001f, force), damage, owner, weapon); + targetplayer->take_damage(direction * max(0.001f, force), damage, owner, weapon); } world->destroy_entity(this); @@ -443,19 +458,21 @@ void projectile::fill_info(NETOBJ_PROJECTILE *proj) { proj->x = (int)pos.x; proj->y = (int)pos.y; - proj->vx = (int)vel.x; - proj->vy = (int)vel.y; + proj->vx = (int)(direction.x*100.0f); + proj->vy = (int)(direction.y*100.0f); proj->start_tick = start_tick; proj->type = type; } void projectile::snap(int snapping_client) { - float ct = (server_tick()-start_tick)/(float)server_tickspeed(); - vec2 curpos = calc_pos(pos, vel, -7.5f*server_tickspeed(), ct); + /*float ct = (server_tick()-start_tick)/(float)server_tickspeed();*/ + /*vec2 curpos = calc_pos(pos, vel, -7.5f*server_tickspeed(), ct);*/ - if(distance(players[snapping_client].pos, curpos) > 1000.0f) - return; + /*if(distance(players[snapping_client].pos, curpos) > 1000.0f) + return;*/ + + /* TODO: FIX ME */ NETOBJ_PROJECTILE *proj = (NETOBJ_PROJECTILE *)snap_new_item(NETOBJTYPE_PROJECTILE, id, sizeof(NETOBJ_PROJECTILE)); fill_info(proj); @@ -989,7 +1006,7 @@ void player::fire_weapon() projectile *proj = new projectile(WEAPON_GUN, client_id, pos+vec2(0,0), - direction*tuning.gun_speed, + direction, server_tickspeed(), this, 1, 0, 0, -1, WEAPON_GUN); @@ -1013,7 +1030,7 @@ void player::fire_weapon() projectile *proj = new projectile(WEAPON_GRENADE, client_id, pos+vec2(0,0), - direction*tuning.grenade_speed, + direction, 100, this, 1, projectile::PROJECTILE_FLAGS_EXPLODE, 0, SOUND_GRENADE_EXPLODE, WEAPON_GRENADE); @@ -1043,13 +1060,12 @@ void player::fire_weapon() { float spreading[] = {-0.185f, -0.070f, 0, 0.070f, 0.185f}; float a = get_angle(direction); - float v = 1.0f-fabs(i/(float)shotspread); a += spreading[i+2]; - float speed = mix((float)tuning.shotgun_speed_wide, (float)tuning.shotgun_speed_center, v); + /*float speed = mix((float)tuning.shotgun_speed_wide, (float)tuning.shotgun_speed_center, v);*/ projectile *proj = new projectile(WEAPON_SHOTGUN, client_id, pos+vec2(0,0), - vec2(cosf(a), sinf(a))*speed, + vec2(cosf(a), sinf(a)), (int)(server_tickspeed()*0.25f), this, 1, 0, 0, -1, WEAPON_SHOTGUN); @@ -1622,9 +1638,17 @@ void player::snap(int snaping_client) character->ammocount = weapons[active_weapon].ammo; character->health = 0; character->armor = 0; + character->weapon = active_weapon; character->attacktick = attack_tick; + character->wanted_direction = 0; + if(input.left && !input.right) + character->wanted_direction = -1; + else if(!input.left && input.right) + character->wanted_direction = 1; + + if(client_id == snaping_client) { character->health = health; @@ -1696,8 +1720,7 @@ void powerup::tick() return; } // Check if a player intersected us - vec2 meh; - player* pplayer = intersect_player(pos, pos + vec2(0,16), meh, 0); + player* pplayer = closest_player(pos, 20.0f, 0); if (pplayer) { // player picked us up, is someone was hooking us, let them go @@ -1957,28 +1980,37 @@ player *intersect_player(vec2 pos0, vec2 pos1, vec2& new_pos, entity *notthis) } return closest; - - /* - entity *ents[64]; - vec2 dir = pos1 - pos0; - float radius = length(dir * 0.5f); - vec2 center = pos0 + dir * 0.5f; - const int types[] = {OBJTYPE_PLAYER_CHARACTER}; - int num = world->find_entities(center, radius, ents, 64, types, 1); - for (int i = 0; i < num; i++) - { - // Check if entity is a player - if (ents[i] != notthis) - { - new_pos = ents[i]->pos; - return (player*)ents[i]; - } - } - - return 0;*/ } +player *closest_player(vec2 pos, float radius, entity *notthis) +{ + // Find other players + float closest_range = radius*2; + player *closest = 0; + + for(int i = 0; i < MAX_CLIENTS; i++) + { + if(players[i].client_id < 0 || (entity *)&players[i] == notthis) + continue; + + if(!(players[i].flags&entity::FLAG_PHYSICS)) + continue; + + float len = distance(pos, players[i].pos); + if(len < player::phys_size+radius) + { + if(len < closest_range) + { + closest_range = len; + closest = &players[i]; + } + } + } + + return closest; +} + // TODO: should be more general @@ -2281,7 +2313,7 @@ static void con_broadcast(void *result, void *user_data) void mods_console_init() { - MACRO_REGISTER_COMMAND("tune", "s?i", con_tune_param, 0); + MACRO_REGISTER_COMMAND("tune", "si", con_tune_param, 0); MACRO_REGISTER_COMMAND("tune_reset", "", con_tune_reset, 0); MACRO_REGISTER_COMMAND("tune_dump", "", con_tune_dump, 0);