added laser weapon

This commit is contained in:
Magnus Auvinen 2008-02-02 18:05:16 +00:00
parent 1fe3202f0b
commit 5f32f5b36f
16 changed files with 338 additions and 77 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

After

Width:  |  Height:  |  Size: 129 KiB

View file

@ -9,12 +9,9 @@ struct weapon {
int meleereach = meleereach@1
int ammoregentime = ammoregentime@1
int maxammo = maxammo@1
int costammo = costammo@1
int duration = duration@1
int movetime = movetime@1
int velocity = velocity@1
float chargetime = chargetime@1
float overchargetime = overchargetime@1
}
struct powerupinf {

View file

@ -11,13 +11,13 @@ sounds {
"data/audio/wp_shotty_fire-03.wv"
}
sniper_fire {
laser_fire {
"data/audio/wp_shotty_fire-01.wv"
"data/audio/wp_shotty_fire-02.wv"
"data/audio/wp_shotty_fire-03.wv"
}
rocket_fire {
grenade_fire {
"data/audio/wp_flump_launch-01.wv"
"data/audio/wp_flump_launch-02.wv"
"data/audio/wp_flump_launch-03.wv"
@ -41,7 +41,7 @@ sounds {
"data/audio/wp_ninja_attack-03.wv"
}
rocket_explode {
grenade_explode {
"data/audio/wp_flump_explo-01.wv"
"data/audio/wp_flump_explo-02.wv"
"data/audio/wp_flump_explo-03.wv"
@ -153,7 +153,7 @@ sounds {
"data/audio/sfx_pickup_arm-04.wv"
}
pickup_rocket {
pickup_grenade {
"data/audio/sfx_pickup_launcher.wv"
}
@ -279,7 +279,6 @@ weapons {
muzzleoffsetx 0.0
muzzleoffsety 0.0
maxammo 10
costammo 0
recoil 10
firedelay 150
muzzleduration 0
@ -292,8 +291,6 @@ weapons {
duration -1
movetime 0
velocity 0
chargetime 0.0
overchargetime 0.0
}
gun {
@ -310,7 +307,6 @@ weapons {
muzzleoffsetx 50.0
muzzleoffsety 6.0
maxammo 10
costammo 1
recoil 10
firedelay 100
muzzleduration 5
@ -323,8 +319,6 @@ weapons {
duration -1
movetime 0
velocity 0
chargetime 0.0
overchargetime 0.0
}
shotgun {
@ -341,7 +335,6 @@ weapons {
muzzleoffsetx 70.0
muzzleoffsety 6.0
maxammo 10
costammo 1
recoil 10
firedelay 500
muzzleduration 5
@ -354,14 +347,12 @@ weapons {
duration -1
movetime 0
velocity 0
chargetime 0.0
overchargetime 0.0
}
rocket {
sprite_body sprites.game.weapon_rocket_body
sprite_cursor sprites.game.weapon_rocket_cursor
sprite_proj sprites.game.weapon_rocket_proj
grenade {
sprite_body sprites.game.weapon_grenade_body
sprite_cursor sprites.game.weapon_grenade_cursor
sprite_proj sprites.game.weapon_grenade_proj
sprite_muzzles {
}
@ -369,7 +360,6 @@ weapons {
muzzleoffsetx 0.0
muzzleoffsety 0.0
maxammo 10
costammo 1
recoil 10
firedelay 600
muzzleduration 0
@ -382,29 +372,23 @@ weapons {
duration -1
movetime 0
velocity 0
chargetime 0.0
overchargetime 0.0
}
sniper {
sprite_body sprites.game.weapon_rocket_body
sprite_cursor sprites.game.weapon_rocket_cursor
sprite_proj sprites.game.weapon_rocket_proj
laser {
sprite_body sprites.game.weapon_laser_body
sprite_cursor sprites.game.weapon_laser_cursor
sprite_proj sprites.game.weapon_shotgun_proj
sprite_muzzles {
sprites.game.weapon_shotgun_muzzle1
sprites.game.weapon_shotgun_muzzle2
sprites.game.weapon_shotgun_muzzle3
}
nummuzzlesprites 3
muzzleoffsetx 0.0
muzzleoffsety 0.0
maxammo 10
costammo 1
recoil 10
firedelay 600
muzzleduration 0
visual_size 96
visual_size 128
offsetx 24.0
offsety -2.0
meleedamage 0
@ -413,8 +397,6 @@ weapons {
duration -1
movetime 0
velocity 0
chargetime 0.5
overchargetime 10.0
}
ninja {
@ -431,7 +413,6 @@ weapons {
muzzleoffsetx 40.0
muzzleoffsety -4.0
maxammo 0
costammo 0
recoil 0
firedelay 800
muzzleduration 0
@ -444,8 +425,6 @@ weapons {
duration 15000
movetime 200
velocity 50
chargetime 0.0
overchargetime 0.0
}
}
@ -500,9 +479,9 @@ sprites {
weapon_shotgun_muzzle2 16 6 3 2
weapon_shotgun_muzzle3 20 6 3 2
weapon_rocket_body 2 8 7 2
weapon_rocket_cursor 0 8 2 2
weapon_rocket_proj 10 8 2 2
weapon_grenade_body 2 8 7 2
weapon_grenade_cursor 0 8 2 2
weapon_grenade_proj 10 8 2 2
weapon_hammer_body 2 1 4 3
weapon_hammer_cursor 0 0 2 2
@ -512,6 +491,9 @@ sprites {
weapon_ninja_cursor 0 10 2 2
weapon_ninja_proj 0 0 0 0
weapon_laser_body 2 12 9 3
weapon_laser_cursor 0 12 2 2
hook_chain 2 0 1 1
hook_head 3 0 2 1

View file

@ -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);

View file

@ -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();

View file

@ -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);

View file

@ -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);

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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)
{

View file

@ -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,

View file

@ -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;

View file

@ -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)

View file

@ -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
{

View file

@ -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)
{

View file

@ -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()