diff options
Diffstat (limited to 'src/game/client')
| -rw-r--r-- | src/game/client/gc_client.cpp | 284 | ||||
| -rw-r--r-- | src/game/client/gc_client.h | 77 | ||||
| -rw-r--r-- | src/game/client/gc_console.cpp | 9 | ||||
| -rw-r--r-- | src/game/client/gc_effects.cpp | 162 | ||||
| -rw-r--r-- | src/game/client/gc_flow.cpp | 87 | ||||
| -rw-r--r-- | src/game/client/gc_hooks.cpp | 14 | ||||
| -rw-r--r-- | src/game/client/gc_menu.cpp | 9 | ||||
| -rw-r--r-- | src/game/client/gc_particles.cpp | 146 | ||||
| -rw-r--r-- | src/game/client/gc_render.cpp | 117 | ||||
| -rw-r--r-- | src/game/client/gc_render.h | 13 | ||||
| -rw-r--r-- | src/game/client/gc_render_map.cpp | 3 | ||||
| -rw-r--r-- | src/game/client/gc_render_obj.cpp | 36 |
12 files changed, 625 insertions, 332 deletions
diff --git a/src/game/client/gc_client.cpp b/src/game/client/gc_client.cpp index 8df0e698..4cc8ba29 100644 --- a/src/game/client/gc_client.cpp +++ b/src/game/client/gc_client.cpp @@ -13,6 +13,7 @@ extern "C" { #include "../g_game.h" #include "../g_version.h" #include "../g_layers.h" +#include "../g_math.h" #include "gc_map_image.h" #include "../generated/gc_data.h" #include "gc_menu.h" @@ -23,6 +24,8 @@ extern "C" { #include "gc_anim.h" #include "gc_console.h" +#include <GL/gl.h> + struct data_container *data = 0; static int64 debug_firedelay = 0; @@ -87,6 +90,15 @@ void snd_play_random(int chn, int setid, float vol, vec2 pos) set->last = id; } + +void send_switch_team(int team) +{ + msg_pack_start(MSG_SETTEAM, MSGFLAG_VITAL); + msg_pack_int(team); + msg_pack_end(); + client_send_msg(); +} + class damage_indicators { public: @@ -179,159 +191,6 @@ void render_damage_indicators() dmgind.render(); } -class particle_system -{ -public: - struct particle - { - vec2 pos; - vec2 vel; - float life; - float max_life; - float size; - - float rot; - float rotspeed; - - float gravity; - float friction; - int iparticle; - - vec4 color; - }; - - enum - { - MAX_PARTICLES=1024, - }; - - particle particles[MAX_PARTICLES]; - int num_particles; - - particle_system() - { - num_particles = 0; - } - - void new_particle(vec2 pos, vec2 vel, float life, float size, float gravity, float friction, vec4 color=vec4(1,1,1,1)) - { - if (num_particles >= MAX_PARTICLES) - return; - - particles[num_particles].iparticle = rand() % data->num_particles; - particles[num_particles].pos = pos; - particles[num_particles].vel = vel; - particles[num_particles].life = life - (data->particles[particles[num_particles].iparticle].lifemod/100.0f) * life; - particles[num_particles].size = size; - particles[num_particles].max_life = life; - particles[num_particles].gravity = gravity; - particles[num_particles].friction = friction; - particles[num_particles].rot = frandom()*pi*2; - particles[num_particles].rotspeed = frandom() * 10.0f; - particles[num_particles].color = color; - num_particles++; - } - - void update(float time_passed) - { - for(int i = 0; i < num_particles; i++) - { - particles[i].vel.y += particles[i].gravity*time_passed; - particles[i].vel *= particles[i].friction; - vec2 vel = particles[i].vel*time_passed; - move_point(&particles[i].pos, &vel, 0.1f+0.9f*frandom(), NULL); - particles[i].vel = vel* (1.0f/time_passed); - particles[i].life += time_passed; - particles[i].rot += time_passed * particles[i].rotspeed; - - // check particle death - if(particles[i].life > particles[i].max_life) - { - num_particles--; - particles[i] = particles[num_particles]; - i--; - } - } - } - - void render() - { - gfx_blend_additive(); - gfx_texture_set(data->images[IMAGE_GAME].id); - gfx_quads_begin(); - - for(int i = 0; i < num_particles; i++) - { - int type = particles[i].iparticle; - select_sprite(data->particles[type].spr); - float a = 1 - particles[i].life / particles[i].max_life; - vec2 p = particles[i].pos; - - gfx_quads_setrotation(particles[i].rot); - - gfx_setcolor( - data->particles[type].color_r * particles[i].color.r, - data->particles[type].color_g * particles[i].color.g, - data->particles[type].color_b * particles[i].color.b, - pow(a, 0.75f) * particles[i].color.a); - - gfx_quads_draw(p.x, p.y,particles[i].size,particles[i].size); - } - gfx_quads_end(); - gfx_blend_normal(); - } -}; - -static particle_system temp_system; - -class projectile_particles -{ -public: - enum - { - LISTSIZE = 1000, - }; - // meh, just use size % - int lastadd[LISTSIZE]; - projectile_particles() - { - reset(); - } - - void reset() - { - for (int i = 0; i < LISTSIZE; i++) - lastadd[i] = -1000; - } - - void addparticle(int projectiletype, int projectileid, vec2 pos, vec2 vel) - { - int particlespersecond = data->projectileinfo[projectiletype].particlespersecond; - int lastaddtick = lastadd[projectileid % LISTSIZE]; - - if(!particlespersecond) - return; - - if ((client_tick() - lastaddtick) > (client_tickspeed() / particlespersecond)) - { - lastadd[projectileid % LISTSIZE] = client_tick(); - float life = data->projectileinfo[projectiletype].particlelife; - float size = data->projectileinfo[projectiletype].particlesize; - vec2 v = vel * 0.2f + normalize(vec2(frandom()-0.5f, -frandom()))*(32.0f+frandom()*32.0f); - - // add the particle (from projectiletype later on, but meh...) - temp_system.new_particle(pos, v, life, size, 0, 0.95f); - } - } -}; - -static projectile_particles proj_particles; - -void reset_projectile_particles() // TODO: remove -{ - proj_particles.reset(); -} - static char chat_input[512]; static unsigned chat_input_len; static const int chat_max_lines = 10; @@ -391,16 +250,7 @@ void chat_add_line(int client_id, int team, const char *line) killmsg killmsgs[killmsg_max]; int killmsg_current = 0; -void effect_air_jump(vec2 pos) -{ - const int count = 12; - for(int i = 0; i <= count; i++) - { - float a = i/(float)count; - vec2 v = vec2((a-0.5f)*512.0f, 0); - temp_system.new_particle(pos+vec2(0,28), v, 0.4f, 16.0f, 0, 0.985f, vec4(0.25f,0.4f,1,1)); - } -} +//bool add_trail = false; extern int render_popup(const char *caption, const char *text, const char *button_text); @@ -425,107 +275,22 @@ void process_events(int snaptype) else if(item.type == EVENT_EXPLOSION) { ev_explosion *ev = (ev_explosion *)data; - vec2 p(ev->x, ev->y); - - // center explosion - temp_system.new_particle(p, vec2(0,0), 0.3f, 96.0f, 0, 0.95f); - temp_system.new_particle(p, vec2(0,0), 0.3f, 64.0f, 0, 0.95f); - temp_system.new_particle(p, vec2(0,0), 0.3f, 32.0f, 0, 0.95f); - temp_system.new_particle(p, vec2(0,0), 0.3f, 16.0f, 0, 0.95f); - - for(int i = 0; i < 16; i++) - { - vec2 v = normalize(vec2(frandom()-0.5f, frandom()-0.5f))*(128.0f+frandom()*128.0f); - temp_system.new_particle(p, v, 0.2f+0.25f*frandom(), 16.0f, 0, 0.985f); - } - - for(int i = 0; i < 16; i++) - { - vec2 v = normalize(vec2(frandom()-0.5f, frandom()-0.5f))*(256.0f+frandom()*512.0f); - temp_system.new_particle(p, v, 0.2f+0.25f*frandom(), 16.0f, 128.0f, 0.985f); - } - - for(int i = 0; i < 64; i++) - { - vec2 v = normalize(vec2(frandom()-0.5f, frandom()-0.5f))*(frandom()*256.0f); - temp_system.new_particle(p, v, 0.2f+0.25f*frandom(), 24.0f, 128.0f, 0.985f); - } + effect_explosion(vec2(ev->x, ev->y)); } else if(item.type == EVENT_SMOKE) { ev_explosion *ev = (ev_explosion *)data; vec2 p(ev->x, ev->y); - - // center explosion - vec2 v = normalize(vec2(frandom()-0.5f, -frandom()))*(32.0f+frandom()*32.0f); - temp_system.new_particle(p, v, 1.2f, 64.0f, 0, 0.95f); - v = normalize(vec2(frandom()-0.5f, -frandom()))*(128.0f+frandom()*128.0f); - temp_system.new_particle(p, v, 1.2f, 32.0f, 0, 0.95f); - v = normalize(vec2(frandom()-0.5f, -frandom()))*(128.0f+frandom()*128.0f); - temp_system.new_particle(p, v, 1.2f, 16.0f, 0, 0.95f); - - for(int i = 0; i < 8; i++) - { - vec2 v = normalize(vec2(frandom()-0.5f, frandom()-0.5f))*(64.0f+frandom()*64.0f); - temp_system.new_particle(p, v, 0.5f+0.5f*frandom(), 16.0f, 0, 0.985f); - } - - for(int i = 0; i < 8; i++) - { - vec2 v = normalize(vec2(frandom()-0.5f, frandom()-0.5f))*(128.0f+frandom()*256.0f); - temp_system.new_particle(p, v, 0.5f+0.5f*frandom(), 16.0f, 128.0f, 0.985f); - } } - else if(item.type == EVENT_SPAWN) + else if(item.type == EVENT_PLAYERSPAWN) { ev_explosion *ev = (ev_explosion *)data; - vec2 p(ev->x, ev->y); - - // center explosion - vec2 v = normalize(vec2(frandom()-0.5f, -frandom()))*(32.0f+frandom()*32.0f); - temp_system.new_particle(p, v, 1.2f, 64.0f, 0, 0.95f); - v = normalize(vec2(frandom()-0.5f, -frandom()))*(128.0f+frandom()*128.0f); - temp_system.new_particle(p, v, 1.2f, 32.0f, 0, 0.95f); - v = normalize(vec2(frandom()-0.5f, -frandom()))*(128.0f+frandom()*128.0f); - temp_system.new_particle(p, v, 1.2f, 16.0f, 0, 0.95f); - - for(int i = 0; i < 8; i++) - { - vec2 v = normalize(vec2(frandom()-0.5f, frandom()-0.5f))*(64.0f+frandom()*64.0f); - temp_system.new_particle(p, v, 0.5f+0.5f*frandom(), 16.0f, 0, 0.985f); - } - - for(int i = 0; i < 8; i++) - { - vec2 v = normalize(vec2(frandom()-0.5f, frandom()-0.5f))*(128.0f+frandom()*256.0f); - temp_system.new_particle(p, v, 0.5f+0.5f*frandom(), 16.0f, 128.0f, 0.985f); - } + effect_playerspawn(vec2(ev->x, ev->y)); } else if(item.type == EVENT_DEATH) { ev_explosion *ev = (ev_explosion *)data; - vec2 p(ev->x, ev->y); - vec4 c(0.5f, 0.1f, 0.1f, 1.0f); - - // center explosion - vec2 v = normalize(vec2(frandom()-0.5f, -frandom()))*(32.0f+frandom()*32.0f); - temp_system.new_particle(p, v, 1.2f, 64.0f, 0, 0.95f, c); - v = normalize(vec2(frandom()-0.5f, -frandom()))*(128.0f+frandom()*128.0f); - temp_system.new_particle(p, v, 1.2f, 32.0f, 0, 0.95f, c); - v = normalize(vec2(frandom()-0.5f, -frandom()))*(128.0f+frandom()*128.0f); - temp_system.new_particle(p, v, 1.2f, 16.0f, 0, 0.95f, c); - - for(int i = 0; i < 8; i++) - { - vec2 v = normalize(vec2(frandom()-0.5f, frandom()-0.5f))*(64.0f+frandom()*64.0f); - temp_system.new_particle(p, v, 0.5f+0.5f*frandom(), 16.0f, 0, 0.985f, c); - } - - for(int i = 0; i < 8; i++) - { - vec2 v = normalize(vec2(frandom()-0.5f, frandom()-0.5f))*(128.0f+frandom()*256.0f); - temp_system.new_particle(p, v, 0.5f+0.5f*frandom(), 16.0f, 128.0f, 0.985f, c); - } + effect_playerdeath(vec2(ev->x, ev->y)); } else if(item.type == EVENT_SOUND_WORLD) { @@ -964,6 +729,11 @@ static int do_input(int *v, int key) void render_game() { + // update the effects + effects_update(); + particle_update(client_frametime()); + + float width = 400*3.0f*gfx_screenaspect(); float height = 400*3.0f; @@ -1195,12 +965,16 @@ void render_game() } // render the world + float zoom = 1.0f; + if(inp_key_pressed('E')) + zoom = 0.5f; + gfx_clear(0.65f,0.78f,0.9f); if(spectate) - render_world(mouse_pos.x, mouse_pos.y, 1.0f); + render_world(mouse_pos.x, mouse_pos.y, zoom); else { - render_world(local_character_pos.x+offx, local_character_pos.y+offy, 1.0f); + render_world(local_character_pos.x+offx, local_character_pos.y+offy, zoom); // draw screen box if(0) @@ -1683,7 +1457,7 @@ void render_game() vec2(local_character->x, local_character->y)); char buf[512]; - sprintf(buf, "%.2f", speed); + sprintf(buf, "%.2f", speed/2); gfx_text(0, 150, 50, 12, buf, -1); } diff --git a/src/game/client/gc_client.h b/src/game/client/gc_client.h index f1ff02b1..def3cad8 100644 --- a/src/game/client/gc_client.h +++ b/src/game/client/gc_client.h @@ -83,12 +83,89 @@ const int killmsg_max = 5; extern killmsg killmsgs[killmsg_max]; extern int killmsg_current; +// +void send_switch_team(int team); + // various helpers void snd_play_random(int chn, int setid, float vol, vec2 pos); void process_events(int snaptype); void clear_object_pointers(); void reset_projectile_particles(); void send_info(bool start); +inline vec2 random_dir() { return normalize(vec2(frandom()-0.5f, frandom()-0.5f)); } + + +// effects +void effects_update(); +void effect_bullettrail(vec2 pos); +void effect_smoketrail(vec2 pos, vec2 vel); +void effect_explosion(vec2 pos); void effect_air_jump(vec2 pos); void effect_damage_indicator(vec2 pos, vec2 dir); +void effect_playerspawn(vec2 pos); +void effect_playerdeath(vec2 pos); + +// particles +struct particle +{ + void set_default() + { + vel = vec2(0,0); + life_span = 0; + start_size = 32; + end_size = 32; + rot = 0; + rotspeed = 0; + gravity = 0; + friction = 0; + flow_affected = 1.0f; + color = vec4(1,1,1,1); + } + + vec2 pos; + vec2 vel; + + int spr; + + float flow_affected; + + float life_span; + + float start_size; + float end_size; + + float rot; + float rotspeed; + + float gravity; + float friction; + + vec4 color; + + // set by the particle system + float life; + int prev_part; + int next_part; +}; + +enum +{ + PARTGROUP_PROJECTILE_TRAIL=0, + PARTGROUP_EXPLOSIONS, + PARTGROUP_GENERAL, + NUM_PARTGROUPS +}; + +void particle_add(int group, particle *part); +void particle_render(int group); +void particle_update(float time_passed); +void particle_reset(); + +// flow grid +vec2 flow_get(vec2 pos); +void flow_add(vec2 pos, vec2 vel, float size); +void flow_dbg_render(); +void flow_init(); +void flow_update(); + diff --git a/src/game/client/gc_console.cpp b/src/game/client/gc_console.cpp index 9cf417e2..0a4bb3d6 100644 --- a/src/game/client/gc_console.cpp +++ b/src/game/client/gc_console.cpp @@ -12,6 +12,7 @@ extern "C" { #include <cstdio> #include "gc_ui.h" +#include "gc_client.h" static unsigned int console_input_len = 0; static char console_input[256] = {0}; @@ -57,12 +58,20 @@ static void quit_command(struct lexer_result *result, void *user_data) client_quit(); } +static void con_team(struct lexer_result *result, void *user_data) +{ + int new_team; + extract_result_int(result, 1, &new_team); + send_switch_team(new_team); +} + void client_console_init() { console_register_print_callback(client_console_print); MACRO_REGISTER_COMMAND("quit", "", quit_command, 0x0); MACRO_REGISTER_COMMAND("connect", "s", connect_command, 0x0); MACRO_REGISTER_COMMAND("disconnect", "", disconnect_command, 0x0); + MACRO_REGISTER_COMMAND("team", "i", con_team, 0x0); } void console_handle_input() diff --git a/src/game/client/gc_effects.cpp b/src/game/client/gc_effects.cpp new file mode 100644 index 00000000..6394075e --- /dev/null +++ b/src/game/client/gc_effects.cpp @@ -0,0 +1,162 @@ +#include <engine/e_client_interface.h> +#include "gc_client.h" +#include "../generated/gc_data.h" + +static bool add_trail = false; + +void effect_air_jump(vec2 pos) +{ + particle p; + p.set_default(); + p.spr = SPRITE_PART_AIRJUMP; + p.pos = pos + vec2(-6.0f, 16.0f); + p.vel = vec2(0, -200); + p.life_span = 0.5f; + p.start_size = 48.0f; + p.end_size = 0; + p.rot = frandom()*pi*2; + p.rotspeed = pi*2; + p.gravity = 500; + p.friction = 0.7f; + p.flow_affected = 0.0f; + particle_add(PARTGROUP_GENERAL, &p); + + p.pos = pos + vec2(6.0f, 16.0f); + particle_add(PARTGROUP_GENERAL, &p); +} + +void effect_smoketrail(vec2 pos, vec2 vel) +{ + if(!add_trail) + 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 = 12.0f + frandom()*8; + p.end_size = 0; + p.friction = 0.7; + p.gravity = frandom()*-500.0f; + particle_add(PARTGROUP_PROJECTILE_TRAIL, &p); +} + + +void effect_bullettrail(vec2 pos) +{ + if(!add_trail) + return; + + particle p; + p.set_default(); + p.spr = SPRITE_PART_BALL; + p.pos = pos; + p.life_span = 0.25f + frandom()*0.25f; + p.start_size = 8.0f; + p.end_size = 0; + p.friction = 0.7; + particle_add(PARTGROUP_PROJECTILE_TRAIL, &p); +} + +void effect_playerspawn(vec2 pos) +{ + for(int i = 0; i < 32; i++) + { + particle p; + p.set_default(); + p.spr = SPRITE_PART_SHELL; + p.pos = pos; + p.vel = random_dir() * (pow(frandom(), 3)*600.0f); + p.life_span = 0.3f + frandom()*0.3f; + p.start_size = 64.0f + frandom()*32; + p.end_size = 0; + p.rot = frandom()*pi*2; + p.rotspeed = frandom(); + p.gravity = frandom()*-400.0f; + p.friction = 0.7f; + p.color = vec4(0xb5/255.0f, 0x50/255.0f, 0xcb/255.0f, 1.0f); + particle_add(PARTGROUP_GENERAL, &p); + + } +} + +void effect_playerdeath(vec2 pos) +{ + for(int i = 0; i < 64; i++) + { + particle p; + p.set_default(); + p.spr = SPRITE_PART_SPLAT01 + (rand()%3); + p.pos = pos; + p.vel = random_dir() * ((frandom()+0.1f)*900.0f); + p.life_span = 0.3f + frandom()*0.3f; + p.start_size = 24.0f + frandom()*16; + p.end_size = 0; + p.rot = frandom()*pi*2; + p.rotspeed = (frandom()-0.5f) * pi; + p.gravity = 800.0f; + p.friction = 0.8f; + p.color = mix(vec4(0.75f,0.2f,0.2f,0.75f), vec4(0.5f,0.1f,0.1f,0.75f), frandom()); + particle_add(PARTGROUP_GENERAL, &p); + + } +} + + +void effect_explosion(vec2 pos) +{ + // add to flow + for(int y = -8; y <= 8; y++) + for(int x = -8; x <= 8; x++) + { + if(x == 0 && y == 0) + continue; + + float a = 1 - (length(vec2(x,y)) / length(vec2(8,8))); + flow_add(pos+vec2(x,y)*16, normalize(vec2(x,y))*5000.0f*a, 10.0f); + } + + // add the explosion + particle p; + p.set_default(); + p.spr = SPRITE_PART_EXPL01; + p.pos = pos; + p.life_span = 0.4f; + p.start_size = 150.0f; + p.end_size = 0; + p.rot = frandom()*pi*2; + particle_add(PARTGROUP_EXPLOSIONS, &p); + + // add the smoke + for(int i = 0; i < 24; i++) + { + particle p; + p.set_default(); + p.spr = SPRITE_PART_SMOKE; + p.pos = pos; + p.vel = random_dir() * ((1.0f + frandom()*0.2f) * 1000.0f); + p.life_span = 0.5f + frandom()*0.4f; + p.start_size = 32.0f + frandom()*8; + p.end_size = 0; + p.gravity = frandom()*-800.0f; + p.friction = 0.4f; + p.color = mix(vec4(0.75f,0.75f,0.75f,1.0f), vec4(0.5f,0.5f,0.5f,1.0f), frandom()); + particle_add(PARTGROUP_GENERAL, &p); + } +} + +void effects_update() +{ + static float last_update = 0; + if(client_localtime()-last_update > 0.02f) + { + add_trail = true; + last_update = client_localtime(); + flow_update(); + } + else + add_trail = false; + +} diff --git a/src/game/client/gc_flow.cpp b/src/game/client/gc_flow.cpp new file mode 100644 index 00000000..aac35058 --- /dev/null +++ b/src/game/client/gc_flow.cpp @@ -0,0 +1,87 @@ +#include <engine/e_client_interface.h> +#include <engine/e_config.h> +#include "gc_client.h" +#include "../g_layers.h" + +struct FLOWCELL +{ + vec2 vel; +}; + +static FLOWCELL *cells = 0; +static int height = 0; +static int width = 0; +static int spacing = 16; + +void flow_init() +{ + if(cells) + { + mem_free(cells); + cells = 0; + } + + MAPITEM_LAYER_TILEMAP *tilemap = layers_game_layer(); + width = tilemap->width*32/spacing; + height = tilemap->height*32/spacing; + + // allocate and clear + cells = (FLOWCELL *)mem_alloc(sizeof(FLOWCELL)*width*height, 1); + for(int y = 0; y < height; y++) + for(int x = 0; x < width; x++) + cells[y*width+x].vel = vec2(0.0f, 0.0f); +} + +void flow_update() +{ + if(!config.cl_flow) + return; + + for(int y = 0; y < height; y++) + for(int x = 0; x < width; x++) + cells[y*width+x].vel *= 0.85f; +} + +void flow_dbg_render() +{ + if(!config.cl_flow) + return; + + gfx_texture_set(-1); + gfx_lines_begin(); + for(int y = 0; y < height; y++) + for(int x = 0; x < width; x++) + { + vec2 pos(x*spacing, y*spacing); + vec2 vel = cells[y*width+x].vel * 0.01f; + gfx_lines_draw(pos.x, pos.y, pos.x+vel.x, pos.y+vel.y); + } + + gfx_lines_end(); +} + +void flow_add(vec2 pos, vec2 vel, float size) +{ + if(!config.cl_flow) + return; + + int x = (int)(pos.x / spacing); + int y = (int)(pos.y / spacing); + if(x < 0 || y < 0 || x >= width || y >= height) + return; + + cells[y*width+x].vel += vel; +} + +vec2 flow_get(vec2 pos) +{ + if(!config.cl_flow) + return vec2(0,0); + + int x = (int)(pos.x / spacing); + int y = (int)(pos.y / spacing); + if(x < 0 || y < 0 || x >= width || y >= height) + return vec2(0,0); + + return cells[y*width+x].vel; +} diff --git a/src/game/client/gc_hooks.cpp b/src/game/client/gc_hooks.cpp index ca425059..c16923b8 100644 --- a/src/game/client/gc_hooks.cpp +++ b/src/game/client/gc_hooks.cpp @@ -40,6 +40,7 @@ extern "C" void modc_init() gfx_text_set_default_font(&default_font); + particle_reset(); menu_init(); // setup sound channels @@ -300,13 +301,11 @@ extern "C" void modc_render() // handle team switching // TODO: FUGLY!!! + /* if(config.cl_team != -10) { - msg_pack_start(MSG_SETTEAM, MSGFLAG_VITAL); - msg_pack_int(config.cl_team); - msg_pack_end(); - client_send_msg(); - } + + }*/ } else // if (client_state() != CLIENTSTATE_CONNECTING && client_state() != CLIENTSTATE_LOADING) { @@ -317,7 +316,7 @@ extern "C" void modc_render() } // - config.cl_team = -10; + //config.cl_team = -10; } @@ -492,11 +491,12 @@ extern "C" void modc_connected() layers_init(); col_init(); img_init(); + flow_init(); //tilemap_init(); chat_reset(); - reset_projectile_particles(); + particle_reset(); clear_object_pointers(); last_new_predicted_tick = -1; diff --git a/src/game/client/gc_menu.cpp b/src/game/client/gc_menu.cpp index 9b72d4b5..6b982c37 100644 --- a/src/game/client/gc_menu.cpp +++ b/src/game/client/gc_menu.cpp @@ -22,6 +22,7 @@ extern "C" { #include "gc_anim.h" #include "gc_skin.h" #include "gc_ui.h" +#include "gc_client.h" #include <mastersrv/mastersrv.h> extern data_container *data; @@ -1623,7 +1624,7 @@ static void menu2_render_game(RECT main_view) static int spectate_button = 0; if(ui_do_button(&spectate_button, "Spectate", 0, &button, ui_draw_menu_button, 0)) { - config.cl_team = -1; + send_switch_team(-1); menu_active = false; } } @@ -1637,7 +1638,7 @@ static void menu2_render_game(RECT main_view) static int spectate_button = 0; if(ui_do_button(&spectate_button, "Join Game", 0, &button, ui_draw_menu_button, 0)) { - config.cl_team = 0; + send_switch_team(0); menu_active = false; } } @@ -1651,7 +1652,7 @@ static void menu2_render_game(RECT main_view) static int spectate_button = 0; if(ui_do_button(&spectate_button, "Join Red", 0, &button, ui_draw_menu_button, 0)) { - config.cl_team = 0; + send_switch_team(0); menu_active = false; } } @@ -1663,7 +1664,7 @@ static void menu2_render_game(RECT main_view) static int spectate_button = 0; if(ui_do_button(&spectate_button, "Join Blue", 0, &button, ui_draw_menu_button, 0)) { - config.cl_team = 1; + send_switch_team(1); menu_active = false; } } diff --git a/src/game/client/gc_particles.cpp b/src/game/client/gc_particles.cpp new file mode 100644 index 00000000..bdeb26fd --- /dev/null +++ b/src/game/client/gc_particles.cpp @@ -0,0 +1,146 @@ +#include <engine/e_client_interface.h> +#include "gc_client.h" +#include "../generated/gc_data.h" + +// NOTE: the way the particle system works isn't very cache friendly + +enum +{ + MAX_PARTICLES=1024*8, +}; + +static particle particles[MAX_PARTICLES]; +static int first_free = -1; +static int first_part[NUM_PARTGROUPS] = {-1}; + +void particle_reset() +{ + // reset particles + for(int i = 0; i < MAX_PARTICLES; i++) + { + particles[i].prev_part = i-1; + particles[i].next_part = i+1; + } + + particles[0].prev_part = 0; + particles[MAX_PARTICLES-1].next_part = -1; + first_free = 0; + + for(int i = 0; i < NUM_PARTGROUPS; i++) + first_part[i] = -1; +} + + +void particle_add(int group, particle *part) +{ + if (first_free == -1) + return; + + // remove from the free list + int id = first_free; + first_free = particles[id].next_part; + particles[first_free].prev_part = -1; + + // copy data + particles[id] = *part; + + // insert to the group list + particles[id].prev_part = -1; + particles[id].next_part = first_part[group]; + if(first_part[group] != -1) + particles[first_part[group]].prev_part = id; + first_part[group] = id; + + // set some parameters + particles[id].life = 0; +} + +void particle_update(float time_passed) +{ + static float friction_fraction = 0; + friction_fraction += time_passed; + + if(friction_fraction > 2.0f) // safty messure + friction_fraction = 0; + + int friction_count = 0; + while(friction_fraction > 0.05f) + { + friction_count++; + friction_fraction -= 0.05f; + } + + for(int g = 0; g < NUM_PARTGROUPS; g++) + { + int i = first_part[g]; + while(i != -1) + { + int next = particles[i].next_part; + particles[i].vel += flow_get(particles[i].pos)*time_passed * particles[i].flow_affected; + particles[i].vel.y += particles[i].gravity*time_passed; + + for(int f = 0; f < friction_count; f++) // apply friction + particles[i].vel *= particles[i].friction; + + // move the point + vec2 vel = particles[i].vel*time_passed; + move_point(&particles[i].pos, &vel, 0.1f+0.9f*frandom(), NULL); + particles[i].vel = vel* (1.0f/time_passed); + + particles[i].life += time_passed; + particles[i].rot += time_passed * particles[i].rotspeed; + + // check particle death + if(particles[i].life > particles[i].life_span) + { + // remove it from the group list + if(particles[i].prev_part != -1) + particles[particles[i].prev_part].next_part = particles[i].next_part; + else + first_part[g] = particles[i].next_part; + + if(particles[i].next_part != -1) + particles[particles[i].next_part].prev_part = particles[i].prev_part; + + // insert to the free list + if(first_free != -1) + particles[first_free].prev_part = i; + particles[i].prev_part = -1; + particles[i].next_part = first_free; + } + + i = next; + } + } +} + +void particle_render(int group) +{ + gfx_blend_normal(); + //gfx_blend_additive(); + gfx_texture_set(data->images[IMAGE_PARTICLES].id); + gfx_quads_begin(); + + int i = first_part[group]; + while(i != -1) + { + select_sprite(particles[i].spr); + float a = particles[i].life / particles[i].life_span; + vec2 p = particles[i].pos; + float size = mix(particles[i].start_size, particles[i].end_size, a); + + gfx_quads_setrotation(particles[i].rot); + + gfx_setcolor( + particles[i].color.r, + particles[i].color.g, + particles[i].color.b, + particles[i].color.a); // pow(a, 0.75f) * + + gfx_quads_draw(p.x, p.y, size, size); + + i = particles[i].next_part; + } + gfx_quads_end(); + gfx_blend_normal(); +} diff --git a/src/game/client/gc_render.cpp b/src/game/client/gc_render.cpp index 91ae5662..6297fc9c 100644 --- a/src/game/client/gc_render.cpp +++ b/src/game/client/gc_render.cpp @@ -197,7 +197,7 @@ void render_tee(animstate *anim, tee_render_info *info, int emote, vec2 dir, vec // draw feet gfx_setcolor(info->color_feet.r, info->color_feet.g, info->color_feet.b, info->color_feet.a); - select_sprite(outline?SPRITE_TEE_FOOT_OUTLINE:SPRITE_TEE_FOOT, 0, 0, 0); + select_sprite((outline||!info->got_airjump)?SPRITE_TEE_FOOT_OUTLINE:SPRITE_TEE_FOOT, 0, 0, 0); keyframe *foot = f ? &anim->front_foot : &anim->back_foot; @@ -278,7 +278,7 @@ void render_layers(float center_x, float center_y, int pass) bool render = false; bool is_game_layer = false; - if(layer == (MAPITEM_LAYER*)layers_game()) + if(layer == (MAPITEM_LAYER*)layers_game_layer()) { is_game_layer = true; passed_gamelayer = 1; @@ -306,7 +306,7 @@ void render_layers(float center_x, float center_y, int pass) else gfx_texture_set(img_get(tmap->image)); TILE *tiles = (TILE *)map_get_data(tmap->data); - render_tilemap(tiles, tmap->width, tmap->height, 32.0f, 1); + render_tilemap(tiles, tmap->width, tmap->height, 32.0f, vec4(1,1,1,1), 1); } else if(layer->type == LAYERTYPE_QUADS) { @@ -323,71 +323,82 @@ void render_layers(float center_x, float center_y, int pass) } } -// renders the complete game world -void render_world(float center_x, float center_y, float zoom) +static void render_items() { - // render background layers - render_layers(center_x, center_y, 0); - - // render items + int num = snap_num_items(SNAP_CURRENT); + for(int i = 0; i < num; i++) { - int num = snap_num_items(SNAP_CURRENT); - for(int i = 0; i < num; i++) - { - SNAP_ITEM item; - const void *data = snap_get_item(SNAP_CURRENT, i, &item); + SNAP_ITEM item; + const void *data = snap_get_item(SNAP_CURRENT, i, &item); - if(item.type == OBJTYPE_PROJECTILE) - { - //const void *prev = snap_find_item(SNAP_PREV, item.type, item.id); - //if(prev) - render_projectile((const obj_projectile *)data, item.id); - } - else if(item.type == OBJTYPE_POWERUP) - { - const void *prev = snap_find_item(SNAP_PREV, item.type, item.id); - if(prev) - render_powerup((const obj_powerup *)prev, (const obj_powerup *)data); - } - else if(item.type == OBJTYPE_FLAG) - { - const void *prev = snap_find_item(SNAP_PREV, item.type, item.id); - if (prev) - render_flag((const obj_flag *)prev, (const obj_flag *)data); - } + if(item.type == OBJTYPE_PROJECTILE) + { + render_projectile((const obj_projectile *)data, item.id); + } + else if(item.type == OBJTYPE_POWERUP) + { + const void *prev = snap_find_item(SNAP_PREV, item.type, item.id); + if(prev) + render_powerup((const obj_powerup *)prev, (const obj_powerup *)data); + } + else if(item.type == OBJTYPE_FLAG) + { + const void *prev = snap_find_item(SNAP_PREV, item.type, item.id); + if (prev) + render_flag((const obj_flag *)prev, (const obj_flag *)data); } } +} - // render players above all + +static void render_players() +{ + int num = snap_num_items(SNAP_CURRENT); + for(int i = 0; i < num; i++) { - int num = snap_num_items(SNAP_CURRENT); - for(int i = 0; i < num; i++) + SNAP_ITEM item; + const void *data = snap_get_item(SNAP_CURRENT, i, &item); + + if(item.type == OBJTYPE_PLAYER_CHARACTER) { - SNAP_ITEM item; - const void *data = snap_get_item(SNAP_CURRENT, i, &item); + const void *prev = snap_find_item(SNAP_PREV, item.type, item.id); + const void *prev_info = snap_find_item(SNAP_PREV, OBJTYPE_PLAYER_INFO, item.id); + const void *info = snap_find_item(SNAP_CURRENT, OBJTYPE_PLAYER_INFO, item.id); - if(item.type == OBJTYPE_PLAYER_CHARACTER) + if(prev && prev_info && info) { - const void *prev = snap_find_item(SNAP_PREV, item.type, item.id); - const void *prev_info = snap_find_item(SNAP_PREV, OBJTYPE_PLAYER_INFO, item.id); - const void *info = snap_find_item(SNAP_CURRENT, OBJTYPE_PLAYER_INFO, item.id); - - if(prev && prev_info && info) - { - render_player( - (const obj_player_character *)prev, - (const obj_player_character *)data, - (const obj_player_info *)prev_info, - (const obj_player_info *)info - ); - } + render_player( + (const obj_player_character *)prev, + (const obj_player_character *)data, + (const obj_player_info *)prev_info, + (const obj_player_info *)info + ); } } } +} + +// renders the complete game world +void render_world(float center_x, float center_y, float zoom) +{ + // render background layers + render_layers(center_x, center_y, 0); + + // render trails + particle_render(PARTGROUP_PROJECTILE_TRAIL); + + // render items + render_items(); + + // render players above all + render_players(); // render particles - //temp_system.update(client_frametime()); - //temp_system.render(); + particle_render(PARTGROUP_EXPLOSIONS); + particle_render(PARTGROUP_GENERAL); + + if(config.dbg_flow) + flow_dbg_render(); // render foreground layers render_layers(center_x, center_y, 1); diff --git a/src/game/client/gc_render.h b/src/game/client/gc_render.h index 5294b89e..d7adeada 100644 --- a/src/game/client/gc_render.h +++ b/src/game/client/gc_render.h @@ -8,10 +8,20 @@ struct tee_render_info { + tee_render_info() + { + texture = -1; + color_body = vec4(1,1,1,1); + color_feet = vec4(1,1,1,1); + size = 1.0f; + got_airjump = 1; + }; + int texture; vec4 color_body; vec4 color_feet; float size; + int got_airjump; }; // sprite renderings @@ -40,6 +50,7 @@ void render_world(float center_x, float center_y, float zoom); void render_loading(float percent); void render_damage_indicators(); +void render_particles(); // object render methods (gc_render_obj.cpp) void render_tee(class animstate *anim, tee_render_info *info, int emote, vec2 dir, vec2 pos); @@ -53,7 +64,7 @@ void render_player( // map render methods (gc_render_map.cpp) void render_eval_envelope(ENVPOINT *points, int num_points, int channels, float time, float *result); void render_quads(QUAD *quads, int num_quads, void (*eval)(float time_offset, int env, float *channels)); -void render_tilemap(TILE *tiles, int w, int h, float scale, int flags); +void render_tilemap(TILE *tiles, int w, int h, float scale, vec4 color, int flags); // helpers void mapscreen_to_world(float center_x, float center_y, float parallax_x, float parallax_y, diff --git a/src/game/client/gc_render_map.cpp b/src/game/client/gc_render_map.cpp index ec96f583..4728f771 100644 --- a/src/game/client/gc_render_map.cpp +++ b/src/game/client/gc_render_map.cpp @@ -148,7 +148,7 @@ void render_quads(QUAD *quads, int num_quads, void (*eval)(float time_offset, in } -void render_tilemap(TILE *tiles, int w, int h, float scale, int flags) +void render_tilemap(TILE *tiles, int w, int h, float scale, vec4 color, int flags) { //gfx_texture_set(img_get(tmap->image)); float screen_x0, screen_y0, screen_x1, screen_y1; @@ -160,6 +160,7 @@ void render_tilemap(TILE *tiles, int w, int h, float scale, int flags) float final_tilesize_scale = final_tilesize/tile_pixelsize; gfx_quads_begin(); + gfx_setcolor(color.r, color.g, color.b, color.a); int starty = (int)(screen_y0/scale)-1; int startx = (int)(screen_x0/scale)-1; diff --git a/src/game/client/gc_render_obj.cpp b/src/game/client/gc_render_obj.cpp index bdb4cfac..3ee1704d 100644 --- a/src/game/client/gc_render_obj.cpp +++ b/src/game/client/gc_render_obj.cpp @@ -1,5 +1,6 @@ /* copyright (c) 2007 magnus auvinen, see licence.txt for more info */ #include <math.h> +#include <stdio.h> #include <engine/e_client_interface.h> #include <engine/e_config.h> #include "../generated/gc_data.h" @@ -27,8 +28,6 @@ void render_projectile(const obj_projectile *current, int itemid) float gravity = -400; if(current->type != WEAPON_ROCKET) gravity = -100; - if(current->type == WEAPON_BOMB) - gravity = 0; float ct = (client_tick()-current->start_tick)/(float)SERVER_TICK_SPEED + client_ticktime()*1/(float)SERVER_TICK_SPEED; vec2 startpos(current->x, current->y); @@ -39,17 +38,26 @@ void render_projectile(const obj_projectile *current, int itemid) select_sprite(data->weapons[current->type%data->num_weapons].sprite_proj); vec2 vel = pos-prevpos; //vec2 pos = mix(vec2(prev->x, prev->y), vec2(current->x, current->y), client_intratick()); + // add particle for this projectile - //proj_particles.addparticle(current->type, itemid, pos, vel); - - if(length(vel) > 0.00001f) - gfx_quads_setrotation(get_angle(vel)); + if(current->type == WEAPON_ROCKET) + { + effect_smoketrail(pos, vel*-1); + flow_add(pos, vel*1000*client_frametime(), 10.0f); + gfx_quads_setrotation(client_localtime()*pi*2*2 + itemid); + } else - gfx_quads_setrotation(0); + { + effect_bullettrail(pos); + flow_add(pos, vel*1000*client_frametime(), 10.0f); - // TODO: do this, but nice - //temp_system.new_particle(pos, vec2(0,0), 0.3f, 14.0f, 0, 0.95f); + if(length(vel) > 0.00001f) + gfx_quads_setrotation(get_angle(vel)); + else + gfx_quads_setrotation(0); + + } gfx_quads_draw(pos.x, pos.y, 32, 32); gfx_quads_setrotation(0); @@ -185,6 +193,7 @@ void render_player( player = *player_char; obj_player_info info = *player_info; + tee_render_info render_info = client_datas[info.clientid].render_info; float intratick = client_intratick(); float ticktime = client_ticktime(); @@ -209,6 +218,11 @@ void render_player( vec2 direction = get_direction(player.angle); float angle = player.angle/256.0f; vec2 position = mix(vec2(prev.x, prev.y), vec2(player.x, player.y), intratick); + vec2 vel = vec2(player.x, player.y)-vec2(prev.x, prev.y); + + flow_add(position, vel*100.0f, 10.0f); + + render_info.got_airjump = player.jumped&2?0:1; if(prev.health < 0) // Don't flicker from previous position position = vec2(player.x, player.y); @@ -411,14 +425,14 @@ void render_player( if(info.local && config.debug) { vec2 ghost_position = mix(vec2(prev_char->x, prev_char->y), vec2(player_char->x, player_char->y), client_intratick()); - tee_render_info ghost = client_datas[info.clientid].render_info; + tee_render_info ghost = render_info; ghost.color_body.a = 0.5f; ghost.color_feet.a = 0.5f; render_tee(&state, &ghost, player.emote, direction, ghost_position); // render ghost } // render the tee - render_tee(&state, &client_datas[info.clientid].render_info, player.emote, direction, position); + render_tee(&state, &render_info, player.emote, direction, position); if(player.state == STATE_CHATTING) { |