diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/engine/client/ec_client.c | 2 | ||||
| -rw-r--r-- | src/game/client/gc_client.cpp | 2 | ||||
| -rw-r--r-- | src/game/client/gc_render.cpp | 4 | ||||
| -rw-r--r-- | src/game/client/gc_render.h | 1 | ||||
| -rw-r--r-- | src/game/client/gc_render_obj.cpp | 72 | ||||
| -rw-r--r-- | src/game/editor/ed_io.cpp | 2 | ||||
| -rw-r--r-- | src/game/g_game.cpp | 2 | ||||
| -rw-r--r-- | src/game/g_mapitems.h | 2 | ||||
| -rw-r--r-- | src/game/g_protocol.h | 10 | ||||
| -rw-r--r-- | src/game/g_tuning.h | 12 | ||||
| -rw-r--r-- | src/game/server/gs_common.h | 21 | ||||
| -rw-r--r-- | src/game/server/gs_game.cpp | 4 | ||||
| -rw-r--r-- | src/game/server/gs_server.cpp | 220 |
13 files changed, 318 insertions, 36 deletions
diff --git a/src/engine/client/ec_client.c b/src/engine/client/ec_client.c index 3c0180b9..27dce4cf 100644 --- a/src/engine/client/ec_client.c +++ b/src/engine/client/ec_client.c @@ -947,7 +947,7 @@ static void client_update() int new_pred_tick = prev_pred_tick+1; static float last_predintra = 0; - intratick = (now - prevtick_start) / (float)(curtick_start-prevtick_start); + intratick = (now - curtick_start) / (float)(curtick_start-prevtick_start); ticktime = (now - curtick_start) / (freq/(float)SERVER_TICK_SPEED); graph_add(&intra_graph, intratick*0.25f); diff --git a/src/game/client/gc_client.cpp b/src/game/client/gc_client.cpp index c092ca73..79b50317 100644 --- a/src/game/client/gc_client.cpp +++ b/src/game/client/gc_client.cpp @@ -1117,7 +1117,7 @@ void render_game() for (int i = 0; i < local_character->weaponstage; i++) gfx_quads_drawTL(x+local_character->ammocount * 12 -i*12, y+22, 11, 11); select_sprite(data->weapons[local_character->weapon%data->num_weapons].sprite_proj); - for (int i = 0; i < local_character->ammocount; i++) + for (int i = 0; i < min(local_character->ammocount, 10); i++) gfx_quads_drawTL(x+i*12,y+24,10,10); gfx_quads_end(); diff --git a/src/game/client/gc_render.cpp b/src/game/client/gc_render.cpp index 6297fc9c..285b6c1c 100644 --- a/src/game/client/gc_render.cpp +++ b/src/game/client/gc_render.cpp @@ -341,6 +341,10 @@ static void render_items() if(prev) render_powerup((const obj_powerup *)prev, (const obj_powerup *)data); } + else if(item.type == OBJTYPE_LASER) + { + render_laser((const obj_laser *)data); + } else if(item.type == OBJTYPE_FLAG) { const void *prev = snap_find_item(SNAP_PREV, item.type, item.id); diff --git a/src/game/client/gc_render.h b/src/game/client/gc_render.h index d7adeada..b62206f7 100644 --- a/src/game/client/gc_render.h +++ b/src/game/client/gc_render.h @@ -57,6 +57,7 @@ void render_tee(class animstate *anim, tee_render_info *info, int emote, vec2 di void render_flag(const struct obj_flag *prev, const struct obj_flag *current); void render_powerup(const struct obj_powerup *prev, const struct obj_powerup *current); void render_projectile(const struct obj_projectile *current, int itemid); +void render_laser(const struct obj_laser *current); void render_player( const struct obj_player_character *prev_char, const struct obj_player_character *player_char, const struct obj_player_info *prev_info, const struct obj_player_info *player_info); diff --git a/src/game/client/gc_render_obj.cpp b/src/game/client/gc_render_obj.cpp index 00f54c89..6f836307 100644 --- a/src/game/client/gc_render_obj.cpp +++ b/src/game/client/gc_render_obj.cpp @@ -26,7 +26,7 @@ void render_projectile(const obj_projectile *current, int itemid) // get positions float gravity = -400; - if(current->type != WEAPON_ROCKET) + if(current->type != WEAPON_GRENADE) gravity = -100; float ct = (client_tick()-current->start_tick)/(float)SERVER_TICK_SPEED + client_ticktime()*1/(float)SERVER_TICK_SPEED; @@ -41,7 +41,7 @@ void render_projectile(const obj_projectile *current, int itemid) // add particle for this projectile - if(current->type == WEAPON_ROCKET) + if(current->type == WEAPON_GRENADE) { effect_smoketrail(pos, vel*-1); flow_add(pos, vel*1000*client_frametime(), 10.0f); @@ -136,6 +136,72 @@ void render_flag(const obj_flag *prev, const obj_flag *current) } +void render_laser(const struct obj_laser *current) +{ + + vec2 pos = vec2(current->x, current->y); + vec2 from = vec2(current->from_x, current->from_y); + vec2 dir = normalize(pos-from); + + + + float ticks = client_tick() + client_intratick() - current->eval_tick; + float ms = (ticks/50.0f) * 1000.0f; + float a = ms / tuning.laser_bounce_delay; + a = clamp(a, 0.0f, 1.0f); + float ia = 1-a; + + + + vec2 out(dir.y, -dir.x); + + out = out * (4.0f*ia); + + gfx_blend_normal(); + gfx_texture_set(-1); + gfx_quads_begin(); + + vec4 start_color(0.25f,0.25f,0.5f,1.0f); + vec4 end_color(0.85f,0.85f,1.0f,1.0f); + start_color = end_color; + + gfx_setcolorvertex(0, start_color.r, start_color.g, start_color.b, start_color.a); + gfx_setcolorvertex(1, start_color.r, start_color.g, start_color.b, start_color.a); + gfx_setcolorvertex(2, end_color.r, end_color.g, end_color.b, end_color.a); + gfx_setcolorvertex(3, end_color.r, end_color.g, end_color.b, end_color.a); + + from = mix(from, pos, a); + + gfx_quads_draw_freeform( + from.x-out.x, from.y-out.y, + from.x+out.x, from.y+out.y, + pos.x-out.x, pos.y-out.y, + pos.x+out.x, pos.y+out.y + ); + + gfx_quads_end(); + + // render head + { + gfx_blend_normal(); + gfx_texture_set(data->images[IMAGE_PARTICLES].id); + gfx_quads_begin(); + + gfx_setcolor(end_color.r, end_color.g, end_color.b, end_color.a); + + int sprites[] = {SPRITE_PART_SPLAT01, SPRITE_PART_SPLAT02, SPRITE_PART_SPLAT03}; + select_sprite(sprites[client_tick()%3]); + gfx_quads_setrotation(client_tick()); + gfx_quads_draw(pos.x, pos.y, 32,32); + gfx_quads_end(); + } + + gfx_blend_normal(); +} + + + + static void render_hand(tee_render_info *info, vec2 center_pos, vec2 dir, float angle_offset, vec2 post_rot_offset) { @@ -416,7 +482,7 @@ void render_player( { case WEAPON_GUN: render_hand(&client_datas[info.clientid].render_info, p, direction, -3*pi/4, vec2(-15, 4)); break; case WEAPON_SHOTGUN: render_hand(&client_datas[info.clientid].render_info, p, direction, -pi/2, vec2(-5, 4)); break; - case WEAPON_ROCKET: render_hand(&client_datas[info.clientid].render_info, p, direction, -pi/2, vec2(-4, 7)); break; + case WEAPON_GRENADE: render_hand(&client_datas[info.clientid].render_info, p, direction, -pi/2, vec2(-4, 7)); break; } } diff --git a/src/game/editor/ed_io.cpp b/src/game/editor/ed_io.cpp index fe8ee19a..80c82548 100644 --- a/src/game/editor/ed_io.cpp +++ b/src/game/editor/ed_io.cpp @@ -176,7 +176,7 @@ void editor_load_old(DATAFILE *df) else if(t == MAPRES_ITEM) { if(e->data[0] == ITEM_WEAPON_SHOTGUN) id = ENTITY_WEAPON_SHOTGUN; - else if(e->data[0] == ITEM_WEAPON_ROCKET) id = ENTITY_WEAPON_ROCKET; + else if(e->data[0] == ITEM_WEAPON_ROCKET) id = ENTITY_WEAPON_GRENADE; else if(e->data[0] == ITEM_NINJA) id = ENTITY_POWERUP_NINJA; else if(e->data[0] == ITEM_ARMOR) id = ENTITY_ARMOR_1; else if(e->data[0] == ITEM_HEALTH) id = ENTITY_HEALTH_1; diff --git a/src/game/g_game.cpp b/src/game/g_game.cpp index 74b9aed4..25114cb7 100644 --- a/src/game/g_game.cpp +++ b/src/game/g_game.cpp @@ -43,8 +43,6 @@ bool tuning_params::get(const char *name, float *value) return false; } - - // TODO: OPT: rewrite this smarter! void move_point(vec2 *inout_pos, vec2 *inout_vel, float elasticity, int *bounces) { diff --git a/src/game/g_mapitems.h b/src/game/g_mapitems.h index 53561beb..a8278a44 100644 --- a/src/game/g_mapitems.h +++ b/src/game/g_mapitems.h @@ -36,7 +36,7 @@ enum ENTITY_ARMOR_1, ENTITY_HEALTH_1, ENTITY_WEAPON_SHOTGUN, - ENTITY_WEAPON_ROCKET, + ENTITY_WEAPON_GRENADE, ENTITY_POWERUP_NINJA, NUM_ENTITIES, diff --git a/src/game/g_protocol.h b/src/game/g_protocol.h index b0d84916..f7d26900 100644 --- a/src/game/g_protocol.h +++ b/src/game/g_protocol.h @@ -12,6 +12,7 @@ enum OBJTYPE_PLAYER_INFO, OBJTYPE_PLAYER_CHARACTER, // use this if you are searching for the player entity OBJTYPE_PROJECTILE, + OBJTYPE_LASER, OBJTYPE_POWERUP, OBJTYPE_FLAG, EVENT_EXPLOSION, @@ -136,12 +137,19 @@ struct obj_game struct obj_projectile { - int type; int x, y; int vx, vy; // should be an angle instead + int type; int start_tick; }; +struct obj_laser +{ + int x, y; + int from_x, from_y; + int eval_tick; +}; + struct obj_powerup { int x, y; diff --git a/src/game/g_tuning.h b/src/game/g_tuning.h index 9f7ffb80..e23b46bf 100644 --- a/src/game/g_tuning.h +++ b/src/game/g_tuning.h @@ -15,3 +15,15 @@ MACRO_TUNING_PARAM(gravity, 0.5f) MACRO_TUNING_PARAM(terminal_velocity, 1000.0f / ticks_per_second) /* weapon tuning */ +MACRO_TUNING_PARAM(gun_speed, 30.0f) + +MACRO_TUNING_PARAM(shotgun_speed_center, 40.0f) +MACRO_TUNING_PARAM(shotgun_speed_wide, 30.0f) + +MACRO_TUNING_PARAM(grenade_speed, 15.0f) + +MACRO_TUNING_PARAM(laser_reach, 800.0f) +MACRO_TUNING_PARAM(laser_bounce_delay, 150) +MACRO_TUNING_PARAM(laser_bounce_num, 2) +MACRO_TUNING_PARAM(laser_bounce_cost, 32) +MACRO_TUNING_PARAM(laser_damage, 8) diff --git a/src/game/server/gs_common.h b/src/game/server/gs_common.h index 4519cf37..838b192f 100644 --- a/src/game/server/gs_common.h +++ b/src/game/server/gs_common.h @@ -213,6 +213,27 @@ public: virtual void snap(int snapping_client); }; +class laser : public entity +{ + vec2 from; + vec2 dir; + float energy; + int bounces; + int eval_tick; + player *owner; + + bool hit_player(vec2 from, vec2 to); + void do_bounce(); + +public: + + laser(vec2 pos, vec2 direction, float start_energy, player *owner); + + virtual void reset(); + virtual void tick(); + virtual void snap(int snapping_client); +}; + // player entity class player : public entity { diff --git a/src/game/server/gs_game.cpp b/src/game/server/gs_game.cpp index 14b5a2c7..9a9c233e 100644 --- a/src/game/server/gs_game.cpp +++ b/src/game/server/gs_game.cpp @@ -60,10 +60,10 @@ bool gameobject::on_entity(int index, vec2 pos) type = POWERUP_WEAPON; subtype = WEAPON_SHOTGUN; } - else if(index == ENTITY_WEAPON_ROCKET) + else if(index == ENTITY_WEAPON_GRENADE) { type = POWERUP_WEAPON; - subtype = WEAPON_ROCKET; + subtype = WEAPON_GRENADE; } else if(index == ENTITY_POWERUP_NINJA) { diff --git a/src/game/server/gs_server.cpp b/src/game/server/gs_server.cpp index 0416c808..c21af02c 100644 --- a/src/game/server/gs_server.cpp +++ b/src/game/server/gs_server.cpp @@ -406,7 +406,7 @@ void projectile::reset() void projectile::tick() { float gravity = -400; - if(type != WEAPON_ROCKET) + if(type != WEAPON_GRENADE) gravity = -100; float pt = (server_tick()-start_tick-1)/(float)server_tickspeed(); @@ -423,7 +423,7 @@ void projectile::tick() if(targetplayer || collide || lifespan < 0) { - if (lifespan >= 0 || weapon == WEAPON_ROCKET) + if (lifespan >= 0 || weapon == WEAPON_GRENADE) create_sound(pos, sound_impact); if (flags & PROJECTILE_FLAGS_EXPLODE) @@ -454,6 +454,110 @@ void projectile::snap(int snapping_client) proj->type = type; } + +////////////////////////////////////////////////// +// laser +////////////////////////////////////////////////// +laser::laser(vec2 pos, vec2 direction, float start_energy, player *owner) +: entity(OBJTYPE_LASER) +{ + this->pos = pos; + this->owner = owner; + energy = start_energy; + dir = direction; + bounces = 0; + do_bounce(); + + world->insert_entity(this); +} + + +bool laser::hit_player(vec2 from, vec2 to) +{ + vec2 at; + player *hit = intersect_player(pos, to, at, owner); + if(!hit) + return false; + + this->from = from; + pos = at; + energy = -1; + hit->take_damage(vec2(0,0), tuning.laser_damage, owner->client_id, WEAPON_LASER); + return true; +} + +void laser::do_bounce() +{ + eval_tick = server_tick(); + + if(energy < 0) + { + //dbg_msg("laser", "%d removed", server_tick()); + world->destroy_entity(this); + return; + } + + vec2 to = pos + dir*energy; + + if(col_intersect_line(pos, to, &to)) + { + if(!hit_player(pos, to)) + { + // intersected + from = pos; + pos = to - dir*2; + vec2 temp_pos = pos; + vec2 temp_dir = dir*4.0f; + + move_point(&temp_pos, &temp_dir, 1.0f, 0); + dir = normalize(temp_dir); + + energy -= distance(from, pos) + tuning.laser_bounce_cost; + bounces++; + + if(bounces > tuning.laser_bounce_num) + energy = -1; + } + } + else + { + if(!hit_player(pos, to)) + { + from = pos; + pos = to; + energy = -1; + } + } + + //dbg_msg("laser", "%d done %f %f %f %f", server_tick(), from.x, from.y, pos.x, pos.y); +} + +void laser::reset() +{ + world->destroy_entity(this); +} + +void laser::tick() +{ + if(server_tick() > eval_tick+(server_tickspeed()*tuning.laser_bounce_delay)/1000.0f) + do_bounce(); + +} + +void laser::snap(int snapping_client) +{ + if(distance(players[snapping_client].pos, pos) > 1000.0f) + return; + + obj_laser *obj = (obj_laser *)snap_new_item(OBJTYPE_LASER, id, sizeof(obj_laser)); + obj->x = (int)pos.x; + obj->y = (int)pos.y; + obj->from_x = (int)from.x; + obj->from_y = (int)from.y; + obj->eval_tick = eval_tick; +} + + ////////////////////////////////////////////////// // player ////////////////////////////////////////////////// @@ -714,8 +818,9 @@ void player::try_respawn() weapons[WEAPON_GUN].got = true; weapons[WEAPON_GUN].ammo = data->weapons[WEAPON_GUN].maxammo; - //weapons[WEAPON_SNIPER].got = true; - //weapons[WEAPON_SNIPER].ammo = data->weapons[WEAPON_SNIPER].maxammo; + weapons[WEAPON_LASER].got = true; + weapons[WEAPON_LASER].ammo = 100000; //data->weapons[WEAPON_LASER].maxammo; + active_weapon = WEAPON_GUN; last_weapon = WEAPON_HAMMER; wanted_weapon = WEAPON_GUN; @@ -909,7 +1014,7 @@ int player::handle_weapons() if(reload_timer == 0) { bool fullauto = false; - if(active_weapon == WEAPON_ROCKET || active_weapon == WEAPON_SHOTGUN) + if(active_weapon == WEAPON_GRENADE || active_weapon == WEAPON_SHOTGUN) fullauto = true; if(count_input(latest_previnput.fire, latest_input.fire).presses || ((fullauto && latest_input.fire&1) && weapons[active_weapon].ammo)) @@ -932,23 +1037,23 @@ int player::handle_weapons() new projectile(WEAPON_GUN, client_id, pos+vec2(0,0), - direction*30.0f, + direction*tuning.gun_speed, server_tickspeed(), this, 1, 0, 0, -1, WEAPON_GUN); create_sound(pos, SOUND_GUN_FIRE); break; } - case WEAPON_ROCKET: + case WEAPON_GRENADE: { - new projectile(WEAPON_ROCKET, + new projectile(WEAPON_GRENADE, client_id, pos+vec2(0,0), - direction*15.0f, + direction*tuning.grenade_speed, 100, this, - 1, projectile::PROJECTILE_FLAGS_EXPLODE, 0, SOUND_ROCKET_EXPLODE, WEAPON_ROCKET); - create_sound(pos, SOUND_ROCKET_FIRE); + 1, projectile::PROJECTILE_FLAGS_EXPLODE, 0, SOUND_GRENADE_EXPLODE, WEAPON_GRENADE); + create_sound(pos, SOUND_GRENADE_FIRE); break; } case WEAPON_SHOTGUN: @@ -960,11 +1065,11 @@ int player::handle_weapons() 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); new projectile(WEAPON_SHOTGUN, client_id, pos+vec2(0,0), - vec2(cosf(a), sinf(a))*(28.0f + 12.0f*v), - //vec2(cosf(a), sinf(a))*20.0f, + vec2(cosf(a), sinf(a))*speed, (int)(server_tickspeed()*0.25f), this, 1, 0, 0, -1, WEAPON_SHOTGUN); @@ -973,16 +1078,10 @@ int player::handle_weapons() break; } - case WEAPON_SNIPER: + case WEAPON_LASER: { - new projectile(WEAPON_SNIPER, - client_id, - pos+vec2(0,0), - direction*300.0f, - 100, - this, - 1, 0, 0, -1, WEAPON_SNIPER); - create_sound(pos, SOUND_SNIPER_FIRE); + new laser(pos, direction, tuning.laser_reach, this); + create_sound(pos, SOUND_LASER_FIRE); break; } @@ -1476,8 +1575,8 @@ void powerup::tick() respawntime = data->powerupinfo[type].respawntime; // TODO: data compiler should take care of stuff like this - if(subtype == WEAPON_ROCKET) - create_sound(pos, SOUND_PICKUP_ROCKET); + if(subtype == WEAPON_GRENADE) + create_sound(pos, SOUND_PICKUP_GRENADE); else if(subtype == WEAPON_SHOTGUN) create_sound(pos, SOUND_PICKUP_SHOTGUN); @@ -1656,10 +1755,82 @@ void create_sound_global(int sound, int target) server_send_msg(target); } +float closest_point_on_line(vec2 line_point0, vec2 line_point1, vec2 target_point) +{ + vec2 c = target_point - line_point0; + vec2 v = (line_point1 - line_point0); + v = normalize(v); + float d = length(line_point0-line_point1); + float t = dot(v, c); + + if (t < 0) return 0; + if (t > d) return 1; + + return t; +} + // TODO: should be more general +player *intersect_player(vec2 pos0, vec2 pos1, vec2& new_pos, entity *notthis) +{ + // Find other players + float closest_time = distance(pos0, pos1) * 100.0f; + vec2 line_dir = normalize(pos1-pos0); + 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 t = closest_point_on_line(pos0, pos1, players[i].pos); + vec2 intersect_pos = pos0 + line_dir*t; + float len = distance(players[i].pos, intersect_pos); + if(len < player::phys_size) + { + if(t < closest_time) + { + new_pos = intersect_pos; + closest_time = t; + closest = &players[i]; + } + } + } + + 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;*/ +} + + + +// TODO: should be more general + + /* player* intersect_player(vec2 pos0, vec2 pos1, vec2& new_pos, entity* notthis) { // Find other players + + entity *ents[64]; vec2 dir = pos1 - pos0; float radius = length(dir * 0.5f); @@ -1678,6 +1849,7 @@ player* intersect_player(vec2 pos0, vec2 pos1, vec2& new_pos, entity* notthis) return 0; } +*/ // Server hooks void mods_tick() |