From 82023866ab4c7483652e9d4605290e39ced3bec3 Mon Sep 17 00:00:00 2001 From: Magnus Auvinen Date: Thu, 24 May 2007 20:54:08 +0000 Subject: large change. moved around all source. splitted server and client into separate files --- src/game/client/game_client.cpp | 1993 +++++++++++++++++++++++++++++++++ src/game/client/mapres_image.cpp | 41 + src/game/client/mapres_image.h | 18 + src/game/client/mapres_tilemap.cpp | 54 + src/game/client/mapres_tilemap.h | 19 + src/game/client/menu.cpp | 600 ++++++++++ src/game/game.h | 2 +- src/game/game_client.cpp | 1993 --------------------------------- src/game/game_server.cpp | 2122 ----------------------------------- src/game/mapres_col.cpp | 2 +- src/game/mapres_image.cpp | 41 - src/game/mapres_image.h | 18 - src/game/mapres_tilemap.cpp | 54 - src/game/mapres_tilemap.h | 19 - src/game/server/game_server.cpp | 2131 ++++++++++++++++++++++++++++++++++++ 15 files changed, 4858 insertions(+), 4249 deletions(-) create mode 100644 src/game/client/game_client.cpp create mode 100644 src/game/client/mapres_image.cpp create mode 100644 src/game/client/mapres_image.h create mode 100644 src/game/client/mapres_tilemap.cpp create mode 100644 src/game/client/mapres_tilemap.h create mode 100644 src/game/client/menu.cpp delete mode 100644 src/game/game_client.cpp delete mode 100644 src/game/game_server.cpp delete mode 100644 src/game/mapres_image.cpp delete mode 100644 src/game/mapres_image.h delete mode 100644 src/game/mapres_tilemap.cpp delete mode 100644 src/game/mapres_tilemap.h create mode 100644 src/game/server/game_server.cpp (limited to 'src/game') diff --git a/src/game/client/game_client.cpp b/src/game/client/game_client.cpp new file mode 100644 index 00000000..f510e00e --- /dev/null +++ b/src/game/client/game_client.cpp @@ -0,0 +1,1993 @@ +#include +#include +#include "../game.h" +#include "mapres_image.h" +#include "mapres_tilemap.h" + +using namespace baselib; + +static int texture_char_default = 0; +static int texture_game = 0; +static int texture_weapon = 0; +static int texture_sun = 0; +static int texture_particles = 0; + +struct weapontexcell +{ + float x; + float y; + float w; + float h; +}; +struct renderparams +{ + float sizex; + float sizey; + float offsetx; + float offsety; +}; +int numcellsx = 32; +int numcellsy = 32; +renderparams weaponrenderparams[WEAPON_NUMWEAPONS]; +renderparams modifierrenderparams[WEAPON_NUMWEAPONS]; + +weapontexcell weaponprojtexcoord[WEAPON_NUMWEAPONS]; +weapontexcell weapontexcoord[WEAPON_NUMWEAPONS]; +weapontexcell weapontexcoordcursor[WEAPON_NUMWEAPONS]; + +weapontexcell poweruptexcoord[POWERUP_TYPE_NUMPOWERUPS]; + +weapontexcell modifiertexcoord[MODIFIER_NUMMODIFIERS]; +weapontexcell modifiertexcoordcursor[MODIFIER_NUMMODIFIERS]; + +int nummuzzletex[WEAPON_NUMWEAPONS]; +weapontexcell muzzletexcoord[WEAPON_NUMWEAPONS][3]; +renderparams muzzleparams[WEAPON_NUMWEAPONS]; + +#define NUMHADOKENS 6 +#define NUMSTARS 2 +#define NUMPARTICLES 9 +int particlesnumcellsx = 16; +int particlesnumcellsy = 16; +weapontexcell chaintexcoord; +weapontexcell chainheadtexcoord; +weapontexcell stars[NUMSTARS]; + +float lifemodifier[NUMPARTICLES]; +vec4 particlecolors[NUMPARTICLES]; +weapontexcell particlestexcoord[NUMPARTICLES]; + +int charnumcellsx = 8; +int charnumcellsy = 32; +int charoffsety = 2; +weapontexcell body[2]; +weapontexcell leye; +weapontexcell reye; +weapontexcell feet[2]; + +int charids[16] = { 2,10,0,4,12,6,14,1,9,15,13,11,7,5,8,3 }; + +renderparams hadokenparams[6]; +weapontexcell hadoken[6]; + +float recoils[WEAPON_NUMWEAPONS] = { 10.0f, 10.0f, 10.0f, 10.0f }; + +static int font_texture = 0; +static vec2 mouse_pos; + + +static vec2 local_player_pos; +static obj_player *local_player; + +float frandom() +{ + return rand()/(float)(RAND_MAX); +} + +float sign(float f) +{ + return f<0.0f?-1.0f:1.0f; +} + +// sound helpers +template +class sound_kit +{ +private: + int sounds[N]; + int last_id; +public: + sound_kit() : last_id(-1) { } + + int& operator[](int id) { return sounds[id]; } + + inline void play_random(float vol = 1.0f, float pan = 0.0f); +}; + +template<> +inline void sound_kit<1>::play_random(float vol, float pan) +{ + snd_play(sounds[0], SND_PLAY_ONCE, vol, pan); +} + +template +inline void sound_kit::play_random(float vol, float pan) +{ + int id; + do { + id = rand() % N; + } while(id == last_id); + snd_play(sounds[id], SND_PLAY_ONCE, vol, pan); + last_id = id; +} + + +// sound volume tweak +static const float stereo_separation = 0.01f; +static const float stereo_separation_deadzone = 512.0f; +static const float volume_distance_falloff = 100.0f; +static const float volume_distance_deadzone = 512.0f; +static const float volume_gun = 0.5f; +static const float volume_tee = 0.5f; +static const float volume_hit = 0.5f; +static const float volume_music = 0.8f; + +// sounds +sound_kit<3> sound_gun_fire; +sound_kit<3> sound_shotty_fire; +sound_kit<3> sound_flump_launch; +sound_kit<3> sound_hammer_swing; +sound_kit<3> sound_ninja_attack; + +sound_kit<3> sound_flump_explode; +sound_kit<4> sound_ninja_hit; + +sound_kit<3> sound_weapon_switch; + +sound_kit<12> sound_pain_short; +sound_kit<2> sound_pain_long; + +sound_kit<4> sound_body_jump; +sound_kit<4> sound_body_land; +sound_kit<2> sound_body_splat; + +sound_kit<7> sound_spawn; +sound_kit<2> sound_tee_cry; + +sound_kit<1> sound_hook_loop; +sound_kit<3> sound_hook_attach; + +void sound_vol_pan(const vec2& p, float *vol, float *pan) +{ + vec2 player_to_ev = p - local_player_pos; + *pan = 0.0f; + *vol = 1.0f; + + if(abs(player_to_ev.x) > stereo_separation_deadzone) + { + *pan = stereo_separation * (player_to_ev.x - sign(player_to_ev.x)*stereo_separation_deadzone); + if(*pan < -1.0f) *pan = -1.0f; + if(*pan > 1.0f) *pan = 1.0f; + } + + float len = length(player_to_ev); + if(len > volume_distance_deadzone) + { + *vol = volume_distance_falloff / (len - volume_distance_deadzone); + + if(*vol < 0.0f) *vol = 0.0f; + if(*vol > 1.0f) *vol = 1.0f; + } +} + +// TODO: we should do something nicer then this +static void cell_select_ex(int cx, int cy, float x, float y, float w, float h) +{ + gfx_quads_setsubset(x/(float)cx,y/(float)cy,(x+w)/(float)cx,(y+h)/(float)cy); +} + +static void cell_select_ex_flip_x(int cx, int cy, float x, float y, float w, float h) +{ + gfx_quads_setsubset((x+w)/(float)cx,y/(float)cy,x /(float)cx,(y+h)/(float)cy); +} + +static void cell_select_ex_flip_y(int cx, int cy, float x, float y, float w, float h) +{ + gfx_quads_setsubset(x/(float)cx,(y+h)/(float)cy,(x+w)/(float)cx,y/(float)cy); +} + +static void cell_select(int x, int y, int w, int h) +{ + gfx_quads_setsubset(x/16.0f,y/16.0f,(x+w)/16.0f,(y+h)/16.0f); +} + +inline void cell_select_flip_x(int x, int y, int w, int h) +{ + gfx_quads_setsubset((x+w)/16.0f,y/16.0f,(x)/16.0f,(y+h)/16.0f); +} + +inline void cell_select_flip_y(int x, int y, int w, int h) +{ + gfx_quads_setsubset(x/16.0f,(y+h)/16.0f,(x+w)/16.0f,(y)/16.0f); +} + +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; +}; + +void move_point(vec2 *inout_pos, vec2 *inout_vel, float elasticity) +{ + vec2 pos = *inout_pos; + vec2 vel = *inout_vel; + if(col_check_point(pos + vel)) + { + int affected = 0; + if(col_check_point(pos.x + vel.x, pos.y)) + { + inout_vel->x *= -elasticity; + affected++; + } + + if(col_check_point(pos.x, pos.y + vel.y)) + { + inout_vel->y *= -elasticity; + affected++; + } + + if(affected == 0) + { + inout_vel->x *= -elasticity; + inout_vel->y *= -elasticity; + } + } + else + { + *inout_pos = pos + vel; + } +} + +class health_texts +{ +public: + int64 lastupdate; + struct item + { + vec2 pos; + vec2 vel; + int amount; + int istar; + float life; + float startangle; + }; + + enum + { + MAX_ITEMS=16, + }; + + health_texts() + { + lastupdate = 0; + } + + item items[MAX_ITEMS]; + int num_items; + + item *create_i() + { + if (num_items < MAX_ITEMS) + { + item *p = &items[num_items]; + num_items++; + return p; + } + return 0; + } + + void destroy_i(item *i) + { + num_items--; + *i = items[num_items]; + } + + void create(vec2 pos, int amount) + { + amount = max(1,amount); + for (int j = 0; j < amount; j++) + { + float a = j/(float)amount-0.5f; + item *i = create_i(); + if (i) + { + i->pos = pos; + i->pos.y -= 20.0f; + i->pos.x += ((float)rand()/(float)RAND_MAX) * 5.0f; + i->amount = amount; + i->life = 1.5f; + i->istar = rand() % NUMSTARS; + i->vel = vec2(((float)rand()/(float)RAND_MAX) * 50.0f,-150.0f); + i->startangle = (( (float)rand()/(float)RAND_MAX) - 1.0f) * 2.0f * pi; + } + } + } + + void render() + { + if (!lastupdate) + lastupdate = time_get(); + + int64 lasttime = lastupdate; + lastupdate = time_get(); + + float delta = (float) (lastupdate - lasttime) / (float)time_freq(); + gfx_texture_set(texture_particles); + gfx_quads_begin(); + for(int i = 0; i < num_items;) + { + items[i].vel += vec2(0,500.0f) * delta; + items[i].pos += items[i].vel * delta; + items[i].life -= delta; + //items[i].pos.y -= frametime*15.0f; + if(items[i].life < 0.0f) + destroy_i(&items[i]); + else + { + gfx_quads_setcolor(1.0f,1.0f,1.0f, items[i].life / 1.5f); + gfx_quads_setrotation(items[i].startangle + items[i].life * 2.0f); + float size = 64.0f; + cell_select_ex(particlesnumcellsx,particlesnumcellsy, stars[items[i].istar].x,stars[items[i].istar].y, stars[items[i].istar].w, stars[items[i].istar].h); + gfx_quads_draw(items[i].pos.x-size/2, items[i].pos.y-size/2, size, size); + /*char buf[32]; + if(items[i].amount < 0) + { + sprintf(buf, "%d", items[i].amount*-1); + } + else + { + sprintf(buf, "%d", items[i].amount); + } + float size = 42.0f; + if(items[i].life > 1.25f) + size += 42.0f * ((items[i].life - 1.25f) * 4); + gfx_quads_text(items[i].pos.x-size/2, items[i].pos.y, size, buf);*/ + i++; + } + } + gfx_quads_end(); + } + +}; + +/*class texture_animator +{ +public: + + int texture; + int numframes; + float duration; + float* framereltime; + weapontexcell* params; + texture_animator() + { + texture = -1; + numframes = 0; + duration = 0; + framereltime = 0; + params = 0; + } + + ~texture_animator() + { + if (params) + mem_free(params); + if (framereltime) + mem_free(framereltime); + } + + void create_anim(int texture, int numframes, float duration) + { + framereltime = 0; + params = 0; + this->texture = texture; + this->numframes = numframes; + this->duration = duration; + if (numframes) + { + framereltime = (float*)mem_alloc(sizeof(float) * numframes,1); + params = (weapontexcell*)mem_alloc(sizeof(renderparams) * numframes,1); + float delta = 1.0f / (float)(numframes - 1); + for (int i = 0; i < numframes; i++) + { + framereltime[i] = delta * i; + } + } + } + + static void create_gunmuzzle(texture_animator& anim, int texture, float duration) + { + anim.create_anim(texture, 3, duration); + anim.params[0].x = 8; + anim.params[0].y = 4; + anim.params[0].w = 3; + anim.params[0].h = 2; + anim.params[1].x = 12; + anim.params[1].y = 4; + anim.params[1].w = 3; + anim.params[1].h = 2; + anim.params[2].x = 16; + anim.params[2].y = 4; + anim.params[2].w = 3; + anim.params[2].h = 2; + } + + static void create_shotgunmuzzle() + { + + } +};*/ + +class keyframe +{ +public: + vec2 pos; + float angle; + float relativetime; +}; + +class anim +{ +public: + keyframe* keyframes; + int numframes; + float duration; + anim() + { + numframes = 0; + keyframes = 0; + } + ~anim() + { + if (keyframes) + mem_free(keyframes); + } + + void create_anim(int numframes, float duration) + { + if (keyframes) + mem_free(keyframes); + + this->numframes = numframes; + this->duration = duration; + keyframes = (keyframe*)mem_alloc(sizeof(keyframe) * numframes,1); + float delta = 1.0f / (float) (numframes - 1); + for (int i = 0; i < numframes; i++) + { + keyframes[i].pos = vec2(0.0f,0.0f); + keyframes[i].angle = 0; + keyframes[i].relativetime = delta * (float)i; + } + } + + void getframes(float relativetime, keyframe*& frame1, keyframe*& frame2, float& blend) + { + for (int i = 1; i < numframes; i++) + { + if (keyframes[i-1].relativetime <= relativetime && keyframes[i].relativetime >= relativetime) + { + frame1 = &keyframes[i-1]; + frame2 = &keyframes[i]; + blend = (relativetime - frame1->relativetime) / (frame2->relativetime - frame1->relativetime); + } + } + } + + void evalanim(float time, vec2& pos, float& angle) + { + float reltime = max(0.0f, min(1.0f, time / duration)); + keyframe* frame1 = 0; + keyframe* frame2 = 0; + float blend = 0.0f; + getframes(reltime, frame1, frame2, blend); + + if (frame1 && frame2) + { + pos = mix(frame1->pos, frame2->pos, blend); + angle = LERP(frame1->angle, frame2->angle, blend); + } + } + + static void setup_hammer(anim& hammeranim) + { + // straight up = -0.25 + // frame0 = standard pose time 0 + // frame1 = back a little time 0.3 + // frame2 = over head time 0.4 + // frame3 = on ground smashed time 0.5 + // frame4 = back to standard pose time 1.0 + hammeranim.create_anim(5, 1.0f); + // only angles... (for now...) + hammeranim.keyframes[0].angle = -0.35f * pi * 2.0f; + hammeranim.keyframes[1].angle = -0.4f * pi * 2.0f; + hammeranim.keyframes[1].relativetime = 0.3f; + hammeranim.keyframes[2].angle = -0.25f; + hammeranim.keyframes[2].relativetime = 0.4f; + hammeranim.keyframes[3].angle = 0.0f * pi * 2.0f; + hammeranim.keyframes[3].relativetime = 0.5f; + hammeranim.keyframes[4].angle = -0.35f * pi * 2.0f; + hammeranim.keyframes[4].relativetime = 1.0f; + } + + static void setup_ninja(anim& ninjanim) + { + // (straight up = -0.25) + // frame0 = standard pose straight back time 0.0 + // frame1 = overhead attack frame 1 time 0.1 + // frame2 = attack end frame time 0.15 + // frame3 = attack hold frame (a bit up) time 0.4 + // frame4 = attack hold frame end time 0.7 + // frame5 = endframe time 1.0 + ninjanim.create_anim(6, 1.0f); + // only angles... (for now...) + ninjanim.keyframes[0].angle = -0.5f * pi * 2.0f; + + ninjanim.keyframes[1].angle = -0.3f * pi * 2.0f; + ninjanim.keyframes[1].relativetime = 0.1f; + + ninjanim.keyframes[2].angle = 0.1f * pi * 2.0f; + ninjanim.keyframes[2].relativetime = 0.15f; + + ninjanim.keyframes[3].angle = -0.05f * pi * 2.0f; + ninjanim.keyframes[3].relativetime = 0.42; + + ninjanim.keyframes[4].angle = -0.05f * pi * 2.0f; + ninjanim.keyframes[4].relativetime = 0.5f; + + ninjanim.keyframes[5].angle = -0.5f * pi * 2.0f; + ninjanim.keyframes[5].relativetime = 1.0f; + } +}; + +static anim hammeranim; +static anim ninjaanim; +static health_texts healthmods; + +class particle_system +{ +public: + 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) + { + if (num_particles >= MAX_PARTICLES) + return; + + particles[num_particles].iparticle = rand() % NUMPARTICLES; + particles[num_particles].pos = pos; + particles[num_particles].vel = vel; + particles[num_particles].life = life - lifemodifier[particles[num_particles].iparticle] * 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; + 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()); + 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(texture_particles); + gfx_quads_begin(); + //cell_select(4,1,1,1); + //cell_select(0,6,2,2); + //gfx_quads_setrotation(get_angle(vec2(proj->vx, proj->vy))); + for(int i = 0; i < num_particles; i++) + { + int type = particles[i].iparticle; + cell_select_ex(particlesnumcellsx,particlesnumcellsy,particlestexcoord[type].x, particlestexcoord[type].y, particlestexcoord[type].w, particlestexcoord[type].h); + float a = 1 - particles[i].life / particles[i].max_life; + vec2 p = particles[i].pos; + //a *= length(particles[i].vel) * 0.01f; + gfx_quads_setrotation(particles[i].rot); + gfx_quads_setcolor(particlecolors[type].x,particlecolors[type].y,particlecolors[type].z,pow(a,0.75f)); + //gfx_quads_setcolor(particlecolors[type].x * 0.5,particlecolors[type].y * 0.5,particlecolors[type].z* 0.5,pow(a,0.75f)); + //gfx_quads_setcolor(particlecolors[type].x * 0.0,particlecolors[type].y * 0.0,particlecolors[type].z* 0.0,pow(a,0.75f)); + //gfx_quads_setcolor(0.64f*2,0.28f*2,0.16f*2,pow(a,0.75f)); + gfx_quads_draw(p.x, p.y,particles[i].size,particles[i].size); + } + gfx_quads_end(); + gfx_blend_normal(); + } +}; + +static particle_system temp_system; + +void modc_init() +{ + // load textures + texture_weapon = gfx_load_texture_tga("data/tileset_weapons.tga"); + texture_game = gfx_load_texture_tga("data/game_main.tga"); + texture_char_default = gfx_load_texture_tga("data/char_teefault.tga"); + texture_sun = gfx_load_texture_tga("data/sun.tga"); + texture_particles = gfx_load_texture_tga("data/tileset_particles.tga"); + font_texture = gfx_load_texture_tga("data/debug_font.tga"); + + + // load sounds + sound_gun_fire[0] = snd_load_wav("data/audio/wp_gun_fire-01.wav"); + sound_gun_fire[0] = snd_load_wav("data/audio/wp_gun_fire-01.wav"); + sound_gun_fire[1] = snd_load_wav("data/audio/wp_gun_fire-02.wav"); + sound_shotty_fire[0] = snd_load_wav("data/audio/wp_shotty_fire-01.wav"); + sound_shotty_fire[1] = snd_load_wav("data/audio/wp_shotty_fire-02.wav"); + sound_shotty_fire[2] = snd_load_wav("data/audio/wp_shotty_fire-03.wav"); + sound_flump_launch[0] = snd_load_wav("data/audio/wp_flump_launch-01.wav"); + sound_flump_launch[1] = snd_load_wav("data/audio/wp_flump_launch-02.wav"); + sound_flump_launch[2] = snd_load_wav("data/audio/wp_flump_launch-03.wav"); + sound_hammer_swing[0] = snd_load_wav("data/audio/wp_hammer_swing-01.wav"); + sound_hammer_swing[1] = snd_load_wav("data/audio/wp_hammer_swing-02.wav"); + sound_hammer_swing[2] = snd_load_wav("data/audio/wp_hammer_swing-03.wav"); + sound_ninja_attack[0] = snd_load_wav("data/audio/wp_ninja_attack-01.wav"); + sound_ninja_attack[1] = snd_load_wav("data/audio/wp_ninja_attack-02.wav"); + sound_ninja_attack[2] = snd_load_wav("data/audio/wp_ninja_attack-03.wav"); + + sound_flump_explode[0] = snd_load_wav("data/audio/wp_flump_explo-01.wav"); + sound_flump_explode[1] = snd_load_wav("data/audio/wp_flump_explo-02.wav"); + sound_flump_explode[2] = snd_load_wav("data/audio/wp_flump_explo-03.wav"); + sound_ninja_hit[0] = snd_load_wav("data/audio/wp_ninja_hit-01.wav"); + sound_ninja_hit[1] = snd_load_wav("data/audio/wp_ninja_hit-02.wav"); + sound_ninja_hit[2] = snd_load_wav("data/audio/wp_ninja_hit-03.wav"); + sound_ninja_hit[3] = snd_load_wav("data/audio/wp_ninja_hit-04.wav"); + + sound_weapon_switch[0] = snd_load_wav("data/audio/wp_switch-01.wav"); + sound_weapon_switch[1] = snd_load_wav("data/audio/wp_switch-02.wav"); + sound_weapon_switch[2] = snd_load_wav("data/audio/wp_switch-03.wav"); + + sound_pain_short[0] = snd_load_wav("data/audio/vo_teefault_pain_short-01.wav"); + sound_pain_short[1] = snd_load_wav("data/audio/vo_teefault_pain_short-02.wav"); + sound_pain_short[2] = snd_load_wav("data/audio/vo_teefault_pain_short-03.wav"); + sound_pain_short[3] = snd_load_wav("data/audio/vo_teefault_pain_short-04.wav"); + sound_pain_short[4] = snd_load_wav("data/audio/vo_teefault_pain_short-05.wav"); + sound_pain_short[5] = snd_load_wav("data/audio/vo_teefault_pain_short-06.wav"); + sound_pain_short[6] = snd_load_wav("data/audio/vo_teefault_pain_short-07.wav"); + sound_pain_short[7] = snd_load_wav("data/audio/vo_teefault_pain_short-08.wav"); + sound_pain_short[8] = snd_load_wav("data/audio/vo_teefault_pain_short-09.wav"); + sound_pain_short[9] = snd_load_wav("data/audio/vo_teefault_pain_short-10.wav"); + sound_pain_short[10] = snd_load_wav("data/audio/vo_teefault_pain_short-11.wav"); + sound_pain_short[11] = snd_load_wav("data/audio/vo_teefault_pain_short-12.wav"); + + sound_pain_long[0] = snd_load_wav("data/audio/vo_teefault_pain_long-01.wav"); + sound_pain_long[1] = snd_load_wav("data/audio/vo_teefault_pain_long-02.wav"); + + sound_body_land[0] = snd_load_wav("data/audio/foley_land-01.wav"); + sound_body_land[1] = snd_load_wav("data/audio/foley_land-02.wav"); + sound_body_land[2] = snd_load_wav("data/audio/foley_land-03.wav"); + sound_body_land[3] = snd_load_wav("data/audio/foley_land-04.wav"); + sound_body_jump[0] = snd_load_wav("data/audio/foley_foot_left-01.wav"); + sound_body_jump[1] = snd_load_wav("data/audio/foley_foot_left-02.wav"); + sound_body_jump[2] = snd_load_wav("data/audio/foley_foot_left-03.wav"); + sound_body_jump[3] = snd_load_wav("data/audio/foley_foot_left-04.wav"); + sound_body_jump[4] = snd_load_wav("data/audio/foley_foot_right-01.wav"); + sound_body_jump[5] = snd_load_wav("data/audio/foley_foot_right-02.wav"); + sound_body_jump[6] = snd_load_wav("data/audio/foley_foot_right-03.wav"); + sound_body_jump[7] = snd_load_wav("data/audio/foley_foot_right-04.wav"); + + sound_body_splat[1] = snd_load_wav("data/audio/foley_body_splat-02.wav"); + sound_body_splat[2] = snd_load_wav("data/audio/foley_body_splat-03.wav"); + sound_body_splat[3] = snd_load_wav("data/audio/foley_body_splat-04.wav"); + + sound_spawn[0] = snd_load_wav("data/audio/vo_teefault_spawn-01.wav"); + sound_spawn[1] = snd_load_wav("data/audio/vo_teefault_spawn-02.wav"); + sound_spawn[2] = snd_load_wav("data/audio/vo_teefault_spawn-03.wav"); + sound_spawn[3] = snd_load_wav("data/audio/vo_teefault_spawn-04.wav"); + sound_spawn[4] = snd_load_wav("data/audio/vo_teefault_spawn-05.wav"); + sound_spawn[5] = snd_load_wav("data/audio/vo_teefault_spawn-06.wav"); + sound_spawn[6] = snd_load_wav("data/audio/vo_teefault_spawn-07.wav"); + + sound_tee_cry[0] = snd_load_wav("data/audio/vo_teefault_cry-01.wav"); + sound_tee_cry[1] = snd_load_wav("data/audio/vo_teefault_cry-02.wav"); + + //sound_hook_loop[0] = snd_load_wav("data/audio/hook_loop-01.wav"); + sound_hook_loop[0] = snd_load_wav("data/audio/hook_loop-02.wav"); + sound_hook_attach[0] = snd_load_wav("data/audio/hook_attach-01.wav"); + sound_hook_attach[1] = snd_load_wav("data/audio/hook_attach-02.wav"); + sound_hook_attach[2] = snd_load_wav("data/audio/hook_attach-03.wav"); + + poweruptexcoord[POWERUP_TYPE_HEALTH].x = 10; + poweruptexcoord[POWERUP_TYPE_HEALTH].y = 2; + poweruptexcoord[POWERUP_TYPE_HEALTH].w = 2; + poweruptexcoord[POWERUP_TYPE_HEALTH].h = 2; + + poweruptexcoord[POWERUP_TYPE_ARMOR].x = 12; + poweruptexcoord[POWERUP_TYPE_ARMOR].y = 2; + poweruptexcoord[POWERUP_TYPE_ARMOR].w = 2; + poweruptexcoord[POWERUP_TYPE_ARMOR].h = 2; + + poweruptexcoord[POWERUP_TYPE_WEAPON].x = 3; + poweruptexcoord[POWERUP_TYPE_WEAPON].y = 0; + poweruptexcoord[POWERUP_TYPE_WEAPON].w = 6; + poweruptexcoord[POWERUP_TYPE_WEAPON].h = 2; + + poweruptexcoord[POWERUP_TYPE_NINJA].x = 3; + poweruptexcoord[POWERUP_TYPE_NINJA].y = 10; + poweruptexcoord[POWERUP_TYPE_NINJA].w = 7; + poweruptexcoord[POWERUP_TYPE_NINJA].h = 2; + + poweruptexcoord[POWERUP_TYPE_TIMEFIELD].x = 3; + poweruptexcoord[POWERUP_TYPE_TIMEFIELD].y = 0; + poweruptexcoord[POWERUP_TYPE_TIMEFIELD].w = 6; + poweruptexcoord[POWERUP_TYPE_TIMEFIELD].h = 2; + + // Setup weapon cell coords + float sizemodifier = 1.0f; + weaponrenderparams[WEAPON_TYPE_GUN].sizex = 60.0f * sizemodifier; + weaponrenderparams[WEAPON_TYPE_GUN].sizey = 30.0f * sizemodifier; + weaponrenderparams[WEAPON_TYPE_GUN].offsetx = 32.0f; + weaponrenderparams[WEAPON_TYPE_GUN].offsety = 4.0f; + weapontexcoordcursor[WEAPON_TYPE_GUN].x = 0; + weapontexcoordcursor[WEAPON_TYPE_GUN].y = 4; + weapontexcoordcursor[WEAPON_TYPE_GUN].w = 2; + weapontexcoordcursor[WEAPON_TYPE_GUN].h = 2; + weapontexcoord[WEAPON_TYPE_GUN].x = 2; + weapontexcoord[WEAPON_TYPE_GUN].y = 4; + weapontexcoord[WEAPON_TYPE_GUN].w = 4; + weapontexcoord[WEAPON_TYPE_GUN].h = 2; + weaponprojtexcoord[WEAPON_TYPE_GUN].x = 6; + weaponprojtexcoord[WEAPON_TYPE_GUN].y = 4; + weaponprojtexcoord[WEAPON_TYPE_GUN].w = 2; + weaponprojtexcoord[WEAPON_TYPE_GUN].h = 2; + + nummuzzletex[WEAPON_TYPE_GUN] = 3; + muzzletexcoord[WEAPON_TYPE_GUN][0].x = 8; + muzzletexcoord[WEAPON_TYPE_GUN][0].y = 4; + muzzletexcoord[WEAPON_TYPE_GUN][0].w = 3; + muzzletexcoord[WEAPON_TYPE_GUN][0].h = 2; + muzzletexcoord[WEAPON_TYPE_GUN][1].x = 12; + muzzletexcoord[WEAPON_TYPE_GUN][1].y = 4; + muzzletexcoord[WEAPON_TYPE_GUN][1].w = 3; + muzzletexcoord[WEAPON_TYPE_GUN][1].h = 2; + muzzletexcoord[WEAPON_TYPE_GUN][2].x = 16; + muzzletexcoord[WEAPON_TYPE_GUN][2].y = 4; + muzzletexcoord[WEAPON_TYPE_GUN][2].w = 3; + muzzletexcoord[WEAPON_TYPE_GUN][2].h = 2; + + muzzleparams[WEAPON_TYPE_GUN].sizex = 60.0f * sizemodifier; + muzzleparams[WEAPON_TYPE_GUN].sizey = 40.0f * sizemodifier; + muzzleparams[WEAPON_TYPE_GUN].offsetx = 50.0f * sizemodifier; + muzzleparams[WEAPON_TYPE_GUN].offsety = 6.0f * sizemodifier; + + sizemodifier = 1.3f; + weaponrenderparams[WEAPON_TYPE_ROCKET].sizex = 70.0f * sizemodifier; + weaponrenderparams[WEAPON_TYPE_ROCKET].sizey = 20.0f * sizemodifier; + weaponrenderparams[WEAPON_TYPE_ROCKET].offsetx = 24.0f; + weaponrenderparams[WEAPON_TYPE_ROCKET].offsety = -2.0f; + weapontexcoordcursor[WEAPON_TYPE_ROCKET].x = 0; + weapontexcoordcursor[WEAPON_TYPE_ROCKET].y = 8; + weapontexcoordcursor[WEAPON_TYPE_ROCKET].w = 2; + weapontexcoordcursor[WEAPON_TYPE_ROCKET].h = 2; + weapontexcoord[WEAPON_TYPE_ROCKET].x = 2; + weapontexcoord[WEAPON_TYPE_ROCKET].y = 8; + weapontexcoord[WEAPON_TYPE_ROCKET].w = 7; + weapontexcoord[WEAPON_TYPE_ROCKET].h = 2; + weaponprojtexcoord[WEAPON_TYPE_ROCKET].x = 10; + weaponprojtexcoord[WEAPON_TYPE_ROCKET].y = 8; + weaponprojtexcoord[WEAPON_TYPE_ROCKET].w = 2; + weaponprojtexcoord[WEAPON_TYPE_ROCKET].h = 2; + + /*weaponrenderparams[WEAPON_TYPE_SNIPER].sizex = 60.0f; + weaponrenderparams[WEAPON_TYPE_SNIPER].sizey = 20.0f; + weaponrenderparams[WEAPON_TYPE_SNIPER].offsetx = 16.0f; + weaponrenderparams[WEAPON_TYPE_SNIPER].offsety = 4.0f; + weapontexcoordcursor[WEAPON_TYPE_SNIPER].x = 0; + weapontexcoordcursor[WEAPON_TYPE_SNIPER].y = 6; + weapontexcoordcursor[WEAPON_TYPE_SNIPER].w = 2; + weapontexcoordcursor[WEAPON_TYPE_SNIPER].h = 2; + weapontexcoord[WEAPON_TYPE_SNIPER].x = 3; + weapontexcoord[WEAPON_TYPE_SNIPER].y = 6; + weapontexcoord[WEAPON_TYPE_SNIPER].w = 6; + weapontexcoord[WEAPON_TYPE_SNIPER].h = 2; + weaponprojtexcoord[WEAPON_TYPE_SNIPER].x = 10; + weaponprojtexcoord[WEAPON_TYPE_SNIPER].y = 6; + weaponprojtexcoord[WEAPON_TYPE_SNIPER].w = 1; + weaponprojtexcoord[WEAPON_TYPE_SNIPER].h = 1;*/ + + weaponrenderparams[WEAPON_TYPE_SHOTGUN].sizex = 80.0f * sizemodifier; + weaponrenderparams[WEAPON_TYPE_SHOTGUN].sizey = 20.0f * sizemodifier; + weaponrenderparams[WEAPON_TYPE_SHOTGUN].offsetx = 24.0f; + weaponrenderparams[WEAPON_TYPE_SHOTGUN].offsety = -2.0f; + weapontexcoordcursor[WEAPON_TYPE_SHOTGUN].x = 0; + weapontexcoordcursor[WEAPON_TYPE_SHOTGUN].y = 6; + weapontexcoordcursor[WEAPON_TYPE_SHOTGUN].w = 2; + weapontexcoordcursor[WEAPON_TYPE_SHOTGUN].h = 2; + weapontexcoord[WEAPON_TYPE_SHOTGUN].x = 2; + weapontexcoord[WEAPON_TYPE_SHOTGUN].y = 6; + weapontexcoord[WEAPON_TYPE_SHOTGUN].w = 8; + weapontexcoord[WEAPON_TYPE_SHOTGUN].h = 2; + weaponprojtexcoord[WEAPON_TYPE_SHOTGUN].x = 10; + weaponprojtexcoord[WEAPON_TYPE_SHOTGUN].y = 6; + weaponprojtexcoord[WEAPON_TYPE_SHOTGUN].w = 2; + weaponprojtexcoord[WEAPON_TYPE_SHOTGUN].h = 2; + + nummuzzletex[WEAPON_TYPE_SHOTGUN] = 3; + muzzletexcoord[WEAPON_TYPE_SHOTGUN][0].x = 12; + muzzletexcoord[WEAPON_TYPE_SHOTGUN][0].y = 6; + muzzletexcoord[WEAPON_TYPE_SHOTGUN][0].w = 3; + muzzletexcoord[WEAPON_TYPE_SHOTGUN][0].h = 2; + muzzletexcoord[WEAPON_TYPE_SHOTGUN][1].x = 16; + muzzletexcoord[WEAPON_TYPE_SHOTGUN][1].y = 6; + muzzletexcoord[WEAPON_TYPE_SHOTGUN][1].w = 3; + muzzletexcoord[WEAPON_TYPE_SHOTGUN][1].h = 2; + muzzletexcoord[WEAPON_TYPE_SHOTGUN][2].x = 20; + muzzletexcoord[WEAPON_TYPE_SHOTGUN][2].y = 6; + muzzletexcoord[WEAPON_TYPE_SHOTGUN][2].w = 3; + muzzletexcoord[WEAPON_TYPE_SHOTGUN][2].h = 2; + + muzzleparams[WEAPON_TYPE_SHOTGUN].sizex = 60.0f * sizemodifier; + muzzleparams[WEAPON_TYPE_SHOTGUN].sizey = 40.0f * sizemodifier; + muzzleparams[WEAPON_TYPE_SHOTGUN].offsetx = 50.0f * sizemodifier; + muzzleparams[WEAPON_TYPE_SHOTGUN].offsety = 6.0f * sizemodifier; + + + + weaponrenderparams[WEAPON_TYPE_MELEE].sizex = 60.0f * sizemodifier; + weaponrenderparams[WEAPON_TYPE_MELEE].sizey = 50.0f * sizemodifier; + weaponrenderparams[WEAPON_TYPE_MELEE].offsetx = 20.0f; + weaponrenderparams[WEAPON_TYPE_MELEE].offsety = -4.0f; + weapontexcoordcursor[WEAPON_TYPE_MELEE].x = 0; + weapontexcoordcursor[WEAPON_TYPE_MELEE].y = 0; + weapontexcoordcursor[WEAPON_TYPE_MELEE].w = 2; + weapontexcoordcursor[WEAPON_TYPE_MELEE].h = 2; + weapontexcoord[WEAPON_TYPE_MELEE].x = 2; + weapontexcoord[WEAPON_TYPE_MELEE].y = 1; + weapontexcoord[WEAPON_TYPE_MELEE].w = 4; + weapontexcoord[WEAPON_TYPE_MELEE].h = 3; + weaponprojtexcoord[WEAPON_TYPE_MELEE].x = 0; + weaponprojtexcoord[WEAPON_TYPE_MELEE].y = 0; + weaponprojtexcoord[WEAPON_TYPE_MELEE].w = 0; + weaponprojtexcoord[WEAPON_TYPE_MELEE].h = 0; + + + // MODIFIERS + sizemodifier = 2.0; + modifierrenderparams[MODIFIER_TYPE_NINJA].sizex = 60.0f * sizemodifier; + modifierrenderparams[MODIFIER_TYPE_NINJA].sizey = 20.0f * sizemodifier; + modifierrenderparams[MODIFIER_TYPE_NINJA].offsetx = 20.0f; + modifierrenderparams[MODIFIER_TYPE_NINJA].offsety = 4.0f; + modifiertexcoord[MODIFIER_TYPE_NINJA].x = 2; + modifiertexcoord[MODIFIER_TYPE_NINJA].y = 10; + modifiertexcoord[MODIFIER_TYPE_NINJA].w = 7; + modifiertexcoord[MODIFIER_TYPE_NINJA].h = 2; + modifiertexcoordcursor[MODIFIER_TYPE_NINJA].x = 0; + modifiertexcoordcursor[MODIFIER_TYPE_NINJA].y = 10; + modifiertexcoordcursor[MODIFIER_TYPE_NINJA].w = 2; + modifiertexcoordcursor[MODIFIER_TYPE_NINJA].h = 2; + + modifierrenderparams[MODIFIER_TYPE_TIMEFIELD].sizex = 60.0f * sizemodifier; + modifierrenderparams[MODIFIER_TYPE_TIMEFIELD].sizey = 20.0f * sizemodifier; + modifierrenderparams[MODIFIER_TYPE_TIMEFIELD].offsetx = 16.0f; + modifierrenderparams[MODIFIER_TYPE_TIMEFIELD].offsety = 4.0f; + modifiertexcoord[MODIFIER_TYPE_TIMEFIELD].x = 0; + modifiertexcoord[MODIFIER_TYPE_TIMEFIELD].y = 0; + modifiertexcoord[MODIFIER_TYPE_TIMEFIELD].w = 0; + modifiertexcoord[MODIFIER_TYPE_TIMEFIELD].h = 0; + + stars[0].x = 0; + stars[0].y = 0; + stars[0].w = 2; + stars[0].h = 2; + + stars[1].x = 0; + stars[1].y = 2; + stars[1].w = 2; + stars[1].h = 2; + + particlecolors[0].x = 0.7f; + particlecolors[0].y = 0.7f; + particlecolors[0].z = 0.7f; + particlecolors[0].w = 1.0f; + particlestexcoord[0].x = 2; + particlestexcoord[0].y = 0; + particlestexcoord[0].w = 2; + particlestexcoord[0].h = 2; + particlecolors[1].x = 1.0f; + particlecolors[1].y = 1.0f; + particlecolors[1].z = 1.0f; + particlecolors[1].w = 1.0f; + particlestexcoord[1].x = 4; + particlestexcoord[1].y = 0; + particlestexcoord[1].w = 2; + particlestexcoord[1].h = 2; + particlecolors[2].x = 0.8f; + particlecolors[2].y = 0.8f; + particlecolors[2].z = 0.8f; + particlecolors[2].w = 1.0f; + particlestexcoord[2].x = 6; + particlestexcoord[2].y = 0; + particlestexcoord[2].w = 2; + particlestexcoord[2].h = 2; + particlecolors[3].x = 0.988f; + particlecolors[3].y = 1.0f; + particlecolors[3].z = 0.16f; + particlecolors[3].w = 1.0f; + particlestexcoord[3].x = 8; + particlestexcoord[3].y = 0; + particlestexcoord[3].w = 2; + particlestexcoord[3].h = 2; + particlecolors[4].x = 1.0f; + particlecolors[4].y = 1.0f; + particlecolors[4].z = 1.0f; + particlecolors[4].w = 1.0f; + particlestexcoord[4].x = 10; + particlestexcoord[4].y = 0; + particlestexcoord[4].w = 2; + particlestexcoord[4].h = 2; + particlecolors[5].x = 0.6f; + particlecolors[5].y = 0.6f; + particlecolors[5].z = 0.6f; + particlecolors[5].w = 1.0f; + particlestexcoord[5].x = 2; + particlestexcoord[5].y = 2; + particlestexcoord[5].w = 2; + particlestexcoord[5].h = 2; + particlecolors[6].x = 1.0f; + particlecolors[6].y = 1.0f; + particlecolors[6].z = 1.0f; + particlecolors[6].w = 1.0f; + particlestexcoord[6].x = 4; + particlestexcoord[6].y = 2; + particlestexcoord[6].w = 2; + particlestexcoord[6].h = 2; + particlecolors[5].x = 0.9f; + particlecolors[5].y = 0.9f; + particlecolors[5].z = 0.9f; + particlecolors[5].w = 1.0f; + particlestexcoord[7].x = 6; + particlestexcoord[7].y = 2; + particlestexcoord[7].w = 2; + particlestexcoord[7].h = 2; + particlecolors[8].x = 1.0f; + particlecolors[8].y = 1.0f; + particlecolors[8].z = 1.0f; + particlecolors[8].w = 1.0f; + particlestexcoord[8].x = 8; + particlestexcoord[8].y = 2; + particlestexcoord[8].w = 2; + particlestexcoord[8].h = 2; + lifemodifier[0] = 0.5f; + lifemodifier[1] = 0.5f; + lifemodifier[2] = 0.5f; + lifemodifier[3] = 0.7f; + lifemodifier[4] = 0.7f; + lifemodifier[5] = 1.0f; + lifemodifier[6] = 1.0f; + lifemodifier[7] = 1.5f; + lifemodifier[8] = 0.4f; + + chaintexcoord.x = 2; + chaintexcoord.y = 0; + chaintexcoord.w = 1; + chaintexcoord.h = 1; + + chainheadtexcoord.x = 3; + chainheadtexcoord.y = 0; + chainheadtexcoord.w = 2; + chainheadtexcoord.h = 1; + + + // anims + anim::setup_hammer(hammeranim); + anim::setup_ninja(ninjaanim); + + for (int i = 0; i < NUMHADOKENS; i++) + { + hadoken[i].x = 1; + hadoken[i].y = 12; + hadoken[i].w = 7; + hadoken[i].h = 4; + hadokenparams[i].sizex = 0.0f; + hadokenparams[i].sizey = 0.0f; + hadokenparams[i].offsetx = 0.0f; + hadokenparams[i].offsety = 0.0f;//-hadokenparams[0].sizey * 0.15f; + } + + // hadoken + hadoken[0].x = 1; + hadoken[0].y = 12; + hadoken[0].w = 7; + hadoken[0].h = 4; + hadokenparams[0].sizex = 70.0f * 2.5f; + hadokenparams[0].sizey = 40.0f * 2.5f; + hadokenparams[0].offsetx = -60.0f; + hadokenparams[0].offsety = 0;//-hadokenparams[0].sizey * 0.15f; + + hadoken[2].x = 8; + hadoken[2].y = 12; + hadoken[2].w = 8; + hadoken[2].h = 4; + hadokenparams[2].sizex = 80.0f * 2.5f; + hadokenparams[2].sizey = 40.0f * 2.5f; + hadokenparams[2].offsetx = -60.0f; + hadokenparams[2].offsety = 0;//-hadokenparams[1].sizey * 0.5f; + + hadoken[4].x = 17; + hadoken[4].y = 12; + hadoken[4].w = 7; + hadoken[4].h = 4; + hadokenparams[4].sizex = 70.0f * 2.5f; + hadokenparams[4].sizey = 40.0f * 2.5f; + hadokenparams[4].offsetx = -60.0f; + hadokenparams[4].offsety = 0;//-hadokenparams[2].sizey * 0.5f; + + // 0 = outline, 1 = body + body[0].x = 2; + body[0].y = 0; + body[0].w = 2; + body[0].h = 2; + body[1].x = 0; + body[1].y = 0; + body[1].w = 2; + body[1].h = 2; + + feet[0].x = 4; + feet[0].y = 1; + feet[0].w = 1; + feet[0].h = 0.5; + feet[1].x = 4; + feet[1].y = 1.52; + feet[1].w = 1; + feet[1].h = 0.48; + + leye.x = 5; + leye.y = 1; + leye.w = 0.5; + leye.h = 0.5; + + reye.x = 5; + reye.y = 1.0; + reye.w = 0.5; + reye.h = 0.5; +} + +void modc_entergame() +{ + col_init(32); + img_init(); + tilemap_init(); +} + +void modc_shutdown() +{ +} + +void modc_newsnapshot() +{ + int num = snap_num_items(SNAP_CURRENT); + for(int i = 0; i < num; i++) + { + snap_item item; + void *data = snap_get_item(SNAP_CURRENT, i, &item); + + if(item.type == EVENT_HEALTHMOD) + { + ev_healthmod *ev = (ev_healthmod *)data; + healthmods.create(vec2(ev->x, ev->y), ev->amount); + } + 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); + } + } + 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_SOUND) + { + ev_sound *ev = (ev_sound *)data; + vec2 p(ev->x, ev->y); + int sound = (ev->sound & SOUND_MASK); + bool bstartloop = (ev->sound & SOUND_LOOPFLAG_STARTLOOP) != 0; + bool bstoploop = (ev->sound & SOUND_LOOPFLAG_STOPLOOP) != 0; + float vol, pan; + sound_vol_pan(p, &vol, &pan); + + switch(sound) + { + + // FIRE! + case SOUND_FIRE_GUN: + sound_gun_fire.play_random(volume_gun*vol, pan); + break; + case SOUND_FIRE_SHOTGUN: + sound_shotty_fire.play_random(volume_gun*vol, pan); + break; + case SOUND_FIRE_ROCKET: + sound_flump_launch.play_random(volume_gun*vol, pan); + break; + case SOUND_FIRE_MELEE: + sound_hammer_swing.play_random(volume_gun*vol, pan); + break; + case SOUND_FIRE_NINJA: + sound_ninja_attack.play_random(volume_gun*vol, pan); + break; + + // IMPACT + case SOUND_IMPACT_PROJECTILE_GUN: + break; + case SOUND_IMPACT_PROJECTILE_SHOTGUN: + break; + case SOUND_IMPACT_PROJECTILE_ROCKET: + sound_flump_explode.play_random(volume_hit*vol, pan); + break; + + // PLAYER + case SOUND_PLAYER_JUMP: + sound_body_jump.play_random(volume_tee*vol, pan); + break; + case SOUND_PLAYER_HURT_SHORT: + sound_pain_short.play_random(volume_tee*vol, pan); + break; + case SOUND_PLAYER_HURT_LONG: + sound_pain_long.play_random(volume_tee*vol, pan); + break; + case SOUND_PLAYER_SPAWN: + sound_spawn.play_random(volume_tee*vol, pan); + break; + case SOUND_PLAYER_CHAIN_LOOP: + sound_hook_loop.play_random(volume_gun*vol, pan); + break; + case SOUND_PLAYER_CHAIN_IMPACT: + sound_hook_attach.play_random(volume_gun*vol, pan); + break; + case SOUND_PLAYER_IMPACT: + sound_body_land.play_random(volume_hit*vol, pan); + break; + case SOUND_PLAYER_IMPACT_NINJA: + sound_ninja_hit.play_random(volume_hit*vol, pan); + break; + case SOUND_PLAYER_DIE: + sound_body_splat.play_random(volume_tee*vol, pan); + break; + case SOUND_PLAYER_SWITCHWEAPON: + sound_weapon_switch.play_random(volume_gun*vol, pan); + break; + case SOUND_PLAYER_EQUIP: + break; + case SOUND_PLAYER_LAND: + sound_body_land.play_random(volume_tee*vol, pan); + break; + } + } + } +} + +static void render_projectile(obj_projectile *prev, obj_projectile *current) +{ + gfx_texture_set(texture_weapon); + gfx_quads_begin(); + cell_select_ex(numcellsx,numcellsy,weaponprojtexcoord[current->type].x, weaponprojtexcoord[current->type].y, weaponprojtexcoord[current->type].w, weaponprojtexcoord[current->type].h); + vec2 vel(current->vx, current->vy); + + // TODO: interpolare angle aswell + if(length(vel) > 0.00001f) + gfx_quads_setrotation(get_angle(vel)); + else + gfx_quads_setrotation(0); + + vec2 pos = mix(vec2(prev->x, prev->y), vec2(current->x, current->y), snap_intratick()); + gfx_quads_draw(pos.x, pos.y,32,32); + gfx_quads_setrotation(0); + gfx_quads_end(); +} + +static void render_powerup(obj_powerup *prev, obj_powerup *current) +{ + //dbg_msg("client", "rendering powerup at %d,%d", current->x, current->y); + + gfx_texture_set(texture_weapon); + gfx_quads_begin(); + float angle = 0.0f; + float sizex = 64.0f; + float sizey = 64.0f; + if (current->type == POWERUP_TYPE_WEAPON) + { + angle = -0.25f * pi * 2.0f; + cell_select_ex(numcellsx,numcellsy,weapontexcoord[current->subtype].x, weapontexcoord[current->subtype].y, weapontexcoord[current->subtype].w, weapontexcoord[current->subtype].h); + sizex = weaponrenderparams[current->subtype].sizex; + sizey = weaponrenderparams[current->subtype].sizey; + } + else + cell_select_ex(numcellsx,numcellsy,poweruptexcoord[current->type].x, poweruptexcoord[current->type].y, poweruptexcoord[current->type].w, poweruptexcoord[current->type].h); + vec2 vel(current->vx, current->vy); + + gfx_quads_setrotation(angle); + // TODO: interpolare angle aswell + /*if(length(vel) > 0.00001f) + gfx_quads_setrotation(get_angle(vel)); + else + gfx_quads_setrotation(0);*/ + + vec2 pos = mix(vec2(prev->x, prev->y), vec2(current->x, current->y), snap_intratick()); + float offset = pos.y/32.0f + pos.x/32.0f; + gfx_quads_draw(pos.x+cosf(client_localtime()*2.0f+offset)*2.5f, pos.y+sinf(client_localtime()*2.0f+offset)*2.5f,sizex * 0.65f,sizey * 0.65f); + gfx_quads_setrotation(0); + gfx_quads_end(); +} + +float getmeleeangle(vec2 direction, obj_player* prev, obj_player* player) +{ + vec2 meleedir(0.53, -0.84); + meleedir = normalize(meleedir); + vec2 meleedirattack(0.95, -0.3); + meleedirattack = normalize(meleedirattack); + + if(direction.x < 0) + { + meleedir.x = -meleedir.x; + meleedirattack.x = -meleedirattack.x; + } + + // 0 -> visualtimeattack go to end pose, (len - visualime) -> go back to normal pose + + float angle = get_angle(meleedir); + if (prev->attackticks) + { + float angleattack = get_angle(meleedirattack); + int phase1tick = (player->attacklen - player->attackticks); + if (phase1tick < player->visualtimeattack) + { + float intratick = snap_intratick(); + float t = ((((float)phase1tick) + intratick)/(float)player->visualtimeattack); + angle = LERP(angle, angleattack, min(1.0f,max(0.0f,t))); + } + else + { + // go back to normal pose + int phase2tick = (player->attacklen - player->visualtimeattack - player->attackticks); + float intratick = snap_intratick(); + float t = ((((float)phase2tick) + intratick)/(float)player->visualtimeattack); + angle = LERP(angleattack, angle, min(1.0f,max(0.0f,t))); + } + } + /*if (prev->attackticks && !player->attackticks) + { + // blend back to normal + float angleattack = get_angle(meleedirattack); + angle = LERP(angleattack, angle, min(1.0f,max(0.0f,snap_intratick()))); + } + else if (player->attackticks) + { + float angleattack = get_angle(meleedirattack); + float intratick = snap_intratick(); + float t = ((((float)player->attackticks) - intratick)/(float)player->attacklen); + angle = LERP(angleattack, angle, min(1.0f,max(0.0f,t))); + }*/ + + return angle; +} + +float gethammereangle(vec2 direction, obj_player* prev, obj_player* player) +{ + float t = 0.0f; + if (prev->attackticks) + t = 1.0f - ((((float)player->attackticks) - snap_intratick())/(float)player->attacklen); + + vec2 pos; + float angle = 0.0f; + hammeranim.evalanim(t,pos,angle); + if(direction.x < 0) + angle = pi -angle;// + ; + //dbg_msg("anim", "Time: %f", t); + return angle; +} + +float getninjaangle(vec2 direction, obj_player* prev, obj_player* player) +{ + float t = 0.0f; + if (prev->attackticks) + t = 1.0f - ((((float)player->attackticks) - snap_intratick())/(float)player->attacklen); + + vec2 pos; + float angle = 0.0f; + ninjaanim.evalanim(t,pos,angle); + if(direction.x < 0) + angle = pi -angle;// + ; + //dbg_msg("anim", "Time: %f", t); + return angle; +} + + +float getrecoil(obj_player* prev, obj_player* player) +{ + // attack = -10 + float recoil = 0.0f; + if (prev->attackticks) + { + float attackrecoil = recoils[player->weapon]; + int phase1tick = (player->attacklen - player->attackticks); + if (phase1tick < player->visualtimeattack) + { + float intratick = snap_intratick(); + float t = ((((float)phase1tick) + intratick)/(float)player->visualtimeattack); + recoil = LERP(0, attackrecoil, min(1.0f,max(0.0f,t))); + } + else + { + // go back to normal pose + int phase2tick = (player->attacklen - player->visualtimeattack - player->attackticks); + float intratick = snap_intratick(); + float t = ((((float)phase2tick) + intratick)/(float)(player->attacklen - player->visualtimeattack)); + recoil = LERP(attackrecoil, 0.0f, min(1.0f,max(0.0f,t))); + } + } + return recoil; +} + +static void render_player(obj_player *prev, obj_player *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), snap_intratick()); + + // draw hook + if(player->hook_active) + { + gfx_texture_set(texture_weapon); + gfx_quads_begin(); + //gfx_quads_begin(); + + vec2 pos = position; + + vec2 hook_pos = mix(vec2(prev->hook_x, prev->hook_y), vec2(player->hook_x, player->hook_y), snap_intratick()); + + float d = distance(pos, hook_pos); + vec2 dir = normalize(pos-hook_pos); + + gfx_quads_setrotation(get_angle(dir)+pi); + + // render head + cell_select_ex(numcellsx,numcellsy, chainheadtexcoord.x,chainheadtexcoord.y, chainheadtexcoord.w, chainheadtexcoord.h); + gfx_quads_draw(hook_pos.x, hook_pos.y, 24,16); + + // render chain + cell_select_ex(numcellsx,numcellsy, chaintexcoord.x, chaintexcoord.y, chaintexcoord.w, chaintexcoord.h); + for(float f = 24; f < d; f += 24) + { + vec2 p = hook_pos + dir*f; + gfx_quads_draw(p.x, p.y,24,16); + } + + gfx_quads_setrotation(0); + gfx_quads_end(); + } + + // draw gun + { + gfx_texture_set(texture_weapon); + gfx_quads_begin(); + gfx_quads_setrotation(angle); + + if (player->modifier & (1 << MODIFIER_TYPE_NINJA)) + { + float playerangle = angle; + // render NINJA!!! (0.53, 0.84) when idle to -> (0.95, 0.3) at the end of attack + if(direction.x < 0) + cell_select_ex_flip_y(numcellsx, numcellsy, modifiertexcoord[MODIFIER_TYPE_NINJA].x, modifiertexcoord[MODIFIER_TYPE_NINJA].y, modifiertexcoord[MODIFIER_TYPE_NINJA].w, modifiertexcoord[MODIFIER_TYPE_NINJA].h); + else + cell_select_ex(numcellsx, numcellsy, modifiertexcoord[MODIFIER_TYPE_NINJA].x, modifiertexcoord[MODIFIER_TYPE_NINJA].y, modifiertexcoord[MODIFIER_TYPE_NINJA].w, modifiertexcoord[MODIFIER_TYPE_NINJA].h); + + angle = getninjaangle(direction, prev, player);//getmeleeangle(direction, prev, player); + vec2 ninjadir = get_direction(angle * 256.0f); + gfx_quads_setrotation(angle); + vec2 p = position + vec2(0,modifierrenderparams[MODIFIER_TYPE_NINJA].offsety)+ ninjadir * modifierrenderparams[MODIFIER_TYPE_NINJA].offsetx; + // if attack is active hold it differently and draw speedlines behind us? + gfx_quads_draw(p.x,p.y/*+bob*/,modifierrenderparams[MODIFIER_TYPE_NINJA].sizex, modifierrenderparams[MODIFIER_TYPE_NINJA].sizey); + + if ((player->attacklen - player->attackticks) <= (SERVER_TICK_SPEED / 5)) + { + gfx_quads_setrotation(playerangle); + int ihadoken = rand() % NUMHADOKENS; + cell_select_ex(numcellsx, numcellsy, hadoken[ihadoken].x, hadoken[ihadoken].y, hadoken[ihadoken].w, hadoken[ihadoken].h); + vec2 p = position + vec2(0,hadokenparams[ihadoken].offsety)+ direction * hadokenparams[ihadoken].offsetx; + gfx_quads_draw(p.x,p.y/*+bob*/,hadokenparams[ihadoken].sizex, hadokenparams[ihadoken].sizey); + } + } + else + { + // normal weapons + if(direction.x < 0) + cell_select_ex_flip_y(numcellsx, numcellsy, weapontexcoord[player->weapon].x, weapontexcoord[player->weapon].y, weapontexcoord[player->weapon].w, weapontexcoord[player->weapon].h); + else + cell_select_ex(numcellsx, numcellsy, weapontexcoord[player->weapon].x, weapontexcoord[player->weapon].y, weapontexcoord[player->weapon].w, weapontexcoord[player->weapon].h); + + vec2 dir = direction; + float recoil = 0.0f; + if (player->weapon == WEAPON_TYPE_MELEE) + { + // if attack is under way, bash stuffs + //angle = getmeleeangle(direction, prev, player); + angle = gethammereangle(direction, prev, player); + gfx_quads_setrotation(angle); + dir = get_direction(angle * 256.0f); + } + else + { + recoil = getrecoil(prev, player); + } + + vec2 p = position + vec2(0,weaponrenderparams[player->weapon].offsety) + dir * weaponrenderparams[player->weapon].offsetx - dir * recoil; + gfx_quads_draw(p.x,p.y/*+bob*/,weaponrenderparams[player->weapon].sizex, weaponrenderparams[player->weapon].sizey); + // draw muzzleflare + if (player->weapon == WEAPON_TYPE_GUN || player->weapon == WEAPON_TYPE_SHOTGUN) + { + // check if we're firing stuff + if (true)///prev->attackticks) + { + float alpha = 0.0f; + int phase1tick = (player->attacklen - player->attackticks); + if (phase1tick < (player->visualtimeattack + 3)) + { + float intratick = snap_intratick(); + float t = ((((float)phase1tick) + intratick)/(float)player->visualtimeattack); + alpha = LERP(2.0, 0.0f, min(1.0f,max(0.0f,t))); + } + + if (alpha > 0.0f) + { + float offsety = -muzzleparams[player->weapon].offsety; + int itex = rand() % nummuzzletex[player->weapon]; + if(direction.x < 0) + { + offsety = -offsety; + cell_select_ex_flip_y(numcellsx, numcellsy, muzzletexcoord[player->weapon][itex].x, muzzletexcoord[player->weapon][itex].y, muzzletexcoord[player->weapon][itex].w, muzzletexcoord[player->weapon][itex].h); + } + else + cell_select_ex(numcellsx, numcellsy, muzzletexcoord[player->weapon][itex].x, muzzletexcoord[player->weapon][itex].y, muzzletexcoord[player->weapon][itex].w, muzzletexcoord[player->weapon][itex].h); + + gfx_quads_setcolor(1.0f,1.0f,1.0f,alpha); + vec2 diry(-dir.y,dir.x); + p += dir * muzzleparams[player->weapon].offsetx + diry * offsety; + gfx_quads_draw(p.x,p.y/*+bob*/,muzzleparams[player->weapon].sizex, muzzleparams[player->weapon].sizey); + } + } + } + } + /*else + { + // minigun + if(direction.x < 0) + cell_select_flip_y(4,4,8,2); + else + cell_select(4,4,8,2); + vec2 p = position + vec2(0,3); + gfx_quads_draw(p.x,p.y,8*8,8*2); + }*/ + + gfx_quads_setrotation(0); + gfx_quads_end(); + } + + + gfx_texture_set(texture_char_default); + gfx_quads_begin(); + + float bob = 0; + + // draw foots + const float cyclelength = 128.0f; + const float steplength = 26; + const float lift = 4.0f; + bool stationary = player->vx < 1 && player->vx > -1; + bool inair = col_check_point(player->x, player->y+16) == 0; + + for(int p = 0; p < 2; p++) + { + // first pass we draw the outline + // second pass we draw the filling + + //int v_offset = p?0:5; + int outline = p;// ? 1 : 0; + float offsety = charids[player->clientid % 16] * 2.0f; + + for(int f = 0; f < 2; f++) + { + float basesize = 10.0f; + if(f == 1) + { + // draw body + float t = fmod(position.x, cyclelength/2)/(cyclelength/2); + bob = -sinf(pow(t,2)*pi) * 3; + cell_select_ex(charnumcellsx,charnumcellsy, body[outline].x,body[outline].y + offsety,body[outline].w,body[outline].h); + //cell_select_ex(16,16, 0,0+v_offset,4,4); + //const float size = 64.0f; + if(stationary || inair) + bob = 0; + gfx_quads_draw(position.x, position.y-5+bob, 4*basesize, 4*basesize); + + // draw eyes + if(p == 1) + { + //cell_select_ex(16,16, 8,3,1,1); + vec2 md = get_direction(player->angle); + float mouse_dir_x = md.x; + float mouse_dir_y = md.y; + + // normal + cell_select_ex(charnumcellsx,charnumcellsy, leye.x,leye.y + offsety,leye.w,leye.h); + gfx_quads_draw(position.x-4+mouse_dir_x*4, position.y-8+mouse_dir_y*3+bob, basesize, basesize); + cell_select_ex(charnumcellsx,charnumcellsy, reye.x,reye.y + offsety,reye.w,reye.h); + gfx_quads_draw(position.x+4+mouse_dir_x*4, position.y-8+mouse_dir_y*3+bob, basesize, basesize); + } + } + + // draw feet + //cell_select_ex(16,16, 5,2+v_offset, 2,2); + cell_select_ex(charnumcellsx,charnumcellsy, feet[outline].x,feet[outline].y + offsety, feet[outline].w,feet[outline].h); + float w = basesize*2.5f; + float h = basesize*1.425f; + if(inair) + { + float r = 0.0f; + if(player->vy < 0.0f) + r = player->vy/3.0f; + else + r = player->vy/15.0f; + + // clamp the rotation + if(r > 0.5f) r = 0.5f; + if(r < -0.5f) r = -0.5f; + + if(player->vx > 0.0f) + r *= -1.0f; + gfx_quads_setrotation(r); + gfx_quads_drawTL(position.x-4+f*7-w/2, position.y+16 - h, w, h); + gfx_quads_setrotation(0); + } + else if(stationary) + { + // stationary + gfx_quads_drawTL(position.x-7+f*14-w/2, position.y+16 - h, w, h); + } + else + { + /* + The walk cycle, 2 parts + + 111 + 1 1 + 2 1 + 2 1 + 2222221 + GROUND GROUND GROUND + */ + + // moving + float tx = position.x+f*(cyclelength/2); + float t = fmod(tx, cyclelength) / cyclelength; + if(player->vx < 0) + t = 1.0f-t; + + float y; + float x = 0; + float r = 0; + float r_back = 1.5f; + + if(t < 0.5f) + { + // stomp down foot (part 1) + float st = t*2; + y = 1.0f-pow(st, 0.5f) + sinf(pow(st,2)*pi)*0.5f; + x = -steplength/2 + st*steplength; + r = r_back*(1-st) + sinf(pow(st,1.5f)*pi*2); + } + else + { + // lift foot up again (part 2) + float st = (t-0.5f)*2; + y = pow(st, 5.0f); + x = steplength/2 - st*steplength; + r = y*r_back; + } + + + if(player->vx > 0) + { + gfx_quads_setrotation(r); + gfx_quads_drawTL(position.x+x-w/2, position.y+16-y*lift - h, w, h); + } + else + { + gfx_quads_setrotation(-r); + gfx_quads_drawTL(position.x-x-w/2, position.y+16-y*lift - h, w, h); + } + gfx_quads_setrotation(0); + } + + } + } + + gfx_quads_end(); + + +} + +static player_input oldinput; +static bool bfirst = true; +void modc_render() +{ + if (bfirst) + { + bfirst = false; + oldinput.activeweapon = 0; + oldinput.angle = 0; + oldinput.blink = 0; + oldinput.fire = 0; + oldinput.hook = 0; + oldinput.jump = 0; + oldinput.left = 0; + oldinput.right = 0; + } + // fetch new input + { + int x, y; + inp_mouse_relative(&x, &y); + mouse_pos += vec2(x, y); + float l = length(mouse_pos); + if(l > 600.0f) + mouse_pos = normalize(mouse_pos)*600.0f; + } + + // snap input + { + player_input input; + input.left = inp_key_pressed('A'); + input.right = inp_key_pressed('D'); + float a = atan((float)mouse_pos.y/(float)mouse_pos.x); + if(mouse_pos.x < 0) + a = a+pi; + input.angle = (int)(a*256.0f); + input.jump = inp_key_pressed(baselib::keys::space) || inp_key_pressed('W'); + + input.fire = inp_mouse_button_pressed(0);// | (oldinput.fire << 16); + //oldinput.fire = input.fire & 0x0000ffff; + + input.hook = inp_mouse_button_pressed(1) || inp_key_pressed(baselib::keys::lctrl); // be nice to mac users O.o + input.blink = inp_key_pressed('S'); + + // Weapon switching + input.activeweapon = inp_key_pressed('1') ? 0x80000000 : 0; + if (!input.activeweapon) + input.activeweapon = inp_key_pressed('2') ? 0x80000000 | 1 : 0; + if (!input.activeweapon) + input.activeweapon = inp_key_pressed('3') ? 0x80000000 | 2 : 0; + if (!input.activeweapon) + input.activeweapon = inp_key_pressed('4') ? 0x80000000 | 3 : 0; + /*if (!input.activeweapon) + input.activeweapon = inp_key_pressed('5') ? 0x80000000 | 4 : 0;*/ + + snap_input(&input, sizeof(input)); + } + + // setup world view + { + // 1. fetch local player + // 2. set him to the center + + int num = snap_num_items(SNAP_CURRENT); + for(int i = 0; i < num; i++) + { + snap_item item; + void *data = snap_get_item(SNAP_CURRENT, i, &item); + + if(item.type == OBJTYPE_PLAYER) + { + obj_player *player = (obj_player *)data; + if(player->local) + { + local_player = player; + local_player_pos = vec2(player->x, player->y); + + void *p = snap_find_item(SNAP_PREV, item.type, item.id); + if(p) + local_player_pos = mix(vec2(((obj_player *)p)->x, ((obj_player *)p)->y), local_player_pos, snap_intratick()); + break; + } + } + } + } + + // pseudo format + float zoom = inp_key_pressed('T') ? 1.0 : 3.0f; + + float width = 400*zoom; + float height = 300*zoom; + float screen_x = 0; + float screen_y = 0; + + // center at char but can be moved when mouse is far away + float offx = 0, offy = 0; + int deadzone = 300; + if(mouse_pos.x > deadzone) offx = mouse_pos.x-deadzone; + if(mouse_pos.x <-deadzone) offx = mouse_pos.x+deadzone; + if(mouse_pos.y > deadzone) offy = mouse_pos.y-deadzone; + if(mouse_pos.y <-deadzone) offy = mouse_pos.y+deadzone; + offx = offx*2/3; + offy = offy*2/3; + + screen_x = local_player_pos.x+offx; + screen_y = local_player_pos.y+offy; + + gfx_mapscreen(screen_x-width/2, screen_y-height/2, screen_x+width/2, screen_y+height/2); + + // draw background + gfx_clear(0.65f,0.78f,0.9f); + + { + + vec2 pos(local_player_pos.x*0.5f, local_player_pos.y*0.5f); + + gfx_texture_set(-1); + gfx_blend_additive(); + gfx_quads_begin(); + const int rays = 10; + gfx_quads_setcolor(1.0f,1.0f,1.0f,0.025f); + for(int r = 0; r < rays; r++) + { + float a = r/(float)rays + client_localtime()*0.05f; + float size = (1.0f/(float)rays)*0.25f; + vec2 dir0(sinf((a-size)*pi*2.0f), cosf((a-size)*pi*2.0f)); + vec2 dir1(sinf((a+size)*pi*2.0f), cosf((a+size)*pi*2.0f)); + + //gfx_quads_draw_freeform(0,0, -100,0, -100,-100, 0,-100); + + gfx_quads_setcolorvertex(0, 1.0f,1.0f,1.0f,0.025f); + gfx_quads_setcolorvertex(1, 1.0f,1.0f,1.0f,0.025f); + gfx_quads_setcolorvertex(2, 1.0f,1.0f,1.0f,0.0f); + gfx_quads_setcolorvertex(3, 1.0f,1.0f,1.0f,0.0f); + const float range = 1000.0f; + gfx_quads_draw_freeform( + pos.x+dir0.x, pos.y+dir0.y, + pos.x+dir1.x, pos.y+dir1.y, + pos.x+dir0.x*range, pos.y+dir0.y*range, + pos.x+dir1.x*range, pos.y+dir1.y*range); + } + gfx_quads_end(); + gfx_blend_normal(); + + gfx_texture_set(texture_sun); + gfx_quads_begin(); + gfx_quads_draw(pos.x, pos.y, 256, 256); + gfx_quads_end(); + } + + // render map + tilemap_render(32.0f, 0); +#ifdef _DEBUG + float speed = 0.0f; +#endif + // render items + int num = snap_num_items(SNAP_CURRENT); + for(int i = 0; i < num; i++) + { + snap_item item; + void *data = snap_get_item(SNAP_CURRENT, i, &item); + + if(item.type == OBJTYPE_PLAYER) + { + void *prev = snap_find_item(SNAP_PREV, item.type, item.id); + if(prev) + { + render_player((obj_player *)prev, (obj_player *)data); +/*#ifdef _DEBUG + { + obj_player *p = (obj_player *)prev; + obj_player *c = (obj_player *)data; + vec2 positionold = vec2(p->x, p->y); + vec2 poscur = vec2(c->x, c->y); + speed = distance(positionold,poscur); + } +#endif*/ + } + } + else if(item.type == OBJTYPE_PROJECTILE) + { + void *prev = snap_find_item(SNAP_PREV, item.type, item.id); + if(prev) + render_projectile((obj_projectile *)prev, (obj_projectile *)data); + } + else if(item.type == OBJTYPE_POWERUP) + { + void *prev = snap_find_item(SNAP_PREV, item.type, item.id); + if(prev) + render_powerup((obj_powerup*)prev, (obj_powerup *)data); + } + } + + // render particles + temp_system.update(client_frametime()); + temp_system.render(); + + tilemap_render(32.0f, 1); + + // render health mods + healthmods.render(); + + // render cursor + // FIXME CURSOR!!! + + if(local_player) + { + gfx_texture_set(texture_weapon); + gfx_quads_begin(); + if (local_player->modifier & (1 << MODIFIER_TYPE_NINJA)) + cell_select_ex(numcellsx,numcellsy, modifiertexcoordcursor[MODIFIER_TYPE_NINJA].x, modifiertexcoordcursor[MODIFIER_TYPE_NINJA].y, modifiertexcoordcursor[MODIFIER_TYPE_NINJA].w, modifiertexcoordcursor[MODIFIER_TYPE_NINJA].h); + else + cell_select_ex(numcellsx,numcellsy, weapontexcoordcursor[local_player->weapon].x, weapontexcoordcursor[local_player->weapon].y, weapontexcoordcursor[local_player->weapon].w, weapontexcoordcursor[local_player->weapon].h); + float cursorsize = 64; + gfx_quads_draw(local_player_pos.x+mouse_pos.x, local_player_pos.y+mouse_pos.y,cursorsize,cursorsize); + + + // render ammo count + // render gui stuff + gfx_quads_end(); + gfx_quads_begin(); + gfx_mapscreen(0,0,400,300); + cell_select_ex(numcellsx,numcellsy, weaponprojtexcoord[local_player->weapon].x, weaponprojtexcoord[local_player->weapon].y, weaponprojtexcoord[local_player->weapon].w, weaponprojtexcoord[local_player->weapon].h); + for (int i = 0; i < local_player->ammocount; i++) + { + gfx_quads_drawTL(10+i*12,34,10,10); + } + gfx_quads_end(); + + gfx_texture_set(texture_game); + gfx_quads_begin(); + int h = 0; + cell_select_ex(32,16, 0,0, 4,4); + for(; h < local_player->health; h++) + gfx_quads_drawTL(10+h*12,10,10,10); + + cell_select_ex(32,16, 5,0, 4,4); + for(; h < 10; h++) + gfx_quads_drawTL(10+h*12,10,10,10); + + h = 0; + cell_select_ex(32,16, 0,5, 4,4); + for(; h < local_player->armor; h++) + gfx_quads_drawTL(10+h*12,22,10,10); + + cell_select_ex(32,16, 5,5, 4,4); + for(; h < 10; h++) + gfx_quads_drawTL(10+h*12,22,10,10); + gfx_quads_end(); + + // render speed +/*#ifdef _DEBUG + gfx_texture_set(font_texture); + char text[256]; + sprintf(text,"speed: %f",speed); + gfx_quads_text(300,20,10,text); +#endif*/ + } + // render gui stuff + gfx_mapscreen(0,0,400,300); + // render score board + if(inp_key_pressed(baselib::keys::tab)) + { + gfx_texture_set(font_texture); + gfx_quads_text(10, 50, 8, "Score Board"); + + int num = snap_num_items(SNAP_CURRENT); + int row = 1; + for(int i = 0; i < num; i++) + { + snap_item item; + void *data = snap_get_item(SNAP_CURRENT, i, &item); + + if(item.type == OBJTYPE_PLAYER) + { + obj_player *player = (obj_player *)data; + if(player) + { + char buf[128]; + char name[32]; + snap_decode_string(player->name, name, 32); + sprintf(buf, "%4d %s", player->score, name); + gfx_quads_text(10, 50 + 10 * row, 8, buf); + row++; + } + } + } + } +} diff --git a/src/game/client/mapres_image.cpp b/src/game/client/mapres_image.cpp new file mode 100644 index 00000000..1c81b309 --- /dev/null +++ b/src/game/client/mapres_image.cpp @@ -0,0 +1,41 @@ +#include +#include "../../engine/interface.h" +#include "mapres_image.h" +#include "../mapres.h" + +static int map_textures[64] = {0}; +static int count = 0; + +int img_init() +{ + int start, count; + map_get_type(MAPRES_IMAGE, &start, &count); + dbg_msg("mapres_image", "start=%d count=%d", start, count); + for(int i = 0; i < 64; i++) + { + if(map_textures[i]) + { + gfx_unload_texture(map_textures[i]); + map_textures[i] = 0; + } + } + + for(int i = 0; i < count; i++) + { + mapres_image *img = (mapres_image *)map_get_item(start+i, 0, 0); + void *data = map_get_data(img->image_data); + map_textures[i] = gfx_load_texture_raw(img->width, img->height, data); + } + + return count; +} + +int img_num() +{ + return count; +} + +int img_get(int index) +{ + return map_textures[index]; +} diff --git a/src/game/client/mapres_image.h b/src/game/client/mapres_image.h new file mode 100644 index 00000000..eab1559a --- /dev/null +++ b/src/game/client/mapres_image.h @@ -0,0 +1,18 @@ + +// loads images from the map to textures +int img_init(); + +// returns the number of images in the map +int img_num(); + +// fetches the texture id for the image +int img_get(int index); + + +class mapres_image +{ +public: + int width; + int height; + int image_data; +}; diff --git a/src/game/client/mapres_tilemap.cpp b/src/game/client/mapres_tilemap.cpp new file mode 100644 index 00000000..36302d0a --- /dev/null +++ b/src/game/client/mapres_tilemap.cpp @@ -0,0 +1,54 @@ +#include "../../engine/interface.h" +#include "mapres_tilemap.h" +#include "mapres_image.h" +#include "../mapres.h" + +int tilemap_init() +{ + return 0; +} + +void tilemap_render(float scale, int fg) +{ + if(!map_is_loaded()) + return; + + // fetch indecies + int start, num; + map_get_type(MAPRES_TILEMAP, &start, &num); + + // render tilemaps + int passed_main = 0; + for(int t = 0; t < num; t++) + { + mapres_tilemap *tmap = (mapres_tilemap *)map_get_item(start+t,0,0); + unsigned char *data = (unsigned char *)map_get_data(tmap->data); + + if(tmap->main) + passed_main = 1; + + if((fg && passed_main) || (!fg && !passed_main)) + { + gfx_texture_set(img_get(tmap->image)); + gfx_quads_begin(); + + int c = 0; + float frac = (1.0f/1024.0f); //2.0f; + for(int y = 0; y < tmap->height; y++) + for(int x = 0; x < tmap->width; x++, c++) + { + unsigned char d = data[c*2]; + if(d) + { + gfx_quads_setsubset( + (d%16)/16.0f+frac, + (d/16)/16.0f+frac, + (d%16)/16.0f+1.0f/16.0f-frac, + (d/16)/16.0f+1.0f/16.0f-frac); + gfx_quads_drawTL(x*scale, y*scale, scale, scale); + } + } + gfx_quads_end(); + } + } +} diff --git a/src/game/client/mapres_tilemap.h b/src/game/client/mapres_tilemap.h new file mode 100644 index 00000000..6e9d81be --- /dev/null +++ b/src/game/client/mapres_tilemap.h @@ -0,0 +1,19 @@ + +// dependencies: image + +// +int tilemap_init(); + +// renders the tilemaps +void tilemap_render(float scale, int fg); + +struct mapres_tilemap +{ + int image; + int width; + int height; + int x, y; + int scale; + int data; + int main; +}; diff --git a/src/game/client/menu.cpp b/src/game/client/menu.cpp new file mode 100644 index 00000000..88c87526 --- /dev/null +++ b/src/game/client/menu.cpp @@ -0,0 +1,600 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include "../mapres.h" + +#include +#include "mapres_image.h" +#include "mapres_tilemap.h" + +using namespace baselib; + +/******************************************************** + MENU +*********************************************************/ + +struct pretty_font +{ + char m_CharStartTable[256]; + char m_CharEndTable[256]; + int font_texture; +}; + +extern pretty_font *current_font; +void gfx_pretty_text(float x, float y, float size, const char *text); +float gfx_pretty_text_width(float size, const char *text); + +void draw_scrolling_background(int id, float w, float h, float t) +{ + float tx = w/256.0f; + float ty = h/256.0f; + + float start_x = fmod(t, 1.0f); + float start_y = 1.0f - fmod(t*0.8f, 1.0f); + + gfx_blend_normal(); + gfx_texture_set(id); + gfx_quads_begin(); + gfx_quads_setcolor(1,1,1,1); + gfx_quads_setsubset( + start_x, // startx + start_y, // starty + start_x+tx, // endx + start_y+ty); // endy + gfx_quads_drawTL(0.0f,0.0f,w,h); + gfx_quads_end(); +} + +int background_texture; +int not_empty_item_texture; +int empty_item_texture; +int active_item_texture; +int selected_item_texture; +int join_button_texture; +int join_button_hot_texture; +int join_button_active_texture; +int join_button_grey_texture; +int quit_button_texture; +int quit_button_hot_texture; +int quit_button_active_texture; +int up_button_texture; +int up_button_active_texture; +int down_button_texture; +int down_button_active_texture; +int teewars_banner_texture; +int scroll_indicator_texture; +int connect_localhost_texture; +int refresh_button_texture; +int refresh_button_hot_texture; +int refresh_button_active_texture; +int input_box_texture; + +int music_menu; +int music_menu_id = -1; + +struct button_textures +{ + int *normal_texture; + int *hot_texture; + int *active_texture; +}; + +button_textures connect_localhost_button = { &connect_localhost_texture, &connect_localhost_texture, &connect_localhost_texture }; +button_textures join_button = { &join_button_texture, &join_button_hot_texture, &join_button_active_texture }; +button_textures quit_button = { &quit_button_texture, &quit_button_hot_texture, &quit_button_active_texture }; +button_textures scroll_up_button = { &up_button_texture, &up_button_texture, &up_button_active_texture }; +button_textures scroll_down_button = { &down_button_texture, &down_button_texture, &down_button_active_texture }; +button_textures list_item_button = { ¬_empty_item_texture, &active_item_texture, &active_item_texture }; +button_textures selected_item_button = { &selected_item_texture, &selected_item_texture, &selected_item_texture }; +button_textures refresh_button = { &refresh_button_texture, &refresh_button_hot_texture, &refresh_button_active_texture }; + +void draw_menu_button(void *id, const char *text, int checked, float x, float y, float w, float h, void *extra) +{ + button_textures *tx = (button_textures *)extra; + + gfx_blend_normal(); + + if (ui_active_item() == id && ui_hot_item() == id) + gfx_texture_set(*tx->active_texture); + else if (ui_hot_item() == id) + gfx_texture_set(*tx->hot_texture); + else + gfx_texture_set(*tx->normal_texture); + + gfx_quads_begin(); + + gfx_quads_setcolor(1,1,1,1); + + gfx_quads_drawTL(x,y,w,h); + gfx_quads_end(); + + gfx_texture_set(current_font->font_texture); + gfx_pretty_text(x + 4, y - 3.5f, 18.f, text); +} + +void draw_image_button(void *id, const char *text, int checked, float x, float y, float w, float h, void *extra) +{ + ui_do_image(*(int *)id, x, y, w, h); +} + +struct server_info +{ + int version; + int players; + int max_players; + netaddr4 address; + char name[129]; + char map[65]; +}; + +struct server_list +{ + server_info infos[10]; + int active_count, info_count; + int scroll_index; + int selected_index; +}; +#include + +int ui_do_edit_box(void *id, float x, float y, float w, float h, char *str, int str_size) +{ + int inside = ui_mouse_inside(x, y, w, h); + int r = 0; + + if(inside) + { + ui_set_hot_item(id); + + if(ui_mouse_button(0)) + ui_set_active_item(id); + } + + if (ui_active_item() == id) + { + char c = keys::last_char(); + int k = keys::last_key(); + int len = strlen(str); + + if (c >= 32 && c < 128) + { + if (len < str_size - 1) + { + str[len] = c; + str[len+1] = 0; + } + } + + if (k == keys::backspace) + { + if (len > 0) + str[len-1] = 0; + } + r = 1; + } + + ui_do_label(x + 4, y - 3.5f, str); + + if (ui_active_item() == id) + { + float w = gfx_pretty_text_width(18.0f, str); + ui_do_label(x + 4 + w, y - 3.5f, "_"); + } + + return r; +} + +int do_scroll_bar(void *id, float x, float y, float height, int steps, int last_index) +{ + int r = last_index; + + if (ui_do_button(&up_button_texture, "", 0, x, y, 8, 8, draw_menu_button, &scroll_up_button)) + { + if (r > 0) + --r; + } + else if (ui_do_button(&down_button_texture, "", 0, x, y + height - 8, 8, 8, draw_menu_button, &scroll_down_button)) + { + if (r < steps) + ++r; + } + else if (steps > 0) // only if there's actually stuff to scroll through + { + int inside = ui_mouse_inside(x, y + 8, 8, height - 16); + if (inside && (!ui_active_item() || ui_active_item() == id)) + ui_set_hot_item(id); + + if(ui_active_item() == id) + { + if (ui_mouse_button(0)) + { + float pos = ui_mouse_y() - y - 8; + float perc = pos / (height - 16); + + r = (steps + 1) * perc; + if (r < 0) + r = 0; + else if (r > steps) + r = steps; + } + else + ui_set_active_item(0); + } + else if (ui_hot_item() == id && ui_mouse_button(0)) + ui_set_active_item(id); + else if (inside && (!ui_active_item() || ui_active_item() == id)) + ui_set_hot_item(id); + } + + ui_do_image(scroll_indicator_texture, x, y + 8 + r * ((height - 32) / steps), 8, 16); + + return r; +} + +int do_server_list(server_list *list, float x, float y, int visible_items) +{ + const float spacing = 1.5f; + const float item_height = 14; + const float item_width = 364; + const float real_width = item_width + 10; + const float real_height = item_height * visible_items + spacing * (visible_items - 1); + + int r = -1; + + for (int i = 0; i < visible_items; i++) + { + int item_index = i + list->scroll_index; + if (item_index >= list->active_count) + ui_do_image(empty_item_texture, x, y + i * item_height + i * spacing, item_width, item_height); + else + { + server_info *item = &list->infos[item_index]; + + bool clicked = false; + if (list->selected_index == item_index) + clicked = ui_do_button(item, item->name, 0, x, y + i * item_height + i * spacing, item_width, item_height, draw_menu_button, &selected_item_button); + else + clicked = ui_do_button(item, item->name, 0, x, y + i * item_height + i * spacing, item_width, item_height, draw_menu_button, &list_item_button); + + char temp[64]; // plenty of extra room so we don't get sad :o + sprintf(temp, "%i/%i", item->players, item->max_players); + + gfx_texture_set(current_font->font_texture); + gfx_pretty_text(x + 300, y + i * item_height + i * spacing - 3.5f, 18.f, temp); + gfx_pretty_text(x + 180, y + i * item_height + i * spacing - 3.5f, 18.f, item->map); + + if (clicked) + { + r = item_index; + list->selected_index = item_index; + } + } + } + + list->scroll_index = do_scroll_bar(&list->scroll_index, x + real_width - 8, y, real_height, list->active_count - visible_items, list->scroll_index); + + return r; +} + +#include + +char *read_int(char *buffer, int *value) +{ + *value = buffer[0] << 24; + *value |= buffer[1] << 16; + *value |= buffer[2] << 8; + *value |= buffer[3]; + + return buffer + 4; +} + +char *read_netaddr(char *buffer, netaddr4 *addr) +{ + addr->ip[0] = *buffer++; + addr->ip[1] = *buffer++; + addr->ip[2] = *buffer++; + addr->ip[3] = *buffer++; + + int port; + buffer = read_int(buffer, &port); + + addr->port = port; + + return buffer; +} + +void refresh_list(server_list *list) +{ + netaddr4 addr; + netaddr4 me(0, 0, 0, 0, 0); + + list->selected_index = -1; + + if (net_host_lookup(MASTER_SERVER_ADDRESS, MASTER_SERVER_PORT, &addr) == 0) + { + socket_tcp4 sock; + sock.open(&me); + + //sock.set_non_blocking(); + + // try and connect with a timeout of 1 second + if (sock.connect_non_blocking(&addr)) + { + char data[256]; + int total_received = 0; + int pointer = 0; + int received; + + int master_server_version = -1; + int server_count = -1; + + // read header + while (total_received < 12 && (received = sock.recv(data + total_received, 12 - total_received)) > 0) + total_received += received; + + // see if we have the header + if (total_received == 12) + { + int signature; + read_int(data, &signature); + + // check signature + if (signature == 'TWSL') + { + read_int(data + 4, &master_server_version); + read_int(data + 8, &server_count); + + // TODO: handle master server version O.o + + const int server_info_size = 212; + const int wanted_data_count = server_count * server_info_size; + + list->active_count = 0; + + for (int i = 0; i < server_count; i++) + { + total_received = 0; + + // read data for a server + while (sock.is_connected() && total_received < server_info_size && (received = sock.recv(data + total_received, server_info_size - total_received)) > 0) + total_received += received; + + // check if we got enough data + if (total_received == server_info_size) + { + char *d = data; + + server_info *info = &list->infos[i]; + + d = read_int(d, &info->version); + d = read_netaddr(d, &info->address); + + //dbg_msg("menu/got_serverinfo", "IP: %i.%i.%i.%i:%i", (int)info->address.ip[0], (int)info->address.ip[1], (int)info->address.ip[2], (int)info->address.ip[3], info->address.port); + + d = read_int(d, &info->players); + d = read_int(d, &info->max_players); + memcpy(info->name, d, 128); + d += 128; + memcpy(info->map, d, 64); + + // let's be safe. + info->name[128] = 0; + info->map[64] = 0; + + ++list->active_count; + } + else + break; + } + + if (list->scroll_index >= list->active_count) + list->scroll_index = list->active_count - 1; + + if (list->scroll_index < 0) + list->scroll_index = 0; + } + } + + sock.close(); + } + } +} + +static int menu_render(netaddr4 *server_address, char *str, int max_len) +{ + // background color + gfx_clear(89/255.f,122/255.f,0.0); + + // GRADIENT: top to bottom + // top color: 60, 80, 0 + // bottom color: 90, 120, 0 + + // world coordsys + float zoom = 3.0f; + gfx_mapscreen(0,0,400.0f*zoom,300.0f*zoom); + + // GUI coordsys + gfx_mapscreen(0,0,400.0f,300.0f); + + static server_list list; + static bool inited = false; + + if (!inited) + { + list.info_count = 256; + + list.scroll_index = 0; + list.selected_index = -1; + + inited = true; + + refresh_list(&list); + } + + static int64 start = time_get(); + + float t = double(time_get() - start) / double(time_freq()); + draw_scrolling_background(background_texture, 400, 300, t * 0.01); + + ui_do_image(teewars_banner_texture, 70, 10, 256, 64); + + do_server_list(&list, 10, 80, 8); + + /* + if (ui_do_button(&connect_localhost_button, "", 0, 15, 250, 64, 24, draw_menu_button, &connect_localhost_button)) + { + *server_address = netaddr4(127, 0, 0, 1, 8303); + return 1; + }*/ + + if (ui_do_button(&refresh_button, "", 0, 220, 210, 64, 24, draw_menu_button, &refresh_button)) + { + refresh_list(&list); + } + + if (list.selected_index == -1) + { + ui_do_image(join_button_grey_texture, 290, 210, 64, 24); + } + else if (ui_do_button(&join_button, "", 0, 290, 210, 64, 24, draw_menu_button, &join_button)) + { + *server_address = list.infos[list.selected_index].address; + + dbg_msg("menu/join_button", "IP: %i.%i.%i.%i:%i", (int)server_address->ip[0], (int)server_address->ip[1], (int)server_address->ip[2], (int)server_address->ip[3], server_address->port); + + return 1; + } + + const float name_x = 10, name_y = 215; + + ui_do_label(name_x + 4, name_y - 3.5f, "Name:"); + ui_do_image(input_box_texture, name_x + 50 - 5, name_y - 5, 150 + 10, 14 + 10); + ui_do_edit_box(str, name_x + 50, name_y, 150, 14, str, max_len); + + if (ui_do_button(&quit_button, "", 0, 290, 250, 69, 25, draw_menu_button, &quit_button)) + return -1; + + ui_do_label(10.0f, 300.0f-20.0f, "Version: " TEEWARS_VERSION); + + return 0; +} + +void modmenu_init() +{ + keys::enable_char_cache(); + keys::enable_key_cache(); + + current_font->font_texture = gfx_load_texture_tga("data/big_font.tga"); + background_texture = gfx_load_texture_tga("data/gui_bg.tga"); + not_empty_item_texture = gfx_load_texture_tga("data/gui/game_list_item_not_empty.tga"); + empty_item_texture = gfx_load_texture_tga("data/gui/game_list_item_empty.tga"); + active_item_texture = gfx_load_texture_tga("data/gui/game_list_item_active.tga"); + selected_item_texture = gfx_load_texture_tga("data/gui/game_list_item_selected.tga"); + + join_button_texture = gfx_load_texture_tga("data/gui/join_button.tga"); + join_button_hot_texture = gfx_load_texture_tga("data/gui/join_button_hot.tga"); + join_button_active_texture = gfx_load_texture_tga("data/gui/join_button_active.tga"); + join_button_grey_texture = gfx_load_texture_tga("data/gui/join_button_greyed.tga"); + + +// button_not_hilighted_texture = gfx_load_texture_tga("data/gui/game_list_join_button.tga"); +// button_hilighted_texture = gfx_load_texture_tga("data/gui/button_hilighted.tga"); +// button_active_texture = gfx_load_texture_tga("data/gui/button_active.tga"); + + quit_button_texture = gfx_load_texture_tga("data/gui/quit_button.tga"); + quit_button_hot_texture = gfx_load_texture_tga("data/gui/quit_button_hot.tga"); + quit_button_active_texture = gfx_load_texture_tga("data/gui/quit_button_active.tga"); + + up_button_texture = gfx_load_texture_tga("data/gui/scroll_arrow_up.tga"); + up_button_active_texture = gfx_load_texture_tga("data/gui/scroll_arrow_up_active.tga"); + + down_button_texture = gfx_load_texture_tga("data/gui/scroll_arrow_down.tga"); + down_button_active_texture = gfx_load_texture_tga("data/gui/scroll_arrow_down_active.tga"); + + teewars_banner_texture = gfx_load_texture_tga("data/gui_logo.tga"); + scroll_indicator_texture = gfx_load_texture_tga("data/gui/scroll_drag.tga"); + connect_localhost_texture = gfx_load_texture_tga("data/gui/game_list_connect_localhost.tga"); + + refresh_button_texture = gfx_load_texture_tga("data/gui/refresh_button.tga"); + refresh_button_hot_texture = gfx_load_texture_tga("data/gui/refresh_button_hot.tga"); + refresh_button_active_texture = gfx_load_texture_tga("data/gui/refresh_button_active.tga"); + + input_box_texture = gfx_load_texture_tga("data/gui/input_box.tga"); + + music_menu = snd_load_wav("data/audio/Music_Menu.wav"); +} + +void modmenu_shutdown() +{ +} + +int modmenu_render(void *ptr, char *str, int max_len) +{ + static int mouse_x = 0; + static int mouse_y = 0; + + if (music_menu_id == -1) + { + dbg_msg("menu", "no music is playing, so let's play some tunes!"); + music_menu_id = snd_play(music_menu, SND_LOOP); + } + + netaddr4 *server_address = (netaddr4 *)ptr; + + // handle mouse movement + float mx, my, mwx, mwy; + { + int rx, ry; + inp_mouse_relative(&rx, &ry); + mouse_x += rx; + mouse_y += ry; + if(mouse_x < 0) mouse_x = 0; + if(mouse_y < 0) mouse_y = 0; + if(mouse_x > gfx_screenwidth()) mouse_x = gfx_screenwidth(); + if(mouse_y > gfx_screenheight()) mouse_y = gfx_screenheight(); + + // update the ui + mx = (mouse_x/(float)gfx_screenwidth())*400.0f; + my = (mouse_y/(float)gfx_screenheight())*300.0f; + mwx = mx*3.0f; // adjust to zoom and offset + mwy = mx*3.0f; // adjust to zoom and offset + + int buttons = 0; + if(inp_mouse_button_pressed(0)) buttons |= 1; + if(inp_mouse_button_pressed(1)) buttons |= 2; + if(inp_mouse_button_pressed(2)) buttons |= 4; + + ui_update(mx,my,mx*3.0f,my*3.0f,buttons); + } + + int r = menu_render(server_address, str, max_len); + + // render butt ugly mouse cursor + gfx_texture_set(-1); + gfx_quads_begin(); + gfx_quads_setcolor(0,0,0,1); + gfx_quads_draw_freeform(mx,my,mx,my, + mx+7,my, + mx,my+7); + gfx_quads_setcolor(1,1,1,1); + gfx_quads_draw_freeform(mx+1,my+1,mx+1,my+1, + mx+5,my+1, + mx+1,my+5); + gfx_quads_end(); + + if (r) + { + snd_stop(music_menu_id); + music_menu_id = -1; + } + + keys::clear_char(); + keys::clear_key(); + + return r; +} diff --git a/src/game/game.h b/src/game/game.h index a1817eea..2696b74d 100644 --- a/src/game/game.h +++ b/src/game/game.h @@ -1,7 +1,7 @@ #include #include #include -#include "../interface.h" +#include "../engine/interface.h" #include "mapres_col.h" // Don't tweak :) diff --git a/src/game/game_client.cpp b/src/game/game_client.cpp deleted file mode 100644 index 8bbdf0b3..00000000 --- a/src/game/game_client.cpp +++ /dev/null @@ -1,1993 +0,0 @@ -#include -#include -#include "game.h" -#include "mapres_image.h" -#include "mapres_tilemap.h" - -using namespace baselib; - -static int texture_char_default = 0; -static int texture_game = 0; -static int texture_weapon = 0; -static int texture_sun = 0; -static int texture_particles = 0; - -struct weapontexcell -{ - float x; - float y; - float w; - float h; -}; -struct renderparams -{ - float sizex; - float sizey; - float offsetx; - float offsety; -}; -int numcellsx = 32; -int numcellsy = 32; -renderparams weaponrenderparams[WEAPON_NUMWEAPONS]; -renderparams modifierrenderparams[WEAPON_NUMWEAPONS]; - -weapontexcell weaponprojtexcoord[WEAPON_NUMWEAPONS]; -weapontexcell weapontexcoord[WEAPON_NUMWEAPONS]; -weapontexcell weapontexcoordcursor[WEAPON_NUMWEAPONS]; - -weapontexcell poweruptexcoord[POWERUP_TYPE_NUMPOWERUPS]; - -weapontexcell modifiertexcoord[MODIFIER_NUMMODIFIERS]; -weapontexcell modifiertexcoordcursor[MODIFIER_NUMMODIFIERS]; - -int nummuzzletex[WEAPON_NUMWEAPONS]; -weapontexcell muzzletexcoord[WEAPON_NUMWEAPONS][3]; -renderparams muzzleparams[WEAPON_NUMWEAPONS]; - -#define NUMHADOKENS 6 -#define NUMSTARS 2 -#define NUMPARTICLES 9 -int particlesnumcellsx = 16; -int particlesnumcellsy = 16; -weapontexcell chaintexcoord; -weapontexcell chainheadtexcoord; -weapontexcell stars[NUMSTARS]; - -float lifemodifier[NUMPARTICLES]; -vec4 particlecolors[NUMPARTICLES]; -weapontexcell particlestexcoord[NUMPARTICLES]; - -int charnumcellsx = 8; -int charnumcellsy = 32; -int charoffsety = 2; -weapontexcell body[2]; -weapontexcell leye; -weapontexcell reye; -weapontexcell feet[2]; - -int charids[16] = { 2,10,0,4,12,6,14,1,9,15,13,11,7,5,8,3 }; - -renderparams hadokenparams[6]; -weapontexcell hadoken[6]; - -float recoils[WEAPON_NUMWEAPONS] = { 10.0f, 10.0f, 10.0f, 10.0f }; - -static int font_texture = 0; -static vec2 mouse_pos; - - -static vec2 local_player_pos; -static obj_player *local_player; - -float frandom() -{ - return rand()/(float)(RAND_MAX); -} - -float sign(float f) -{ - return f<0.0f?-1.0f:1.0f; -} - -// sound helpers -template -class sound_kit -{ -private: - int sounds[N]; - int last_id; -public: - sound_kit() : last_id(-1) { } - - int& operator[](int id) { return sounds[id]; } - - inline void play_random(float vol = 1.0f, float pan = 0.0f); -}; - -template<> -inline void sound_kit<1>::play_random(float vol, float pan) -{ - snd_play(sounds[0], SND_PLAY_ONCE, vol, pan); -} - -template -inline void sound_kit::play_random(float vol, float pan) -{ - int id; - do { - id = rand() % N; - } while(id == last_id); - snd_play(sounds[id], SND_PLAY_ONCE, vol, pan); - last_id = id; -} - - -// sound volume tweak -static const float stereo_separation = 0.01f; -static const float stereo_separation_deadzone = 512.0f; -static const float volume_distance_falloff = 100.0f; -static const float volume_distance_deadzone = 512.0f; -static const float volume_gun = 0.5f; -static const float volume_tee = 0.5f; -static const float volume_hit = 0.5f; -static const float volume_music = 0.8f; - -// sounds -sound_kit<3> sound_gun_fire; -sound_kit<3> sound_shotty_fire; -sound_kit<3> sound_flump_launch; -sound_kit<3> sound_hammer_swing; -sound_kit<3> sound_ninja_attack; - -sound_kit<3> sound_flump_explode; -sound_kit<4> sound_ninja_hit; - -sound_kit<3> sound_weapon_switch; - -sound_kit<12> sound_pain_short; -sound_kit<2> sound_pain_long; - -sound_kit<4> sound_body_jump; -sound_kit<4> sound_body_land; -sound_kit<2> sound_body_splat; - -sound_kit<7> sound_spawn; -sound_kit<2> sound_tee_cry; - -sound_kit<1> sound_hook_loop; -sound_kit<3> sound_hook_attach; - -void sound_vol_pan(const vec2& p, float *vol, float *pan) -{ - vec2 player_to_ev = p - local_player_pos; - *pan = 0.0f; - *vol = 1.0f; - - if(abs(player_to_ev.x) > stereo_separation_deadzone) - { - *pan = stereo_separation * (player_to_ev.x - sign(player_to_ev.x)*stereo_separation_deadzone); - if(*pan < -1.0f) *pan = -1.0f; - if(*pan > 1.0f) *pan = 1.0f; - } - - float len = length(player_to_ev); - if(len > volume_distance_deadzone) - { - *vol = volume_distance_falloff / (len - volume_distance_deadzone); - - if(*vol < 0.0f) *vol = 0.0f; - if(*vol > 1.0f) *vol = 1.0f; - } -} - -// TODO: we should do something nicer then this -static void cell_select_ex(int cx, int cy, float x, float y, float w, float h) -{ - gfx_quads_setsubset(x/(float)cx,y/(float)cy,(x+w)/(float)cx,(y+h)/(float)cy); -} - -static void cell_select_ex_flip_x(int cx, int cy, float x, float y, float w, float h) -{ - gfx_quads_setsubset((x+w)/(float)cx,y/(float)cy,x /(float)cx,(y+h)/(float)cy); -} - -static void cell_select_ex_flip_y(int cx, int cy, float x, float y, float w, float h) -{ - gfx_quads_setsubset(x/(float)cx,(y+h)/(float)cy,(x+w)/(float)cx,y/(float)cy); -} - -static void cell_select(int x, int y, int w, int h) -{ - gfx_quads_setsubset(x/16.0f,y/16.0f,(x+w)/16.0f,(y+h)/16.0f); -} - -inline void cell_select_flip_x(int x, int y, int w, int h) -{ - gfx_quads_setsubset((x+w)/16.0f,y/16.0f,(x)/16.0f,(y+h)/16.0f); -} - -inline void cell_select_flip_y(int x, int y, int w, int h) -{ - gfx_quads_setsubset(x/16.0f,(y+h)/16.0f,(x+w)/16.0f,(y)/16.0f); -} - -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; -}; - -void move_point(vec2 *inout_pos, vec2 *inout_vel, float elasticity) -{ - vec2 pos = *inout_pos; - vec2 vel = *inout_vel; - if(col_check_point(pos + vel)) - { - int affected = 0; - if(col_check_point(pos.x + vel.x, pos.y)) - { - inout_vel->x *= -elasticity; - affected++; - } - - if(col_check_point(pos.x, pos.y + vel.y)) - { - inout_vel->y *= -elasticity; - affected++; - } - - if(affected == 0) - { - inout_vel->x *= -elasticity; - inout_vel->y *= -elasticity; - } - } - else - { - *inout_pos = pos + vel; - } -} - -class health_texts -{ -public: - int64 lastupdate; - struct item - { - vec2 pos; - vec2 vel; - int amount; - int istar; - float life; - float startangle; - }; - - enum - { - MAX_ITEMS=16, - }; - - health_texts() - { - lastupdate = 0; - } - - item items[MAX_ITEMS]; - int num_items; - - item *create_i() - { - if (num_items < MAX_ITEMS) - { - item *p = &items[num_items]; - num_items++; - return p; - } - return 0; - } - - void destroy_i(item *i) - { - num_items--; - *i = items[num_items]; - } - - void create(vec2 pos, int amount) - { - amount = max(1,amount); - for (int j = 0; j < amount; j++) - { - float a = j/(float)amount-0.5f; - item *i = create_i(); - if (i) - { - i->pos = pos; - i->pos.y -= 20.0f; - i->pos.x += ((float)rand()/(float)RAND_MAX) * 5.0f; - i->amount = amount; - i->life = 1.5f; - i->istar = rand() % NUMSTARS; - i->vel = vec2(((float)rand()/(float)RAND_MAX) * 50.0f,-150.0f); - i->startangle = (( (float)rand()/(float)RAND_MAX) - 1.0f) * 2.0f * pi; - } - } - } - - void render() - { - if (!lastupdate) - lastupdate = time_get(); - - int64 lasttime = lastupdate; - lastupdate = time_get(); - - float delta = (float) (lastupdate - lasttime) / (float)time_freq(); - gfx_texture_set(texture_particles); - gfx_quads_begin(); - for(int i = 0; i < num_items;) - { - items[i].vel += vec2(0,500.0f) * delta; - items[i].pos += items[i].vel * delta; - items[i].life -= delta; - //items[i].pos.y -= frametime*15.0f; - if(items[i].life < 0.0f) - destroy_i(&items[i]); - else - { - gfx_quads_setcolor(1.0f,1.0f,1.0f, items[i].life / 1.5f); - gfx_quads_setrotation(items[i].startangle + items[i].life * 2.0f); - float size = 64.0f; - cell_select_ex(particlesnumcellsx,particlesnumcellsy, stars[items[i].istar].x,stars[items[i].istar].y, stars[items[i].istar].w, stars[items[i].istar].h); - gfx_quads_draw(items[i].pos.x-size/2, items[i].pos.y-size/2, size, size); - /*char buf[32]; - if(items[i].amount < 0) - { - sprintf(buf, "%d", items[i].amount*-1); - } - else - { - sprintf(buf, "%d", items[i].amount); - } - float size = 42.0f; - if(items[i].life > 1.25f) - size += 42.0f * ((items[i].life - 1.25f) * 4); - gfx_quads_text(items[i].pos.x-size/2, items[i].pos.y, size, buf);*/ - i++; - } - } - gfx_quads_end(); - } - -}; - -/*class texture_animator -{ -public: - - int texture; - int numframes; - float duration; - float* framereltime; - weapontexcell* params; - texture_animator() - { - texture = -1; - numframes = 0; - duration = 0; - framereltime = 0; - params = 0; - } - - ~texture_animator() - { - if (params) - mem_free(params); - if (framereltime) - mem_free(framereltime); - } - - void create_anim(int texture, int numframes, float duration) - { - framereltime = 0; - params = 0; - this->texture = texture; - this->numframes = numframes; - this->duration = duration; - if (numframes) - { - framereltime = (float*)mem_alloc(sizeof(float) * numframes,1); - params = (weapontexcell*)mem_alloc(sizeof(renderparams) * numframes,1); - float delta = 1.0f / (float)(numframes - 1); - for (int i = 0; i < numframes; i++) - { - framereltime[i] = delta * i; - } - } - } - - static void create_gunmuzzle(texture_animator& anim, int texture, float duration) - { - anim.create_anim(texture, 3, duration); - anim.params[0].x = 8; - anim.params[0].y = 4; - anim.params[0].w = 3; - anim.params[0].h = 2; - anim.params[1].x = 12; - anim.params[1].y = 4; - anim.params[1].w = 3; - anim.params[1].h = 2; - anim.params[2].x = 16; - anim.params[2].y = 4; - anim.params[2].w = 3; - anim.params[2].h = 2; - } - - static void create_shotgunmuzzle() - { - - } -};*/ - -class keyframe -{ -public: - vec2 pos; - float angle; - float relativetime; -}; - -class anim -{ -public: - keyframe* keyframes; - int numframes; - float duration; - anim() - { - numframes = 0; - keyframes = 0; - } - ~anim() - { - if (keyframes) - mem_free(keyframes); - } - - void create_anim(int numframes, float duration) - { - if (keyframes) - mem_free(keyframes); - - this->numframes = numframes; - this->duration = duration; - keyframes = (keyframe*)mem_alloc(sizeof(keyframe) * numframes,1); - float delta = 1.0f / (float) (numframes - 1); - for (int i = 0; i < numframes; i++) - { - keyframes[i].pos = vec2(0.0f,0.0f); - keyframes[i].angle = 0; - keyframes[i].relativetime = delta * (float)i; - } - } - - void getframes(float relativetime, keyframe*& frame1, keyframe*& frame2, float& blend) - { - for (int i = 1; i < numframes; i++) - { - if (keyframes[i-1].relativetime <= relativetime && keyframes[i].relativetime >= relativetime) - { - frame1 = &keyframes[i-1]; - frame2 = &keyframes[i]; - blend = (relativetime - frame1->relativetime) / (frame2->relativetime - frame1->relativetime); - } - } - } - - void evalanim(float time, vec2& pos, float& angle) - { - float reltime = max(0.0f, min(1.0f, time / duration)); - keyframe* frame1 = 0; - keyframe* frame2 = 0; - float blend = 0.0f; - getframes(reltime, frame1, frame2, blend); - - if (frame1 && frame2) - { - pos = mix(frame1->pos, frame2->pos, blend); - angle = LERP(frame1->angle, frame2->angle, blend); - } - } - - static void setup_hammer(anim& hammeranim) - { - // straight up = -0.25 - // frame0 = standard pose time 0 - // frame1 = back a little time 0.3 - // frame2 = over head time 0.4 - // frame3 = on ground smashed time 0.5 - // frame4 = back to standard pose time 1.0 - hammeranim.create_anim(5, 1.0f); - // only angles... (for now...) - hammeranim.keyframes[0].angle = -0.35f * pi * 2.0f; - hammeranim.keyframes[1].angle = -0.4f * pi * 2.0f; - hammeranim.keyframes[1].relativetime = 0.3f; - hammeranim.keyframes[2].angle = -0.25f; - hammeranim.keyframes[2].relativetime = 0.4f; - hammeranim.keyframes[3].angle = 0.0f * pi * 2.0f; - hammeranim.keyframes[3].relativetime = 0.5f; - hammeranim.keyframes[4].angle = -0.35f * pi * 2.0f; - hammeranim.keyframes[4].relativetime = 1.0f; - } - - static void setup_ninja(anim& ninjanim) - { - // (straight up = -0.25) - // frame0 = standard pose straight back time 0.0 - // frame1 = overhead attack frame 1 time 0.1 - // frame2 = attack end frame time 0.15 - // frame3 = attack hold frame (a bit up) time 0.4 - // frame4 = attack hold frame end time 0.7 - // frame5 = endframe time 1.0 - ninjanim.create_anim(6, 1.0f); - // only angles... (for now...) - ninjanim.keyframes[0].angle = -0.5f * pi * 2.0f; - - ninjanim.keyframes[1].angle = -0.3f * pi * 2.0f; - ninjanim.keyframes[1].relativetime = 0.1f; - - ninjanim.keyframes[2].angle = 0.1f * pi * 2.0f; - ninjanim.keyframes[2].relativetime = 0.15f; - - ninjanim.keyframes[3].angle = -0.05f * pi * 2.0f; - ninjanim.keyframes[3].relativetime = 0.42; - - ninjanim.keyframes[4].angle = -0.05f * pi * 2.0f; - ninjanim.keyframes[4].relativetime = 0.5f; - - ninjanim.keyframes[5].angle = -0.5f * pi * 2.0f; - ninjanim.keyframes[5].relativetime = 1.0f; - } -}; - -static anim hammeranim; -static anim ninjaanim; -static health_texts healthmods; - -class particle_system -{ -public: - 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) - { - if (num_particles >= MAX_PARTICLES) - return; - - particles[num_particles].iparticle = rand() % NUMPARTICLES; - particles[num_particles].pos = pos; - particles[num_particles].vel = vel; - particles[num_particles].life = life - lifemodifier[particles[num_particles].iparticle] * 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; - 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()); - 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(texture_particles); - gfx_quads_begin(); - //cell_select(4,1,1,1); - //cell_select(0,6,2,2); - //gfx_quads_setrotation(get_angle(vec2(proj->vx, proj->vy))); - for(int i = 0; i < num_particles; i++) - { - int type = particles[i].iparticle; - cell_select_ex(particlesnumcellsx,particlesnumcellsy,particlestexcoord[type].x, particlestexcoord[type].y, particlestexcoord[type].w, particlestexcoord[type].h); - float a = 1 - particles[i].life / particles[i].max_life; - vec2 p = particles[i].pos; - //a *= length(particles[i].vel) * 0.01f; - gfx_quads_setrotation(particles[i].rot); - gfx_quads_setcolor(particlecolors[type].x,particlecolors[type].y,particlecolors[type].z,pow(a,0.75f)); - //gfx_quads_setcolor(particlecolors[type].x * 0.5,particlecolors[type].y * 0.5,particlecolors[type].z* 0.5,pow(a,0.75f)); - //gfx_quads_setcolor(particlecolors[type].x * 0.0,particlecolors[type].y * 0.0,particlecolors[type].z* 0.0,pow(a,0.75f)); - //gfx_quads_setcolor(0.64f*2,0.28f*2,0.16f*2,pow(a,0.75f)); - gfx_quads_draw(p.x, p.y,particles[i].size,particles[i].size); - } - gfx_quads_end(); - gfx_blend_normal(); - } -}; - -static particle_system temp_system; - -void modc_init() -{ - // load textures - texture_weapon = gfx_load_texture_tga("data/tileset_weapons.tga"); - texture_game = gfx_load_texture_tga("data/game_main.tga"); - texture_char_default = gfx_load_texture_tga("data/char_teefault.tga"); - texture_sun = gfx_load_texture_tga("data/sun.tga"); - texture_particles = gfx_load_texture_tga("data/tileset_particles.tga"); - font_texture = gfx_load_texture_tga("data/debug_font.tga"); - - - // load sounds - sound_gun_fire[0] = snd_load_wav("data/audio/wp_gun_fire-01.wav"); - sound_gun_fire[0] = snd_load_wav("data/audio/wp_gun_fire-01.wav"); - sound_gun_fire[1] = snd_load_wav("data/audio/wp_gun_fire-02.wav"); - sound_shotty_fire[0] = snd_load_wav("data/audio/wp_shotty_fire-01.wav"); - sound_shotty_fire[1] = snd_load_wav("data/audio/wp_shotty_fire-02.wav"); - sound_shotty_fire[2] = snd_load_wav("data/audio/wp_shotty_fire-03.wav"); - sound_flump_launch[0] = snd_load_wav("data/audio/wp_flump_launch-01.wav"); - sound_flump_launch[1] = snd_load_wav("data/audio/wp_flump_launch-02.wav"); - sound_flump_launch[2] = snd_load_wav("data/audio/wp_flump_launch-03.wav"); - sound_hammer_swing[0] = snd_load_wav("data/audio/wp_hammer_swing-01.wav"); - sound_hammer_swing[1] = snd_load_wav("data/audio/wp_hammer_swing-02.wav"); - sound_hammer_swing[2] = snd_load_wav("data/audio/wp_hammer_swing-03.wav"); - sound_ninja_attack[0] = snd_load_wav("data/audio/wp_ninja_attack-01.wav"); - sound_ninja_attack[1] = snd_load_wav("data/audio/wp_ninja_attack-02.wav"); - sound_ninja_attack[2] = snd_load_wav("data/audio/wp_ninja_attack-03.wav"); - - sound_flump_explode[0] = snd_load_wav("data/audio/wp_flump_explo-01.wav"); - sound_flump_explode[1] = snd_load_wav("data/audio/wp_flump_explo-02.wav"); - sound_flump_explode[2] = snd_load_wav("data/audio/wp_flump_explo-03.wav"); - sound_ninja_hit[0] = snd_load_wav("data/audio/wp_ninja_hit-01.wav"); - sound_ninja_hit[1] = snd_load_wav("data/audio/wp_ninja_hit-02.wav"); - sound_ninja_hit[2] = snd_load_wav("data/audio/wp_ninja_hit-03.wav"); - sound_ninja_hit[3] = snd_load_wav("data/audio/wp_ninja_hit-04.wav"); - - sound_weapon_switch[0] = snd_load_wav("data/audio/wp_switch-01.wav"); - sound_weapon_switch[1] = snd_load_wav("data/audio/wp_switch-02.wav"); - sound_weapon_switch[2] = snd_load_wav("data/audio/wp_switch-03.wav"); - - sound_pain_short[0] = snd_load_wav("data/audio/vo_teefault_pain_short-01.wav"); - sound_pain_short[1] = snd_load_wav("data/audio/vo_teefault_pain_short-02.wav"); - sound_pain_short[2] = snd_load_wav("data/audio/vo_teefault_pain_short-03.wav"); - sound_pain_short[3] = snd_load_wav("data/audio/vo_teefault_pain_short-04.wav"); - sound_pain_short[4] = snd_load_wav("data/audio/vo_teefault_pain_short-05.wav"); - sound_pain_short[5] = snd_load_wav("data/audio/vo_teefault_pain_short-06.wav"); - sound_pain_short[6] = snd_load_wav("data/audio/vo_teefault_pain_short-07.wav"); - sound_pain_short[7] = snd_load_wav("data/audio/vo_teefault_pain_short-08.wav"); - sound_pain_short[8] = snd_load_wav("data/audio/vo_teefault_pain_short-09.wav"); - sound_pain_short[9] = snd_load_wav("data/audio/vo_teefault_pain_short-10.wav"); - sound_pain_short[10] = snd_load_wav("data/audio/vo_teefault_pain_short-11.wav"); - sound_pain_short[11] = snd_load_wav("data/audio/vo_teefault_pain_short-12.wav"); - - sound_pain_long[0] = snd_load_wav("data/audio/vo_teefault_pain_long-01.wav"); - sound_pain_long[1] = snd_load_wav("data/audio/vo_teefault_pain_long-02.wav"); - - sound_body_land[0] = snd_load_wav("data/audio/foley_land-01.wav"); - sound_body_land[1] = snd_load_wav("data/audio/foley_land-02.wav"); - sound_body_land[2] = snd_load_wav("data/audio/foley_land-03.wav"); - sound_body_land[3] = snd_load_wav("data/audio/foley_land-04.wav"); - sound_body_jump[0] = snd_load_wav("data/audio/foley_foot_left-01.wav"); - sound_body_jump[1] = snd_load_wav("data/audio/foley_foot_left-02.wav"); - sound_body_jump[2] = snd_load_wav("data/audio/foley_foot_left-03.wav"); - sound_body_jump[3] = snd_load_wav("data/audio/foley_foot_left-04.wav"); - sound_body_jump[4] = snd_load_wav("data/audio/foley_foot_right-01.wav"); - sound_body_jump[5] = snd_load_wav("data/audio/foley_foot_right-02.wav"); - sound_body_jump[6] = snd_load_wav("data/audio/foley_foot_right-03.wav"); - sound_body_jump[7] = snd_load_wav("data/audio/foley_foot_right-04.wav"); - - sound_body_splat[1] = snd_load_wav("data/audio/foley_body_splat-02.wav"); - sound_body_splat[2] = snd_load_wav("data/audio/foley_body_splat-03.wav"); - sound_body_splat[3] = snd_load_wav("data/audio/foley_body_splat-04.wav"); - - sound_spawn[0] = snd_load_wav("data/audio/vo_teefault_spawn-01.wav"); - sound_spawn[1] = snd_load_wav("data/audio/vo_teefault_spawn-02.wav"); - sound_spawn[2] = snd_load_wav("data/audio/vo_teefault_spawn-03.wav"); - sound_spawn[3] = snd_load_wav("data/audio/vo_teefault_spawn-04.wav"); - sound_spawn[4] = snd_load_wav("data/audio/vo_teefault_spawn-05.wav"); - sound_spawn[5] = snd_load_wav("data/audio/vo_teefault_spawn-06.wav"); - sound_spawn[6] = snd_load_wav("data/audio/vo_teefault_spawn-07.wav"); - - sound_tee_cry[0] = snd_load_wav("data/audio/vo_teefault_cry-01.wav"); - sound_tee_cry[1] = snd_load_wav("data/audio/vo_teefault_cry-02.wav"); - - //sound_hook_loop[0] = snd_load_wav("data/audio/hook_loop-01.wav"); - sound_hook_loop[0] = snd_load_wav("data/audio/hook_loop-02.wav"); - sound_hook_attach[0] = snd_load_wav("data/audio/hook_attach-01.wav"); - sound_hook_attach[1] = snd_load_wav("data/audio/hook_attach-02.wav"); - sound_hook_attach[2] = snd_load_wav("data/audio/hook_attach-03.wav"); - - poweruptexcoord[POWERUP_TYPE_HEALTH].x = 10; - poweruptexcoord[POWERUP_TYPE_HEALTH].y = 2; - poweruptexcoord[POWERUP_TYPE_HEALTH].w = 2; - poweruptexcoord[POWERUP_TYPE_HEALTH].h = 2; - - poweruptexcoord[POWERUP_TYPE_ARMOR].x = 12; - poweruptexcoord[POWERUP_TYPE_ARMOR].y = 2; - poweruptexcoord[POWERUP_TYPE_ARMOR].w = 2; - poweruptexcoord[POWERUP_TYPE_ARMOR].h = 2; - - poweruptexcoord[POWERUP_TYPE_WEAPON].x = 3; - poweruptexcoord[POWERUP_TYPE_WEAPON].y = 0; - poweruptexcoord[POWERUP_TYPE_WEAPON].w = 6; - poweruptexcoord[POWERUP_TYPE_WEAPON].h = 2; - - poweruptexcoord[POWERUP_TYPE_NINJA].x = 3; - poweruptexcoord[POWERUP_TYPE_NINJA].y = 10; - poweruptexcoord[POWERUP_TYPE_NINJA].w = 7; - poweruptexcoord[POWERUP_TYPE_NINJA].h = 2; - - poweruptexcoord[POWERUP_TYPE_TIMEFIELD].x = 3; - poweruptexcoord[POWERUP_TYPE_TIMEFIELD].y = 0; - poweruptexcoord[POWERUP_TYPE_TIMEFIELD].w = 6; - poweruptexcoord[POWERUP_TYPE_TIMEFIELD].h = 2; - - // Setup weapon cell coords - float sizemodifier = 1.0f; - weaponrenderparams[WEAPON_TYPE_GUN].sizex = 60.0f * sizemodifier; - weaponrenderparams[WEAPON_TYPE_GUN].sizey = 30.0f * sizemodifier; - weaponrenderparams[WEAPON_TYPE_GUN].offsetx = 32.0f; - weaponrenderparams[WEAPON_TYPE_GUN].offsety = 4.0f; - weapontexcoordcursor[WEAPON_TYPE_GUN].x = 0; - weapontexcoordcursor[WEAPON_TYPE_GUN].y = 4; - weapontexcoordcursor[WEAPON_TYPE_GUN].w = 2; - weapontexcoordcursor[WEAPON_TYPE_GUN].h = 2; - weapontexcoord[WEAPON_TYPE_GUN].x = 2; - weapontexcoord[WEAPON_TYPE_GUN].y = 4; - weapontexcoord[WEAPON_TYPE_GUN].w = 4; - weapontexcoord[WEAPON_TYPE_GUN].h = 2; - weaponprojtexcoord[WEAPON_TYPE_GUN].x = 6; - weaponprojtexcoord[WEAPON_TYPE_GUN].y = 4; - weaponprojtexcoord[WEAPON_TYPE_GUN].w = 2; - weaponprojtexcoord[WEAPON_TYPE_GUN].h = 2; - - nummuzzletex[WEAPON_TYPE_GUN] = 3; - muzzletexcoord[WEAPON_TYPE_GUN][0].x = 8; - muzzletexcoord[WEAPON_TYPE_GUN][0].y = 4; - muzzletexcoord[WEAPON_TYPE_GUN][0].w = 3; - muzzletexcoord[WEAPON_TYPE_GUN][0].h = 2; - muzzletexcoord[WEAPON_TYPE_GUN][1].x = 12; - muzzletexcoord[WEAPON_TYPE_GUN][1].y = 4; - muzzletexcoord[WEAPON_TYPE_GUN][1].w = 3; - muzzletexcoord[WEAPON_TYPE_GUN][1].h = 2; - muzzletexcoord[WEAPON_TYPE_GUN][2].x = 16; - muzzletexcoord[WEAPON_TYPE_GUN][2].y = 4; - muzzletexcoord[WEAPON_TYPE_GUN][2].w = 3; - muzzletexcoord[WEAPON_TYPE_GUN][2].h = 2; - - muzzleparams[WEAPON_TYPE_GUN].sizex = 60.0f * sizemodifier; - muzzleparams[WEAPON_TYPE_GUN].sizey = 40.0f * sizemodifier; - muzzleparams[WEAPON_TYPE_GUN].offsetx = 50.0f * sizemodifier; - muzzleparams[WEAPON_TYPE_GUN].offsety = 6.0f * sizemodifier; - - sizemodifier = 1.3f; - weaponrenderparams[WEAPON_TYPE_ROCKET].sizex = 70.0f * sizemodifier; - weaponrenderparams[WEAPON_TYPE_ROCKET].sizey = 20.0f * sizemodifier; - weaponrenderparams[WEAPON_TYPE_ROCKET].offsetx = 24.0f; - weaponrenderparams[WEAPON_TYPE_ROCKET].offsety = -2.0f; - weapontexcoordcursor[WEAPON_TYPE_ROCKET].x = 0; - weapontexcoordcursor[WEAPON_TYPE_ROCKET].y = 8; - weapontexcoordcursor[WEAPON_TYPE_ROCKET].w = 2; - weapontexcoordcursor[WEAPON_TYPE_ROCKET].h = 2; - weapontexcoord[WEAPON_TYPE_ROCKET].x = 2; - weapontexcoord[WEAPON_TYPE_ROCKET].y = 8; - weapontexcoord[WEAPON_TYPE_ROCKET].w = 7; - weapontexcoord[WEAPON_TYPE_ROCKET].h = 2; - weaponprojtexcoord[WEAPON_TYPE_ROCKET].x = 10; - weaponprojtexcoord[WEAPON_TYPE_ROCKET].y = 8; - weaponprojtexcoord[WEAPON_TYPE_ROCKET].w = 2; - weaponprojtexcoord[WEAPON_TYPE_ROCKET].h = 2; - - /*weaponrenderparams[WEAPON_TYPE_SNIPER].sizex = 60.0f; - weaponrenderparams[WEAPON_TYPE_SNIPER].sizey = 20.0f; - weaponrenderparams[WEAPON_TYPE_SNIPER].offsetx = 16.0f; - weaponrenderparams[WEAPON_TYPE_SNIPER].offsety = 4.0f; - weapontexcoordcursor[WEAPON_TYPE_SNIPER].x = 0; - weapontexcoordcursor[WEAPON_TYPE_SNIPER].y = 6; - weapontexcoordcursor[WEAPON_TYPE_SNIPER].w = 2; - weapontexcoordcursor[WEAPON_TYPE_SNIPER].h = 2; - weapontexcoord[WEAPON_TYPE_SNIPER].x = 3; - weapontexcoord[WEAPON_TYPE_SNIPER].y = 6; - weapontexcoord[WEAPON_TYPE_SNIPER].w = 6; - weapontexcoord[WEAPON_TYPE_SNIPER].h = 2; - weaponprojtexcoord[WEAPON_TYPE_SNIPER].x = 10; - weaponprojtexcoord[WEAPON_TYPE_SNIPER].y = 6; - weaponprojtexcoord[WEAPON_TYPE_SNIPER].w = 1; - weaponprojtexcoord[WEAPON_TYPE_SNIPER].h = 1;*/ - - weaponrenderparams[WEAPON_TYPE_SHOTGUN].sizex = 80.0f * sizemodifier; - weaponrenderparams[WEAPON_TYPE_SHOTGUN].sizey = 20.0f * sizemodifier; - weaponrenderparams[WEAPON_TYPE_SHOTGUN].offsetx = 24.0f; - weaponrenderparams[WEAPON_TYPE_SHOTGUN].offsety = -2.0f; - weapontexcoordcursor[WEAPON_TYPE_SHOTGUN].x = 0; - weapontexcoordcursor[WEAPON_TYPE_SHOTGUN].y = 6; - weapontexcoordcursor[WEAPON_TYPE_SHOTGUN].w = 2; - weapontexcoordcursor[WEAPON_TYPE_SHOTGUN].h = 2; - weapontexcoord[WEAPON_TYPE_SHOTGUN].x = 2; - weapontexcoord[WEAPON_TYPE_SHOTGUN].y = 6; - weapontexcoord[WEAPON_TYPE_SHOTGUN].w = 8; - weapontexcoord[WEAPON_TYPE_SHOTGUN].h = 2; - weaponprojtexcoord[WEAPON_TYPE_SHOTGUN].x = 10; - weaponprojtexcoord[WEAPON_TYPE_SHOTGUN].y = 6; - weaponprojtexcoord[WEAPON_TYPE_SHOTGUN].w = 2; - weaponprojtexcoord[WEAPON_TYPE_SHOTGUN].h = 2; - - nummuzzletex[WEAPON_TYPE_SHOTGUN] = 3; - muzzletexcoord[WEAPON_TYPE_SHOTGUN][0].x = 12; - muzzletexcoord[WEAPON_TYPE_SHOTGUN][0].y = 6; - muzzletexcoord[WEAPON_TYPE_SHOTGUN][0].w = 3; - muzzletexcoord[WEAPON_TYPE_SHOTGUN][0].h = 2; - muzzletexcoord[WEAPON_TYPE_SHOTGUN][1].x = 16; - muzzletexcoord[WEAPON_TYPE_SHOTGUN][1].y = 6; - muzzletexcoord[WEAPON_TYPE_SHOTGUN][1].w = 3; - muzzletexcoord[WEAPON_TYPE_SHOTGUN][1].h = 2; - muzzletexcoord[WEAPON_TYPE_SHOTGUN][2].x = 20; - muzzletexcoord[WEAPON_TYPE_SHOTGUN][2].y = 6; - muzzletexcoord[WEAPON_TYPE_SHOTGUN][2].w = 3; - muzzletexcoord[WEAPON_TYPE_SHOTGUN][2].h = 2; - - muzzleparams[WEAPON_TYPE_SHOTGUN].sizex = 60.0f * sizemodifier; - muzzleparams[WEAPON_TYPE_SHOTGUN].sizey = 40.0f * sizemodifier; - muzzleparams[WEAPON_TYPE_SHOTGUN].offsetx = 50.0f * sizemodifier; - muzzleparams[WEAPON_TYPE_SHOTGUN].offsety = 6.0f * sizemodifier; - - - - weaponrenderparams[WEAPON_TYPE_MELEE].sizex = 60.0f * sizemodifier; - weaponrenderparams[WEAPON_TYPE_MELEE].sizey = 50.0f * sizemodifier; - weaponrenderparams[WEAPON_TYPE_MELEE].offsetx = 20.0f; - weaponrenderparams[WEAPON_TYPE_MELEE].offsety = -4.0f; - weapontexcoordcursor[WEAPON_TYPE_MELEE].x = 0; - weapontexcoordcursor[WEAPON_TYPE_MELEE].y = 0; - weapontexcoordcursor[WEAPON_TYPE_MELEE].w = 2; - weapontexcoordcursor[WEAPON_TYPE_MELEE].h = 2; - weapontexcoord[WEAPON_TYPE_MELEE].x = 2; - weapontexcoord[WEAPON_TYPE_MELEE].y = 1; - weapontexcoord[WEAPON_TYPE_MELEE].w = 4; - weapontexcoord[WEAPON_TYPE_MELEE].h = 3; - weaponprojtexcoord[WEAPON_TYPE_MELEE].x = 0; - weaponprojtexcoord[WEAPON_TYPE_MELEE].y = 0; - weaponprojtexcoord[WEAPON_TYPE_MELEE].w = 0; - weaponprojtexcoord[WEAPON_TYPE_MELEE].h = 0; - - - // MODIFIERS - sizemodifier = 2.0; - modifierrenderparams[MODIFIER_TYPE_NINJA].sizex = 60.0f * sizemodifier; - modifierrenderparams[MODIFIER_TYPE_NINJA].sizey = 20.0f * sizemodifier; - modifierrenderparams[MODIFIER_TYPE_NINJA].offsetx = 20.0f; - modifierrenderparams[MODIFIER_TYPE_NINJA].offsety = 4.0f; - modifiertexcoord[MODIFIER_TYPE_NINJA].x = 2; - modifiertexcoord[MODIFIER_TYPE_NINJA].y = 10; - modifiertexcoord[MODIFIER_TYPE_NINJA].w = 7; - modifiertexcoord[MODIFIER_TYPE_NINJA].h = 2; - modifiertexcoordcursor[MODIFIER_TYPE_NINJA].x = 0; - modifiertexcoordcursor[MODIFIER_TYPE_NINJA].y = 10; - modifiertexcoordcursor[MODIFIER_TYPE_NINJA].w = 2; - modifiertexcoordcursor[MODIFIER_TYPE_NINJA].h = 2; - - modifierrenderparams[MODIFIER_TYPE_TIMEFIELD].sizex = 60.0f * sizemodifier; - modifierrenderparams[MODIFIER_TYPE_TIMEFIELD].sizey = 20.0f * sizemodifier; - modifierrenderparams[MODIFIER_TYPE_TIMEFIELD].offsetx = 16.0f; - modifierrenderparams[MODIFIER_TYPE_TIMEFIELD].offsety = 4.0f; - modifiertexcoord[MODIFIER_TYPE_TIMEFIELD].x = 0; - modifiertexcoord[MODIFIER_TYPE_TIMEFIELD].y = 0; - modifiertexcoord[MODIFIER_TYPE_TIMEFIELD].w = 0; - modifiertexcoord[MODIFIER_TYPE_TIMEFIELD].h = 0; - - stars[0].x = 0; - stars[0].y = 0; - stars[0].w = 2; - stars[0].h = 2; - - stars[1].x = 0; - stars[1].y = 2; - stars[1].w = 2; - stars[1].h = 2; - - particlecolors[0].x = 0.7f; - particlecolors[0].y = 0.7f; - particlecolors[0].z = 0.7f; - particlecolors[0].w = 1.0f; - particlestexcoord[0].x = 2; - particlestexcoord[0].y = 0; - particlestexcoord[0].w = 2; - particlestexcoord[0].h = 2; - particlecolors[1].x = 1.0f; - particlecolors[1].y = 1.0f; - particlecolors[1].z = 1.0f; - particlecolors[1].w = 1.0f; - particlestexcoord[1].x = 4; - particlestexcoord[1].y = 0; - particlestexcoord[1].w = 2; - particlestexcoord[1].h = 2; - particlecolors[2].x = 0.8f; - particlecolors[2].y = 0.8f; - particlecolors[2].z = 0.8f; - particlecolors[2].w = 1.0f; - particlestexcoord[2].x = 6; - particlestexcoord[2].y = 0; - particlestexcoord[2].w = 2; - particlestexcoord[2].h = 2; - particlecolors[3].x = 0.988f; - particlecolors[3].y = 1.0f; - particlecolors[3].z = 0.16f; - particlecolors[3].w = 1.0f; - particlestexcoord[3].x = 8; - particlestexcoord[3].y = 0; - particlestexcoord[3].w = 2; - particlestexcoord[3].h = 2; - particlecolors[4].x = 1.0f; - particlecolors[4].y = 1.0f; - particlecolors[4].z = 1.0f; - particlecolors[4].w = 1.0f; - particlestexcoord[4].x = 10; - particlestexcoord[4].y = 0; - particlestexcoord[4].w = 2; - particlestexcoord[4].h = 2; - particlecolors[5].x = 0.6f; - particlecolors[5].y = 0.6f; - particlecolors[5].z = 0.6f; - particlecolors[5].w = 1.0f; - particlestexcoord[5].x = 2; - particlestexcoord[5].y = 2; - particlestexcoord[5].w = 2; - particlestexcoord[5].h = 2; - particlecolors[6].x = 1.0f; - particlecolors[6].y = 1.0f; - particlecolors[6].z = 1.0f; - particlecolors[6].w = 1.0f; - particlestexcoord[6].x = 4; - particlestexcoord[6].y = 2; - particlestexcoord[6].w = 2; - particlestexcoord[6].h = 2; - particlecolors[5].x = 0.9f; - particlecolors[5].y = 0.9f; - particlecolors[5].z = 0.9f; - particlecolors[5].w = 1.0f; - particlestexcoord[7].x = 6; - particlestexcoord[7].y = 2; - particlestexcoord[7].w = 2; - particlestexcoord[7].h = 2; - particlecolors[8].x = 1.0f; - particlecolors[8].y = 1.0f; - particlecolors[8].z = 1.0f; - particlecolors[8].w = 1.0f; - particlestexcoord[8].x = 8; - particlestexcoord[8].y = 2; - particlestexcoord[8].w = 2; - particlestexcoord[8].h = 2; - lifemodifier[0] = 0.5f; - lifemodifier[1] = 0.5f; - lifemodifier[2] = 0.5f; - lifemodifier[3] = 0.7f; - lifemodifier[4] = 0.7f; - lifemodifier[5] = 1.0f; - lifemodifier[6] = 1.0f; - lifemodifier[7] = 1.5f; - lifemodifier[8] = 0.4f; - - chaintexcoord.x = 2; - chaintexcoord.y = 0; - chaintexcoord.w = 1; - chaintexcoord.h = 1; - - chainheadtexcoord.x = 3; - chainheadtexcoord.y = 0; - chainheadtexcoord.w = 2; - chainheadtexcoord.h = 1; - - - // anims - anim::setup_hammer(hammeranim); - anim::setup_ninja(ninjaanim); - - for (int i = 0; i < NUMHADOKENS; i++) - { - hadoken[i].x = 1; - hadoken[i].y = 12; - hadoken[i].w = 7; - hadoken[i].h = 4; - hadokenparams[i].sizex = 0.0f; - hadokenparams[i].sizey = 0.0f; - hadokenparams[i].offsetx = 0.0f; - hadokenparams[i].offsety = 0.0f;//-hadokenparams[0].sizey * 0.15f; - } - - // hadoken - hadoken[0].x = 1; - hadoken[0].y = 12; - hadoken[0].w = 7; - hadoken[0].h = 4; - hadokenparams[0].sizex = 70.0f * 2.5f; - hadokenparams[0].sizey = 40.0f * 2.5f; - hadokenparams[0].offsetx = -60.0f; - hadokenparams[0].offsety = 0;//-hadokenparams[0].sizey * 0.15f; - - hadoken[2].x = 8; - hadoken[2].y = 12; - hadoken[2].w = 8; - hadoken[2].h = 4; - hadokenparams[2].sizex = 80.0f * 2.5f; - hadokenparams[2].sizey = 40.0f * 2.5f; - hadokenparams[2].offsetx = -60.0f; - hadokenparams[2].offsety = 0;//-hadokenparams[1].sizey * 0.5f; - - hadoken[4].x = 17; - hadoken[4].y = 12; - hadoken[4].w = 7; - hadoken[4].h = 4; - hadokenparams[4].sizex = 70.0f * 2.5f; - hadokenparams[4].sizey = 40.0f * 2.5f; - hadokenparams[4].offsetx = -60.0f; - hadokenparams[4].offsety = 0;//-hadokenparams[2].sizey * 0.5f; - - // 0 = outline, 1 = body - body[0].x = 2; - body[0].y = 0; - body[0].w = 2; - body[0].h = 2; - body[1].x = 0; - body[1].y = 0; - body[1].w = 2; - body[1].h = 2; - - feet[0].x = 4; - feet[0].y = 1; - feet[0].w = 1; - feet[0].h = 0.5; - feet[1].x = 4; - feet[1].y = 1.52; - feet[1].w = 1; - feet[1].h = 0.48; - - leye.x = 5; - leye.y = 1; - leye.w = 0.5; - leye.h = 0.5; - - reye.x = 5; - reye.y = 1.0; - reye.w = 0.5; - reye.h = 0.5; -} - -void modc_entergame() -{ - col_init(32); - img_init(); - tilemap_init(); -} - -void modc_shutdown() -{ -} - -void modc_newsnapshot() -{ - int num = snap_num_items(SNAP_CURRENT); - for(int i = 0; i < num; i++) - { - snap_item item; - void *data = snap_get_item(SNAP_CURRENT, i, &item); - - if(item.type == EVENT_HEALTHMOD) - { - ev_healthmod *ev = (ev_healthmod *)data; - healthmods.create(vec2(ev->x, ev->y), ev->amount); - } - 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); - } - } - 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_SOUND) - { - ev_sound *ev = (ev_sound *)data; - vec2 p(ev->x, ev->y); - int sound = (ev->sound & SOUND_MASK); - bool bstartloop = (ev->sound & SOUND_LOOPFLAG_STARTLOOP) != 0; - bool bstoploop = (ev->sound & SOUND_LOOPFLAG_STOPLOOP) != 0; - float vol, pan; - sound_vol_pan(p, &vol, &pan); - - switch(sound) - { - - // FIRE! - case SOUND_FIRE_GUN: - sound_gun_fire.play_random(volume_gun*vol, pan); - break; - case SOUND_FIRE_SHOTGUN: - sound_shotty_fire.play_random(volume_gun*vol, pan); - break; - case SOUND_FIRE_ROCKET: - sound_flump_launch.play_random(volume_gun*vol, pan); - break; - case SOUND_FIRE_MELEE: - sound_hammer_swing.play_random(volume_gun*vol, pan); - break; - case SOUND_FIRE_NINJA: - sound_ninja_attack.play_random(volume_gun*vol, pan); - break; - - // IMPACT - case SOUND_IMPACT_PROJECTILE_GUN: - break; - case SOUND_IMPACT_PROJECTILE_SHOTGUN: - break; - case SOUND_IMPACT_PROJECTILE_ROCKET: - sound_flump_explode.play_random(volume_hit*vol, pan); - break; - - // PLAYER - case SOUND_PLAYER_JUMP: - sound_body_jump.play_random(volume_tee*vol, pan); - break; - case SOUND_PLAYER_HURT_SHORT: - sound_pain_short.play_random(volume_tee*vol, pan); - break; - case SOUND_PLAYER_HURT_LONG: - sound_pain_long.play_random(volume_tee*vol, pan); - break; - case SOUND_PLAYER_SPAWN: - sound_spawn.play_random(volume_tee*vol, pan); - break; - case SOUND_PLAYER_CHAIN_LOOP: - sound_hook_loop.play_random(volume_gun*vol, pan); - break; - case SOUND_PLAYER_CHAIN_IMPACT: - sound_hook_attach.play_random(volume_gun*vol, pan); - break; - case SOUND_PLAYER_IMPACT: - sound_body_land.play_random(volume_hit*vol, pan); - break; - case SOUND_PLAYER_IMPACT_NINJA: - sound_ninja_hit.play_random(volume_hit*vol, pan); - break; - case SOUND_PLAYER_DIE: - sound_body_splat.play_random(volume_tee*vol, pan); - break; - case SOUND_PLAYER_SWITCHWEAPON: - sound_weapon_switch.play_random(volume_gun*vol, pan); - break; - case SOUND_PLAYER_EQUIP: - break; - case SOUND_PLAYER_LAND: - sound_body_land.play_random(volume_tee*vol, pan); - break; - } - } - } -} - -static void render_projectile(obj_projectile *prev, obj_projectile *current) -{ - gfx_texture_set(texture_weapon); - gfx_quads_begin(); - cell_select_ex(numcellsx,numcellsy,weaponprojtexcoord[current->type].x, weaponprojtexcoord[current->type].y, weaponprojtexcoord[current->type].w, weaponprojtexcoord[current->type].h); - vec2 vel(current->vx, current->vy); - - // TODO: interpolare angle aswell - if(length(vel) > 0.00001f) - gfx_quads_setrotation(get_angle(vel)); - else - gfx_quads_setrotation(0); - - vec2 pos = mix(vec2(prev->x, prev->y), vec2(current->x, current->y), snap_intratick()); - gfx_quads_draw(pos.x, pos.y,32,32); - gfx_quads_setrotation(0); - gfx_quads_end(); -} - -static void render_powerup(obj_powerup *prev, obj_powerup *current) -{ - //dbg_msg("client", "rendering powerup at %d,%d", current->x, current->y); - - gfx_texture_set(texture_weapon); - gfx_quads_begin(); - float angle = 0.0f; - float sizex = 64.0f; - float sizey = 64.0f; - if (current->type == POWERUP_TYPE_WEAPON) - { - angle = -0.25f * pi * 2.0f; - cell_select_ex(numcellsx,numcellsy,weapontexcoord[current->subtype].x, weapontexcoord[current->subtype].y, weapontexcoord[current->subtype].w, weapontexcoord[current->subtype].h); - sizex = weaponrenderparams[current->subtype].sizex; - sizey = weaponrenderparams[current->subtype].sizey; - } - else - cell_select_ex(numcellsx,numcellsy,poweruptexcoord[current->type].x, poweruptexcoord[current->type].y, poweruptexcoord[current->type].w, poweruptexcoord[current->type].h); - vec2 vel(current->vx, current->vy); - - gfx_quads_setrotation(angle); - // TODO: interpolare angle aswell - /*if(length(vel) > 0.00001f) - gfx_quads_setrotation(get_angle(vel)); - else - gfx_quads_setrotation(0);*/ - - vec2 pos = mix(vec2(prev->x, prev->y), vec2(current->x, current->y), snap_intratick()); - float offset = pos.y/32.0f + pos.x/32.0f; - gfx_quads_draw(pos.x+cosf(client_localtime()*2.0f+offset)*2.5f, pos.y+sinf(client_localtime()*2.0f+offset)*2.5f,sizex * 0.65f,sizey * 0.65f); - gfx_quads_setrotation(0); - gfx_quads_end(); -} - -float getmeleeangle(vec2 direction, obj_player* prev, obj_player* player) -{ - vec2 meleedir(0.53, -0.84); - meleedir = normalize(meleedir); - vec2 meleedirattack(0.95, -0.3); - meleedirattack = normalize(meleedirattack); - - if(direction.x < 0) - { - meleedir.x = -meleedir.x; - meleedirattack.x = -meleedirattack.x; - } - - // 0 -> visualtimeattack go to end pose, (len - visualime) -> go back to normal pose - - float angle = get_angle(meleedir); - if (prev->attackticks) - { - float angleattack = get_angle(meleedirattack); - int phase1tick = (player->attacklen - player->attackticks); - if (phase1tick < player->visualtimeattack) - { - float intratick = snap_intratick(); - float t = ((((float)phase1tick) + intratick)/(float)player->visualtimeattack); - angle = LERP(angle, angleattack, min(1.0f,max(0.0f,t))); - } - else - { - // go back to normal pose - int phase2tick = (player->attacklen - player->visualtimeattack - player->attackticks); - float intratick = snap_intratick(); - float t = ((((float)phase2tick) + intratick)/(float)player->visualtimeattack); - angle = LERP(angleattack, angle, min(1.0f,max(0.0f,t))); - } - } - /*if (prev->attackticks && !player->attackticks) - { - // blend back to normal - float angleattack = get_angle(meleedirattack); - angle = LERP(angleattack, angle, min(1.0f,max(0.0f,snap_intratick()))); - } - else if (player->attackticks) - { - float angleattack = get_angle(meleedirattack); - float intratick = snap_intratick(); - float t = ((((float)player->attackticks) - intratick)/(float)player->attacklen); - angle = LERP(angleattack, angle, min(1.0f,max(0.0f,t))); - }*/ - - return angle; -} - -float gethammereangle(vec2 direction, obj_player* prev, obj_player* player) -{ - float t = 0.0f; - if (prev->attackticks) - t = 1.0f - ((((float)player->attackticks) - snap_intratick())/(float)player->attacklen); - - vec2 pos; - float angle = 0.0f; - hammeranim.evalanim(t,pos,angle); - if(direction.x < 0) - angle = pi -angle;// + ; - //dbg_msg("anim", "Time: %f", t); - return angle; -} - -float getninjaangle(vec2 direction, obj_player* prev, obj_player* player) -{ - float t = 0.0f; - if (prev->attackticks) - t = 1.0f - ((((float)player->attackticks) - snap_intratick())/(float)player->attacklen); - - vec2 pos; - float angle = 0.0f; - ninjaanim.evalanim(t,pos,angle); - if(direction.x < 0) - angle = pi -angle;// + ; - //dbg_msg("anim", "Time: %f", t); - return angle; -} - - -float getrecoil(obj_player* prev, obj_player* player) -{ - // attack = -10 - float recoil = 0.0f; - if (prev->attackticks) - { - float attackrecoil = recoils[player->weapon]; - int phase1tick = (player->attacklen - player->attackticks); - if (phase1tick < player->visualtimeattack) - { - float intratick = snap_intratick(); - float t = ((((float)phase1tick) + intratick)/(float)player->visualtimeattack); - recoil = LERP(0, attackrecoil, min(1.0f,max(0.0f,t))); - } - else - { - // go back to normal pose - int phase2tick = (player->attacklen - player->visualtimeattack - player->attackticks); - float intratick = snap_intratick(); - float t = ((((float)phase2tick) + intratick)/(float)(player->attacklen - player->visualtimeattack)); - recoil = LERP(attackrecoil, 0.0f, min(1.0f,max(0.0f,t))); - } - } - return recoil; -} - -static void render_player(obj_player *prev, obj_player *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), snap_intratick()); - - // draw hook - if(player->hook_active) - { - gfx_texture_set(texture_weapon); - gfx_quads_begin(); - //gfx_quads_begin(); - - vec2 pos = position; - - vec2 hook_pos = mix(vec2(prev->hook_x, prev->hook_y), vec2(player->hook_x, player->hook_y), snap_intratick()); - - float d = distance(pos, hook_pos); - vec2 dir = normalize(pos-hook_pos); - - gfx_quads_setrotation(get_angle(dir)+pi); - - // render head - cell_select_ex(numcellsx,numcellsy, chainheadtexcoord.x,chainheadtexcoord.y, chainheadtexcoord.w, chainheadtexcoord.h); - gfx_quads_draw(hook_pos.x, hook_pos.y, 24,16); - - // render chain - cell_select_ex(numcellsx,numcellsy, chaintexcoord.x, chaintexcoord.y, chaintexcoord.w, chaintexcoord.h); - for(float f = 24; f < d; f += 24) - { - vec2 p = hook_pos + dir*f; - gfx_quads_draw(p.x, p.y,24,16); - } - - gfx_quads_setrotation(0); - gfx_quads_end(); - } - - // draw gun - { - gfx_texture_set(texture_weapon); - gfx_quads_begin(); - gfx_quads_setrotation(angle); - - if (player->modifier & (1 << MODIFIER_TYPE_NINJA)) - { - float playerangle = angle; - // render NINJA!!! (0.53, 0.84) when idle to -> (0.95, 0.3) at the end of attack - if(direction.x < 0) - cell_select_ex_flip_y(numcellsx, numcellsy, modifiertexcoord[MODIFIER_TYPE_NINJA].x, modifiertexcoord[MODIFIER_TYPE_NINJA].y, modifiertexcoord[MODIFIER_TYPE_NINJA].w, modifiertexcoord[MODIFIER_TYPE_NINJA].h); - else - cell_select_ex(numcellsx, numcellsy, modifiertexcoord[MODIFIER_TYPE_NINJA].x, modifiertexcoord[MODIFIER_TYPE_NINJA].y, modifiertexcoord[MODIFIER_TYPE_NINJA].w, modifiertexcoord[MODIFIER_TYPE_NINJA].h); - - angle = getninjaangle(direction, prev, player);//getmeleeangle(direction, prev, player); - vec2 ninjadir = get_direction(angle * 256.0f); - gfx_quads_setrotation(angle); - vec2 p = position + vec2(0,modifierrenderparams[MODIFIER_TYPE_NINJA].offsety)+ ninjadir * modifierrenderparams[MODIFIER_TYPE_NINJA].offsetx; - // if attack is active hold it differently and draw speedlines behind us? - gfx_quads_draw(p.x,p.y/*+bob*/,modifierrenderparams[MODIFIER_TYPE_NINJA].sizex, modifierrenderparams[MODIFIER_TYPE_NINJA].sizey); - - if ((player->attacklen - player->attackticks) <= (SERVER_TICK_SPEED / 5)) - { - gfx_quads_setrotation(playerangle); - int ihadoken = rand() % NUMHADOKENS; - cell_select_ex(numcellsx, numcellsy, hadoken[ihadoken].x, hadoken[ihadoken].y, hadoken[ihadoken].w, hadoken[ihadoken].h); - vec2 p = position + vec2(0,hadokenparams[ihadoken].offsety)+ direction * hadokenparams[ihadoken].offsetx; - gfx_quads_draw(p.x,p.y/*+bob*/,hadokenparams[ihadoken].sizex, hadokenparams[ihadoken].sizey); - } - } - else - { - // normal weapons - if(direction.x < 0) - cell_select_ex_flip_y(numcellsx, numcellsy, weapontexcoord[player->weapon].x, weapontexcoord[player->weapon].y, weapontexcoord[player->weapon].w, weapontexcoord[player->weapon].h); - else - cell_select_ex(numcellsx, numcellsy, weapontexcoord[player->weapon].x, weapontexcoord[player->weapon].y, weapontexcoord[player->weapon].w, weapontexcoord[player->weapon].h); - - vec2 dir = direction; - float recoil = 0.0f; - if (player->weapon == WEAPON_TYPE_MELEE) - { - // if attack is under way, bash stuffs - //angle = getmeleeangle(direction, prev, player); - angle = gethammereangle(direction, prev, player); - gfx_quads_setrotation(angle); - dir = get_direction(angle * 256.0f); - } - else - { - recoil = getrecoil(prev, player); - } - - vec2 p = position + vec2(0,weaponrenderparams[player->weapon].offsety) + dir * weaponrenderparams[player->weapon].offsetx - dir * recoil; - gfx_quads_draw(p.x,p.y/*+bob*/,weaponrenderparams[player->weapon].sizex, weaponrenderparams[player->weapon].sizey); - // draw muzzleflare - if (player->weapon == WEAPON_TYPE_GUN || player->weapon == WEAPON_TYPE_SHOTGUN) - { - // check if we're firing stuff - if (true)///prev->attackticks) - { - float alpha = 0.0f; - int phase1tick = (player->attacklen - player->attackticks); - if (phase1tick < (player->visualtimeattack + 3)) - { - float intratick = snap_intratick(); - float t = ((((float)phase1tick) + intratick)/(float)player->visualtimeattack); - alpha = LERP(2.0, 0.0f, min(1.0f,max(0.0f,t))); - } - - if (alpha > 0.0f) - { - float offsety = -muzzleparams[player->weapon].offsety; - int itex = rand() % nummuzzletex[player->weapon]; - if(direction.x < 0) - { - offsety = -offsety; - cell_select_ex_flip_y(numcellsx, numcellsy, muzzletexcoord[player->weapon][itex].x, muzzletexcoord[player->weapon][itex].y, muzzletexcoord[player->weapon][itex].w, muzzletexcoord[player->weapon][itex].h); - } - else - cell_select_ex(numcellsx, numcellsy, muzzletexcoord[player->weapon][itex].x, muzzletexcoord[player->weapon][itex].y, muzzletexcoord[player->weapon][itex].w, muzzletexcoord[player->weapon][itex].h); - - gfx_quads_setcolor(1.0f,1.0f,1.0f,alpha); - vec2 diry(-dir.y,dir.x); - p += dir * muzzleparams[player->weapon].offsetx + diry * offsety; - gfx_quads_draw(p.x,p.y/*+bob*/,muzzleparams[player->weapon].sizex, muzzleparams[player->weapon].sizey); - } - } - } - } - /*else - { - // minigun - if(direction.x < 0) - cell_select_flip_y(4,4,8,2); - else - cell_select(4,4,8,2); - vec2 p = position + vec2(0,3); - gfx_quads_draw(p.x,p.y,8*8,8*2); - }*/ - - gfx_quads_setrotation(0); - gfx_quads_end(); - } - - - gfx_texture_set(texture_char_default); - gfx_quads_begin(); - - float bob = 0; - - // draw foots - const float cyclelength = 128.0f; - const float steplength = 26; - const float lift = 4.0f; - bool stationary = player->vx < 1 && player->vx > -1; - bool inair = col_check_point(player->x, player->y+16) == 0; - - for(int p = 0; p < 2; p++) - { - // first pass we draw the outline - // second pass we draw the filling - - //int v_offset = p?0:5; - int outline = p;// ? 1 : 0; - float offsety = charids[player->clientid % 16] * 2.0f; - - for(int f = 0; f < 2; f++) - { - float basesize = 10.0f; - if(f == 1) - { - // draw body - float t = fmod(position.x, cyclelength/2)/(cyclelength/2); - bob = -sinf(pow(t,2)*pi) * 3; - cell_select_ex(charnumcellsx,charnumcellsy, body[outline].x,body[outline].y + offsety,body[outline].w,body[outline].h); - //cell_select_ex(16,16, 0,0+v_offset,4,4); - //const float size = 64.0f; - if(stationary || inair) - bob = 0; - gfx_quads_draw(position.x, position.y-5+bob, 4*basesize, 4*basesize); - - // draw eyes - if(p == 1) - { - //cell_select_ex(16,16, 8,3,1,1); - vec2 md = get_direction(player->angle); - float mouse_dir_x = md.x; - float mouse_dir_y = md.y; - - // normal - cell_select_ex(charnumcellsx,charnumcellsy, leye.x,leye.y + offsety,leye.w,leye.h); - gfx_quads_draw(position.x-4+mouse_dir_x*4, position.y-8+mouse_dir_y*3+bob, basesize, basesize); - cell_select_ex(charnumcellsx,charnumcellsy, reye.x,reye.y + offsety,reye.w,reye.h); - gfx_quads_draw(position.x+4+mouse_dir_x*4, position.y-8+mouse_dir_y*3+bob, basesize, basesize); - } - } - - // draw feet - //cell_select_ex(16,16, 5,2+v_offset, 2,2); - cell_select_ex(charnumcellsx,charnumcellsy, feet[outline].x,feet[outline].y + offsety, feet[outline].w,feet[outline].h); - float w = basesize*2.5f; - float h = basesize*1.425f; - if(inair) - { - float r = 0.0f; - if(player->vy < 0.0f) - r = player->vy/3.0f; - else - r = player->vy/15.0f; - - // clamp the rotation - if(r > 0.5f) r = 0.5f; - if(r < -0.5f) r = -0.5f; - - if(player->vx > 0.0f) - r *= -1.0f; - gfx_quads_setrotation(r); - gfx_quads_drawTL(position.x-4+f*7-w/2, position.y+16 - h, w, h); - gfx_quads_setrotation(0); - } - else if(stationary) - { - // stationary - gfx_quads_drawTL(position.x-7+f*14-w/2, position.y+16 - h, w, h); - } - else - { - /* - The walk cycle, 2 parts - - 111 - 1 1 - 2 1 - 2 1 - 2222221 - GROUND GROUND GROUND - */ - - // moving - float tx = position.x+f*(cyclelength/2); - float t = fmod(tx, cyclelength) / cyclelength; - if(player->vx < 0) - t = 1.0f-t; - - float y; - float x = 0; - float r = 0; - float r_back = 1.5f; - - if(t < 0.5f) - { - // stomp down foot (part 1) - float st = t*2; - y = 1.0f-pow(st, 0.5f) + sinf(pow(st,2)*pi)*0.5f; - x = -steplength/2 + st*steplength; - r = r_back*(1-st) + sinf(pow(st,1.5f)*pi*2); - } - else - { - // lift foot up again (part 2) - float st = (t-0.5f)*2; - y = pow(st, 5.0f); - x = steplength/2 - st*steplength; - r = y*r_back; - } - - - if(player->vx > 0) - { - gfx_quads_setrotation(r); - gfx_quads_drawTL(position.x+x-w/2, position.y+16-y*lift - h, w, h); - } - else - { - gfx_quads_setrotation(-r); - gfx_quads_drawTL(position.x-x-w/2, position.y+16-y*lift - h, w, h); - } - gfx_quads_setrotation(0); - } - - } - } - - gfx_quads_end(); - - -} - -static player_input oldinput; -static bool bfirst = true; -void modc_render() -{ - if (bfirst) - { - bfirst = false; - oldinput.activeweapon = 0; - oldinput.angle = 0; - oldinput.blink = 0; - oldinput.fire = 0; - oldinput.hook = 0; - oldinput.jump = 0; - oldinput.left = 0; - oldinput.right = 0; - } - // fetch new input - { - int x, y; - inp_mouse_relative(&x, &y); - mouse_pos += vec2(x, y); - float l = length(mouse_pos); - if(l > 600.0f) - mouse_pos = normalize(mouse_pos)*600.0f; - } - - // snap input - { - player_input input; - input.left = inp_key_pressed('A'); - input.right = inp_key_pressed('D'); - float a = atan((float)mouse_pos.y/(float)mouse_pos.x); - if(mouse_pos.x < 0) - a = a+pi; - input.angle = (int)(a*256.0f); - input.jump = inp_key_pressed(baselib::keys::space) || inp_key_pressed('W'); - - input.fire = inp_mouse_button_pressed(0);// | (oldinput.fire << 16); - //oldinput.fire = input.fire & 0x0000ffff; - - input.hook = inp_mouse_button_pressed(1) || inp_key_pressed(baselib::keys::lctrl); // be nice to mac users O.o - input.blink = inp_key_pressed('S'); - - // Weapon switching - input.activeweapon = inp_key_pressed('1') ? 0x80000000 : 0; - if (!input.activeweapon) - input.activeweapon = inp_key_pressed('2') ? 0x80000000 | 1 : 0; - if (!input.activeweapon) - input.activeweapon = inp_key_pressed('3') ? 0x80000000 | 2 : 0; - if (!input.activeweapon) - input.activeweapon = inp_key_pressed('4') ? 0x80000000 | 3 : 0; - /*if (!input.activeweapon) - input.activeweapon = inp_key_pressed('5') ? 0x80000000 | 4 : 0;*/ - - snap_input(&input, sizeof(input)); - } - - // setup world view - { - // 1. fetch local player - // 2. set him to the center - - int num = snap_num_items(SNAP_CURRENT); - for(int i = 0; i < num; i++) - { - snap_item item; - void *data = snap_get_item(SNAP_CURRENT, i, &item); - - if(item.type == OBJTYPE_PLAYER) - { - obj_player *player = (obj_player *)data; - if(player->local) - { - local_player = player; - local_player_pos = vec2(player->x, player->y); - - void *p = snap_find_item(SNAP_PREV, item.type, item.id); - if(p) - local_player_pos = mix(vec2(((obj_player *)p)->x, ((obj_player *)p)->y), local_player_pos, snap_intratick()); - break; - } - } - } - } - - // pseudo format - float zoom = inp_key_pressed('T') ? 1.0 : 3.0f; - - float width = 400*zoom; - float height = 300*zoom; - float screen_x = 0; - float screen_y = 0; - - // center at char but can be moved when mouse is far away - float offx = 0, offy = 0; - int deadzone = 300; - if(mouse_pos.x > deadzone) offx = mouse_pos.x-deadzone; - if(mouse_pos.x <-deadzone) offx = mouse_pos.x+deadzone; - if(mouse_pos.y > deadzone) offy = mouse_pos.y-deadzone; - if(mouse_pos.y <-deadzone) offy = mouse_pos.y+deadzone; - offx = offx*2/3; - offy = offy*2/3; - - screen_x = local_player_pos.x+offx; - screen_y = local_player_pos.y+offy; - - gfx_mapscreen(screen_x-width/2, screen_y-height/2, screen_x+width/2, screen_y+height/2); - - // draw background - gfx_clear(0.65f,0.78f,0.9f); - - { - - vec2 pos(local_player_pos.x*0.5f, local_player_pos.y*0.5f); - - gfx_texture_set(-1); - gfx_blend_additive(); - gfx_quads_begin(); - const int rays = 10; - gfx_quads_setcolor(1.0f,1.0f,1.0f,0.025f); - for(int r = 0; r < rays; r++) - { - float a = r/(float)rays + client_localtime()*0.05f; - float size = (1.0f/(float)rays)*0.25f; - vec2 dir0(sinf((a-size)*pi*2.0f), cosf((a-size)*pi*2.0f)); - vec2 dir1(sinf((a+size)*pi*2.0f), cosf((a+size)*pi*2.0f)); - - //gfx_quads_draw_freeform(0,0, -100,0, -100,-100, 0,-100); - - gfx_quads_setcolorvertex(0, 1.0f,1.0f,1.0f,0.025f); - gfx_quads_setcolorvertex(1, 1.0f,1.0f,1.0f,0.025f); - gfx_quads_setcolorvertex(2, 1.0f,1.0f,1.0f,0.0f); - gfx_quads_setcolorvertex(3, 1.0f,1.0f,1.0f,0.0f); - const float range = 1000.0f; - gfx_quads_draw_freeform( - pos.x+dir0.x, pos.y+dir0.y, - pos.x+dir1.x, pos.y+dir1.y, - pos.x+dir0.x*range, pos.y+dir0.y*range, - pos.x+dir1.x*range, pos.y+dir1.y*range); - } - gfx_quads_end(); - gfx_blend_normal(); - - gfx_texture_set(texture_sun); - gfx_quads_begin(); - gfx_quads_draw(pos.x, pos.y, 256, 256); - gfx_quads_end(); - } - - // render map - tilemap_render(32.0f, 0); -#ifdef _DEBUG - float speed = 0.0f; -#endif - // render items - int num = snap_num_items(SNAP_CURRENT); - for(int i = 0; i < num; i++) - { - snap_item item; - void *data = snap_get_item(SNAP_CURRENT, i, &item); - - if(item.type == OBJTYPE_PLAYER) - { - void *prev = snap_find_item(SNAP_PREV, item.type, item.id); - if(prev) - { - render_player((obj_player *)prev, (obj_player *)data); -/*#ifdef _DEBUG - { - obj_player *p = (obj_player *)prev; - obj_player *c = (obj_player *)data; - vec2 positionold = vec2(p->x, p->y); - vec2 poscur = vec2(c->x, c->y); - speed = distance(positionold,poscur); - } -#endif*/ - } - } - else if(item.type == OBJTYPE_PROJECTILE) - { - void *prev = snap_find_item(SNAP_PREV, item.type, item.id); - if(prev) - render_projectile((obj_projectile *)prev, (obj_projectile *)data); - } - else if(item.type == OBJTYPE_POWERUP) - { - void *prev = snap_find_item(SNAP_PREV, item.type, item.id); - if(prev) - render_powerup((obj_powerup*)prev, (obj_powerup *)data); - } - } - - // render particles - temp_system.update(client_frametime()); - temp_system.render(); - - tilemap_render(32.0f, 1); - - // render health mods - healthmods.render(); - - // render cursor - // FIXME CURSOR!!! - - if(local_player) - { - gfx_texture_set(texture_weapon); - gfx_quads_begin(); - if (local_player->modifier & (1 << MODIFIER_TYPE_NINJA)) - cell_select_ex(numcellsx,numcellsy, modifiertexcoordcursor[MODIFIER_TYPE_NINJA].x, modifiertexcoordcursor[MODIFIER_TYPE_NINJA].y, modifiertexcoordcursor[MODIFIER_TYPE_NINJA].w, modifiertexcoordcursor[MODIFIER_TYPE_NINJA].h); - else - cell_select_ex(numcellsx,numcellsy, weapontexcoordcursor[local_player->weapon].x, weapontexcoordcursor[local_player->weapon].y, weapontexcoordcursor[local_player->weapon].w, weapontexcoordcursor[local_player->weapon].h); - float cursorsize = 64; - gfx_quads_draw(local_player_pos.x+mouse_pos.x, local_player_pos.y+mouse_pos.y,cursorsize,cursorsize); - - - // render ammo count - // render gui stuff - gfx_quads_end(); - gfx_quads_begin(); - gfx_mapscreen(0,0,400,300); - cell_select_ex(numcellsx,numcellsy, weaponprojtexcoord[local_player->weapon].x, weaponprojtexcoord[local_player->weapon].y, weaponprojtexcoord[local_player->weapon].w, weaponprojtexcoord[local_player->weapon].h); - for (int i = 0; i < local_player->ammocount; i++) - { - gfx_quads_drawTL(10+i*12,34,10,10); - } - gfx_quads_end(); - - gfx_texture_set(texture_game); - gfx_quads_begin(); - int h = 0; - cell_select_ex(32,16, 0,0, 4,4); - for(; h < local_player->health; h++) - gfx_quads_drawTL(10+h*12,10,10,10); - - cell_select_ex(32,16, 5,0, 4,4); - for(; h < 10; h++) - gfx_quads_drawTL(10+h*12,10,10,10); - - h = 0; - cell_select_ex(32,16, 0,5, 4,4); - for(; h < local_player->armor; h++) - gfx_quads_drawTL(10+h*12,22,10,10); - - cell_select_ex(32,16, 5,5, 4,4); - for(; h < 10; h++) - gfx_quads_drawTL(10+h*12,22,10,10); - gfx_quads_end(); - - // render speed -/*#ifdef _DEBUG - gfx_texture_set(font_texture); - char text[256]; - sprintf(text,"speed: %f",speed); - gfx_quads_text(300,20,10,text); -#endif*/ - } - // render gui stuff - gfx_mapscreen(0,0,400,300); - // render score board - if(inp_key_pressed(baselib::keys::tab)) - { - gfx_texture_set(font_texture); - gfx_quads_text(10, 50, 8, "Score Board"); - - int num = snap_num_items(SNAP_CURRENT); - int row = 1; - for(int i = 0; i < num; i++) - { - snap_item item; - void *data = snap_get_item(SNAP_CURRENT, i, &item); - - if(item.type == OBJTYPE_PLAYER) - { - obj_player *player = (obj_player *)data; - if(player) - { - char buf[128]; - char name[32]; - snap_decode_string(player->name, name, 32); - sprintf(buf, "%4d %s", player->score, name); - gfx_quads_text(10, 50 + 10 * row, 8, buf); - row++; - } - } - } - } -} diff --git a/src/game/game_server.cpp b/src/game/game_server.cpp deleted file mode 100644 index 5e93165a..00000000 --- a/src/game/game_server.cpp +++ /dev/null @@ -1,2122 +0,0 @@ -#include -#include -#include "game.h" - -using namespace baselib; - -// --------- PHYSICS TWEAK! -------- -const float ground_control_speed = 7.0f; -const float ground_control_accel = 2.0f; -const float ground_friction = 0.5f; -const float ground_jump_speed = 12.0f; -const float air_control_speed = 3.5f; -const float air_control_accel = 1.2f; -const float air_friction = 0.95f; -const float hook_length = 32*10.0f; -const float hook_fire_speed = 45.0f; -const float hook_drag_accel = 3.0f; -const float hook_drag_speed = 15.0f; -const float gravity = 0.5f; - -class player* get_player(int index); -void create_healthmod(vec2 p, int amount); -void create_explosion(vec2 p, int owner = -1, bool bnodamage = false); -void create_smoke(vec2 p); -void create_sound(vec2 pos, int sound, int loopflags = 0); -class player* intersect_player(vec2 pos0, vec2 pos1, vec2& new_pos, class entity* notthis = 0); - -// TODO: rewrite this smarter! -void move_box(vec2 *inout_pos, vec2 *inout_vel, vec2 size, float elasticity) -{ - // do the move - vec2 pos = *inout_pos; - vec2 vel = *inout_vel; - - float distance = length(vel); - int max = (int)distance; - - vec2 offsets[4] = { vec2(-size.x/2, -size.y/2), vec2( size.x/2, -size.y/2), - vec2(-size.x/2, size.y/2), vec2( size.x/2, size.y/2)}; - - if(distance > 0.00001f) - { - vec2 old_pos = pos; - for(int i = 0; i <= max; i++) - { - float amount = i/(float)max; - if(max == 0) - amount = 0; - - vec2 new_pos = pos + vel*amount; // TODO: this row is not nice - - for(int p = 0; p < 4; p++) - { - vec2 np = new_pos+offsets[p]; - vec2 op = old_pos+offsets[p]; - if(col_check_point(np)) - { - int affected = 0; - if(col_check_point(np.x, op.y)) - { - vel.x = -vel.x*elasticity; - pos.x = old_pos.x; - new_pos.x = old_pos.x; - affected++; - } - - if(col_check_point(op.x, np.y)) - { - vel.y = -vel.y*elasticity; - pos.y = old_pos.y; - new_pos.y = old_pos.y; - affected++; - } - - if(!affected) - { - new_pos = old_pos; - pos = old_pos; - vel *= -elasticity; - } - } - } - - old_pos = new_pos; - } - - pos = old_pos; - } - - *inout_pos = pos; - *inout_vel = vel; -} - -// TODO: rewrite this smarter! -bool intersect_line(vec2 pos0, vec2 pos1, vec2 *out) -{ - float d = distance(pos0, pos1); - - for(float f = 0; f < d; f++) - { - float a = f/d; - vec2 pos = mix(pos0, pos1, a); - if(col_check_point(pos)) - { - if(out) - *out = pos; - return true; - } - } - if(out) - *out = pos1; - return false; -} - -// -class event_handler -{ - static const int MAX_EVENTS = 128; - static const int MAX_DATASIZE = 128*4; - - int types[MAX_EVENTS]; // TODO: remove some of these arrays - int offsets[MAX_EVENTS]; - int sizes[MAX_EVENTS]; - char data[MAX_DATASIZE]; - - int current_offset; - int num_events; -public: - event_handler() - { - num_events = 0; - } - - void *create(int type, int size) - { - void *p = &data[current_offset]; - offsets[num_events] = current_offset; - types[num_events] = type; - sizes[num_events] = size; - current_offset += size; - num_events++; - return p; - } - - void clear() - { - num_events = 0; - current_offset = 0; - } - - void snap(int snapping_client) - { - for(int i = 0; i < num_events; i++) - { - void *d = snap_new_item(types[i], i, sizes[i]); - mem_copy(d, &data[offsets[i]], sizes[i]); - } - } -}; - -static event_handler events; -/* -template -class pool -{ - struct element - { - int next_free; - T data; - }; - - element elements[SIZE]; - int first_free; -public: - pool() - { - first_free = 0; - for(int i = 0; i < SIZE; i++) - elements[i].next_free = i+1; - elements[SIZE-1].next_free = -1; - } -};*/ - -// a basic entity -class entity -{ -private: - friend class game_world; - friend class player; - entity *prev_entity; - entity *next_entity; - int index; - -public: - vec2 pos; - float proximity_radius; - unsigned flags; - int objtype; - - enum - { - FLAG_DESTROY=0x00000001, - }; - - entity(int objtype) - { - this->objtype = objtype; - pos = vec2(0,0); - flags = 0; - proximity_radius = 0; - } - - virtual ~entity() - { - } - - virtual void destroy() { delete this; } - virtual void tick() {} - virtual void snap(int snapping_client) {} - - virtual bool take_damage(vec2 force, int dmg, int from) { return true; } -}; - -class powerup : public entity -{ -public: - static const int phys_size = 14; - enum - { - POWERUP_FLAG_HOOKABLE = 1 << 0, - }; - vec2 vel; - class player* playerhooked; - int type; - int id; - int subtype; // weapon type for instance? - int numitems; // number off powerup items - int flags; - int spawntick; - powerup(int _type, int _subtype = 0, int _numitems = 0, int _flags = 0); - - static void spawnrandom(int _lifespan); - - void tick(); - - void snap(int snapping_client); -}; - -// game world. handles all entities -class game_world -{ -public: - entity *first_entity; - game_world() - { - first_entity = 0x0; - } - - int find_entities(vec2 pos, float radius, entity **ents, int max) - { - int num = 0; - for(entity *ent = first_entity; ent; ent = ent->next_entity) - { - if(distance(ent->pos, pos) < radius+ent->proximity_radius) - { - ents[num] = ent; - num++; - if(num == max) - break; - } - } - - return num; - } - - int find_entities(vec2 pos, float radius, entity **ents, int max, const int* types, int maxtypes) - { - int num = 0; - for(entity *ent = first_entity; ent; ent = ent->next_entity) - { - for (int i = 0; i < maxtypes; i++) - { - if (ent->objtype != types[i]) - continue; - - if(distance(ent->pos, pos) < radius+ent->proximity_radius) - { - ents[num] = ent; - num++; - if(num == max) - break; - } - } - } - - return num; - } - - void insert_entity(entity *ent) - { - // insert it - if(first_entity) - first_entity->prev_entity = ent; - ent->next_entity = first_entity; - ent->prev_entity = 0x0; - first_entity = ent; - } - - void destroy_entity(entity *ent) - { - ent->flags |= entity::FLAG_DESTROY; - // call destroy - //remove_entity(ent); - //ent->destroy(); - } - - void remove_entity(entity *ent) - { - // remove - if(ent->prev_entity) - ent->prev_entity->next_entity = ent->next_entity; - else - first_entity = ent->next_entity; - if(ent->next_entity) - ent->next_entity->prev_entity = ent->prev_entity; - } - - // - void snap(int snapping_client) - { - for(entity *ent = first_entity; ent; ent = ent->next_entity) - ent->snap(snapping_client); - } - - void tick() - { - // update all objects - for(entity *ent = first_entity; ent; ent = ent->next_entity) - ent->tick(); - - // destroy objects marked for destruction - entity *ent = first_entity; - while(ent) - { - entity *next = ent->next_entity; - if(ent->flags&entity::FLAG_DESTROY) - { - remove_entity(ent); - ent->destroy(); - } - ent = next; - } - } -}; - -static game_world world; - -// projectile entity -class projectile : public entity -{ -public: - enum - { - PROJECTILE_FLAGS_EXPLODE = 1 << 0, - }; - vec2 vel; - entity* powner; - int lifespan; - int id; - int owner; - int type; - int flags; - int damage; - int sound_impact; - float force; - - projectile(int type, int owner, vec2 pos, vec2 vel, int span, entity* powner, int damage, int flags = 0, float force = 0.0f, int sound_impact = -1) : - entity(OBJTYPE_PROJECTILE) - { - static int current_id = 0; - this->id = current_id++; - this->type = type; - this->pos = pos; - this->vel = vel; - this->lifespan = span; - this->owner = owner; - this->powner = powner; - this->flags = flags; - this->force = force; - this->damage = damage; - this->sound_impact = sound_impact; - world.insert_entity(this); - } - - void tick() - { - vec2 oldpos = pos; - vel.y += 0.25f; - pos += vel; - lifespan--; - // check player intersection as well - entity* targetplayer = (entity*)intersect_player(oldpos, pos, oldpos, powner); - if(targetplayer || lifespan < 0 || col_check_point((int)pos.x, (int)pos.y)) - { - if (lifespan >= 0) - create_sound(pos, sound_impact); - if (flags & PROJECTILE_FLAGS_EXPLODE) - { - create_explosion(oldpos, owner); - } - else if (targetplayer) - { - targetplayer->take_damage(normalize(vel) * force, damage, owner); - } - world.destroy_entity(this); - } - } - - void snap(int snapping_client) - { - obj_projectile *proj = (obj_projectile *)snap_new_item(OBJTYPE_PROJECTILE, id, sizeof(obj_projectile)); - proj->x = (int)pos.x; - proj->y = (int)pos.y; - proj->vx = (int)vel.x; - proj->vy = (int)vel.y; - proj->type = type; - } -}; - -// player entity -class player : public entity -{ -public: - static const int phys_size = 28; - enum - { - WEAPON_NEEDRELOAD = 1 << 0, - WEAPON_DROPONUNEQUIP = 1 << 1, - WEAPON_DRAWSAMMO = 1 << 2, - WEAPON_HASSECONDARY = 1 << 3, - WEAPON_ISACTIVE = 1 << 4, // has the item - WEAPON_AUTOFIRE = 1 << 5, - - WEAPON_PROJECTILETYPE_GUN = 0, - WEAPON_PROJECTILETYPE_ROCKET = 1, - WEAPON_PROJECTILETYPE_SHOTGUN = 2, - - // Gun - - - // modifiers - MODIFIER_HASACTIVATIONS = 1 << 0, - MODIFIER_TIMELIMITED = 1 << 1, - MODIFIER_ISACTIVE = 1 << 2, - MODIFIER_NEEDSACTIVATION = 1 << 3, - - MODIFIER_RETURNFLAGS_OVERRIDEWEAPON = 1 << 0, - MODIFIER_RETURNFLAGS_OVERRIDEVELOCITY = 1 << 1, - MODIFIER_RETURNFLAGS_OVERRIDEPOSITION = 1 << 2, - MODIFIER_RETURNFLAGS_OVERRIDEGRAVITY = 1 << 3, - }; - class weapon - { - public: - entity* hitobjects[10]; - int numobjectshit; // for melee, so we don't hit the same object more than once per bash - int weapontype; - int equiptime; - int unequiptime; - int numammo; - int magsize; - int nummagazines; - int flags; - int firetime; - int reloadtime; - int projectileclass; - int damage; - int sound_fire; - int sound_equip; - int sound_impact; - int sound_impact_projectile; - int visualtimeattack; - float projectilevel; - float projectilespan; - float reach; // for melee - float force; - float recoilforce; - float projoffsety; - float projoffsetx; - - weapon() - { - weapontype = 0; - numammo = 0; - flags = 0; - reloadtime = 0; - projectileclass = 0; - numobjectshit = 0; - reach = 0.0f; - force = 5.0f; - damage = 1; - sound_fire = -1; - sound_equip = -1; - sound_impact = -1; - sound_impact_projectile = -1, - visualtimeattack = 3; - recoilforce = 0.0f; - projoffsety = 0.0f; - projoffsetx = 0.0f; - } - - void setgun(int ammo = 10) - { - weapontype = WEAPON_TYPE_GUN; - flags = 0;//WEAPON_DRAWSAMMO; - numammo = ammo; - projectileclass = WEAPON_PROJECTILETYPE_GUN; - firetime = SERVER_TICK_SPEED/10; - magsize = 0; - projectilevel = 30.0f; - projectilespan = 50.0f * 1.0f; - sound_fire = SOUND_FIRE_GUN; - sound_equip = SOUND_EQUIP_GUN; - sound_impact_projectile = SOUND_IMPACT_PROJECTILE_GUN; - projoffsety = -10.0f; - projoffsetx = 24.0f; - } - - void setrocket(int ammo = 10) - { - weapontype = WEAPON_TYPE_ROCKET; - flags = WEAPON_DRAWSAMMO; - numammo = ammo; - projectileclass = WEAPON_PROJECTILETYPE_ROCKET; - projectilevel = 15.0f; - projectilespan = 50.0f * 5.0f; - firetime = SERVER_TICK_SPEED * 4/5; - magsize = 0; - recoilforce = 5.0f; - sound_fire = SOUND_FIRE_ROCKET; - sound_equip = SOUND_EQUIP_ROCKET; - sound_impact_projectile = SOUND_IMPACT_PROJECTILE_ROCKET; - projoffsety = -17.0f; - projoffsetx = 24.0f; - } - - /*void setsniper(int ammo = 10) - { - weapontype = WEAPON_TYPE_SNIPER; - flags = WEAPON_DRAWSAMMO | WEAPON_HASSECONDARY | WEAPON_NEEDRELOAD; - numammo = ammo; - projectileclass = WEAPON_PROJECTILETYPE_SNIPER; - projectilevel = 30.0f; - projectilespan = 50.0f * 5.0f; - firetime = SERVER_TICK_SPEED; - reloadtime = SERVER_TICK_SPEED/2; - magsize = 2; - recoilforce = 20.0f; - }*/ - - void setshotgun(int ammo = 10) - { - weapontype = WEAPON_TYPE_SHOTGUN; - flags = WEAPON_DRAWSAMMO | WEAPON_NEEDRELOAD; - numammo = ammo; - projectileclass = WEAPON_PROJECTILETYPE_SHOTGUN; - projectilevel = 30.0f; - projectilespan = 50.0f * 5.0f; - firetime = SERVER_TICK_SPEED/2; - reloadtime = SERVER_TICK_SPEED/2; - magsize = 2; - damage = 3; - recoilforce = 5.0f; - sound_fire = SOUND_FIRE_SHOTGUN; - sound_equip = SOUND_EQUIP_SHOTGUN; - sound_impact_projectile = SOUND_IMPACT_PROJECTILE_SHOTGUN; - projoffsety = -17.0f; - projoffsetx = 24.0f; - } - - void setmelee(int ammo = 10) - { - weapontype = WEAPON_TYPE_MELEE; - flags = 0;//WEAPON_AUTOFIRE; - numammo = ammo; - projectileclass = -1; - firetime = SERVER_TICK_SPEED/5; - reloadtime = 0; - magsize = 2; - numobjectshit = 0; - reach = 15.0f; - damage = 1; - sound_fire = SOUND_FIRE_MELEE; - sound_equip = SOUND_EQUIP_MELEE; - sound_impact = SOUND_PLAYER_IMPACT; - } - - void settype() - { - switch(weapontype) - { - case WEAPON_TYPE_GUN: - { - setgun(); - break; - } - case WEAPON_TYPE_ROCKET: - { - setrocket(); - break; - } - /*case WEAPON_TYPE_SNIPER: - { - setsniper(); - break; - }*/ - case WEAPON_TYPE_SHOTGUN: - { - setshotgun(); - break; - } - case WEAPON_TYPE_MELEE: - { - setmelee(); - break; - } - default: - break; - } - } - - int activate(player* player) - { - // create sound event for fire - int projectileflags = 0; - create_sound(player->pos, sound_fire); - - switch (weapontype) - { - case WEAPON_TYPE_ROCKET: - projectileflags |= projectile::PROJECTILE_FLAGS_EXPLODE; - case WEAPON_TYPE_GUN: - //case WEAPON_TYPE_SNIPER: - case WEAPON_TYPE_SHOTGUN: - { - if (flags & WEAPON_DRAWSAMMO) - numammo--; - // Create projectile - new projectile(projectileclass, player->client_id, player->pos+vec2(0,projoffsety)+player->direction*projoffsetx, player->direction*projectilevel, projectilespan, player, damage, projectileflags, force, sound_impact_projectile); - // recoil force if any - if (recoilforce > 0.0f) - { - vec2 dir(player->direction.x,0.5); - if (dir.x == 0.0f) - dir.x = 0.5f; - else - dir = normalize(dir); - player->vel -= dir * recoilforce; - } - return firetime; - } - case WEAPON_TYPE_MELEE: - { - // Start bash sequence - numobjectshit = 0; - return firetime; - } - default: - return 0; - } - } - - void update(player* owner, int fire_timeout) - { - switch(weapontype) - { - case WEAPON_TYPE_MELEE: - { - // No more melee - if (fire_timeout <= 0) - return; - - // only one that needs update (for now) - // do selection for the weapon and bash anything in it - // check if we hit anything along the way - int type = OBJTYPE_PLAYER; - entity *ents[64]; - vec2 dir = owner->pos + owner->direction * reach; - float radius = length(dir * 0.5f); - vec2 center = owner->pos + dir * 0.5f; - int num = world.find_entities(center, radius, ents, 64, &type, 1); - - for (int i = 0; i < num; i++) - { - // Check if entity is a player - if (ents[i] == owner) - continue; - // make sure we haven't hit this object before - bool balreadyhit = false; - for (int j = 0; j < numobjectshit; j++) - { - if (hitobjects[j] == ents[i]) - balreadyhit = true; - } - if (balreadyhit) - continue; - - // check so we are sufficiently close - if (distance(ents[i]->pos, owner->pos) > (owner->phys_size * 2.0f)) - continue; - - // hit a player, give him damage and stuffs... - // create sound for bash - create_sound(ents[i]->pos, sound_impact); - - // set his velocity to fast upward (for now) - create_smoke(ents[i]->pos); - hitobjects[numobjectshit++] = ents[i]; - ents[i]->take_damage(vec2(0,10.0f), damage, owner->client_id); - player* target = (player*)ents[i]; - vec2 dir; - if (length(target->pos - owner->pos) > 0.0f) - dir = normalize(target->pos - owner->pos); - else - dir = vec2(0,-1); - target->vel += dir * 10.0f + vec2(0,-10.0f); - } - break; - } - default: - break; - } - } - }; - - class modifier - { - public: - vec2 activationdir; - entity* hitobjects[10]; - int numobjectshit; - float velocity; - int modifiertype; - int duration; - int numactivations; - int activationtime; - int cooldown; - int movetime; - int visualtimeattack; - int currentactivation; - int currentmovetime; - int currentcooldown; - int damage; - int flags; - int sound_impact; - int sound_activate; - - modifier() - { - modifiertype = 0; - duration = 0; - numobjectshit = 0; - numactivations = 0; - activationtime = 0; - cooldown = 0; - movetime = 0; - currentactivation = 0; - currentmovetime = 0; - currentcooldown =0; - damage = 0; - flags = 0; - activationdir = vec2(0.0f, 1.0f); - velocity = 0.0f; - visualtimeattack = 0; - sound_impact = -1; - } - - void setninja() - { - modifiertype = MODIFIER_TYPE_NINJA; - duration = SERVER_TICK_SPEED * 15; - numactivations = -1; - movetime = SERVER_TICK_SPEED / 5; - activationtime = SERVER_TICK_SPEED / 2; - cooldown = SERVER_TICK_SPEED; - currentactivation = 0; - currentmovetime = 0; - numobjectshit = 0; - damage = 3; - flags = MODIFIER_TIMELIMITED | MODIFIER_NEEDSACTIVATION; - velocity = 50.0f; - visualtimeattack = 3; - sound_impact = SOUND_PLAYER_IMPACT_NINJA; - sound_activate = SOUND_FIRE_NINJA; - } - - void settimefield() - { - modifiertype = MODIFIER_TYPE_TIMEFIELD; - duration = SERVER_TICK_SPEED * 10; - numactivations = -1; - activationtime = SERVER_TICK_SPEED; - numobjectshit = 0; - currentactivation = 0; - flags = MODIFIER_TIMELIMITED; - velocity = 0.0f; - } - - void settype() - { - switch (modifiertype) - { - case MODIFIER_TYPE_NINJA: - { - setninja(); - break; - } - case MODIFIER_TYPE_TIMEFIELD: - { - settimefield(); - break; - } - default: - break; - } - } - - int updateninja(player* player) - { - if (currentactivation <= 0) - return MODIFIER_RETURNFLAGS_OVERRIDEWEAPON; - currentactivation--; - currentmovetime--; - - if (currentmovetime == 0) - { - // reset player velocity - player->vel *= 0.2f; - //return MODIFIER_RETURNFLAGS_OVERRIDEWEAPON; - } - - if (currentmovetime > 0) - { - // Set player velocity - player->vel = activationdir * velocity; - vec2 oldpos = player->pos; - move_box(&player->pos, &player->vel, vec2(player->phys_size, player->phys_size), 0.0f); - // reset velocity so the client doesn't predict stuff - player->vel = vec2(0.0f,0.0f); - if ((currentmovetime % 2) == 0) - { - create_smoke(player->pos); - } - - // check if we hit anything along the way - { - int type = OBJTYPE_PLAYER; - entity *ents[64]; - vec2 dir = player->pos - oldpos; - float radius = length(dir * 0.5f); - vec2 center = oldpos + dir * 0.5f; - int num = world.find_entities(center, radius, ents, 64, &type, 1); - - for (int i = 0; i < num; i++) - { - // Check if entity is a player - if (ents[i] == player) - continue; - // make sure we haven't hit this object before - bool balreadyhit = false; - for (int j = 0; j < numobjectshit; j++) - { - if (hitobjects[j] == ents[i]) - balreadyhit = true; - } - if (balreadyhit) - continue; - - // check so we are sufficiently close - if (distance(ents[i]->pos, player->pos) > (player->phys_size * 2.0f)) - continue; - - // hit a player, give him damage and stuffs... - create_sound(ents[i]->pos, sound_impact); - // set his velocity to fast upward (for now) - hitobjects[numobjectshit++] = ents[i]; - ents[i]->take_damage(vec2(0,10.0f), damage, player->client_id); - } - } - return MODIFIER_RETURNFLAGS_OVERRIDEWEAPON | MODIFIER_RETURNFLAGS_OVERRIDEVELOCITY | MODIFIER_RETURNFLAGS_OVERRIDEPOSITION|MODIFIER_RETURNFLAGS_OVERRIDEGRAVITY; - } - - - // move char, and check intersection from us to target - return MODIFIER_RETURNFLAGS_OVERRIDEWEAPON | MODIFIER_RETURNFLAGS_OVERRIDEVELOCITY; - } - - int activateninja(player* player) - { - // ok then, activate ninja - activationdir = player->direction; - currentactivation = activationtime; - currentmovetime = movetime; - currentcooldown = cooldown; - // reset hit objects - numobjectshit = 0; - - create_sound(player->pos, SOUND_FIRE_NINJA); - - return MODIFIER_RETURNFLAGS_OVERRIDEWEAPON; - } - - int activate(player* player) - { - if (flags & MODIFIER_NEEDSACTIVATION) - { - if (!numactivations) - return 0; - numactivations--; - } - - switch (modifiertype) - { - case MODIFIER_TYPE_NINJA: - { - return activateninja(player); - } - /*case MODIFIER_TYPE_TIMEFIELD: - { - updatetimefield(); - break; - }*/ - default: - return 0; - } - } - int update(player* player) - { - switch (modifiertype) - { - case MODIFIER_TYPE_NINJA: - { - return updateninja(player); - } - /*case MODIFIER_TYPE_TIMEFIELD: - { - updatetimefield(); - break; - }*/ - default: - return 0; - } - } - }; - - enum - { - PLAYER_FLAGS_ISRELOADING = 1 << 0, - PLAYER_FLAGS_ISEQUIPPING = 1 << 1, - }; - - weapon lweapons[WEAPON_NUMWEAPONS]; - modifier modifiers[MODIFIER_NUMMODIFIERS]; - int iactiveweapon; - int inextweapon; - int equip_time; - - int client_id; - int flags; - - char name[32]; - player_input previnput; - player_input input; - int tick_count; - int damage_taken_tick; - - vec2 vel; - vec2 direction; - - int jumped; - int airjumped; - - //int firing; - int hooking; - - int fire_timeout; - int reload_timeout; - - int health; - int armor; - - int score; - - // sounds - int sound_player_jump; - int sound_player_land; - int sound_player_hurt_short; - int sound_player_hurt_long; - int sound_player_spawn; - int sound_player_chain_loop; - int sound_player_chain_impact; - int sound_player_impact; - int sound_player_impact_ninja; - int sound_player_die; - int sound_player_switchweapon; - - player* phookedplayer; - powerup* phookedpowerup; - int numhooked; - vec2 hook_pos; - vec2 hook_dir; - - player() : - entity(OBJTYPE_PLAYER) - { - reset(); - - //firing = 0; - // setup weaponflags and stuff - lweapons[WEAPON_TYPE_GUN].setgun(); - lweapons[WEAPON_TYPE_ROCKET].setrocket(); - //lweapons[WEAPON_TYPE_SNIPER].setsniper(); - lweapons[WEAPON_TYPE_SHOTGUN].setshotgun(); - lweapons[WEAPON_TYPE_MELEE].setmelee(); - - modifiers[MODIFIER_TYPE_NINJA].setninja(); - modifiers[MODIFIER_TYPE_TIMEFIELD].settimefield(); - //modifiers[MODIFIER_TYPE_NINJA].flags |= MODIFIER_ISACTIVE; - - sound_player_jump = SOUND_PLAYER_JUMP; - sound_player_hurt_short = SOUND_PLAYER_HURT_SHORT; - sound_player_hurt_long = SOUND_PLAYER_HURT_LONG; - sound_player_spawn = SOUND_PLAYER_SPAWN; - sound_player_chain_loop = SOUND_PLAYER_CHAIN_LOOP; - sound_player_chain_impact = SOUND_PLAYER_CHAIN_IMPACT; - sound_player_impact = SOUND_PLAYER_IMPACT; - sound_player_impact_ninja = SOUND_PLAYER_IMPACT_NINJA; - sound_player_die = SOUND_PLAYER_DIE; - sound_player_switchweapon = SOUND_PLAYER_SWITCHWEAPON; - sound_player_land = SOUND_PLAYER_LAND; - } - - void reset() - { - equip_time = 0; - phookedplayer = 0; - numhooked = 0; - proximity_radius = phys_size; - name[0] = 'n'; - name[1] = 'o'; - name[2] = 'o'; - name[3] = 'b'; - name[4] = 0; - - pos = vec2(100.0f, 0.0f); - vel = vec2(0.0f, 0.0f); - direction = vec2(0.0f, 1.0f); - client_id = -1; - tick_count = 0; - score = 0; - flags = 0; - } - - virtual void destroy() { flags = 0; } - - void respawn() - { - health = PLAYER_MAXHEALTH; - armor = 0; - - hooking = 0; - phookedplayer = 0; - phookedpowerup = 0; - numhooked = 0; - fire_timeout = 0; - reload_timeout = 0; - iactiveweapon = 0; - inextweapon = -1; - equip_time = 0; - jumped = 0; - airjumped = 0; - mem_zero(&input, sizeof(input)); - vel = vec2(0.0f, 0.0f); - - int start, num; - map_get_type(1, &start, &num); - - if(num) - { - mapres_spawnpoint *sp = (mapres_spawnpoint*)map_get_item(start + (rand()%num), NULL, NULL); - pos = vec2(sp->x, sp->y); - } - else - pos = vec2(100.0f, -60.0f); - - // reset active flags - for (int i = 0; i < WEAPON_NUMWEAPONS; i++) - { - // reset and remove - lweapons[i].settype(); - lweapons[i].flags &= ~WEAPON_ISACTIVE; - } - - - // TEMP REMOVE - - /*for (int i = 0; i < WEAPON_NUMWEAPONS; i++) - { - lweapons[i].settype(); - lweapons[i].flags |= WEAPON_ISACTIVE; - }*/ - lweapons[WEAPON_TYPE_MELEE].flags |= WEAPON_ISACTIVE; - // Add gun as default weapon - iactiveweapon = WEAPON_TYPE_GUN; - lweapons[WEAPON_TYPE_GUN].numammo = 10; - lweapons[WEAPON_TYPE_GUN].flags |= WEAPON_ISACTIVE; - - create_sound(pos, sound_player_spawn); - } - - bool is_grounded() - { - if(col_check_point((int)(pos.x+phys_size/2), (int)(pos.y+phys_size/2+5))) - return true; - if(col_check_point((int)(pos.x-phys_size/2), (int)(pos.y+phys_size/2+5))) - return true; - return false; - } - - // Disable weapon activation if this returns true - int handlemodifiers() - { - int returnflags = 0; - for (int i = 0; i < MODIFIER_NUMMODIFIERS; i++) - { - if (modifiers[i].flags & MODIFIER_ISACTIVE) - { - modifiers[i].duration--; - modifiers[i].currentcooldown--; - - // Check if it should activate - if (modifiers[i].currentcooldown <= 0 && - (modifiers[i].flags & MODIFIER_NEEDSACTIVATION) && - input.fire && !(previnput.fire)) - { - returnflags |= modifiers[i].activate(this); - } - - returnflags |= modifiers[i].update(this); - - // remove active if timed out - if (modifiers[i].duration <= 0 && modifiers[i].currentactivation <= 0) - modifiers[i].flags &= ~MODIFIER_ISACTIVE; - } - } - return returnflags; - } - - void handleweapon() - { - // handle weapon - if(input.fire && (!previnput.fire || lweapons[iactiveweapon].flags & WEAPON_AUTOFIRE) && - !(flags & PLAYER_FLAGS_ISEQUIPPING) && !reload_timeout) - { - if(fire_timeout == 0) - { - if (lweapons[iactiveweapon].numammo || !(lweapons[iactiveweapon].flags & WEAPON_DRAWSAMMO)) - { - // Decrease ammo - fire_timeout = lweapons[iactiveweapon].activate(this); - } - else if ((lweapons[iactiveweapon].flags & WEAPON_NEEDRELOAD) && lweapons[iactiveweapon].nummagazines) - { - // reload - reload_timeout = lweapons[iactiveweapon].reloadtime; - lweapons[iactiveweapon].nummagazines--; - lweapons[iactiveweapon].numammo = lweapons[iactiveweapon].magsize; - } - } - } - - // update active weapon - lweapons[iactiveweapon].update(this, fire_timeout); - } - - void handlehook() - { - // handle hook - if(input.hook) - { - if(hooking == 0) - { - hooking = 1; - hook_pos = pos; - hook_dir = direction; - // Sound - create_sound(pos, sound_player_chain_loop, SOUND_LOOPFLAG_STARTLOOP); - } - else if(hooking == 1) - { - vec2 new_pos = hook_pos+hook_dir*hook_fire_speed; - - // Check against other players and powerups first - player* targetplayer = 0; - powerup* targetpowerup = 0; - { - static const int typelist[2] = { OBJTYPE_PLAYER, OBJTYPE_POWERUP}; - entity *ents[64]; - vec2 dir = new_pos - hook_pos; - float radius = length(dir * 0.5f); - vec2 center = hook_pos + dir * 0.5f; - int num = world.find_entities(center, radius, ents, 64,typelist,2); - - for (int i = 0; i < num; i++) - { - // Check if entity is a player - if (ents[i] == this || (targetplayer && targetpowerup)) - continue; - - if (!targetplayer && ents[i]->objtype == OBJTYPE_PLAYER) - { - // temp, set hook pos to our position - if (((player*)ents[i])->phookedplayer != this) - targetplayer = (player*)ents[i]; - } - else if (!targetpowerup && ents[i]->objtype == OBJTYPE_POWERUP && - (((powerup*)ents[i])->flags & powerup::POWERUP_FLAG_HOOKABLE)) - { - targetpowerup = (powerup*)ents[i]; - } - } - } - - //player* targetplayer = intersect_player(hook_pos, hook_pos, new_pos, this); - if (targetplayer) - { - // So he can't move "normally" - new_pos = targetplayer->pos; - phookedplayer = targetplayer; - targetplayer->numhooked++; - hooking = 3; - create_sound(pos, sound_player_chain_impact); - - // stop looping chain sound - create_sound(pos, sound_player_chain_loop, SOUND_LOOPFLAG_STOPLOOP); - } - else if (targetpowerup) - { - new_pos = targetpowerup->pos; - phookedpowerup = targetpowerup; - phookedpowerup->playerhooked = this; - hooking = 4; - create_sound(pos, sound_player_chain_impact); - - // stop looping chain sound - create_sound(pos, sound_player_chain_loop, SOUND_LOOPFLAG_STOPLOOP); - } - else if(intersect_line(hook_pos, new_pos, &new_pos)) - { - hooking = 2; - create_sound(pos, sound_player_chain_impact); - - // stop looping chain sound - create_sound(pos, sound_player_chain_loop, SOUND_LOOPFLAG_STOPLOOP); - } - else if(distance(pos, new_pos) > hook_length) - { - hooking = -1; - create_sound(pos, sound_player_chain_loop, SOUND_LOOPFLAG_STOPLOOP); - } - - hook_pos = new_pos; - } - else if(hooking == 2) - { - vec2 hookvel = normalize(hook_pos-pos)*hook_drag_accel; - // the hook as more power to drag you up then down. - // this makes it easier to get on top of an platform - if(hookvel.y > 0) - hookvel.y *= 0.3f; - - // the hook will boost it's power if the player wants to move - // in that direction. otherwise it will dampen everything abit - if((hookvel.x < 0 && input.left) || (hookvel.x > 0 && input.right)) - hookvel.x *= 0.95f; - else - hookvel.x *= 0.75f; - vec2 new_vel = vel+hookvel; - - // check if we are under the legal limit for the hook - if(length(new_vel) < hook_drag_speed || length(new_vel) < length(vel)) - vel = new_vel; // no problem. apply - } - else if (hooking == 3) - { - // hmm, force the targetplayer towards us if possible, otherwise us towards them if they are already hooked - if (phookedplayer) - { - if (phookedplayer->hooking > 1) - { - // Drag us towards target player - vec2 hookvel = normalize(hook_pos-pos)*hook_drag_accel; - if((hookvel.x < 0 && input.left) || (hookvel.x > 0 && input.right)) - hookvel.x *= 0.95f; - else - hookvel.x *= 0.75f; - - // Apply the velocity - // the hook will boost it's power if the player wants to move - // in that direction. otherwise it will dampen everything abit - vec2 new_vel = vel+hookvel; - - // check if we are under the legal limit for the hook - if(length(new_vel) < hook_drag_speed || length(new_vel) < length(vel)) - vel = new_vel; // no problem. apply - } - else - { - // Drag targetplayer towards us - vec2 hookvel = normalize(pos-hook_pos)*hook_drag_accel; - - // Apply the velocity - // the hook will boost it's power if the player wants to move - // in that direction. otherwise it will dampen everything abit - vec2 new_vel = phookedplayer->vel+hookvel; - - // check if we are under the legal limit for the hook - if(length(new_vel) < hook_drag_speed || length(new_vel) < length(vel)) - phookedplayer->vel = new_vel; // no problem. apply - } - hook_pos = phookedplayer->pos; - // if hooked player dies, release the hook - } - else - { - hooking = -1; - phookedplayer = 0; - } - } - else if (hooking == 4) - { - // Have a powerup, drag it towards us - vec2 hookvel = normalize(pos-hook_pos)*hook_drag_accel; - - // Apply the velocity - // the hook will boost it's power if the player wants to move - // in that direction. otherwise it will dampen everything abit - vec2 new_vel = phookedpowerup->vel+hookvel; - - // check if we are under the legal limit for the hook - if(length(new_vel) < hook_drag_speed || length(new_vel) < length(vel)) - phookedpowerup->vel = new_vel; // no problem. apply - hook_pos = phookedpowerup->pos; - } - } - else - { - hooking = 0; - hook_pos = pos; - if (phookedplayer) - { - phookedplayer->numhooked--; - phookedplayer = 0; - } - } - } - - void getattackticks(int& curattack, int& attacklen, int& visualtimeattack) - { - // time left from current attack (if any) - // first check modifiers (ninja...) - for (int i = 0; i < MODIFIER_NUMMODIFIERS; i++) - { - if ((modifiers[i].flags & (MODIFIER_ISACTIVE | MODIFIER_NEEDSACTIVATION)) == (MODIFIER_ISACTIVE | MODIFIER_NEEDSACTIVATION)) - { - curattack = modifiers[i].currentactivation; - attacklen = modifiers[i].activationtime; - visualtimeattack = modifiers[i].visualtimeattack; - return; - } - } - - // otherwise current fire timeout - curattack = fire_timeout; - attacklen = lweapons[iactiveweapon].firetime; - visualtimeattack = lweapons[iactiveweapon].visualtimeattack; - } - - virtual void tick() - { - tick_count++; - - // fetch some info - bool grounded = is_grounded(); - direction = get_direction(input.angle); - - // decrease reload timer - if(fire_timeout) - fire_timeout--; - if (reload_timeout) - reload_timeout--; - - // Switch weapons - if (flags & PLAYER_FLAGS_ISEQUIPPING) - { - equip_time--; - if (equip_time <= 0) - { - if (inextweapon >= 0) - { - equip_time = SERVER_TICK_SPEED * lweapons[inextweapon].equiptime; - iactiveweapon = inextweapon; - inextweapon = -1; - - // Send switch weapon event to client? - } - else - { - flags &= ~PLAYER_FLAGS_ISEQUIPPING; - } - } - } - else if (input.activeweapon && iactiveweapon != (input.activeweapon & ~0x80000000)) - { - input.activeweapon &= ~0x80000000; - // check which weapon to activate - if (input.activeweapon >= 0 && input.activeweapon < WEAPON_NUMWEAPONS && - (lweapons[input.activeweapon].flags & WEAPON_ISACTIVE)) - { - inextweapon = input.activeweapon; - equip_time = SERVER_TICK_SPEED * lweapons[iactiveweapon].unequiptime; - // unequip current - flags |= PLAYER_FLAGS_ISEQUIPPING; - - create_sound(pos, sound_player_switchweapon); - } - } - - // don't do any weapon activations if modifier is currently overriding - int modifierflags = handlemodifiers(); - if (!(modifierflags & MODIFIER_RETURNFLAGS_OVERRIDEWEAPON)) - handleweapon(); - - handlehook(); - - // handle movement - if(grounded) - { - if (airjumped) - create_sound(pos, SOUND_PLAYER_LAND); - airjumped = 0; - } - - float elast = 0.0f; - - if (!numhooked) - { - // I'm hooked by someone, so don't do any movement plz (temp) - if (!(modifierflags & MODIFIER_RETURNFLAGS_OVERRIDEVELOCITY)) - { - if(grounded) - { - // ground movement - if(input.left) - { - if(vel.x > -ground_control_speed) - { - vel.x -= ground_control_accel; - if(vel.x < -ground_control_speed) - vel.x = -ground_control_speed; - } - } - else if(input.right) - { - if(vel.x < ground_control_speed) - { - vel.x += ground_control_accel; - if(vel.x > ground_control_speed) - vel.x = ground_control_speed; - } - } - else - vel.x *= ground_friction; // ground fiction - } - else - { - // air movement - if(input.left) - { - if(vel.x > -air_control_speed) - vel.x -= air_control_accel; - } - else if(input.right) - { - if(vel.x < air_control_speed) - vel.x += air_control_accel; - } - else - vel.x *= air_friction; // air fiction - } - - if(input.jump) - { - if(jumped == 0) - { - if(grounded) - { - create_sound(pos, sound_player_jump); - vel.y = -ground_jump_speed; - jumped++; - } - /* - else if(airjumped == 0) - { - vel.y = -12; - airjumped++; - jumped++; - }*/ - } - else if (!grounded) - { - airjumped++; - } - } - else - jumped = 0; - } - - // meh, go through all players and stop their hook on me - /* - for(entity *ent = world.first_entity; ent; ent = ent->next_entity) - { - if (ent && ent->objtype == OBJTYPE_PLAYER) - { - player *p = (player*)ent; - if(p != this) - { - float d = distance(pos, p->pos); - vec2 dir = normalize(pos - p->pos); - if(d < phys_size*1.5f) - { - float a = phys_size*1.5f - d; - vel = vel + dir*a; - } - - if(p->phookedplayer == this) - { - if(d > phys_size*2.5f) - { - elast = 0.0f; - vel = vel - dir*2.5f; - } - } - } - } - }*/ - - // gravity - if (!(modifierflags & MODIFIER_RETURNFLAGS_OVERRIDEGRAVITY)) - vel.y += gravity; - } - - if (!(modifierflags & MODIFIER_RETURNFLAGS_OVERRIDEPOSITION)) - move_box(&pos, &vel, vec2(phys_size, phys_size), elast); - } - - void die() - { - create_sound(pos, sound_player_die); - // release our hooked player - if (phookedplayer) - { - phookedplayer->numhooked--; - phookedplayer = 0; - hooking = -1; - numhooked = 0; - } - respawn(); - - // meh, go through all players and stop their hook on me - for(entity *ent = world.first_entity; ent; ent = ent->next_entity) - { - if (ent && ent->objtype == OBJTYPE_PLAYER) - { - player* p = (player*)ent; - if (p->phookedplayer == this) - { - p->phookedplayer = 0; - p->hooking = -1; - //p->numhooked--; - } - } - } - } - - virtual bool take_damage(vec2 force, int dmg, int from) - { - vel += force; - - if(armor) - { - armor -= 1; - dmg--; - } - - if(dmg > armor) - { - dmg -= armor; - armor = 0; - health -= dmg; - } - else - armor -= dmg; - /* - int armordmg = (dmg+1)/2; - int healthdmg = dmg-armordmg; - if(armor < armordmg) - { - healthdmg += armordmg - armor; - armor = 0; - } - else - armor -= armordmg; - - health -= healthdmg; - */ - - // create healthmod indicator - create_healthmod(pos, dmg); - - damage_taken_tick = tick_count+50; - - // check for death - if(health <= 0) - { - // apply score - if(from != -1) - { - if(from == client_id) - score--; - else - { - player *p = get_player(from); - p->score++; - } - } - - die(); - return false; - } - - if (dmg > 2) - create_sound(pos, sound_player_hurt_long); - else - create_sound(pos, sound_player_hurt_short); - - // spawn blood? - - return true; - } - - virtual void snap(int snaping_client) - { - obj_player *player = (obj_player *)snap_new_item(OBJTYPE_PLAYER, client_id, sizeof(obj_player)); - - client_info info; - if(server_getclientinfo(client_id, &info)) - snap_encode_string(info.name, player->name, strlen(info.name), 32); - - player->x = (int)pos.x; - player->y = (int)pos.y; - player->vx = (int)vel.x; - player->vy = (int)vel.y; - player->emote = EMOTE_NORMAL; - - player->ammocount = lweapons[iactiveweapon].numammo; - player->health = 0; - player->armor = 0; - player->local = 0; - player->clientid = client_id; - player->weapon = iactiveweapon; - player->modifier = 0; - for (int i = 0; i < MODIFIER_NUMMODIFIERS; i++) - { - // add active modifiers - if (modifiers[i].flags & MODIFIER_ISACTIVE) - player->modifier |= 1 << i; - } - // get current attack ticks - getattackticks(player->attackticks, player->attacklen, player->visualtimeattack); - - - if(client_id == snaping_client) - { - player->local = 1; - player->health = health; - player->armor = armor; - } - - if(length(vel) > 15.0f) - player->emote = EMOTE_HAPPY; - - if(damage_taken_tick > tick_count) - player->emote = EMOTE_PAIN; - - if(player->emote == EMOTE_NORMAL) - { - if((tick_count%(50*5)) < 10) - player->emote = EMOTE_BLINK; - } - - player->hook_active = hooking>0?1:0; - player->hook_x = (int)hook_pos.x; - player->hook_y = (int)hook_pos.y; - - player->angle = input.angle; - player->score = score; - } -}; - -// POWERUP /////////////////////// - -powerup::powerup(int _type, int _subtype, int _numitems, int _flags) : - entity(OBJTYPE_POWERUP) -{ - static int current_id = 0; - playerhooked = 0; - id = current_id++; - vel = vec2(0.0f,0.0f); - type = _type; - subtype = _subtype; - numitems = _numitems; - flags = _flags; - // set radius (so it can collide and be hooked and stuff) - proximity_radius = phys_size; - spawntick = -1; - world.insert_entity(this); -} - -void powerup::spawnrandom(int _lifespan) -{ - return; - /* - vec2 pos; - int start, num; - map_get_type(1, &start, &num); - - if(!num) - return; - - mapres_spawnpoint *sp = (mapres_spawnpoint*)map_get_item(start + (rand()%num), NULL, NULL); - pos = vec2(sp->x, sp->y); - - // Check if there already is a powerup at that location - { - int type = OBJTYPE_POWERUP; - entity *ents[64]; - int num = world.find_entities(pos, 5.0f, ents, 64,&type,1); - for (int i = 0; i < num; i++) - { - if (ents[i]->objtype == OBJTYPE_POWERUP) - { - // location busy - return; - } - } - } - - powerup* ppower = new powerup(rand() % POWERUP_TYPE_NUMPOWERUPS,_lifespan); - ppower->pos = pos; - if (ppower->type == POWERUP_TYPE_WEAPON) - { - ppower->subtype = rand() % WEAPON_NUMWEAPONS; - ppower->numitems = 10; - } - else if (ppower->type == POWERUP_TYPE_HEALTH || ppower->type == POWERUP_TYPE_ARMOR) - { - ppower->numitems = rand() % 5; - } - ppower->flags |= POWERUP_FLAG_HOOKABLE;*/ -} - -void powerup::tick() -{ - // wait for respawn - if(spawntick > 0) - { - if(server_tick() > spawntick) - spawntick = -1; - else - return; - } - - vec2 oldpos = pos; - //vel.y += 0.25f; - pos += vel; - move_box(&pos, &vel, vec2(phys_size, phys_size), 0.0f); - - // Check if a player intersected us - vec2 meh; - player* pplayer = intersect_player(pos, pos + vec2(0,16), meh, 0); - if (pplayer) - { - // player picked us up, is someone was hooking us, let them go - if (playerhooked) - playerhooked->hooking = -1; - int respawntime = -1; - switch (type) - { - case POWERUP_TYPE_HEALTH: - { - if(pplayer->health < PLAYER_MAXHEALTH) - { - pplayer->health = min(PLAYER_MAXHEALTH, pplayer->health + numitems); - respawntime = 20; - } - break; - } - case POWERUP_TYPE_ARMOR: - { - if(pplayer->armor < PLAYER_MAXARMOR) - { - pplayer->armor = min(PLAYER_MAXARMOR, pplayer->armor + numitems); - respawntime = 20; - } - break; - } - case POWERUP_TYPE_WEAPON: - { - if (pplayer->lweapons[subtype].flags & player::WEAPON_ISACTIVE) - { - // add ammo - /* - if (pplayer->lweapons[subtype].flags & player::WEAPON_NEEDRELOAD) - { - int numtoadd = min(numitems, pplayer->lweapons[subtype].magsize); - pplayer->lweapons[subtype].numammo = min(10, pplayer->lweapons[subtype].numammo + numtoadd); - pplayer->lweapons[subtype].nummagazines += (numitems - numtoadd) % pplayer->lweapons[subtype].magsize; - } - else*/ - if(pplayer->lweapons[subtype].numammo < 10) - { - respawntime = 20; - pplayer->lweapons[subtype].numammo = min(10, pplayer->lweapons[subtype].numammo + numitems); - } - } - else - { - pplayer->lweapons[subtype].settype(); - pplayer->lweapons[subtype].flags |= player::WEAPON_ISACTIVE; - respawntime = 20; - } - break; - } - case POWERUP_TYPE_NINJA: - { - respawntime = 60; - // reset and activate - pplayer->modifiers[MODIFIER_TYPE_NINJA].settype(); - pplayer->modifiers[MODIFIER_TYPE_NINJA].flags |= player::MODIFIER_ISACTIVE; - break; - } - //POWERUP_TYPE_TIMEFIELD = 4, - default: - break; - }; - - if(respawntime >= 0) - spawntick = server_tick() + server_tickspeed() * respawntime; - //world.destroy_entity(this); - } -} - -void powerup::snap(int snapping_client) -{ - if(spawntick != -1) - return; - - obj_powerup *powerup = (obj_powerup *)snap_new_item(OBJTYPE_POWERUP, id, sizeof(obj_powerup)); - powerup->x = (int)pos.x; - powerup->y = (int)pos.y; - powerup->vx = (int)vel.x; - powerup->vy = (int)vel.y; - powerup->type = type; - powerup->subtype = subtype; -} - -// POWERUP END /////////////////////// - -static player players[MAX_CLIENTS]; - -player *get_player(int index) -{ - return &players[index]; -} - -void create_healthmod(vec2 p, int amount) -{ - ev_healthmod *ev = (ev_healthmod *)events.create(EVENT_HEALTHMOD, sizeof(ev_healthmod)); - ev->x = (int)p.x; - ev->y = (int)p.y; - ev->amount = amount; -} - -void create_explosion(vec2 p, int owner, bool bnodamage) -{ - // create the event - ev_explosion *ev = (ev_explosion *)events.create(EVENT_EXPLOSION, sizeof(ev_explosion)); - ev->x = (int)p.x; - ev->y = (int)p.y; - - if (!bnodamage) - { - // deal damage - entity *ents[64]; - const float radius = 128.0f; - int num = world.find_entities(p, radius, ents, 64); - for(int i = 0; i < num; i++) - { - vec2 diff = ents[i]->pos - p; - vec2 forcedir(0,1); - if (length(diff)) - forcedir = normalize(diff); - float l = length(diff); - float dmg = 5 * (1 - (l/radius)); - if((int)dmg) - { - ents[i]->take_damage(forcedir*dmg*2, (int)dmg, owner);/* && - ents[i]->objtype == OBJTYPE_PLAYER && - owner >= 0) - { - player *p = (player*)ents[i]; - if(p->client_id == owner) - p->score--; - else - ((player*)ents[owner])->score++; - - }*/ - } - } - } -} - -void create_smoke(vec2 p) -{ - // create the event - ev_explosion *ev = (ev_explosion *)events.create(EVENT_SMOKE, sizeof(ev_explosion)); - ev->x = (int)p.x; - ev->y = (int)p.y; -} - -void create_sound(vec2 pos, int sound, int loopingflags) -{ - if (sound < 0) - return; - - // create a sound - ev_sound *ev = (ev_sound *)events.create(EVENT_SOUND, sizeof(ev_sound)); - ev->x = (int)pos.x; - ev->y = (int)pos.y; - ev->sound = sound | loopingflags; -} - -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); - vec2 center = pos0 + dir * 0.5f; - int num = world.find_entities(center, radius, ents, 64); - for (int i = 0; i < num; i++) - { - // Check if entity is a player - if (ents[i] != notthis && ents[i]->objtype == OBJTYPE_PLAYER) - { - // temp, set hook pos to our position - new_pos = ents[i]->pos; - return (player*)ents[i]; - } - } - - return 0; -} - -// Server hooks -static int addtick = SERVER_TICK_SPEED * 5; -void mods_tick() -{ - // clear all events - events.clear(); - world.tick(); - - if (addtick <= 0) - { - powerup::spawnrandom(SERVER_TICK_SPEED * 5); - addtick = SERVER_TICK_SPEED * 5; - } - addtick--; -} - -void mods_snap(int client_id) -{ - world.snap(client_id); - events.snap(client_id); -} - -void mods_client_input(int client_id, void *input) -{ - players[client_id].previnput = players[client_id].input; - players[client_id].input = *(player_input*)input; -} - -void mods_client_enter(int client_id) -{ - players[client_id].reset(); - players[client_id].client_id = client_id; - players[client_id].respawn(); - world.insert_entity(&players[client_id]); - -} - -void mods_client_drop(int client_id) -{ - players[client_id].client_id = -1; - world.remove_entity(&players[client_id]); -} - -void mods_init() -{ - col_init(32); - - int start, num; - map_get_type(MAPRES_ITEM, &start, &num); - - for(int i = 0; i < num; i++) - { - mapres_item *it = (mapres_item *)map_get_item(start+i, 0, 0); - - int type = -1; - int subtype = -1; - int numitems = 1; - - switch(it->type) - { - case ITEM_WEAPON_GUN: - type = POWERUP_TYPE_WEAPON; - subtype = WEAPON_TYPE_GUN; - break; - case ITEM_WEAPON_SHOTGUN: - type = POWERUP_TYPE_WEAPON; - subtype = WEAPON_TYPE_SHOTGUN; - numitems = 5; - break; - case ITEM_WEAPON_ROCKET: - type = POWERUP_TYPE_WEAPON; - subtype = WEAPON_TYPE_ROCKET; - numitems = 5; - break; - /*case ITEM_WEAPON_SNIPER: - type = POWERUP_TYPE_WEAPON; - subtype = WEAPON_TYPE_ROCKET; - break;*/ - case ITEM_WEAPON_HAMMER: - type = POWERUP_TYPE_WEAPON; - subtype = WEAPON_TYPE_MELEE; - break; - - case ITEM_HEALTH_1: - type = POWERUP_TYPE_HEALTH; - numitems = 1; - break; - case ITEM_HEALTH_5: - type = POWERUP_TYPE_HEALTH; - numitems = 5; - break; - case ITEM_HEALTH_10: - type = POWERUP_TYPE_HEALTH; - numitems = 10; - break; - - case ITEM_ARMOR_1: - type = POWERUP_TYPE_ARMOR; - numitems = 1; - break; - case ITEM_ARMOR_5: - type = POWERUP_TYPE_ARMOR; - numitems = 5; - break; - case ITEM_ARMOR_10: - type = POWERUP_TYPE_ARMOR; - numitems = 10; - break; - }; - - powerup* ppower = new powerup(type, subtype, numitems); - ppower->pos.x = it->x; - ppower->pos.y = it->y; - } - - - /* - powerup* ppower = new powerup(rand() % POWERUP_TYPE_NUMPOWERUPS,_lifespan); - ppower->pos = pos; - if (ppower->type == POWERUP_TYPE_WEAPON) - { - ppower->subtype = rand() % WEAPON_NUMWEAPONS; - ppower->numitems = 10; - } - else if (ppower->type == POWERUP_TYPE_HEALTH || ppower->type == POWERUP_TYPE_ARMOR) - { - ppower->numitems = rand() % 5; - } - ppower->flags |= POWERUP_FLAG_HOOKABLE; - */ - - //powerup::spawnrandom(SERVER_TICK_SPEED * 5); -} - -void mods_shutdown() {} -void mods_presnap() {} -void mods_postsnap() {} diff --git a/src/game/mapres_col.cpp b/src/game/mapres_col.cpp index 0cf71986..29215d7d 100644 --- a/src/game/mapres_col.cpp +++ b/src/game/mapres_col.cpp @@ -1,5 +1,5 @@ #include -#include "../interface.h" +#include "../engine/interface.h" #include "mapres_col.h" #include "mapres.h" diff --git a/src/game/mapres_image.cpp b/src/game/mapres_image.cpp deleted file mode 100644 index baf7f09b..00000000 --- a/src/game/mapres_image.cpp +++ /dev/null @@ -1,41 +0,0 @@ -#include -#include "../interface.h" -#include "mapres_image.h" -#include "mapres.h" - -static int map_textures[64] = {0}; -static int count = 0; - -int img_init() -{ - int start, count; - map_get_type(MAPRES_IMAGE, &start, &count); - dbg_msg("mapres_image", "start=%d count=%d", start, count); - for(int i = 0; i < 64; i++) - { - if(map_textures[i]) - { - gfx_unload_texture(map_textures[i]); - map_textures[i] = 0; - } - } - - for(int i = 0; i < count; i++) - { - mapres_image *img = (mapres_image *)map_get_item(start+i, 0, 0); - void *data = map_get_data(img->image_data); - map_textures[i] = gfx_load_texture_raw(img->width, img->height, data); - } - - return count; -} - -int img_num() -{ - return count; -} - -int img_get(int index) -{ - return map_textures[index]; -} diff --git a/src/game/mapres_image.h b/src/game/mapres_image.h deleted file mode 100644 index eab1559a..00000000 --- a/src/game/mapres_image.h +++ /dev/null @@ -1,18 +0,0 @@ - -// loads images from the map to textures -int img_init(); - -// returns the number of images in the map -int img_num(); - -// fetches the texture id for the image -int img_get(int index); - - -class mapres_image -{ -public: - int width; - int height; - int image_data; -}; diff --git a/src/game/mapres_tilemap.cpp b/src/game/mapres_tilemap.cpp deleted file mode 100644 index 0868d2e4..00000000 --- a/src/game/mapres_tilemap.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include "../interface.h" -#include "mapres_tilemap.h" -#include "mapres_image.h" -#include "mapres.h" - -int tilemap_init() -{ - return 0; -} - -void tilemap_render(float scale, int fg) -{ - if(!map_is_loaded()) - return; - - // fetch indecies - int start, num; - map_get_type(MAPRES_TILEMAP, &start, &num); - - // render tilemaps - int passed_main = 0; - for(int t = 0; t < num; t++) - { - mapres_tilemap *tmap = (mapres_tilemap *)map_get_item(start+t,0,0); - unsigned char *data = (unsigned char *)map_get_data(tmap->data); - - if(tmap->main) - passed_main = 1; - - if((fg && passed_main) || (!fg && !passed_main)) - { - gfx_texture_set(img_get(tmap->image)); - gfx_quads_begin(); - - int c = 0; - float frac = (1.0f/1024.0f); //2.0f; - for(int y = 0; y < tmap->height; y++) - for(int x = 0; x < tmap->width; x++, c++) - { - unsigned char d = data[c*2]; - if(d) - { - gfx_quads_setsubset( - (d%16)/16.0f+frac, - (d/16)/16.0f+frac, - (d%16)/16.0f+1.0f/16.0f-frac, - (d/16)/16.0f+1.0f/16.0f-frac); - gfx_quads_drawTL(x*scale, y*scale, scale, scale); - } - } - gfx_quads_end(); - } - } -} diff --git a/src/game/mapres_tilemap.h b/src/game/mapres_tilemap.h deleted file mode 100644 index 6e9d81be..00000000 --- a/src/game/mapres_tilemap.h +++ /dev/null @@ -1,19 +0,0 @@ - -// dependencies: image - -// -int tilemap_init(); - -// renders the tilemaps -void tilemap_render(float scale, int fg); - -struct mapres_tilemap -{ - int image; - int width; - int height; - int x, y; - int scale; - int data; - int main; -}; diff --git a/src/game/server/game_server.cpp b/src/game/server/game_server.cpp new file mode 100644 index 00000000..769a250f --- /dev/null +++ b/src/game/server/game_server.cpp @@ -0,0 +1,2131 @@ +#include +#include +#include "../game.h" + +using namespace baselib; + +// --------- PHYSICS TWEAK! -------- +const float ground_control_speed = 7.0f; +const float ground_control_accel = 2.0f; +const float ground_friction = 0.5f; +const float ground_jump_speed = 12.0f; +const float air_control_speed = 3.5f; +const float air_control_accel = 1.2f; +const float air_friction = 0.95f; +const float hook_length = 32*10.0f; +const float hook_fire_speed = 45.0f; +const float hook_drag_accel = 3.0f; +const float hook_drag_speed = 15.0f; +const float gravity = 0.5f; + +class player* get_player(int index); +void create_healthmod(vec2 p, int amount); +void create_explosion(vec2 p, int owner = -1, bool bnodamage = false); +void create_smoke(vec2 p); +void create_sound(vec2 pos, int sound, int loopflags = 0); +class player* intersect_player(vec2 pos0, vec2 pos1, vec2& new_pos, class entity* notthis = 0); + +// TODO: rewrite this smarter! +void move_box(vec2 *inout_pos, vec2 *inout_vel, vec2 size, float elasticity) +{ + // do the move + vec2 pos = *inout_pos; + vec2 vel = *inout_vel; + + float distance = length(vel); + int max = (int)distance; + + vec2 offsets[4] = { vec2(-size.x/2, -size.y/2), vec2( size.x/2, -size.y/2), + vec2(-size.x/2, size.y/2), vec2( size.x/2, size.y/2)}; + + if(distance > 0.00001f) + { + vec2 old_pos = pos; + for(int i = 0; i <= max; i++) + { + float amount = i/(float)max; + if(max == 0) + amount = 0; + + vec2 new_pos = pos + vel*amount; // TODO: this row is not nice + + for(int p = 0; p < 4; p++) + { + vec2 np = new_pos+offsets[p]; + vec2 op = old_pos+offsets[p]; + if(col_check_point(np)) + { + int affected = 0; + if(col_check_point(np.x, op.y)) + { + vel.x = -vel.x*elasticity; + pos.x = old_pos.x; + new_pos.x = old_pos.x; + affected++; + } + + if(col_check_point(op.x, np.y)) + { + vel.y = -vel.y*elasticity; + pos.y = old_pos.y; + new_pos.y = old_pos.y; + affected++; + } + + if(!affected) + { + new_pos = old_pos; + pos = old_pos; + vel *= -elasticity; + } + } + } + + old_pos = new_pos; + } + + pos = old_pos; + } + + *inout_pos = pos; + *inout_vel = vel; +} + +// TODO: rewrite this smarter! +bool intersect_line(vec2 pos0, vec2 pos1, vec2 *out) +{ + float d = distance(pos0, pos1); + + for(float f = 0; f < d; f++) + { + float a = f/d; + vec2 pos = mix(pos0, pos1, a); + if(col_check_point(pos)) + { + if(out) + *out = pos; + return true; + } + } + if(out) + *out = pos1; + return false; +} + +// +class event_handler +{ + static const int MAX_EVENTS = 128; + static const int MAX_DATASIZE = 128*4; + + int types[MAX_EVENTS]; // TODO: remove some of these arrays + int offsets[MAX_EVENTS]; + int sizes[MAX_EVENTS]; + char data[MAX_DATASIZE]; + + int current_offset; + int num_events; +public: + event_handler() + { + num_events = 0; + } + + void *create(int type, int size) + { + void *p = &data[current_offset]; + offsets[num_events] = current_offset; + types[num_events] = type; + sizes[num_events] = size; + current_offset += size; + num_events++; + return p; + } + + void clear() + { + num_events = 0; + current_offset = 0; + } + + void snap(int snapping_client) + { + for(int i = 0; i < num_events; i++) + { + void *d = snap_new_item(types[i], i, sizes[i]); + mem_copy(d, &data[offsets[i]], sizes[i]); + } + } +}; + +static event_handler events; +/* +template +class pool +{ + struct element + { + int next_free; + T data; + }; + + element elements[SIZE]; + int first_free; +public: + pool() + { + first_free = 0; + for(int i = 0; i < SIZE; i++) + elements[i].next_free = i+1; + elements[SIZE-1].next_free = -1; + } +};*/ + +// a basic entity +class entity +{ +private: + friend class game_world; + friend class player; + entity *prev_entity; + entity *next_entity; + int index; + +public: + vec2 pos; + float proximity_radius; + unsigned flags; + int objtype; + + enum + { + FLAG_DESTROY=0x00000001, + }; + + entity(int objtype) + { + this->objtype = objtype; + pos = vec2(0,0); + flags = 0; + proximity_radius = 0; + } + + virtual ~entity() + { + } + + virtual void destroy() { delete this; } + virtual void tick() {} + virtual void snap(int snapping_client) {} + + virtual bool take_damage(vec2 force, int dmg, int from) { return true; } +}; + +class powerup : public entity +{ +public: + static const int phys_size = 14; + enum + { + POWERUP_FLAG_HOOKABLE = 1 << 0, + }; + vec2 vel; + class player* playerhooked; + int type; + int id; + int subtype; // weapon type for instance? + int numitems; // number off powerup items + int flags; + int spawntick; + powerup(int _type, int _subtype = 0, int _numitems = 0, int _flags = 0); + + static void spawnrandom(int _lifespan); + + void tick(); + + void snap(int snapping_client); +}; + +// game world. handles all entities +class game_world +{ +public: + entity *first_entity; + game_world() + { + first_entity = 0x0; + } + + int find_entities(vec2 pos, float radius, entity **ents, int max) + { + int num = 0; + for(entity *ent = first_entity; ent; ent = ent->next_entity) + { + if(distance(ent->pos, pos) < radius+ent->proximity_radius) + { + ents[num] = ent; + num++; + if(num == max) + break; + } + } + + return num; + } + + int find_entities(vec2 pos, float radius, entity **ents, int max, const int* types, int maxtypes) + { + int num = 0; + for(entity *ent = first_entity; ent; ent = ent->next_entity) + { + for (int i = 0; i < maxtypes; i++) + { + if (ent->objtype != types[i]) + continue; + + if(distance(ent->pos, pos) < radius+ent->proximity_radius) + { + ents[num] = ent; + num++; + if(num == max) + break; + } + } + } + + return num; + } + + void insert_entity(entity *ent) + { + // insert it + if(first_entity) + first_entity->prev_entity = ent; + ent->next_entity = first_entity; + ent->prev_entity = 0x0; + first_entity = ent; + } + + void destroy_entity(entity *ent) + { + ent->flags |= entity::FLAG_DESTROY; + // call destroy + //remove_entity(ent); + //ent->destroy(); + } + + void remove_entity(entity *ent) + { + // remove + if(ent->prev_entity) + ent->prev_entity->next_entity = ent->next_entity; + else + first_entity = ent->next_entity; + if(ent->next_entity) + ent->next_entity->prev_entity = ent->prev_entity; + } + + // + void snap(int snapping_client) + { + for(entity *ent = first_entity; ent; ent = ent->next_entity) + ent->snap(snapping_client); + } + + void tick() + { + // update all objects + for(entity *ent = first_entity; ent; ent = ent->next_entity) + ent->tick(); + + // destroy objects marked for destruction + entity *ent = first_entity; + while(ent) + { + entity *next = ent->next_entity; + if(ent->flags&entity::FLAG_DESTROY) + { + remove_entity(ent); + ent->destroy(); + } + ent = next; + } + } +}; + +static game_world world; + +// projectile entity +class projectile : public entity +{ +public: + enum + { + PROJECTILE_FLAGS_EXPLODE = 1 << 0, + }; + vec2 vel; + entity* powner; + int lifespan; + int id; + int owner; + int type; + int flags; + int damage; + int sound_impact; + float force; + + projectile(int type, int owner, vec2 pos, vec2 vel, int span, entity* powner, int damage, int flags = 0, float force = 0.0f, int sound_impact = -1) : + entity(OBJTYPE_PROJECTILE) + { + static int current_id = 0; + this->id = current_id++; + this->type = type; + this->pos = pos; + this->vel = vel; + this->lifespan = span; + this->owner = owner; + this->powner = powner; + this->flags = flags; + this->force = force; + this->damage = damage; + this->sound_impact = sound_impact; + world.insert_entity(this); + } + + void tick() + { + vec2 oldpos = pos; + vel.y += 0.25f; + pos += vel; + lifespan--; + // check player intersection as well + entity* targetplayer = (entity*)intersect_player(oldpos, pos, oldpos, powner); + if(targetplayer || lifespan < 0 || col_check_point((int)pos.x, (int)pos.y)) + { + if (lifespan >= 0) + create_sound(pos, sound_impact); + if (flags & PROJECTILE_FLAGS_EXPLODE) + { + create_explosion(oldpos, owner); + } + else if (targetplayer) + { + targetplayer->take_damage(normalize(vel) * force, damage, owner); + } + world.destroy_entity(this); + } + } + + void snap(int snapping_client) + { + obj_projectile *proj = (obj_projectile *)snap_new_item(OBJTYPE_PROJECTILE, id, sizeof(obj_projectile)); + proj->x = (int)pos.x; + proj->y = (int)pos.y; + proj->vx = (int)vel.x; + proj->vy = (int)vel.y; + proj->type = type; + } +}; + +// player entity +class player : public entity +{ +public: + static const int phys_size = 28; + enum + { + WEAPON_NEEDRELOAD = 1 << 0, + WEAPON_DROPONUNEQUIP = 1 << 1, + WEAPON_DRAWSAMMO = 1 << 2, + WEAPON_HASSECONDARY = 1 << 3, + WEAPON_ISACTIVE = 1 << 4, // has the item + WEAPON_AUTOFIRE = 1 << 5, + + WEAPON_PROJECTILETYPE_GUN = 0, + WEAPON_PROJECTILETYPE_ROCKET = 1, + WEAPON_PROJECTILETYPE_SHOTGUN = 2, + + // Gun + + + // modifiers + MODIFIER_HASACTIVATIONS = 1 << 0, + MODIFIER_TIMELIMITED = 1 << 1, + MODIFIER_ISACTIVE = 1 << 2, + MODIFIER_NEEDSACTIVATION = 1 << 3, + + MODIFIER_RETURNFLAGS_OVERRIDEWEAPON = 1 << 0, + MODIFIER_RETURNFLAGS_OVERRIDEVELOCITY = 1 << 1, + MODIFIER_RETURNFLAGS_OVERRIDEPOSITION = 1 << 2, + MODIFIER_RETURNFLAGS_OVERRIDEGRAVITY = 1 << 3, + }; + class weapon + { + public: + entity* hitobjects[10]; + int numobjectshit; // for melee, so we don't hit the same object more than once per bash + int weapontype; + int equiptime; + int unequiptime; + int numammo; + int magsize; + int nummagazines; + int flags; + int firetime; + int reloadtime; + int projectileclass; + int damage; + int sound_fire; + int sound_equip; + int sound_impact; + int sound_impact_projectile; + int visualtimeattack; + float projectilevel; + float projectilespan; + float reach; // for melee + float force; + float recoilforce; + float projoffsety; + float projoffsetx; + + weapon() + { + weapontype = 0; + numammo = 0; + flags = 0; + reloadtime = 0; + projectileclass = 0; + numobjectshit = 0; + reach = 0.0f; + force = 5.0f; + damage = 1; + sound_fire = -1; + sound_equip = -1; + sound_impact = -1; + sound_impact_projectile = -1, + visualtimeattack = 3; + recoilforce = 0.0f; + projoffsety = 0.0f; + projoffsetx = 0.0f; + } + + void setgun(int ammo = 10) + { + weapontype = WEAPON_TYPE_GUN; + flags = 0;//WEAPON_DRAWSAMMO; + numammo = ammo; + projectileclass = WEAPON_PROJECTILETYPE_GUN; + firetime = SERVER_TICK_SPEED/10; + magsize = 0; + projectilevel = 30.0f; + projectilespan = 50.0f * 1.0f; + sound_fire = SOUND_FIRE_GUN; + sound_equip = SOUND_EQUIP_GUN; + sound_impact_projectile = SOUND_IMPACT_PROJECTILE_GUN; + projoffsety = -10.0f; + projoffsetx = 24.0f; + } + + void setrocket(int ammo = 10) + { + weapontype = WEAPON_TYPE_ROCKET; + flags = WEAPON_DRAWSAMMO; + numammo = ammo; + projectileclass = WEAPON_PROJECTILETYPE_ROCKET; + projectilevel = 15.0f; + projectilespan = 50.0f * 5.0f; + firetime = SERVER_TICK_SPEED * 4/5; + magsize = 0; + recoilforce = 5.0f; + sound_fire = SOUND_FIRE_ROCKET; + sound_equip = SOUND_EQUIP_ROCKET; + sound_impact_projectile = SOUND_IMPACT_PROJECTILE_ROCKET; + projoffsety = -17.0f; + projoffsetx = 24.0f; + } + + /*void setsniper(int ammo = 10) + { + weapontype = WEAPON_TYPE_SNIPER; + flags = WEAPON_DRAWSAMMO | WEAPON_HASSECONDARY | WEAPON_NEEDRELOAD; + numammo = ammo; + projectileclass = WEAPON_PROJECTILETYPE_SNIPER; + projectilevel = 30.0f; + projectilespan = 50.0f * 5.0f; + firetime = SERVER_TICK_SPEED; + reloadtime = SERVER_TICK_SPEED/2; + magsize = 2; + recoilforce = 20.0f; + }*/ + + void setshotgun(int ammo = 10) + { + weapontype = WEAPON_TYPE_SHOTGUN; + flags = WEAPON_DRAWSAMMO | WEAPON_NEEDRELOAD; + numammo = ammo; + projectileclass = WEAPON_PROJECTILETYPE_SHOTGUN; + projectilevel = 30.0f; + projectilespan = 50.0f * 5.0f; + firetime = SERVER_TICK_SPEED/2; + reloadtime = SERVER_TICK_SPEED/2; + magsize = 2; + damage = 3; + recoilforce = 5.0f; + sound_fire = SOUND_FIRE_SHOTGUN; + sound_equip = SOUND_EQUIP_SHOTGUN; + sound_impact_projectile = SOUND_IMPACT_PROJECTILE_SHOTGUN; + projoffsety = -17.0f; + projoffsetx = 24.0f; + } + + void setmelee(int ammo = 10) + { + weapontype = WEAPON_TYPE_MELEE; + flags = 0;//WEAPON_AUTOFIRE; + numammo = ammo; + projectileclass = -1; + firetime = SERVER_TICK_SPEED/5; + reloadtime = 0; + magsize = 2; + numobjectshit = 0; + reach = 15.0f; + damage = 1; + sound_fire = SOUND_FIRE_MELEE; + sound_equip = SOUND_EQUIP_MELEE; + sound_impact = SOUND_PLAYER_IMPACT; + } + + void settype() + { + switch(weapontype) + { + case WEAPON_TYPE_GUN: + { + setgun(); + break; + } + case WEAPON_TYPE_ROCKET: + { + setrocket(); + break; + } + /*case WEAPON_TYPE_SNIPER: + { + setsniper(); + break; + }*/ + case WEAPON_TYPE_SHOTGUN: + { + setshotgun(); + break; + } + case WEAPON_TYPE_MELEE: + { + setmelee(); + break; + } + default: + break; + } + } + + int activate(player* player) + { + // create sound event for fire + int projectileflags = 0; + create_sound(player->pos, sound_fire); + + switch (weapontype) + { + case WEAPON_TYPE_ROCKET: + projectileflags |= projectile::PROJECTILE_FLAGS_EXPLODE; + case WEAPON_TYPE_GUN: + //case WEAPON_TYPE_SNIPER: + case WEAPON_TYPE_SHOTGUN: + { + if (flags & WEAPON_DRAWSAMMO) + numammo--; + // Create projectile + new projectile(projectileclass, + player->client_id, + player->pos+vec2(0,projoffsety)+player->direction*projoffsetx, + player->direction*projectilevel, + (int)projectilespan, + player, + damage, + projectileflags, + force, + sound_impact_projectile); + // recoil force if any + if (recoilforce > 0.0f) + { + vec2 dir(player->direction.x,0.5); + if (dir.x == 0.0f) + dir.x = 0.5f; + else + dir = normalize(dir); + player->vel -= dir * recoilforce; + } + return firetime; + } + case WEAPON_TYPE_MELEE: + { + // Start bash sequence + numobjectshit = 0; + return firetime; + } + default: + return 0; + } + } + + void update(player* owner, int fire_timeout) + { + switch(weapontype) + { + case WEAPON_TYPE_MELEE: + { + // No more melee + if (fire_timeout <= 0) + return; + + // only one that needs update (for now) + // do selection for the weapon and bash anything in it + // check if we hit anything along the way + int type = OBJTYPE_PLAYER; + entity *ents[64]; + vec2 dir = owner->pos + owner->direction * reach; + float radius = length(dir * 0.5f); + vec2 center = owner->pos + dir * 0.5f; + int num = world.find_entities(center, radius, ents, 64, &type, 1); + + for (int i = 0; i < num; i++) + { + // Check if entity is a player + if (ents[i] == owner) + continue; + // make sure we haven't hit this object before + bool balreadyhit = false; + for (int j = 0; j < numobjectshit; j++) + { + if (hitobjects[j] == ents[i]) + balreadyhit = true; + } + if (balreadyhit) + continue; + + // check so we are sufficiently close + if (distance(ents[i]->pos, owner->pos) > (owner->phys_size * 2.0f)) + continue; + + // hit a player, give him damage and stuffs... + // create sound for bash + create_sound(ents[i]->pos, sound_impact); + + // set his velocity to fast upward (for now) + create_smoke(ents[i]->pos); + hitobjects[numobjectshit++] = ents[i]; + ents[i]->take_damage(vec2(0,10.0f), damage, owner->client_id); + player* target = (player*)ents[i]; + vec2 dir; + if (length(target->pos - owner->pos) > 0.0f) + dir = normalize(target->pos - owner->pos); + else + dir = vec2(0,-1); + target->vel += dir * 10.0f + vec2(0,-10.0f); + } + break; + } + default: + break; + } + } + }; + + class modifier + { + public: + vec2 activationdir; + entity* hitobjects[10]; + int numobjectshit; + float velocity; + int modifiertype; + int duration; + int numactivations; + int activationtime; + int cooldown; + int movetime; + int visualtimeattack; + int currentactivation; + int currentmovetime; + int currentcooldown; + int damage; + int flags; + int sound_impact; + int sound_activate; + + modifier() + { + modifiertype = 0; + duration = 0; + numobjectshit = 0; + numactivations = 0; + activationtime = 0; + cooldown = 0; + movetime = 0; + currentactivation = 0; + currentmovetime = 0; + currentcooldown =0; + damage = 0; + flags = 0; + activationdir = vec2(0.0f, 1.0f); + velocity = 0.0f; + visualtimeattack = 0; + sound_impact = -1; + } + + void setninja() + { + modifiertype = MODIFIER_TYPE_NINJA; + duration = SERVER_TICK_SPEED * 15; + numactivations = -1; + movetime = SERVER_TICK_SPEED / 5; + activationtime = SERVER_TICK_SPEED / 2; + cooldown = SERVER_TICK_SPEED; + currentactivation = 0; + currentmovetime = 0; + numobjectshit = 0; + damage = 3; + flags = MODIFIER_TIMELIMITED | MODIFIER_NEEDSACTIVATION; + velocity = 50.0f; + visualtimeattack = 3; + sound_impact = SOUND_PLAYER_IMPACT_NINJA; + sound_activate = SOUND_FIRE_NINJA; + } + + void settimefield() + { + modifiertype = MODIFIER_TYPE_TIMEFIELD; + duration = SERVER_TICK_SPEED * 10; + numactivations = -1; + activationtime = SERVER_TICK_SPEED; + numobjectshit = 0; + currentactivation = 0; + flags = MODIFIER_TIMELIMITED; + velocity = 0.0f; + } + + void settype() + { + switch (modifiertype) + { + case MODIFIER_TYPE_NINJA: + { + setninja(); + break; + } + case MODIFIER_TYPE_TIMEFIELD: + { + settimefield(); + break; + } + default: + break; + } + } + + int updateninja(player* player) + { + if (currentactivation <= 0) + return MODIFIER_RETURNFLAGS_OVERRIDEWEAPON; + currentactivation--; + currentmovetime--; + + if (currentmovetime == 0) + { + // reset player velocity + player->vel *= 0.2f; + //return MODIFIER_RETURNFLAGS_OVERRIDEWEAPON; + } + + if (currentmovetime > 0) + { + // Set player velocity + player->vel = activationdir * velocity; + vec2 oldpos = player->pos; + move_box(&player->pos, &player->vel, vec2(player->phys_size, player->phys_size), 0.0f); + // reset velocity so the client doesn't predict stuff + player->vel = vec2(0.0f,0.0f); + if ((currentmovetime % 2) == 0) + { + create_smoke(player->pos); + } + + // check if we hit anything along the way + { + int type = OBJTYPE_PLAYER; + entity *ents[64]; + vec2 dir = player->pos - oldpos; + float radius = length(dir * 0.5f); + vec2 center = oldpos + dir * 0.5f; + int num = world.find_entities(center, radius, ents, 64, &type, 1); + + for (int i = 0; i < num; i++) + { + // Check if entity is a player + if (ents[i] == player) + continue; + // make sure we haven't hit this object before + bool balreadyhit = false; + for (int j = 0; j < numobjectshit; j++) + { + if (hitobjects[j] == ents[i]) + balreadyhit = true; + } + if (balreadyhit) + continue; + + // check so we are sufficiently close + if (distance(ents[i]->pos, player->pos) > (player->phys_size * 2.0f)) + continue; + + // hit a player, give him damage and stuffs... + create_sound(ents[i]->pos, sound_impact); + // set his velocity to fast upward (for now) + hitobjects[numobjectshit++] = ents[i]; + ents[i]->take_damage(vec2(0,10.0f), damage, player->client_id); + } + } + return MODIFIER_RETURNFLAGS_OVERRIDEWEAPON | MODIFIER_RETURNFLAGS_OVERRIDEVELOCITY | MODIFIER_RETURNFLAGS_OVERRIDEPOSITION|MODIFIER_RETURNFLAGS_OVERRIDEGRAVITY; + } + + + // move char, and check intersection from us to target + return MODIFIER_RETURNFLAGS_OVERRIDEWEAPON | MODIFIER_RETURNFLAGS_OVERRIDEVELOCITY; + } + + int activateninja(player* player) + { + // ok then, activate ninja + activationdir = player->direction; + currentactivation = activationtime; + currentmovetime = movetime; + currentcooldown = cooldown; + // reset hit objects + numobjectshit = 0; + + create_sound(player->pos, SOUND_FIRE_NINJA); + + return MODIFIER_RETURNFLAGS_OVERRIDEWEAPON; + } + + int activate(player* player) + { + if (flags & MODIFIER_NEEDSACTIVATION) + { + if (!numactivations) + return 0; + numactivations--; + } + + switch (modifiertype) + { + case MODIFIER_TYPE_NINJA: + { + return activateninja(player); + } + /*case MODIFIER_TYPE_TIMEFIELD: + { + updatetimefield(); + break; + }*/ + default: + return 0; + } + } + int update(player* player) + { + switch (modifiertype) + { + case MODIFIER_TYPE_NINJA: + { + return updateninja(player); + } + /*case MODIFIER_TYPE_TIMEFIELD: + { + updatetimefield(); + break; + }*/ + default: + return 0; + } + } + }; + + enum + { + PLAYER_FLAGS_ISRELOADING = 1 << 0, + PLAYER_FLAGS_ISEQUIPPING = 1 << 1, + }; + + weapon lweapons[WEAPON_NUMWEAPONS]; + modifier modifiers[MODIFIER_NUMMODIFIERS]; + int iactiveweapon; + int inextweapon; + int equip_time; + + int client_id; + int flags; + + char name[32]; + player_input previnput; + player_input input; + int tick_count; + int damage_taken_tick; + + vec2 vel; + vec2 direction; + + int jumped; + int airjumped; + + //int firing; + int hooking; + + int fire_timeout; + int reload_timeout; + + int health; + int armor; + + int score; + + // sounds + int sound_player_jump; + int sound_player_land; + int sound_player_hurt_short; + int sound_player_hurt_long; + int sound_player_spawn; + int sound_player_chain_loop; + int sound_player_chain_impact; + int sound_player_impact; + int sound_player_impact_ninja; + int sound_player_die; + int sound_player_switchweapon; + + player* phookedplayer; + powerup* phookedpowerup; + int numhooked; + vec2 hook_pos; + vec2 hook_dir; + + player() : + entity(OBJTYPE_PLAYER) + { + reset(); + + //firing = 0; + // setup weaponflags and stuff + lweapons[WEAPON_TYPE_GUN].setgun(); + lweapons[WEAPON_TYPE_ROCKET].setrocket(); + //lweapons[WEAPON_TYPE_SNIPER].setsniper(); + lweapons[WEAPON_TYPE_SHOTGUN].setshotgun(); + lweapons[WEAPON_TYPE_MELEE].setmelee(); + + modifiers[MODIFIER_TYPE_NINJA].setninja(); + modifiers[MODIFIER_TYPE_TIMEFIELD].settimefield(); + //modifiers[MODIFIER_TYPE_NINJA].flags |= MODIFIER_ISACTIVE; + + sound_player_jump = SOUND_PLAYER_JUMP; + sound_player_hurt_short = SOUND_PLAYER_HURT_SHORT; + sound_player_hurt_long = SOUND_PLAYER_HURT_LONG; + sound_player_spawn = SOUND_PLAYER_SPAWN; + sound_player_chain_loop = SOUND_PLAYER_CHAIN_LOOP; + sound_player_chain_impact = SOUND_PLAYER_CHAIN_IMPACT; + sound_player_impact = SOUND_PLAYER_IMPACT; + sound_player_impact_ninja = SOUND_PLAYER_IMPACT_NINJA; + sound_player_die = SOUND_PLAYER_DIE; + sound_player_switchweapon = SOUND_PLAYER_SWITCHWEAPON; + sound_player_land = SOUND_PLAYER_LAND; + } + + void reset() + { + equip_time = 0; + phookedplayer = 0; + numhooked = 0; + proximity_radius = phys_size; + name[0] = 'n'; + name[1] = 'o'; + name[2] = 'o'; + name[3] = 'b'; + name[4] = 0; + + pos = vec2(100.0f, 0.0f); + vel = vec2(0.0f, 0.0f); + direction = vec2(0.0f, 1.0f); + client_id = -1; + tick_count = 0; + score = 0; + flags = 0; + } + + virtual void destroy() { flags = 0; } + + void respawn() + { + health = PLAYER_MAXHEALTH; + armor = 0; + + hooking = 0; + phookedplayer = 0; + phookedpowerup = 0; + numhooked = 0; + fire_timeout = 0; + reload_timeout = 0; + iactiveweapon = 0; + inextweapon = -1; + equip_time = 0; + jumped = 0; + airjumped = 0; + mem_zero(&input, sizeof(input)); + vel = vec2(0.0f, 0.0f); + + int start, num; + map_get_type(1, &start, &num); + + if(num) + { + mapres_spawnpoint *sp = (mapres_spawnpoint*)map_get_item(start + (rand()%num), NULL, NULL); + pos = vec2(sp->x, sp->y); + } + else + pos = vec2(100.0f, -60.0f); + + // reset active flags + for (int i = 0; i < WEAPON_NUMWEAPONS; i++) + { + // reset and remove + lweapons[i].settype(); + lweapons[i].flags &= ~WEAPON_ISACTIVE; + } + + + // TEMP REMOVE + + /*for (int i = 0; i < WEAPON_NUMWEAPONS; i++) + { + lweapons[i].settype(); + lweapons[i].flags |= WEAPON_ISACTIVE; + }*/ + lweapons[WEAPON_TYPE_MELEE].flags |= WEAPON_ISACTIVE; + // Add gun as default weapon + iactiveweapon = WEAPON_TYPE_GUN; + lweapons[WEAPON_TYPE_GUN].numammo = 10; + lweapons[WEAPON_TYPE_GUN].flags |= WEAPON_ISACTIVE; + + create_sound(pos, sound_player_spawn); + } + + bool is_grounded() + { + if(col_check_point((int)(pos.x+phys_size/2), (int)(pos.y+phys_size/2+5))) + return true; + if(col_check_point((int)(pos.x-phys_size/2), (int)(pos.y+phys_size/2+5))) + return true; + return false; + } + + // Disable weapon activation if this returns true + int handlemodifiers() + { + int returnflags = 0; + for (int i = 0; i < MODIFIER_NUMMODIFIERS; i++) + { + if (modifiers[i].flags & MODIFIER_ISACTIVE) + { + modifiers[i].duration--; + modifiers[i].currentcooldown--; + + // Check if it should activate + if (modifiers[i].currentcooldown <= 0 && + (modifiers[i].flags & MODIFIER_NEEDSACTIVATION) && + input.fire && !(previnput.fire)) + { + returnflags |= modifiers[i].activate(this); + } + + returnflags |= modifiers[i].update(this); + + // remove active if timed out + if (modifiers[i].duration <= 0 && modifiers[i].currentactivation <= 0) + modifiers[i].flags &= ~MODIFIER_ISACTIVE; + } + } + return returnflags; + } + + void handleweapon() + { + // handle weapon + if(input.fire && (!previnput.fire || lweapons[iactiveweapon].flags & WEAPON_AUTOFIRE) && + !(flags & PLAYER_FLAGS_ISEQUIPPING) && !reload_timeout) + { + if(fire_timeout == 0) + { + if (lweapons[iactiveweapon].numammo || !(lweapons[iactiveweapon].flags & WEAPON_DRAWSAMMO)) + { + // Decrease ammo + fire_timeout = lweapons[iactiveweapon].activate(this); + } + else if ((lweapons[iactiveweapon].flags & WEAPON_NEEDRELOAD) && lweapons[iactiveweapon].nummagazines) + { + // reload + reload_timeout = lweapons[iactiveweapon].reloadtime; + lweapons[iactiveweapon].nummagazines--; + lweapons[iactiveweapon].numammo = lweapons[iactiveweapon].magsize; + } + } + } + + // update active weapon + lweapons[iactiveweapon].update(this, fire_timeout); + } + + void handlehook() + { + // handle hook + if(input.hook) + { + if(hooking == 0) + { + hooking = 1; + hook_pos = pos; + hook_dir = direction; + // Sound + create_sound(pos, sound_player_chain_loop, SOUND_LOOPFLAG_STARTLOOP); + } + else if(hooking == 1) + { + vec2 new_pos = hook_pos+hook_dir*hook_fire_speed; + + // Check against other players and powerups first + player* targetplayer = 0; + powerup* targetpowerup = 0; + { + static const int typelist[2] = { OBJTYPE_PLAYER, OBJTYPE_POWERUP}; + entity *ents[64]; + vec2 dir = new_pos - hook_pos; + float radius = length(dir * 0.5f); + vec2 center = hook_pos + dir * 0.5f; + int num = world.find_entities(center, radius, ents, 64,typelist,2); + + for (int i = 0; i < num; i++) + { + // Check if entity is a player + if (ents[i] == this || (targetplayer && targetpowerup)) + continue; + + if (!targetplayer && ents[i]->objtype == OBJTYPE_PLAYER) + { + // temp, set hook pos to our position + if (((player*)ents[i])->phookedplayer != this) + targetplayer = (player*)ents[i]; + } + else if (!targetpowerup && ents[i]->objtype == OBJTYPE_POWERUP && + (((powerup*)ents[i])->flags & powerup::POWERUP_FLAG_HOOKABLE)) + { + targetpowerup = (powerup*)ents[i]; + } + } + } + + //player* targetplayer = intersect_player(hook_pos, hook_pos, new_pos, this); + if (targetplayer) + { + // So he can't move "normally" + new_pos = targetplayer->pos; + phookedplayer = targetplayer; + targetplayer->numhooked++; + hooking = 3; + create_sound(pos, sound_player_chain_impact); + + // stop looping chain sound + create_sound(pos, sound_player_chain_loop, SOUND_LOOPFLAG_STOPLOOP); + } + else if (targetpowerup) + { + new_pos = targetpowerup->pos; + phookedpowerup = targetpowerup; + phookedpowerup->playerhooked = this; + hooking = 4; + create_sound(pos, sound_player_chain_impact); + + // stop looping chain sound + create_sound(pos, sound_player_chain_loop, SOUND_LOOPFLAG_STOPLOOP); + } + else if(intersect_line(hook_pos, new_pos, &new_pos)) + { + hooking = 2; + create_sound(pos, sound_player_chain_impact); + + // stop looping chain sound + create_sound(pos, sound_player_chain_loop, SOUND_LOOPFLAG_STOPLOOP); + } + else if(distance(pos, new_pos) > hook_length) + { + hooking = -1; + create_sound(pos, sound_player_chain_loop, SOUND_LOOPFLAG_STOPLOOP); + } + + hook_pos = new_pos; + } + else if(hooking == 2) + { + vec2 hookvel = normalize(hook_pos-pos)*hook_drag_accel; + // the hook as more power to drag you up then down. + // this makes it easier to get on top of an platform + if(hookvel.y > 0) + hookvel.y *= 0.3f; + + // the hook will boost it's power if the player wants to move + // in that direction. otherwise it will dampen everything abit + if((hookvel.x < 0 && input.left) || (hookvel.x > 0 && input.right)) + hookvel.x *= 0.95f; + else + hookvel.x *= 0.75f; + vec2 new_vel = vel+hookvel; + + // check if we are under the legal limit for the hook + if(length(new_vel) < hook_drag_speed || length(new_vel) < length(vel)) + vel = new_vel; // no problem. apply + } + else if (hooking == 3) + { + // hmm, force the targetplayer towards us if possible, otherwise us towards them if they are already hooked + if (phookedplayer) + { + if (phookedplayer->hooking > 1) + { + // Drag us towards target player + vec2 hookvel = normalize(hook_pos-pos)*hook_drag_accel; + if((hookvel.x < 0 && input.left) || (hookvel.x > 0 && input.right)) + hookvel.x *= 0.95f; + else + hookvel.x *= 0.75f; + + // Apply the velocity + // the hook will boost it's power if the player wants to move + // in that direction. otherwise it will dampen everything abit + vec2 new_vel = vel+hookvel; + + // check if we are under the legal limit for the hook + if(length(new_vel) < hook_drag_speed || length(new_vel) < length(vel)) + vel = new_vel; // no problem. apply + } + else + { + // Drag targetplayer towards us + vec2 hookvel = normalize(pos-hook_pos)*hook_drag_accel; + + // Apply the velocity + // the hook will boost it's power if the player wants to move + // in that direction. otherwise it will dampen everything abit + vec2 new_vel = phookedplayer->vel+hookvel; + + // check if we are under the legal limit for the hook + if(length(new_vel) < hook_drag_speed || length(new_vel) < length(vel)) + phookedplayer->vel = new_vel; // no problem. apply + } + hook_pos = phookedplayer->pos; + // if hooked player dies, release the hook + } + else + { + hooking = -1; + phookedplayer = 0; + } + } + else if (hooking == 4) + { + // Have a powerup, drag it towards us + vec2 hookvel = normalize(pos-hook_pos)*hook_drag_accel; + + // Apply the velocity + // the hook will boost it's power if the player wants to move + // in that direction. otherwise it will dampen everything abit + vec2 new_vel = phookedpowerup->vel+hookvel; + + // check if we are under the legal limit for the hook + if(length(new_vel) < hook_drag_speed || length(new_vel) < length(vel)) + phookedpowerup->vel = new_vel; // no problem. apply + hook_pos = phookedpowerup->pos; + } + } + else + { + hooking = 0; + hook_pos = pos; + if (phookedplayer) + { + phookedplayer->numhooked--; + phookedplayer = 0; + } + } + } + + void getattackticks(int& curattack, int& attacklen, int& visualtimeattack) + { + // time left from current attack (if any) + // first check modifiers (ninja...) + for (int i = 0; i < MODIFIER_NUMMODIFIERS; i++) + { + if ((modifiers[i].flags & (MODIFIER_ISACTIVE | MODIFIER_NEEDSACTIVATION)) == (MODIFIER_ISACTIVE | MODIFIER_NEEDSACTIVATION)) + { + curattack = modifiers[i].currentactivation; + attacklen = modifiers[i].activationtime; + visualtimeattack = modifiers[i].visualtimeattack; + return; + } + } + + // otherwise current fire timeout + curattack = fire_timeout; + attacklen = lweapons[iactiveweapon].firetime; + visualtimeattack = lweapons[iactiveweapon].visualtimeattack; + } + + virtual void tick() + { + tick_count++; + + // fetch some info + bool grounded = is_grounded(); + direction = get_direction(input.angle); + + // decrease reload timer + if(fire_timeout) + fire_timeout--; + if (reload_timeout) + reload_timeout--; + + // Switch weapons + if (flags & PLAYER_FLAGS_ISEQUIPPING) + { + equip_time--; + if (equip_time <= 0) + { + if (inextweapon >= 0) + { + equip_time = SERVER_TICK_SPEED * lweapons[inextweapon].equiptime; + iactiveweapon = inextweapon; + inextweapon = -1; + + // Send switch weapon event to client? + } + else + { + flags &= ~PLAYER_FLAGS_ISEQUIPPING; + } + } + } + else if (input.activeweapon && iactiveweapon != (input.activeweapon & ~0x80000000)) + { + input.activeweapon &= ~0x80000000; + // check which weapon to activate + if (input.activeweapon >= 0 && input.activeweapon < WEAPON_NUMWEAPONS && + (lweapons[input.activeweapon].flags & WEAPON_ISACTIVE)) + { + inextweapon = input.activeweapon; + equip_time = SERVER_TICK_SPEED * lweapons[iactiveweapon].unequiptime; + // unequip current + flags |= PLAYER_FLAGS_ISEQUIPPING; + + create_sound(pos, sound_player_switchweapon); + } + } + + // don't do any weapon activations if modifier is currently overriding + int modifierflags = handlemodifiers(); + if (!(modifierflags & MODIFIER_RETURNFLAGS_OVERRIDEWEAPON)) + handleweapon(); + + handlehook(); + + // handle movement + if(grounded) + { + if (airjumped) + create_sound(pos, SOUND_PLAYER_LAND); + airjumped = 0; + } + + float elast = 0.0f; + + if (!numhooked) + { + // I'm hooked by someone, so don't do any movement plz (temp) + if (!(modifierflags & MODIFIER_RETURNFLAGS_OVERRIDEVELOCITY)) + { + if(grounded) + { + // ground movement + if(input.left) + { + if(vel.x > -ground_control_speed) + { + vel.x -= ground_control_accel; + if(vel.x < -ground_control_speed) + vel.x = -ground_control_speed; + } + } + else if(input.right) + { + if(vel.x < ground_control_speed) + { + vel.x += ground_control_accel; + if(vel.x > ground_control_speed) + vel.x = ground_control_speed; + } + } + else + vel.x *= ground_friction; // ground fiction + } + else + { + // air movement + if(input.left) + { + if(vel.x > -air_control_speed) + vel.x -= air_control_accel; + } + else if(input.right) + { + if(vel.x < air_control_speed) + vel.x += air_control_accel; + } + else + vel.x *= air_friction; // air fiction + } + + if(input.jump) + { + if(jumped == 0) + { + if(grounded) + { + create_sound(pos, sound_player_jump); + vel.y = -ground_jump_speed; + jumped++; + } + /* + else if(airjumped == 0) + { + vel.y = -12; + airjumped++; + jumped++; + }*/ + } + else if (!grounded) + { + airjumped++; + } + } + else + jumped = 0; + } + + // meh, go through all players and stop their hook on me + /* + for(entity *ent = world.first_entity; ent; ent = ent->next_entity) + { + if (ent && ent->objtype == OBJTYPE_PLAYER) + { + player *p = (player*)ent; + if(p != this) + { + float d = distance(pos, p->pos); + vec2 dir = normalize(pos - p->pos); + if(d < phys_size*1.5f) + { + float a = phys_size*1.5f - d; + vel = vel + dir*a; + } + + if(p->phookedplayer == this) + { + if(d > phys_size*2.5f) + { + elast = 0.0f; + vel = vel - dir*2.5f; + } + } + } + } + }*/ + + // gravity + if (!(modifierflags & MODIFIER_RETURNFLAGS_OVERRIDEGRAVITY)) + vel.y += gravity; + } + + if (!(modifierflags & MODIFIER_RETURNFLAGS_OVERRIDEPOSITION)) + move_box(&pos, &vel, vec2(phys_size, phys_size), elast); + } + + void die() + { + create_sound(pos, sound_player_die); + // release our hooked player + if (phookedplayer) + { + phookedplayer->numhooked--; + phookedplayer = 0; + hooking = -1; + numhooked = 0; + } + respawn(); + + // meh, go through all players and stop their hook on me + for(entity *ent = world.first_entity; ent; ent = ent->next_entity) + { + if (ent && ent->objtype == OBJTYPE_PLAYER) + { + player* p = (player*)ent; + if (p->phookedplayer == this) + { + p->phookedplayer = 0; + p->hooking = -1; + //p->numhooked--; + } + } + } + } + + virtual bool take_damage(vec2 force, int dmg, int from) + { + vel += force; + + if(armor) + { + armor -= 1; + dmg--; + } + + if(dmg > armor) + { + dmg -= armor; + armor = 0; + health -= dmg; + } + else + armor -= dmg; + /* + int armordmg = (dmg+1)/2; + int healthdmg = dmg-armordmg; + if(armor < armordmg) + { + healthdmg += armordmg - armor; + armor = 0; + } + else + armor -= armordmg; + + health -= healthdmg; + */ + + // create healthmod indicator + create_healthmod(pos, dmg); + + damage_taken_tick = tick_count+50; + + // check for death + if(health <= 0) + { + // apply score + if(from != -1) + { + if(from == client_id) + score--; + else + { + player *p = get_player(from); + p->score++; + } + } + + die(); + return false; + } + + if (dmg > 2) + create_sound(pos, sound_player_hurt_long); + else + create_sound(pos, sound_player_hurt_short); + + // spawn blood? + + return true; + } + + virtual void snap(int snaping_client) + { + obj_player *player = (obj_player *)snap_new_item(OBJTYPE_PLAYER, client_id, sizeof(obj_player)); + + client_info info; + if(server_getclientinfo(client_id, &info)) + snap_encode_string(info.name, player->name, strlen(info.name), 32); + + player->x = (int)pos.x; + player->y = (int)pos.y; + player->vx = (int)vel.x; + player->vy = (int)vel.y; + player->emote = EMOTE_NORMAL; + + player->ammocount = lweapons[iactiveweapon].numammo; + player->health = 0; + player->armor = 0; + player->local = 0; + player->clientid = client_id; + player->weapon = iactiveweapon; + player->modifier = 0; + for (int i = 0; i < MODIFIER_NUMMODIFIERS; i++) + { + // add active modifiers + if (modifiers[i].flags & MODIFIER_ISACTIVE) + player->modifier |= 1 << i; + } + // get current attack ticks + getattackticks(player->attackticks, player->attacklen, player->visualtimeattack); + + + if(client_id == snaping_client) + { + player->local = 1; + player->health = health; + player->armor = armor; + } + + if(length(vel) > 15.0f) + player->emote = EMOTE_HAPPY; + + if(damage_taken_tick > tick_count) + player->emote = EMOTE_PAIN; + + if(player->emote == EMOTE_NORMAL) + { + if((tick_count%(50*5)) < 10) + player->emote = EMOTE_BLINK; + } + + player->hook_active = hooking>0?1:0; + player->hook_x = (int)hook_pos.x; + player->hook_y = (int)hook_pos.y; + + player->angle = input.angle; + player->score = score; + } +}; + +// POWERUP /////////////////////// + +powerup::powerup(int _type, int _subtype, int _numitems, int _flags) : + entity(OBJTYPE_POWERUP) +{ + static int current_id = 0; + playerhooked = 0; + id = current_id++; + vel = vec2(0.0f,0.0f); + type = _type; + subtype = _subtype; + numitems = _numitems; + flags = _flags; + // set radius (so it can collide and be hooked and stuff) + proximity_radius = phys_size; + spawntick = -1; + world.insert_entity(this); +} + +void powerup::spawnrandom(int _lifespan) +{ + return; + /* + vec2 pos; + int start, num; + map_get_type(1, &start, &num); + + if(!num) + return; + + mapres_spawnpoint *sp = (mapres_spawnpoint*)map_get_item(start + (rand()%num), NULL, NULL); + pos = vec2(sp->x, sp->y); + + // Check if there already is a powerup at that location + { + int type = OBJTYPE_POWERUP; + entity *ents[64]; + int num = world.find_entities(pos, 5.0f, ents, 64,&type,1); + for (int i = 0; i < num; i++) + { + if (ents[i]->objtype == OBJTYPE_POWERUP) + { + // location busy + return; + } + } + } + + powerup* ppower = new powerup(rand() % POWERUP_TYPE_NUMPOWERUPS,_lifespan); + ppower->pos = pos; + if (ppower->type == POWERUP_TYPE_WEAPON) + { + ppower->subtype = rand() % WEAPON_NUMWEAPONS; + ppower->numitems = 10; + } + else if (ppower->type == POWERUP_TYPE_HEALTH || ppower->type == POWERUP_TYPE_ARMOR) + { + ppower->numitems = rand() % 5; + } + ppower->flags |= POWERUP_FLAG_HOOKABLE;*/ +} + +void powerup::tick() +{ + // wait for respawn + if(spawntick > 0) + { + if(server_tick() > spawntick) + spawntick = -1; + else + return; + } + + vec2 oldpos = pos; + //vel.y += 0.25f; + pos += vel; + move_box(&pos, &vel, vec2(phys_size, phys_size), 0.0f); + + // Check if a player intersected us + vec2 meh; + player* pplayer = intersect_player(pos, pos + vec2(0,16), meh, 0); + if (pplayer) + { + // player picked us up, is someone was hooking us, let them go + if (playerhooked) + playerhooked->hooking = -1; + int respawntime = -1; + switch (type) + { + case POWERUP_TYPE_HEALTH: + { + if(pplayer->health < PLAYER_MAXHEALTH) + { + pplayer->health = min(PLAYER_MAXHEALTH, pplayer->health + numitems); + respawntime = 20; + } + break; + } + case POWERUP_TYPE_ARMOR: + { + if(pplayer->armor < PLAYER_MAXARMOR) + { + pplayer->armor = min(PLAYER_MAXARMOR, pplayer->armor + numitems); + respawntime = 20; + } + break; + } + case POWERUP_TYPE_WEAPON: + { + if (pplayer->lweapons[subtype].flags & player::WEAPON_ISACTIVE) + { + // add ammo + /* + if (pplayer->lweapons[subtype].flags & player::WEAPON_NEEDRELOAD) + { + int numtoadd = min(numitems, pplayer->lweapons[subtype].magsize); + pplayer->lweapons[subtype].numammo = min(10, pplayer->lweapons[subtype].numammo + numtoadd); + pplayer->lweapons[subtype].nummagazines += (numitems - numtoadd) % pplayer->lweapons[subtype].magsize; + } + else*/ + if(pplayer->lweapons[subtype].numammo < 10) + { + respawntime = 20; + pplayer->lweapons[subtype].numammo = min(10, pplayer->lweapons[subtype].numammo + numitems); + } + } + else + { + pplayer->lweapons[subtype].settype(); + pplayer->lweapons[subtype].flags |= player::WEAPON_ISACTIVE; + respawntime = 20; + } + break; + } + case POWERUP_TYPE_NINJA: + { + respawntime = 60; + // reset and activate + pplayer->modifiers[MODIFIER_TYPE_NINJA].settype(); + pplayer->modifiers[MODIFIER_TYPE_NINJA].flags |= player::MODIFIER_ISACTIVE; + break; + } + //POWERUP_TYPE_TIMEFIELD = 4, + default: + break; + }; + + if(respawntime >= 0) + spawntick = server_tick() + server_tickspeed() * respawntime; + //world.destroy_entity(this); + } +} + +void powerup::snap(int snapping_client) +{ + if(spawntick != -1) + return; + + obj_powerup *powerup = (obj_powerup *)snap_new_item(OBJTYPE_POWERUP, id, sizeof(obj_powerup)); + powerup->x = (int)pos.x; + powerup->y = (int)pos.y; + powerup->vx = (int)vel.x; + powerup->vy = (int)vel.y; + powerup->type = type; + powerup->subtype = subtype; +} + +// POWERUP END /////////////////////// + +static player players[MAX_CLIENTS]; + +player *get_player(int index) +{ + return &players[index]; +} + +void create_healthmod(vec2 p, int amount) +{ + ev_healthmod *ev = (ev_healthmod *)events.create(EVENT_HEALTHMOD, sizeof(ev_healthmod)); + ev->x = (int)p.x; + ev->y = (int)p.y; + ev->amount = amount; +} + +void create_explosion(vec2 p, int owner, bool bnodamage) +{ + // create the event + ev_explosion *ev = (ev_explosion *)events.create(EVENT_EXPLOSION, sizeof(ev_explosion)); + ev->x = (int)p.x; + ev->y = (int)p.y; + + if (!bnodamage) + { + // deal damage + entity *ents[64]; + const float radius = 128.0f; + int num = world.find_entities(p, radius, ents, 64); + for(int i = 0; i < num; i++) + { + vec2 diff = ents[i]->pos - p; + vec2 forcedir(0,1); + if (length(diff)) + forcedir = normalize(diff); + float l = length(diff); + float dmg = 5 * (1 - (l/radius)); + if((int)dmg) + { + ents[i]->take_damage(forcedir*dmg*2, (int)dmg, owner);/* && + ents[i]->objtype == OBJTYPE_PLAYER && + owner >= 0) + { + player *p = (player*)ents[i]; + if(p->client_id == owner) + p->score--; + else + ((player*)ents[owner])->score++; + + }*/ + } + } + } +} + +void create_smoke(vec2 p) +{ + // create the event + ev_explosion *ev = (ev_explosion *)events.create(EVENT_SMOKE, sizeof(ev_explosion)); + ev->x = (int)p.x; + ev->y = (int)p.y; +} + +void create_sound(vec2 pos, int sound, int loopingflags) +{ + if (sound < 0) + return; + + // create a sound + ev_sound *ev = (ev_sound *)events.create(EVENT_SOUND, sizeof(ev_sound)); + ev->x = (int)pos.x; + ev->y = (int)pos.y; + ev->sound = sound | loopingflags; +} + +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); + vec2 center = pos0 + dir * 0.5f; + int num = world.find_entities(center, radius, ents, 64); + for (int i = 0; i < num; i++) + { + // Check if entity is a player + if (ents[i] != notthis && ents[i]->objtype == OBJTYPE_PLAYER) + { + // temp, set hook pos to our position + new_pos = ents[i]->pos; + return (player*)ents[i]; + } + } + + return 0; +} + +// Server hooks +static int addtick = SERVER_TICK_SPEED * 5; +void mods_tick() +{ + // clear all events + events.clear(); + world.tick(); + + if (addtick <= 0) + { + powerup::spawnrandom(SERVER_TICK_SPEED * 5); + addtick = SERVER_TICK_SPEED * 5; + } + addtick--; +} + +void mods_snap(int client_id) +{ + world.snap(client_id); + events.snap(client_id); +} + +void mods_client_input(int client_id, void *input) +{ + players[client_id].previnput = players[client_id].input; + players[client_id].input = *(player_input*)input; +} + +void mods_client_enter(int client_id) +{ + players[client_id].reset(); + players[client_id].client_id = client_id; + players[client_id].respawn(); + world.insert_entity(&players[client_id]); + +} + +void mods_client_drop(int client_id) +{ + players[client_id].client_id = -1; + world.remove_entity(&players[client_id]); +} + +void mods_init() +{ + col_init(32); + + int start, num; + map_get_type(MAPRES_ITEM, &start, &num); + + for(int i = 0; i < num; i++) + { + mapres_item *it = (mapres_item *)map_get_item(start+i, 0, 0); + + int type = -1; + int subtype = -1; + int numitems = 1; + + switch(it->type) + { + case ITEM_WEAPON_GUN: + type = POWERUP_TYPE_WEAPON; + subtype = WEAPON_TYPE_GUN; + break; + case ITEM_WEAPON_SHOTGUN: + type = POWERUP_TYPE_WEAPON; + subtype = WEAPON_TYPE_SHOTGUN; + numitems = 5; + break; + case ITEM_WEAPON_ROCKET: + type = POWERUP_TYPE_WEAPON; + subtype = WEAPON_TYPE_ROCKET; + numitems = 5; + break; + /*case ITEM_WEAPON_SNIPER: + type = POWERUP_TYPE_WEAPON; + subtype = WEAPON_TYPE_ROCKET; + break;*/ + case ITEM_WEAPON_HAMMER: + type = POWERUP_TYPE_WEAPON; + subtype = WEAPON_TYPE_MELEE; + break; + + case ITEM_HEALTH_1: + type = POWERUP_TYPE_HEALTH; + numitems = 1; + break; + case ITEM_HEALTH_5: + type = POWERUP_TYPE_HEALTH; + numitems = 5; + break; + case ITEM_HEALTH_10: + type = POWERUP_TYPE_HEALTH; + numitems = 10; + break; + + case ITEM_ARMOR_1: + type = POWERUP_TYPE_ARMOR; + numitems = 1; + break; + case ITEM_ARMOR_5: + type = POWERUP_TYPE_ARMOR; + numitems = 5; + break; + case ITEM_ARMOR_10: + type = POWERUP_TYPE_ARMOR; + numitems = 10; + break; + }; + + powerup* ppower = new powerup(type, subtype, numitems); + ppower->pos.x = it->x; + ppower->pos.y = it->y; + } + + + /* + powerup* ppower = new powerup(rand() % POWERUP_TYPE_NUMPOWERUPS,_lifespan); + ppower->pos = pos; + if (ppower->type == POWERUP_TYPE_WEAPON) + { + ppower->subtype = rand() % WEAPON_NUMWEAPONS; + ppower->numitems = 10; + } + else if (ppower->type == POWERUP_TYPE_HEALTH || ppower->type == POWERUP_TYPE_ARMOR) + { + ppower->numitems = rand() % 5; + } + ppower->flags |= POWERUP_FLAG_HOOKABLE; + */ + + //powerup::spawnrandom(SERVER_TICK_SPEED * 5); +} + +void mods_shutdown() {} +void mods_presnap() {} +void mods_postsnap() {} -- cgit 1.4.1