From a2566b3ebd93e0bbc55a920a7be08054a9377f11 Mon Sep 17 00:00:00 2001 From: Magnus Auvinen Date: Sat, 15 Dec 2007 10:24:49 +0000 Subject: cleaned up code structure a bit --- src/game/client/cl_render.h | 24 - src/game/client/cl_skin.cpp | 167 -- src/game/client/cl_skin.h | 20 - src/game/client/data/createdir.txt | 1 - src/game/client/game_client.cpp | 3103 --------------------------------- src/game/client/gc_client.cpp | 3103 +++++++++++++++++++++++++++++++++ src/game/client/gc_mapres_image.cpp | 125 ++ src/game/client/gc_mapres_image.h | 19 + src/game/client/gc_mapres_tilemap.cpp | 102 ++ src/game/client/gc_mapres_tilemap.h | 26 + src/game/client/gc_menu.cpp | 1893 ++++++++++++++++++++ src/game/client/gc_menu.h | 16 + src/game/client/gc_render.h | 24 + src/game/client/gc_skin.cpp | 167 ++ src/game/client/gc_skin.h | 20 + src/game/client/mapres_image.cpp | 125 -- src/game/client/mapres_image.h | 19 - src/game/client/mapres_tilemap.cpp | 102 -- src/game/client/mapres_tilemap.h | 26 - src/game/client/menu.cpp | 1865 -------------------- src/game/client/menu.h | 16 - src/game/client/menu2.cpp | 1893 -------------------- 22 files changed, 5495 insertions(+), 7361 deletions(-) delete mode 100644 src/game/client/cl_render.h delete mode 100644 src/game/client/cl_skin.cpp delete mode 100644 src/game/client/cl_skin.h delete mode 100644 src/game/client/data/createdir.txt delete mode 100644 src/game/client/game_client.cpp create mode 100644 src/game/client/gc_client.cpp create mode 100644 src/game/client/gc_mapres_image.cpp create mode 100644 src/game/client/gc_mapres_image.h create mode 100644 src/game/client/gc_mapres_tilemap.cpp create mode 100644 src/game/client/gc_mapres_tilemap.h create mode 100644 src/game/client/gc_menu.cpp create mode 100644 src/game/client/gc_menu.h create mode 100644 src/game/client/gc_render.h create mode 100644 src/game/client/gc_skin.cpp create mode 100644 src/game/client/gc_skin.h delete mode 100644 src/game/client/mapres_image.cpp delete mode 100644 src/game/client/mapres_image.h delete mode 100644 src/game/client/mapres_tilemap.cpp delete mode 100644 src/game/client/mapres_tilemap.h delete mode 100644 src/game/client/menu.cpp delete mode 100644 src/game/client/menu.h delete mode 100644 src/game/client/menu2.cpp (limited to 'src/game/client') diff --git a/src/game/client/cl_render.h b/src/game/client/cl_render.h deleted file mode 100644 index fc85d49a..00000000 --- a/src/game/client/cl_render.h +++ /dev/null @@ -1,24 +0,0 @@ -/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */ -struct animstate -{ - keyframe body; - keyframe back_foot; - keyframe front_foot; - keyframe attach; -}; - -void anim_seq_eval(sequence *seq, float time, keyframe *frame); -void anim_eval(animation *anim, float time, animstate *state); -void anim_add_keyframe(keyframe *seq, keyframe *added, float amount); -void anim_add(animstate *state, animstate *added, float amount); -void anim_eval_add(animstate *state, animation *anim, float time, float amount); - -struct tee_render_info -{ - int texture; - vec4 color_body; - vec4 color_feet; - float size; -}; - -void render_tee(animstate *anim, tee_render_info *info, int emote, vec2 dir, vec2 pos); diff --git a/src/game/client/cl_skin.cpp b/src/game/client/cl_skin.cpp deleted file mode 100644 index da8fe535..00000000 --- a/src/game/client/cl_skin.cpp +++ /dev/null @@ -1,167 +0,0 @@ -/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */ -#include -#include -#include -#include -#include "cl_skin.h" -#include "../math.h" - -enum -{ - MAX_SKINS=256, -}; - -static skin skins[MAX_SKINS] = {{0}}; -static int num_skins = 0; - -static void skinscan(const char *name, int is_dir, void *user) -{ - int l = strlen(name); - if(l < 4 || is_dir || num_skins == MAX_SKINS) - return; - if(strcmp(name+l-4, ".png") != 0) - return; - - char buf[512]; - sprintf(buf, "data/skins/%s", name); - IMAGE_INFO info; - if(!gfx_load_png(&info, buf)) - { - dbg_msg("game", "failed to load skin from %s", name); - return; - } - - skins[num_skins].org_texture = gfx_load_texture_raw(info.width, info.height, info.format, info.data); - - // create colorless version - unsigned char *d = (unsigned char *)info.data; - int step = info.format == IMG_RGBA ? 4 : 3; - - for(int i = 0; i < info.width*info.height; i++) - { - int v = (d[i*step]+d[i*step+1]+d[i*step+2])/3; - d[i*step] = v; - d[i*step+1] = v; - d[i*step+2] = v; - } - - if(1) - { - int bs = 96; // body size - int pitch = info.width*4; - int freq[256] = {0}; - - for(int y = 0; y < bs; y++) - for(int x = 0; x < bs; x++) - { - if(d[y*pitch+x*4+3] > 128) - freq[d[y*pitch+x*4]]++; - } - - int org_weight = 0; - int new_weight = 192; - for(int i = 1; i < 256; i++) - { - if(freq[org_weight] < freq[i]) - org_weight = i; - } - - int inv_org_weight = 255-org_weight; - int inv_new_weight = 255-new_weight; - for(int y = 0; y < bs; y++) - for(int x = 0; x < bs; x++) - { - int v = d[y*pitch+x*4]; - if(v <= org_weight) - v = (int)(((v/(float)org_weight) * new_weight)); - else - v = (int)(((v-org_weight)/(float)inv_org_weight)*inv_new_weight + new_weight); - d[y*pitch+x*4] = v; - d[y*pitch+x*4+1] = v; - d[y*pitch+x*4+2] = v; - } - } - - skins[num_skins].color_texture = gfx_load_texture_raw(info.width, info.height, info.format, info.data); - mem_free(info.data); - - // set skin data - strncpy(skins[num_skins].name, name, min((int)sizeof(skins[num_skins].name),l-4)); - dbg_msg("game", "load skin %s", skins[num_skins].name); - num_skins++; -} - - -void skin_init() -{ - // load skins - fs_listdir("data/skins", skinscan, 0); -} - -int skin_num() -{ - return num_skins; -} - -const skin *skin_get(int index) -{ - return &skins[index%num_skins]; -} - -int skin_find(const char *name) -{ - for(int i = 0; i < num_skins; i++) - { - if(strcmp(skins[i].name, name) == 0) - return i; - } - return -1; -} - - - - -// these converter functions were nicked from some random internet pages -static float hue_to_rgb(float v1, float v2, float h) -{ - if(h < 0) h += 1; - if(h > 1) h -= 1; - if((6 * h) < 1) return v1 + ( v2 - v1 ) * 6 * h; - if((2 * h) < 1) return v2; - if((3 * h) < 2) return v1 + ( v2 - v1 ) * ((2.0f/3.0f) - h) * 6; - return v1; -} - -vec3 hsl_to_rgb(vec3 in) -{ - float v1, v2; - vec3 out; - - if(in.s == 0) - { - out.r = in.l; - out.g = in.l; - out.b = in.l; - } - else - { - if(in.l < 0.5f) - v2 = in.l * (1 + in.s); - else - v2 = (in.l+in.s) - (in.s*in.l); - - v1 = 2 * in.l - v2; - - out.r = hue_to_rgb(v1, v2, in.h + (1.0f/3.0f)); - out.g = hue_to_rgb(v1, v2, in.h); - out.b = hue_to_rgb(v1, v2, in.h - (1.0f/3.0f)); - } - - return out; -} - -vec4 skin_get_color(int v) -{ - vec3 r = hsl_to_rgb(vec3((v>>16)/255.0f, ((v>>8)&0xff)/255.0f, 0.5f+(v&0xff)/255.0f*0.5f)); - return vec4(r.r, r.g, r.b, 1.0f); -} diff --git a/src/game/client/cl_skin.h b/src/game/client/cl_skin.h deleted file mode 100644 index bafc76b9..00000000 --- a/src/game/client/cl_skin.h +++ /dev/null @@ -1,20 +0,0 @@ -/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */ -#include "../vmath.h" - -// do this better and nicer -typedef struct -{ - int org_texture; - int color_texture; - char name[31]; - char term[1]; -} skin; - -vec4 skin_get_color(int v); -void skin_init(); -int skin_num(); -const skin *skin_get(int index); -int skin_find(const char *name); - - -vec3 hsl_to_rgb(vec3 in); diff --git a/src/game/client/data/createdir.txt b/src/game/client/data/createdir.txt deleted file mode 100644 index 258b42d5..00000000 --- a/src/game/client/data/createdir.txt +++ /dev/null @@ -1 +0,0 @@ -this file is here to make sure that this directory gets created diff --git a/src/game/client/game_client.cpp b/src/game/client/game_client.cpp deleted file mode 100644 index 00deea5f..00000000 --- a/src/game/client/game_client.cpp +++ /dev/null @@ -1,3103 +0,0 @@ -/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */ -#include -#include -#include -#include - -extern "C" { - #include - #include -}; - -#include "../game.h" -#include "../version.h" -#include "../mapres.h" -#include "mapres_image.h" -#include "mapres_tilemap.h" -#include "data.h" -#include "menu.h" -#include "cl_skin.h" -#include "cl_render.h" - -// sound channels -enum -{ - CHN_GUI=0, - CHN_MUSIC, - CHN_WORLD, - CHN_GLOBAL, -}; - -data_container *data = 0x0; - -int gametype = GAMETYPE_DM; - -extern void modmenu_render(); - -enum -{ - CHATMODE_NONE=0, - CHATMODE_ALL, - CHATMODE_TEAM, - CHATMODE_CONSOLE, - CHATMODE_REMOTECONSOLE, -}; - -typedef struct -{ - float x, y, w, h; -} RECT; -RECT *ui2_screen(); - -static int chat_mode = CHATMODE_NONE; -bool menu_active = false; -bool menu_game_active = false; -static bool emoticon_selector_active = false; - -static vec2 mouse_pos; -static vec2 local_character_pos; -static vec2 local_target_pos; -static const obj_player_character *local_character = 0; -static const obj_player_character *local_prev_character = 0; -const obj_player_info *local_info = 0; -static const obj_flag *flags[2] = {0,0}; -static const obj_game *gameobj = 0; - -static int picked_up_weapon = 0; - -static struct client_data -{ - char name[64]; - char skin_name[64]; - int skin_id; - int skin_color; - int team; - int emoticon; - int emoticon_start; - player_core predicted; - - tee_render_info skin_info; - -} client_datas[MAX_CLIENTS]; - -class client_effects -{ -public: - float zoom; - float currentzoom; - float stage; - int lastzoomin; - int lastincrease; - - client_effects() - { - currentzoom = zoom = 3.0f; - stage = 0.0f; - } - - float getorgzoom() { return zoom; } - - float getzoom(int tick, float intratick, const obj_player_character *player) - { - float currentstage = ((float)player->weaponstage) * 0.1f; - if (currentstage < stage) - { - if ((tick - lastincrease) > (client_tickspeed() / 2)) - stage = currentstage; - } - else - { - lastincrease = tick; - stage = currentstage; - } - - float targetzoom = 3.0f + stage; - currentzoom = LERP(currentzoom, targetzoom, 0.1); - return currentzoom; - } -}; - -client_effects cl_effects; - -inline float frandom() { return rand()/(float)(RAND_MAX); } - -void snd_play_random(int chn, int setid, float vol, vec2 pos) -{ - soundset *set = &data->sounds[setid]; - - if(!set->num_sounds) - return; - - if(set->num_sounds == 1) - { - snd_play_at(chn, set->sounds[0].id, 0, pos.x, pos.y); - return; - } - - // play a random one - int id; - do { - id = rand() % set->num_sounds; - } while(id == set->last); - snd_play_at(chn, set->sounds[id].id, 0, pos.x, pos.y); - set->last = id; -} - -// sound volume tweak -static const float stereo_separation = 0.001f; -static const float stereo_separation_deadzone = 200.0f; -static const float volume_distance_falloff = 200.0f; -static const float volume_distance_deadzone = 320.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; - -void sound_vol_pan(const vec2& p, float *vol, float *pan) -{ - vec2 player_to_ev = p - local_character_pos; - *pan = 0.0f; - *vol = 1.0f; - - if(fabs(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; - } -} - -enum -{ - SPRITE_FLAG_FLIP_Y=1, - SPRITE_FLAG_FLIP_X=2, -}; - -static float sprite_w_scale; -static float sprite_h_scale; - -static void select_sprite(sprite *spr, int flags=0, int sx=0, int sy=0) -{ - int x = spr->x+sx; - int y = spr->y+sy; - int w = spr->w; - int h = spr->h; - int cx = spr->set->gridx; - int cy = spr->set->gridy; - - float f = sqrtf(h*h + w*w); - sprite_w_scale = w/f; - sprite_h_scale = h/f; - - float x1 = x/(float)cx; - float x2 = (x+w)/(float)cx; - float y1 = y/(float)cy; - float y2 = (y+h)/(float)cy; - float temp = 0; - - if(flags&SPRITE_FLAG_FLIP_Y) - { - temp = y1; - y1 = y2; - y2 = temp; - } - - if(flags&SPRITE_FLAG_FLIP_X) - { - temp = x1; - x1 = x2; - x2 = temp; - } - - gfx_quads_setsubset(x1, y1, x2, y2); -} - -void select_sprite(int id, int flags=0, int sx=0, int sy=0) -{ - if(id < 0 || id > data->num_sprites) - return; - select_sprite(&data->sprites[id], flags, sx, sy); -} - -void draw_sprite(float x, float y, float size) -{ - gfx_quads_draw(x, y, size*sprite_w_scale, size*sprite_h_scale); -} - -class damage_indicators -{ -public: - int64 lastupdate; - struct item - { - vec2 pos; - vec2 dir; - float life; - float startangle; - }; - - enum - { - MAX_ITEMS=64, - }; - - damage_indicators() - { - lastupdate = 0; - num_items = 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, vec2 dir) - { - item *i = create_i(); - if (i) - { - i->pos = pos; - i->life = 0.75f; - i->dir = dir*-1; - i->startangle = (( (float)rand()/(float)RAND_MAX) - 1.0f) * 2.0f * pi; - } - } - - void render() - { - gfx_texture_set(data->images[IMAGE_GAME].id); - gfx_quads_begin(); - for(int i = 0; i < num_items;) - { - vec2 pos = mix(items[i].pos+items[i].dir*75.0f, items[i].pos, clamp((items[i].life-0.60f)/0.15f, 0.0f, 1.0f)); - - items[i].life -= client_frametime(); - if(items[i].life < 0.0f) - destroy_i(&items[i]); - else - { - gfx_setcolor(1.0f,1.0f,1.0f, items[i].life/0.1f); - gfx_quads_setrotation(items[i].startangle + items[i].life * 2.0f); - select_sprite(SPRITE_STAR1); - draw_sprite(pos.x, pos.y, 48.0f); - i++; - } - } - gfx_quads_end(); - } - -}; - -static damage_indicators damageind; - -class particle_system -{ -public: - struct particle - { - vec2 pos; - vec2 vel; - float life; - float max_life; - float size; - - float rot; - float rotspeed; - - float gravity; - float friction; - int iparticle; - - vec4 color; - }; - - enum - { - MAX_PARTICLES=1024, - }; - - particle particles[MAX_PARTICLES]; - int num_particles; - - particle_system() - { - num_particles = 0; - } - - void new_particle(vec2 pos, vec2 vel, float life, float size, float gravity, float friction, vec4 color=vec4(1,1,1,1)) - { - if (num_particles >= MAX_PARTICLES) - return; - - particles[num_particles].iparticle = rand() % data->num_particles; - particles[num_particles].pos = pos; - particles[num_particles].vel = vel; - particles[num_particles].life = life - (data->particles[particles[num_particles].iparticle].lifemod/100.0f) * life; - particles[num_particles].size = size; - particles[num_particles].max_life = life; - particles[num_particles].gravity = gravity; - particles[num_particles].friction = friction; - particles[num_particles].rot = frandom()*pi*2; - particles[num_particles].rotspeed = frandom() * 10.0f; - particles[num_particles].color = color; - num_particles++; - } - - void update(float time_passed) - { - for(int i = 0; i < num_particles; i++) - { - particles[i].vel.y += particles[i].gravity*time_passed; - particles[i].vel *= particles[i].friction; - vec2 vel = particles[i].vel*time_passed; - move_point(&particles[i].pos, &vel, 0.1f+0.9f*frandom(), NULL); - particles[i].vel = vel* (1.0f/time_passed); - particles[i].life += time_passed; - particles[i].rot += time_passed * particles[i].rotspeed; - - // check particle death - if(particles[i].life > particles[i].max_life) - { - num_particles--; - particles[i] = particles[num_particles]; - i--; - } - } - } - - void render() - { - gfx_blend_additive(); - gfx_texture_set(data->images[IMAGE_GAME].id); - gfx_quads_begin(); - - for(int i = 0; i < num_particles; i++) - { - int type = particles[i].iparticle; - select_sprite(data->particles[type].spr); - float a = 1 - particles[i].life / particles[i].max_life; - vec2 p = particles[i].pos; - - gfx_quads_setrotation(particles[i].rot); - - gfx_setcolor( - data->particles[type].color_r * particles[i].color.r, - data->particles[type].color_g * particles[i].color.g, - data->particles[type].color_b * particles[i].color.b, - pow(a, 0.75f) * particles[i].color.a); - - gfx_quads_draw(p.x, p.y,particles[i].size,particles[i].size); - } - gfx_quads_end(); - gfx_blend_normal(); - } -}; - -static particle_system temp_system; - -class projectile_particles -{ -public: - enum - { - LISTSIZE = 1000, - }; - // meh, just use size % - int lastadd[LISTSIZE]; - projectile_particles() - { - reset(); - } - - void reset() - { - for (int i = 0; i < LISTSIZE; i++) - lastadd[i] = -1000; - } - - void addparticle(int projectiletype, int projectileid, vec2 pos, vec2 vel) - { - int particlespersecond = data->projectileinfo[projectiletype].particlespersecond; - int lastaddtick = lastadd[projectileid % LISTSIZE]; - - if(!particlespersecond) - return; - - if ((client_tick() - lastaddtick) > (client_tickspeed() / particlespersecond)) - { - lastadd[projectileid % LISTSIZE] = client_tick(); - float life = data->projectileinfo[projectiletype].particlelife; - float size = data->projectileinfo[projectiletype].particlesize; - vec2 v = vel * 0.2f + normalize(vec2(frandom()-0.5f, -frandom()))*(32.0f+frandom()*32.0f); - - // add the particle (from projectiletype later on, but meh...) - temp_system.new_particle(pos, v, life, size, 0, 0.95f); - } - } -}; -static projectile_particles proj_particles; - -static char chat_input[512]; -static unsigned chat_input_len; -static const int chat_max_lines = 10; - -struct chatline -{ - int tick; - int client_id; - int team; - char text[512+64]; -}; - -chatline chat_lines[chat_max_lines]; -static int chat_current_line = 0; - -void chat_reset() -{ - for(int i = 0; i < chat_max_lines; i++) - chat_lines[i].tick = -1000000; - chat_current_line = 0; -} - -void chat_add_line(int client_id, int team, const char *line) -{ - chat_current_line = (chat_current_line+1)%chat_max_lines; - chat_lines[chat_current_line].tick = client_tick(); - chat_lines[chat_current_line].client_id = client_id; - chat_lines[chat_current_line].team = team; - - if(client_id == -1) // server message - sprintf(chat_lines[chat_current_line].text, "*** %s", line); - else - { - sprintf(chat_lines[chat_current_line].text, "%s: %s", client_datas[client_id].name, line); - } -} - -struct killmsg -{ - int weapon; - int victim; - int killer; - int mode_special; // for CTF, if the guy is carrying a flag for example - int tick; -}; - -static const int killmsg_max = 5; -killmsg killmsgs[killmsg_max]; -static int killmsg_current = 0; - -extern unsigned char internal_data[]; - -void create_air_jump_effect(vec2 pos) -{ - const int count = 12; - for(int i = 0; i <= count; i++) - { - float a = i/(float)count; - vec2 v = vec2((a-0.5f)*512.0f, 0); - temp_system.new_particle(pos+vec2(0,28), v, 0.4f, 16.0f, 0, 0.985f, vec4(0.25f,0.4f,1,1)); - } -} - - -extern void draw_round_rect(float x, float y, float w, float h, float r); -extern int render_popup(const char *caption, const char *text, const char *button_text); - -static void render_loading(float percent) -{ - gfx_clear(0.65f,0.78f,0.9f); - RECT screen = *ui2_screen(); - gfx_mapscreen(screen.x, screen.y, screen.w, screen.h); - - float tw; - - float w = 700; - float h = 200; - float x = screen.w/2-w/2; - float y = screen.h/2-h/2; - - gfx_blend_normal(); - - gfx_texture_set(-1); - gfx_quads_begin(); - gfx_setcolor(0,0,0,0.50f); - draw_round_rect(x, y, w, h, 40.0f); - gfx_quads_end(); - - const char *caption = "Loading"; - - tw = gfx_pretty_text_width(48.0f, caption, -1); - ui_do_label(x+w/2-tw/2, y+20, caption, 48.0f); - - gfx_texture_set(-1); - gfx_quads_begin(); - gfx_setcolor(1,1,1,1.0f); - draw_round_rect(x+40, y+h-75, (w-80)*percent, 25, 5.0f); - gfx_quads_end(); - - gfx_swap(); -} - -extern "C" void modc_init() -{ - // setup sound channels - snd_set_channel(CHN_GUI, 1.0f, 0.0f); - snd_set_channel(CHN_MUSIC, 1.0f, 0.0f); - snd_set_channel(CHN_WORLD, 0.9f, 1.0f); - snd_set_channel(CHN_GLOBAL, 1.0f, 0.0f); - - // load the data container - data = load_data_from_memory(internal_data); - - // TODO: should be removed - snd_set_listener_pos(0.0f, 0.0f); - - float total = data->num_sounds+data->num_images; - float current = 0; - - // load sounds - for(int s = 0; s < data->num_sounds; s++) - { - render_loading(current/total); - for(int i = 0; i < data->sounds[s].num_sounds; i++) - { - int id; - //if (strcmp(data->sounds[s].sounds[i].filename + strlen(data->sounds[s].sounds[i].filename) - 3, ".wv") == 0) - id = snd_load_wv(data->sounds[s].sounds[i].filename); - //else - // id = snd_load_wav(data->sounds[s].sounds[i].filename); - - data->sounds[s].sounds[i].id = id; - } - - current++; - } - - // load textures - for(int i = 0; i < data->num_images; i++) - { - render_loading(current/total); - data->images[i].id = gfx_load_texture(data->images[i].filename); - current++; - } - - skin_init(); -} - -extern "C" void modc_entergame() -{ -} - -extern "C" void modc_shutdown() -{ - // shutdown the menu -} - -static void process_events(int s) -{ - int num = snap_num_items(s); - for(int index = 0; index < num; index++) - { - SNAP_ITEM item; - const void *data = snap_get_item(s, index, &item); - - if(item.type == EVENT_DAMAGEINDICATION) - { - ev_damageind *ev = (ev_damageind *)data; - damageind.create(vec2(ev->x, ev->y), get_direction(ev->angle)); - } - else if(item.type == EVENT_AIR_JUMP) - { - ev_common *ev = (ev_common *)data; - create_air_jump_effect(vec2(ev->x, ev->y)); - } - 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_SPAWN) - { - 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_DEATH) - { - ev_explosion *ev = (ev_explosion *)data; - vec2 p(ev->x, ev->y); - vec4 c(0.5f, 0.1f, 0.1f, 1.0f); - - // center explosion - vec2 v = normalize(vec2(frandom()-0.5f, -frandom()))*(32.0f+frandom()*32.0f); - temp_system.new_particle(p, v, 1.2f, 64.0f, 0, 0.95f, c); - v = normalize(vec2(frandom()-0.5f, -frandom()))*(128.0f+frandom()*128.0f); - temp_system.new_particle(p, v, 1.2f, 32.0f, 0, 0.95f, c); - v = normalize(vec2(frandom()-0.5f, -frandom()))*(128.0f+frandom()*128.0f); - temp_system.new_particle(p, v, 1.2f, 16.0f, 0, 0.95f, c); - - for(int i = 0; i < 8; i++) - { - vec2 v = normalize(vec2(frandom()-0.5f, frandom()-0.5f))*(64.0f+frandom()*64.0f); - temp_system.new_particle(p, v, 0.5f+0.5f*frandom(), 16.0f, 0, 0.985f, c); - } - - for(int i = 0; i < 8; i++) - { - vec2 v = normalize(vec2(frandom()-0.5f, frandom()-0.5f))*(128.0f+frandom()*256.0f); - temp_system.new_particle(p, v, 0.5f+0.5f*frandom(), 16.0f, 128.0f, 0.985f, c); - } - } - else if(item.type == EVENT_SOUND_WORLD) - { - ev_sound *ev = (ev_sound *)data; - if(ev->sound >= 0 && ev->sound < NUM_SOUNDS) - snd_play_random(CHN_WORLD, ev->sound, 1.0f, vec2(ev->x, ev->y)); - } - } -} - -static player_core predicted_prev_player; -static player_core predicted_player; -static int predicted_tick = 0; -static int last_new_predicted_tick = -1; - -extern "C" void modc_predict() -{ - player_core before_prev_player = predicted_prev_player; - player_core before_player = predicted_player; - - - // repredict player - world_core world; - int local_cid = -1; - - // search for players - for(int i = 0; i < snap_num_items(SNAP_CURRENT); i++) - { - SNAP_ITEM item; - const void *data = snap_get_item(SNAP_CURRENT, i, &item); - int client_id = item.id; - - if(item.type == OBJTYPE_PLAYER_CHARACTER) - { - const obj_player_character *character = (const obj_player_character *)data; - client_datas[client_id].predicted.world = &world; - world.players[client_id] = &client_datas[client_id].predicted; - - client_datas[client_id].predicted.read(character); - } - else if(item.type == OBJTYPE_PLAYER_INFO) - { - const obj_player_info *info = (const obj_player_info *)data; - if(info->local) - local_cid = client_id; - } - } - - // predict - for(int tick = client_tick()+1; tick <= client_predtick(); tick++) - { - // fetch the local - if(tick == client_predtick() && world.players[local_cid]) - predicted_prev_player = *world.players[local_cid]; - - // first calculate where everyone should move - for(int c = 0; c < MAX_CLIENTS; c++) - { - if(!world.players[c]) - continue; - - mem_zero(&world.players[c]->input, sizeof(world.players[c]->input)); - if(local_cid == c) - { - // apply player input - int *input = client_get_input(tick); - if(input) - world.players[c]->input = *((player_input*)input); - } - - world.players[c]->tick(); - } - - // move all players and quantize their data - for(int c = 0; c < MAX_CLIENTS; c++) - { - if(!world.players[c]) - continue; - - world.players[c]->move(); - world.players[c]->quantize(); - } - - if(tick > last_new_predicted_tick) - { - last_new_predicted_tick = tick; - - if(local_cid != -1 && world.players[local_cid]) - { - vec2 pos = world.players[local_cid]->pos; - int events = world.players[local_cid]->triggered_events; - if(events&COREEVENT_GROUND_JUMP) snd_play_random(CHN_WORLD, SOUND_PLAYER_JUMP, 1.0f, pos); - if(events&COREEVENT_AIR_JUMP) - { - create_air_jump_effect(pos); - snd_play_random(CHN_WORLD, SOUND_PLAYER_JUMP, 1.0f, pos); - } - //if(events&COREEVENT_HOOK_LAUNCH) snd_play_random(CHN_WORLD, SOUND_HOOK_LOOP, 1.0f, pos); - if(events&COREEVENT_HOOK_ATTACH_PLAYER) snd_play_random(CHN_WORLD, SOUND_HOOK_ATTACH_PLAYER, 1.0f, pos); - if(events&COREEVENT_HOOK_ATTACH_GROUND) snd_play_random(CHN_WORLD, SOUND_HOOK_ATTACH_GROUND, 1.0f, pos); - //if(events&COREEVENT_HOOK_RETRACT) snd_play_random(CHN_WORLD, SOUND_PLAYER_JUMP, 1.0f, pos); - } - - - /* - dbg_msg("predict", "%d %d %d", tick, - (int)world.players[c]->pos.x, (int)world.players[c]->pos.y, - (int)world.players[c]->vel.x, (int)world.players[c]->vel.y);*/ - } - - if(tick == client_predtick() && world.players[local_cid]) - predicted_player = *world.players[local_cid]; - } - - if(config.debug && predicted_tick == client_predtick()) - { - if(predicted_player.pos.x != before_player.pos.x || - predicted_player.pos.y != before_player.pos.y) - { - dbg_msg("client", "prediction error, (%d %d) (%d %d)", - (int)before_player.pos.x, (int)before_player.pos.y, - (int)predicted_player.pos.x, (int)predicted_player.pos.y); - } - - if(predicted_prev_player.pos.x != before_prev_player.pos.x || - predicted_prev_player.pos.y != before_prev_player.pos.y) - { - dbg_msg("client", "prediction error, prev (%d %d) (%d %d)", - (int)before_prev_player.pos.x, (int)before_prev_player.pos.y, - (int)predicted_prev_player.pos.x, (int)predicted_prev_player.pos.y); - } - } - - predicted_tick = client_predtick(); -} - -static void clear_object_pointers() -{ - // clear out the invalid pointers - local_character = 0; - local_prev_character = 0; - local_info = 0; - flags[0] = 0; - flags[1] = 0; - gameobj = 0; -} - -extern "C" void modc_newsnapshot() -{ - process_events(SNAP_CURRENT); - - if(config.dbg_stress) - { - if((client_tick()%250) == 0) - { - msg_pack_start(MSG_SAY, MSGFLAG_VITAL); - msg_pack_int(-1); - msg_pack_string("galenskap!!!!", 512); - msg_pack_end(); - client_send_msg(); - } - } - - clear_object_pointers(); - - // 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; - const void *data = snap_get_item(SNAP_CURRENT, i, &item); - - if(item.type == OBJTYPE_PLAYER_INFO) - { - const obj_player_info *info = (const obj_player_info *)data; - if(info->local) - { - local_info = info; - const void *data = snap_find_item(SNAP_CURRENT, OBJTYPE_PLAYER_CHARACTER, item.id); - if(data) - { - local_character = (const obj_player_character *)data; - local_character_pos = vec2(local_character->x, local_character->y); - - const void *p = snap_find_item(SNAP_PREV, OBJTYPE_PLAYER_CHARACTER, item.id); - if(p) - local_prev_character = (obj_player_character *)p; - } - } - } - else if(item.type == OBJTYPE_GAME) - gameobj = (obj_game *)data; - else if(item.type == OBJTYPE_FLAG) - { - flags[item.id%2] = (const obj_flag *)data; - } - } - } -} - -void send_info(bool start) -{ - if(start) - msg_pack_start(MSG_STARTINFO, MSGFLAG_VITAL); - else - msg_pack_start(MSG_CHANGEINFO, MSGFLAG_VITAL); - msg_pack_string(config.player_name, 64); - msg_pack_string(config.player_skin, 64); - msg_pack_int(config.player_use_custom_color); - msg_pack_int(config.player_color_body); - msg_pack_int(config.player_color_feet); - msg_pack_end(); - client_send_msg(); -} - -void send_emoticon(int emoticon) -{ - msg_pack_start(MSG_EMOTICON, MSGFLAG_VITAL); - msg_pack_int(emoticon); - msg_pack_end(); - client_send_msg(); -} - -static void render_projectile(const obj_projectile *prev, const obj_projectile *current, int itemid) -{ - gfx_texture_set(data->images[IMAGE_GAME].id); - gfx_quads_begin(); - - // get positions - float gravity = -400; - if(current->type != WEAPON_ROCKET) - gravity = -100; - - float ct = (client_tick()-current->start_tick)/(float)SERVER_TICK_SPEED + client_intratick()*1/(float)SERVER_TICK_SPEED; - vec2 startpos(current->x, current->y); - vec2 startvel(current->vx, current->vy); - vec2 pos = calc_pos(startpos, startvel, gravity, ct); - vec2 prevpos = calc_pos(startpos, startvel, gravity, ct-0.001f); - - select_sprite(data->weapons[current->type%data->num_weapons].sprite_proj); - vec2 vel = pos-prevpos; - //vec2 pos = mix(vec2(prev->x, prev->y), vec2(current->x, current->y), client_intratick()); - - // add particle for this projectile - proj_particles.addparticle(current->type, itemid, pos, vel); - - if(length(vel) > 0.00001f) - gfx_quads_setrotation(get_angle(vel)); - else - gfx_quads_setrotation(0); - - // TODO: do this, but nice - //temp_system.new_particle(pos, vec2(0,0), 0.3f, 14.0f, 0, 0.95f); - - gfx_quads_draw(pos.x, pos.y, 32, 32); - gfx_quads_setrotation(0); - gfx_quads_end(); -} - -static void render_powerup(const obj_powerup *prev, const obj_powerup *current) -{ - gfx_texture_set(data->images[IMAGE_GAME].id); - gfx_quads_begin(); - vec2 pos = mix(vec2(prev->x, prev->y), vec2(current->x, current->y), client_intratick()); - float angle = 0.0f; - float size = 64.0f; - if (current->type == POWERUP_WEAPON) - { - angle = 0; //-pi/6;//-0.25f * pi * 2.0f; - select_sprite(data->weapons[current->subtype%data->num_weapons].sprite_body); - size = data->weapons[current->subtype%data->num_weapons].visual_size; - } - else - { - const int c[] = { - SPRITE_POWERUP_HEALTH, - SPRITE_POWERUP_ARMOR, - SPRITE_POWERUP_WEAPON, - SPRITE_POWERUP_NINJA, - SPRITE_POWERUP_TIMEFIELD - }; - select_sprite(c[current->type]); - - if(c[current->type] == SPRITE_POWERUP_NINJA) - { - proj_particles.addparticle(0, 0, - pos+vec2((frandom()-0.5f)*80.0f, (frandom()-0.5f)*20.0f), - vec2((frandom()-0.5f)*10.0f, (frandom()-0.5f)*10.0f)); - size *= 2.0f; - pos.x += 10.0f; - } - } - - gfx_quads_setrotation(angle); - - float offset = pos.y/32.0f + pos.x/32.0f; - pos.x += cosf(client_localtime()*2.0f+offset)*2.5f; - pos.y += sinf(client_localtime()*2.0f+offset)*2.5f; - draw_sprite(pos.x, pos.y, size); - gfx_quads_end(); -} - -static void render_flag(const obj_flag *prev, const obj_flag *current) -{ - float angle = 0.0f; - float size = 42.0f; - - gfx_blend_normal(); - gfx_texture_set(data->images[IMAGE_GAME].id); - gfx_quads_begin(); - - if(current->team == 0) // red team - select_sprite(SPRITE_FLAG_RED); - else - select_sprite(SPRITE_FLAG_BLUE); - - gfx_quads_setrotation(angle); - - vec2 pos = mix(vec2(prev->x, prev->y), vec2(current->x, current->y), client_intratick()); - - if(local_info && current->carried_by == local_info->clientid) - pos = local_character_pos; - - gfx_setcolor(current->team ? 0 : 1,0,current->team ? 1 : 0,1); - //draw_sprite(pos.x, pos.y, size); - gfx_quads_draw(pos.x, pos.y-size*0.75f, size, size*2); - gfx_quads_end(); -} - -void anim_seq_eval(sequence *seq, float time, keyframe *frame) -{ - if(seq->num_frames == 0) - { - frame->time = 0; - frame->x = 0; - frame->y = 0; - frame->angle = 0; - } - else if(seq->num_frames == 1) - { - *frame = seq->frames[0]; - } - else - { - //time = max(0.0f, min(1.0f, time / duration)); // TODO: use clamp - keyframe *frame1 = 0; - keyframe *frame2 = 0; - float blend = 0.0f; - - // TODO: make this smarter.. binary search - for (int i = 1; i < seq->num_frames; i++) - { - if (seq->frames[i-1].time <= time && seq->frames[i].time >= time) - { - frame1 = &seq->frames[i-1]; - frame2 = &seq->frames[i]; - blend = (time - frame1->time) / (frame2->time - frame1->time); - break; - } - } - - if (frame1 && frame2) - { - frame->time = time; - frame->x = mix(frame1->x, frame2->x, blend); - frame->y = mix(frame1->y, frame2->y, blend); - frame->angle = mix(frame1->angle, frame2->angle, blend); - } - } -} - -void anim_eval(animation *anim, float time, animstate *state) -{ - anim_seq_eval(&anim->body, time, &state->body); - anim_seq_eval(&anim->back_foot, time, &state->back_foot); - anim_seq_eval(&anim->front_foot, time, &state->front_foot); - anim_seq_eval(&anim->attach, time, &state->attach); -} - -void anim_add_keyframe(keyframe *seq, keyframe *added, float amount) -{ - seq->x += added->x*amount; - seq->y += added->y*amount; - seq->angle += added->angle*amount; -} - -void anim_add(animstate *state, animstate *added, float amount) -{ - anim_add_keyframe(&state->body, &added->body, amount); - anim_add_keyframe(&state->back_foot, &added->back_foot, amount); - anim_add_keyframe(&state->front_foot, &added->front_foot, amount); - anim_add_keyframe(&state->attach, &added->attach, amount); -} - -void anim_eval_add(animstate *state, animation *anim, float time, float amount) -{ - animstate add; - anim_eval(anim, time, &add); - anim_add(state, &add, amount); -} - -static void render_hand(int skin_id, vec2 center_pos, vec2 dir, float angle_offset, vec2 post_rot_offset) -{ - // for drawing hand - const skin *s = skin_get(skin_id); - - float basesize = 10.0f; - //dir = normalize(hook_pos-pos); - - vec2 hand_pos = center_pos + dir; - float angle = get_angle(dir); - if (dir.x < 0) - angle -= angle_offset; - else - angle += angle_offset; - - vec2 dirx = dir; - vec2 diry(-dir.y,dir.x); - - if (dir.x < 0) - diry = -diry; - - hand_pos += dirx * post_rot_offset.x; - hand_pos += diry * post_rot_offset.y; - - //gfx_texture_set(data->images[IMAGE_CHAR_DEFAULT].id); - gfx_texture_set(s->color_texture); - gfx_quads_begin(); - - // two passes - for (int i = 0; i < 2; i++) - { - bool outline = i == 0; - - select_sprite(outline?SPRITE_TEE_HAND_OUTLINE:SPRITE_TEE_HAND, 0, 0, 0); - gfx_quads_setrotation(angle); - gfx_quads_draw(hand_pos.x, hand_pos.y, 2*basesize, 2*basesize); - } - - gfx_quads_setrotation(0); - gfx_quads_end(); -} - -void render_tee(animstate *anim, tee_render_info *info, int emote, vec2 dir, vec2 pos) -{ - vec2 direction = dir; - vec2 position = pos; - - //gfx_texture_set(data->images[IMAGE_CHAR_DEFAULT].id); - gfx_texture_set(info->texture); - gfx_quads_begin(); - //gfx_quads_draw(pos.x, pos.y-128, 128, 128); - - // first pass we draw the outline - // second pass we draw the filling - for(int p = 0; p < 2; p++) - { - int outline = p==0 ? 1 : 0; - - for(int f = 0; f < 2; f++) - { - float animscale = info->size * 1.0f/64.0f; - float basesize = info->size; - if(f == 1) - { - gfx_quads_setrotation(anim->body.angle*pi*2); - - // draw body - gfx_setcolor(info->color_body.r, info->color_body.g, info->color_body.b, info->color_body.a); - vec2 body_pos = position + vec2(anim->body.x, anim->body.y)*animscale; - select_sprite(outline?SPRITE_TEE_BODY_OUTLINE:SPRITE_TEE_BODY, 0, 0, 0); - gfx_quads_draw(body_pos.x, body_pos.y, basesize, basesize); - - // draw eyes - if(p == 1) - { - switch (emote) - { - case EMOTE_PAIN: - select_sprite(SPRITE_TEE_EYE_PAIN, 0, 0, 0); - break; - case EMOTE_HAPPY: - select_sprite(SPRITE_TEE_EYE_HAPPY, 0, 0, 0); - break; - case EMOTE_SURPRISE: - select_sprite(SPRITE_TEE_EYE_SURPRISE, 0, 0, 0); - break; - case EMOTE_ANGRY: - select_sprite(SPRITE_TEE_EYE_ANGRY, 0, 0, 0); - break; - default: - select_sprite(SPRITE_TEE_EYE_NORMAL, 0, 0, 0); - break; - } - - float eyescale = basesize*0.40f; - float h = emote == EMOTE_BLINK ? basesize*0.15f : eyescale; - float eyeseparation = (0.075f - 0.010f*fabs(direction.x))*basesize; - vec2 offset = vec2(direction.x*0.125f, -0.05f+direction.y*0.10f)*basesize; - gfx_quads_draw(body_pos.x-eyeseparation+offset.x, body_pos.y+offset.y, eyescale, h); - gfx_quads_draw(body_pos.x+eyeseparation+offset.x, body_pos.y+offset.y, -eyescale, h); - } - } - - // draw feet - gfx_setcolor(info->color_feet.r, info->color_feet.g, info->color_feet.b, info->color_feet.a); - select_sprite(outline?SPRITE_TEE_FOOT_OUTLINE:SPRITE_TEE_FOOT, 0, 0, 0); - - keyframe *foot = f ? &anim->front_foot : &anim->back_foot; - - float w = basesize; - float h = basesize/2; - - gfx_quads_setrotation(foot->angle*pi*2); - gfx_quads_draw(position.x+foot->x*animscale, position.y+foot->y*animscale, w, h); - } - } - - gfx_quads_end(); -} - -void draw_circle(float x, float y, float r, int segments) -{ - float f_segments = (float)segments; - for(int i = 0; i < segments; i+=2) - { - float a1 = i/f_segments * 2*pi; - float a2 = (i+1)/f_segments * 2*pi; - float a3 = (i+2)/f_segments * 2*pi; - float ca1 = cosf(a1); - float ca2 = cosf(a2); - float ca3 = cosf(a3); - float sa1 = sinf(a1); - float sa2 = sinf(a2); - float sa3 = sinf(a3); - - gfx_quads_draw_freeform( - x, y, - x+ca1*r, y+sa1*r, - x+ca3*r, y+sa3*r, - x+ca2*r, y+sa2*r); - } -} - -void draw_round_rect_ext(float x, float y, float w, float h, float r, int corners) -{ - int num = 8; - for(int i = 0; i < num; i+=2) - { - float a1 = i/(float)num * pi/2; - float a2 = (i+1)/(float)num * pi/2; - float a3 = (i+2)/(float)num * pi/2; - float ca1 = cosf(a1); - float ca2 = cosf(a2); - float ca3 = cosf(a3); - float sa1 = sinf(a1); - float sa2 = sinf(a2); - float sa3 = sinf(a3); - - if(corners&1) // TL - gfx_quads_draw_freeform( - x+r, y+r, - x+(1-ca1)*r, y+(1-sa1)*r, - x+(1-ca3)*r, y+(1-sa3)*r, - x+(1-ca2)*r, y+(1-sa2)*r); - - if(corners&2) // TR - gfx_quads_draw_freeform( - x+w-r, y+r, - x+w-r+ca1*r, y+(1-sa1)*r, - x+w-r+ca3*r, y+(1-sa3)*r, - x+w-r+ca2*r, y+(1-sa2)*r); - - if(corners&4) // BL - gfx_quads_draw_freeform( - x+r, y+h-r, - x+(1-ca1)*r, y+h-r+sa1*r, - x+(1-ca3)*r, y+h-r+sa3*r, - x+(1-ca2)*r, y+h-r+sa2*r); - - if(corners&8) // BR - gfx_quads_draw_freeform( - x+w-r, y+h-r, - x+w-r+ca1*r, y+h-r+sa1*r, - x+w-r+ca3*r, y+h-r+sa3*r, - x+w-r+ca2*r, y+h-r+sa2*r); - } - - gfx_quads_drawTL(x+r, y+r, w-r*2, h-r*2); // center - gfx_quads_drawTL(x+r, y, w-r*2, r); // top - gfx_quads_drawTL(x+r, y+h-r, w-r*2, r); // bottom - gfx_quads_drawTL(x, y+r, r, h-r*2); // left - gfx_quads_drawTL(x+w-r, y+r, r, h-r*2); // right - - if(!(corners&1)) gfx_quads_drawTL(x, y, r, r); // TL - if(!(corners&2)) gfx_quads_drawTL(x+w, y, -r, r); // TR - if(!(corners&4)) gfx_quads_drawTL(x, y+h, r, -r); // BL - if(!(corners&8)) gfx_quads_drawTL(x+w, y+h, -r, -r); // BR -} - -void draw_round_rect(float x, float y, float w, float h, float r) -{ - draw_round_rect_ext(x,y,w,h,r,0xf); -} - - -static void render_player( - const obj_player_character *prev_char, - const obj_player_character *player_char, - const obj_player_info *prev_info, - const obj_player_info *player_info - ) -{ - obj_player_character prev; - obj_player_character player; - prev = *prev_char; - player = *player_char; - - obj_player_info info = *player_info; - - float intratick = client_intratick(); - - if(player.health < 0) // dont render dead players - return; - - if(info.local && config.cl_predict) - { - if(!local_character || (local_character->health < 0) || (gameobj && gameobj->game_over)) - { - } - else - { - // apply predicted results - predicted_player.write(&player); - predicted_prev_player.write(&prev); - intratick = client_intrapredtick(); - } - } - - // TODO: proper skin selection - int skin_id = client_datas[info.clientid].skin_id; //charids[info.clientid]; - //if(gametype != GAMETYPE_DM) - //skin_id = info.team*9; // 0 or 9 - - vec2 direction = get_direction(player.angle); - float angle = player.angle/256.0f; - vec2 position = mix(vec2(prev.x, prev.y), vec2(player.x, player.y), intratick); - - if(prev.health < 0) // Don't flicker from previous position - position = vec2(player.x, player.y); - - bool stationary = player.vx < 1 && player.vx > -1; - bool inair = col_check_point(player.x, player.y+16) == 0; - - // evaluate animation - float walk_time = fmod(position.x, 100.0f)/100.0f; - animstate state; - anim_eval(&data->animations[ANIM_BASE], 0, &state); - - if(inair) - anim_eval_add(&state, &data->animations[ANIM_INAIR], 0, 1.0f); // TODO: some sort of time here - else if(stationary) - anim_eval_add(&state, &data->animations[ANIM_IDLE], 0, 1.0f); // TODO: some sort of time here - else - anim_eval_add(&state, &data->animations[ANIM_WALK], walk_time, 1.0f); - - if (player.weapon == WEAPON_HAMMER) - { - float a = clamp((client_tick()-player.attacktick+intratick)/10.0f, 0.0f, 1.0f); - anim_eval_add(&state, &data->animations[ANIM_HAMMER_SWING], a, 1.0f); - } - if (player.weapon == WEAPON_NINJA) - { - float a = clamp((client_tick()-player.attacktick+intratick)/40.0f, 0.0f, 1.0f); - anim_eval_add(&state, &data->animations[ANIM_NINJA_SWING], a, 1.0f); - } - - // draw hook - if (prev.hook_state>0 && player.hook_state>0) - { - gfx_texture_set(data->images[IMAGE_GAME].id); - 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), intratick); - - float d = distance(pos, hook_pos); - vec2 dir = normalize(pos-hook_pos); - - gfx_quads_setrotation(get_angle(dir)+pi); - - // render head - select_sprite(SPRITE_HOOK_HEAD); - gfx_quads_draw(hook_pos.x, hook_pos.y, 24,16); - - // render chain - select_sprite(SPRITE_HOOK_CHAIN); - 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(); - - render_hand(skin_id, position, normalize(hook_pos-pos), -pi/2, vec2(20, 0)); - } - - // draw gun - { - gfx_texture_set(data->images[IMAGE_GAME].id); - gfx_quads_begin(); - gfx_quads_setrotation(state.attach.angle*pi*2+angle); - - // normal weapons - int iw = clamp(player.weapon, 0, NUM_WEAPONS-1); - select_sprite(data->weapons[iw].sprite_body, direction.x < 0 ? SPRITE_FLAG_FLIP_Y : 0); - - vec2 dir = direction; - float recoil = 0.0f; - vec2 p; - if (player.weapon == WEAPON_HAMMER) - { - // Static position for hammer - p = position; - p.y += data->weapons[iw].offsety; - // if attack is under way, bash stuffs - if(direction.x < 0) - { - gfx_quads_setrotation(-pi/2-state.attach.angle*pi*2); - p.x -= data->weapons[iw].offsetx; - } - else - { - gfx_quads_setrotation(-pi/2+state.attach.angle*pi*2); - } - draw_sprite(p.x, p.y, data->weapons[iw].visual_size); - } - else if (player.weapon == WEAPON_NINJA) - { - p = position; - p.y += data->weapons[iw].offsety; - - if(direction.x < 0) - { - gfx_quads_setrotation(-pi/2-state.attach.angle*pi*2); - p.x -= data->weapons[iw].offsetx; - } - else - { - gfx_quads_setrotation(-pi/2+state.attach.angle*pi*2); - } - draw_sprite(p.x, p.y, data->weapons[iw].visual_size); - - // HADOKEN - if ((client_tick()-player.attacktick) <= (SERVER_TICK_SPEED / 6) && data->weapons[iw].nummuzzlesprites) - { - int itex = rand() % data->weapons[iw].nummuzzlesprites; - float alpha = 1.0f; - if (alpha > 0.0f && data->weapons[iw].sprite_muzzle[itex].psprite) - { - vec2 dir = vec2(player_char->x,player_char->y) - vec2(prev_char->x, prev_char->y); - dir = normalize(dir); - float hadokenangle = get_angle(dir); - gfx_quads_setrotation(hadokenangle); - //float offsety = -data->weapons[iw].muzzleoffsety; - select_sprite(data->weapons[iw].sprite_muzzle[itex].psprite, 0); - vec2 diry(-dir.y,dir.x); - p = position; - float offsetx = data->weapons[iw].muzzleoffsetx; - p -= dir * offsetx; - draw_sprite(p.x, p.y, 160.0f); - } - } - } - else - { - // TODO: should be an animation - recoil = 0; - float a = (client_tick()-player.attacktick+intratick)/5.0f; - if(a < 1) - recoil = sinf(a*pi); - p = position + dir * data->weapons[iw].offsetx - dir*recoil*10.0f; - p.y += data->weapons[iw].offsety; - draw_sprite(p.x, p.y, data->weapons[iw].visual_size); - } - - if (player.weapon == WEAPON_GUN || player.weapon == WEAPON_SHOTGUN) - { - // check if we're firing stuff - if (true)//prev.attackticks) - { - float alpha = 0.0f; - int phase1tick = (client_tick() - player.attacktick); - if (phase1tick < (data->weapons[iw].muzzleduration + 3)) - { - float t = ((((float)phase1tick) + intratick)/(float)data->weapons[iw].muzzleduration); - alpha = LERP(2.0, 0.0f, min(1.0f,max(0.0f,t))); - } - - int itex = rand() % data->weapons[iw].nummuzzlesprites; - if (alpha > 0.0f && data->weapons[iw].sprite_muzzle[itex].psprite) - { - float offsety = -data->weapons[iw].muzzleoffsety; - select_sprite(data->weapons[iw].sprite_muzzle[itex].psprite, direction.x < 0 ? SPRITE_FLAG_FLIP_Y : 0); - if(direction.x < 0) - offsety = -offsety; - - vec2 diry(-dir.y,dir.x); - vec2 muzzlepos = p + dir * data->weapons[iw].muzzleoffsetx + diry * offsety; - - draw_sprite(muzzlepos.x, muzzlepos.y, data->weapons[iw].visual_size); - /*gfx_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,muzzleparams[player.weapon].sizex, muzzleparams[player.weapon].sizey);*/ - } - } - } - gfx_quads_end(); - - switch (player.weapon) - { - case WEAPON_GUN: render_hand(skin_id, p, direction, -3*pi/4, vec2(-15, 4)); break; - case WEAPON_SHOTGUN: render_hand(skin_id, p, direction, -pi/2, vec2(-5, 4)); break; - case WEAPON_ROCKET: render_hand(skin_id, p, direction, -pi/2, vec2(-4, 7)); break; - } - - } - - // render the "shadow" tee - if(info.local && config.debug) - { - vec2 ghost_position = mix(vec2(prev_char->x, prev_char->y), vec2(player_char->x, player_char->y), client_intratick()); - tee_render_info ghost = client_datas[info.clientid].skin_info; - ghost.color_body.a = 0.5f; - ghost.color_feet.a = 0.5f; - render_tee(&state, &ghost, player.emote, direction, ghost_position); // render ghost - } - - // render the tee - render_tee(&state, &client_datas[info.clientid].skin_info, player.emote, direction, position); - - if(player.state == STATE_CHATTING) - { - gfx_texture_set(data->images[IMAGE_EMOTICONS].id); - gfx_quads_begin(); - select_sprite(SPRITE_DOTDOT); - gfx_quads_draw(position.x + 24, position.y - 40, 64,64); - gfx_quads_end(); - } - - if (client_datas[info.clientid].emoticon_start != -1 && client_datas[info.clientid].emoticon_start + 2 * client_tickspeed() > client_tick()) - { - gfx_texture_set(data->images[IMAGE_EMOTICONS].id); - gfx_quads_begin(); - - int since_start = client_tick() - client_datas[info.clientid].emoticon_start; - int from_end = client_datas[info.clientid].emoticon_start + 2 * client_tickspeed() - client_tick(); - - float a = 1; - - if (from_end < client_tickspeed() / 5) - a = from_end / (client_tickspeed() / 5.0); - - float h = 1; - if (since_start < client_tickspeed() / 10) - h = since_start / (client_tickspeed() / 10.0); - - float wiggle = 0; - if (since_start < client_tickspeed() / 5) - wiggle = since_start / (client_tickspeed() / 5.0); - - float wiggle_angle = sin(5*wiggle); - - gfx_quads_setrotation(pi/6*wiggle_angle); - - gfx_setcolor(1.0f,1.0f,1.0f,a); - // client_datas::emoticon is an offset from the first emoticon - select_sprite(SPRITE_OOP + client_datas[info.clientid].emoticon); - gfx_quads_draw(position.x, position.y - 23 - 32*h, 64, 64*h); - gfx_quads_end(); - } - - // render name plate - if(!info.local && config.cl_nameplates) - { - //gfx_pretty_text_color - float a = 1; - if(config.cl_nameplates_always == 0) - a = clamp(1-powf(distance(local_target_pos, position)/200.0f,16.0f), 0.0f, 1.0f); - - const char *name = client_datas[info.clientid].name; - float tw = gfx_pretty_text_width(28.0f, name, -1); - gfx_pretty_text_color(1,1,1,a); - gfx_pretty_text(position.x-tw/2.0f, position.y-60, 28.0f, name, -1); - gfx_pretty_text_color(1,1,1,1); - } -} - -void render_moon(float x, float y) -{ - gfx_texture_set(data->images[IMAGE_MOON].id); - gfx_quads_begin(); - gfx_quads_draw(x, y, 512, 512); - gfx_quads_end(); -} - -void render_stars() -{ - struct star - { - vec2 p; - float tingle; - float rot; - float size; - }; - - static const int NUM_STARS = 100; - static star stars[NUM_STARS]; - static bool init = true; - if(init) - { - for(int i = 0; i < NUM_STARS; i++) - { - stars[i].p.x = (frandom()-0.5f)*800*3; - stars[i].p.y = (frandom()-0.5f)*600*3; - stars[i].tingle = frandom(); - stars[i].rot = frandom()*pi; - stars[i].size = 10.0f+frandom()*10.0f; - } - - init = false; - } - - int64 now = time_get(); - int64 freq = time_freq()*5; - float t = (now%freq)/(float)freq; - gfx_texture_set(data->images[IMAGE_STARS].id); - gfx_quads_begin(); - gfx_quads_setsubset(0,0,0.5f,1); - for(int i = 0; i < NUM_STARS; i++) - { - float a = fmod(t+stars[i].tingle, 1.0f); - gfx_quads_setrotation(stars[i].rot); - gfx_setcolor(1,1,1,0.25f+sinf(a*pi)*0.75f); - gfx_quads_draw(stars[i].p.x, stars[i].p.y, stars[i].size, stars[i].size); - } - - gfx_quads_end(); -} - -void render_snow() -{ - vec2 tl, br; - gfx_getscreen(&tl.x, &tl.y, &br.x, &br.y); - tl.x += 1000; // this is here to fix positions below 0,0 - tl.y += 1000; - br.x += 1000; - br.y += 1000; - - struct flake - { - vec2 p; - float tingle; - float rot; - float size; - float yspeed; - float xspeed; - }; - - static const int NUM_FLAKES = 100; - static flake flakes[NUM_FLAKES]; - static bool init = true; - - float w = br.x-tl.x; - float h = br.y-tl.y; - - if(init) - { - for(int i = 0; i < NUM_FLAKES; i++) - { - flakes[i].p.x = frandom()*w; - flakes[i].p.y = frandom()*h; - flakes[i].tingle = frandom(); - flakes[i].rot = frandom()*pi; - flakes[i].size = 50.0f+frandom()*10.0f; - flakes[i].yspeed = 50+frandom()*20.0f; - flakes[i].xspeed = flakes[i].yspeed * (0.4+frandom()*0.4f); - } - - init = false; - } - - int basex = (int)(tl.x/w); - float splitx = tl.x-basex*w; - int basey = (int)(tl.y/h); - float splity = tl.y-basey*h; - - float f = client_frametime(); - gfx_texture_set(data->images[IMAGE_SNOW].id); - gfx_quads_begin(); - for(int i = 0; i < NUM_FLAKES; i++) - { - flakes[i].p.x -= f*flakes[i].xspeed; - flakes[i].p.y += f*flakes[i].yspeed; - if(flakes[i].p.x < 0) - flakes[i].p.x += w; - if(flakes[i].p.y > h) - flakes[i].p.y -= h; - - float x = flakes[i].p.x + basex*w; - float y = flakes[i].p.y + basey*h; - - if(flakes[i].p.x < splitx) - x += w; - if(flakes[i].p.y < splity) - y += h; - - x -= 1000; - y -= 1000; - - gfx_quads_setrotation(flakes[i].rot); - gfx_quads_draw(x, y, flakes[i].size, flakes[i].size); - } - - gfx_quads_end(); -} - -void render_sun(float x, float y) -{ - vec2 pos(x, y); - - gfx_texture_set(-1); - gfx_blend_additive(); - gfx_quads_begin(); - const int rays = 10; - gfx_setcolor(1.0f,1.0f,1.0f,0.025f); - for(int r = 0; r < rays; r++) - { - float a = r/(float)rays + client_localtime()*0.025f; - 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_setcolorvertex(0, 1.0f,1.0f,1.0f,0.025f); - gfx_setcolorvertex(1, 1.0f,1.0f,1.0f,0.025f); - gfx_setcolorvertex(2, 1.0f,1.0f,1.0f,0.0f); - gfx_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(data->images[IMAGE_SUN].id); - gfx_quads_begin(); - gfx_quads_draw(pos.x, pos.y, 256, 256); - gfx_quads_end(); -} - -static vec2 emoticon_selector_mouse; - -void emoticon_selector_reset() -{ - emoticon_selector_mouse = vec2(0, 0); -} - -int emoticon_selector_render() -{ - int x, y; - inp_mouse_relative(&x, &y); - - emoticon_selector_mouse.x += x; - emoticon_selector_mouse.y += y; - - if (length(emoticon_selector_mouse) > 140) - emoticon_selector_mouse = normalize(emoticon_selector_mouse) * 140; - - float selected_angle = get_angle(emoticon_selector_mouse) + 2*pi/24; - if (selected_angle < 0) - selected_angle += 2*pi; - - bool return_now = false; - int selected_emoticon = -1; - - if (length(emoticon_selector_mouse) > 100) - selected_emoticon = (int)(selected_angle / (2*pi) * 12.0f); - - if(!inp_key_pressed(config.key_emoticon)) - { - return_now = true; - emoticon_selector_active = false; - } - - RECT screen = *ui2_screen(); - - gfx_mapscreen(screen.x, screen.y, screen.w, screen.h); - - gfx_blend_normal(); - - gfx_texture_set(-1); - gfx_quads_begin(); - gfx_setcolor(0,0,0,0.3f); - draw_circle(screen.w/2, screen.h/2, 160, 64); - gfx_quads_end(); - - gfx_texture_set(data->images[IMAGE_EMOTICONS].id); - gfx_quads_begin(); - - for (int i = 0; i < 12; i++) - { - float angle = 2*pi*i/12.0; - if (angle > pi) - angle -= 2*pi; - - bool selected = selected_emoticon == i; - - float size = selected ? 96 : 64; - - float nudge_x = 120 * cos(angle); - float nudge_y = 120 * sin(angle); - select_sprite(SPRITE_OOP + i); - gfx_quads_draw(screen.w/2 + nudge_x, screen.h/2 + nudge_y, size, size); - } - - gfx_quads_end(); - - gfx_texture_set(data->images[IMAGE_CURSOR].id); - gfx_quads_begin(); - gfx_setcolor(1,1,1,1); - gfx_quads_drawTL(emoticon_selector_mouse.x+screen.w/2,emoticon_selector_mouse.y+screen.h/2,24,24); - gfx_quads_end(); - - return return_now ? selected_emoticon : -1; -} - -void render_goals(float x, float y, float w) -{ - float h = 50.0f; - - gfx_blend_normal(); - gfx_texture_set(-1); - gfx_quads_begin(); - gfx_setcolor(0,0,0,0.5f); - draw_round_rect(x-10.f, y-10.f, w, h, 10.0f); - gfx_quads_end(); - - // render goals - //y = ystart+h-54; - if(gameobj && gameobj->time_limit) - { - char buf[64]; - sprintf(buf, "Time Limit: %d min", gameobj->time_limit); - gfx_pretty_text(x+w/2, y, 32, buf, -1); - } - if(gameobj && gameobj->score_limit) - { - char buf[64]; - sprintf(buf, "Score Limit: %d", gameobj->score_limit); - gfx_pretty_text(x+40, y, 32, buf, -1); - } - -} - -void render_scoreboard(float x, float y, float w, int team, const char *title) -{ - //float w = 550.0f; - //float x = width/2-w/2; - //; - //float y = ystart; - //float w = 550.0f; - - animstate idlestate; - anim_eval(&data->animations[ANIM_BASE], 0, &idlestate); - anim_eval_add(&idlestate, &data->animations[ANIM_IDLE], 0, 1.0f); - - //float ystart = y; - float h = 600.0f; - - gfx_blend_normal(); - gfx_texture_set(-1); - gfx_quads_begin(); - gfx_setcolor(0,0,0,0.5f); - draw_round_rect(x-10.f, y-10.f, w, h, 40.0f); - gfx_quads_end(); - - // render title - if(!title) - { - if(gameobj->game_over) - title = "Game Over"; - else - title = "Score Board"; - } - - float tw = gfx_pretty_text_width( 64, title, -1); - - if(team == -1) - { - gfx_pretty_text(x+w/2-tw/2, y, 64, title, -1); - } - else - { - gfx_pretty_text(x+10, y, 64, title, -1); - - if(gameobj) - { - char buf[128]; - sprintf(buf, "%d", gameobj->teamscore[team&1]); - tw = gfx_pretty_text_width(64, buf, -1); - gfx_pretty_text(x+w-tw-40, y, 64, buf, -1); - } - } - - y += 64.0f; - - /* - if(team) - { - char buf[128]; - sprintf(buf, "%4d", gameobj->teamscore[team&1]); - gfx_pretty_text(x+w/2-tw/2, y, 32, buf, -1); - }*/ - - - // find players - const obj_player_info *players[MAX_CLIENTS] = {0}; - int num_players = 0; - for(int i = 0; i < snap_num_items(SNAP_CURRENT); i++) - { - SNAP_ITEM item; - const void *data = snap_get_item(SNAP_CURRENT, i, &item); - - if(item.type == OBJTYPE_PLAYER_INFO) - { - players[num_players] = (const obj_player_info *)data; - num_players++; - } - } - - // sort players - for(int k = 0; k < num_players; k++) // ffs, bubblesort - { - for(int i = 0; i < num_players-k-1; i++) - { - if(players[i]->score < players[i+1]->score) - { - const obj_player_info *tmp = players[i]; - players[i] = players[i+1]; - players[i+1] = tmp; - } - } - } - - // render headlines - gfx_pretty_text(x+10, y, 32, "Score", -1); - gfx_pretty_text(x+125, y, 32, "Name", -1); - gfx_pretty_text(x+w-70, y, 32, "Ping", -1); - y += 38.0f; - - // render player scores - for(int i = 0; i < num_players; i++) - { - const obj_player_info *info = players[i]; - - // make sure that we render the correct team - if(team != -1 && info->team != team) - continue; - - char buf[128]; - float font_size = 46.0f; - if(info->local) - { - // background so it's easy to find the local player - gfx_texture_set(-1); - gfx_quads_begin(); - gfx_setcolor(1,1,1,0.25f); - draw_round_rect(x, y, w-20, 48, 20.0f); - gfx_quads_end(); - } - - sprintf(buf, "%4d", info->score); - gfx_pretty_text(x+60-gfx_pretty_text_width(font_size,buf,-1), y, font_size, buf, -1); - gfx_pretty_text(x+128, y, font_size, client_datas[info->clientid].name, -1); - - sprintf(buf, "%4d", info->latency); - float tw = gfx_pretty_text_width(font_size, buf, -1); - gfx_pretty_text(x+w-tw-35, y, font_size, buf, -1); - - // render avatar - render_tee(&idlestate, &client_datas[info->clientid].skin_info, EMOTE_NORMAL, vec2(1,0), vec2(x+90, y+28)); - y += 50.0f; - } -} - -void mapscreen_to_world(float center_x, float center_y, float zoom) -{ - RECT screen = *ui2_screen(); - - const float default_zoom = 1.5f; - float width = screen.w*default_zoom*zoom; - float height = screen.h*default_zoom*zoom; - gfx_mapscreen(center_x-width/2, center_y-height/2, center_x+width/2, center_y+height/2); -} - -// renders the complete game world -void render_world(float center_x, float center_y, float zoom) -{ - mapscreen_to_world(center_x, center_y, zoom); - //gfx_mapscreen(center_x-width/2, center_y-height/2, center_x+width/2, center_y+height/2); - - // render background environment - int theme_id = 0; - mapres_theme *t = (mapres_theme *)map_find_item(MAPRES_TEMP_THEME, 0); - if(t) - theme_id = t->id; - - if(config.gfx_high_detail) - { - if(theme_id == 1) - { - // Winter night - gfx_mapscreen(0,0,1,1); - gfx_texture_set(-1); - gfx_quads_begin(); - vec4 top(0x11/(float)0xff, 0x1a/(float)0xff, 0x21/(float)0xff, 1.0f); - vec4 bottom(0x2a/(float)0xff, 0x40/(float)0xff, 0x52/(float)0xff, 1.0f); - gfx_setcolorvertex(0, top.r, top.g, top.b, top.a); - gfx_setcolorvertex(1, top.r, top.g, top.b, top.a); - gfx_setcolorvertex(2, bottom.r, bottom.g, bottom.b, bottom.a); - gfx_setcolorvertex(3, bottom.r, bottom.g, bottom.b, bottom.a); - gfx_quads_drawTL(0, 0, 1, 1); - gfx_quads_end(); - - mapscreen_to_world(center_x*0.1f, center_y*0.1f, zoom); - render_stars(); - - mapscreen_to_world(center_x, center_y, zoom); - - render_moon(center_x*0.8f, center_y*0.8f); - - mapscreen_to_world(center_x, center_y, zoom); - } - else - { - // Summer day - render_sun(20+center_x*0.6f, 20+center_y*0.6f); - - // draw clouds - static vec2 cloud_pos[6] = {vec2(-500,0),vec2(-500,200),vec2(-500,400)}; - static float cloud_speed[6] = {30, 20, 10}; - static int cloud_sprites[6] = {SPRITE_CLOUD1, SPRITE_CLOUD2, SPRITE_CLOUD3}; - - gfx_texture_set(data->images[IMAGE_CLOUDS].id); - gfx_quads_begin(); - for(int i = 0; i < 3; i++) - { - float parallax_amount = 0.55f; - select_sprite(cloud_sprites[i]); - draw_sprite((cloud_pos[i].x+fmod(client_localtime()*cloud_speed[i]+i*100.0f, 3000.0f))+center_x*parallax_amount, - cloud_pos[i].y+center_y*parallax_amount, 300); - } - gfx_quads_end(); - - // draw backdrop - gfx_texture_set(data->images[IMAGE_BACKDROP].id); - gfx_quads_begin(); - float parallax_amount = 0.25f; - for(int x = -1; x < 3; x++) - gfx_quads_drawTL(1024*x+center_x*parallax_amount, (center_y)*parallax_amount+150+512, 1024, 512); - gfx_quads_end(); - } - } - - // render background tilemaps - tilemap_render(32.0f, 0); - - // render items - { - int num = snap_num_items(SNAP_CURRENT); - for(int i = 0; i < num; i++) - { - SNAP_ITEM item; - const void *data = snap_get_item(SNAP_CURRENT, i, &item); - - if(item.type == OBJTYPE_PROJECTILE) - { - const void *prev = snap_find_item(SNAP_PREV, item.type, item.id); - if(prev) - render_projectile((const obj_projectile *)prev, (const obj_projectile *)data, item.id); - } - else if(item.type == OBJTYPE_POWERUP) - { - const void *prev = snap_find_item(SNAP_PREV, item.type, item.id); - if(prev) - render_powerup((const obj_powerup *)prev, (const obj_powerup *)data); - } - else if(item.type == OBJTYPE_FLAG) - { - const void *prev = snap_find_item(SNAP_PREV, item.type, item.id); - if (prev) - render_flag((const obj_flag *)prev, (const obj_flag *)data); - } - } - } - - // render players above all - { - int num = snap_num_items(SNAP_CURRENT); - for(int i = 0; i < num; i++) - { - SNAP_ITEM item; - const void *data = snap_get_item(SNAP_CURRENT, i, &item); - - if(item.type == OBJTYPE_PLAYER_CHARACTER) - { - const void *prev = snap_find_item(SNAP_PREV, item.type, item.id); - const void *prev_info = snap_find_item(SNAP_PREV, OBJTYPE_PLAYER_INFO, item.id); - const void *info = snap_find_item(SNAP_CURRENT, OBJTYPE_PLAYER_INFO, item.id); - if(prev && prev_info && info) - { - client_datas[((const obj_player_info *)info)->clientid].team = ((const obj_player_info *)info)->team; - render_player( - (const obj_player_character *)prev, - (const obj_player_character *)data, - (const obj_player_info *)prev_info, - (const obj_player_info *)info - ); - } - } - } - } - - // render particles - temp_system.update(client_frametime()); - temp_system.render(); - - // render foreground tilemaps - tilemap_render(32.0f, 1); - - // render front environment effects - if(config.gfx_high_detail) - { - if(theme_id == 1) - { - //mapscreen_to_world(center_x, center_y, zoom); - render_snow(); - } - } - - // render damage indications - damageind.render(); -} - -static void do_input(int *v, int key) -{ - *v += inp_key_presses(key) + inp_key_releases(key); - if((*v&1) != inp_key_state(key)) - (*v)++; - *v &= INPUT_STATE_MASK; -} - -void render_game() -{ - float width = 400*3.0f; - float height = 300*3.0f; - - bool spectate = false; - - if(config.cl_predict) - { - if(!local_character || (local_character->health < 0) || (gameobj && gameobj->game_over)) - { - // don't use predicted - } - else - local_character_pos = mix(predicted_prev_player.pos, predicted_player.pos, client_intrapredtick()); - } - else if(local_character && local_prev_character) - { - local_character_pos = mix( - vec2(local_prev_character->x, local_prev_character->y), - vec2(local_character->x, local_character->y), client_intratick()); - } - - if(local_info && local_info->team == -1) - spectate = true; - - animstate idlestate; - anim_eval(&data->animations[ANIM_BASE], 0, &idlestate); - anim_eval_add(&idlestate, &data->animations[ANIM_IDLE], 0, 1.0f); - - if (inp_key_down(KEY_ESC)) - { - if (chat_mode) - chat_mode = CHATMODE_NONE; - else - { - menu_active = !menu_active; - if(menu_active) - menu_game_active = true; - } - } - - // make sure to send our info again if the menu closes - static bool menu_was_active = false; - if(menu_active) - menu_was_active = true; - else if(menu_was_active) - { - send_info(false); - menu_was_active = false; - } - - // handle chat input - if (!menu_active) - { - if(chat_mode != CHATMODE_NONE) - { - if(inp_key_down(KEY_ENTER)) - { - // send message - if(chat_input_len) - { - if(chat_mode == CHATMODE_CONSOLE) - config_set(chat_input); - else if(chat_mode == CHATMODE_REMOTECONSOLE) - client_rcon(chat_input); - else - { - // send chat message - msg_pack_start(MSG_SAY, MSGFLAG_VITAL); - if(chat_mode == CHATMODE_ALL) - msg_pack_int(0); - else - msg_pack_int(1); - msg_pack_string(chat_input, 512); - msg_pack_end(); - client_send_msg(); - } - } - - chat_mode = CHATMODE_NONE; - } - - int c = inp_last_char(); - int k = inp_last_key(); - - if (!(c >= 0 && c < 32)) - { - if (chat_input_len < sizeof(chat_input) - 1) - { - chat_input[chat_input_len] = c; - chat_input[chat_input_len+1] = 0; - chat_input_len++; - } - } - - if(k == KEY_BACKSPACE) - { - if(chat_input_len > 0) - { - chat_input[chat_input_len-1] = 0; - chat_input_len--; - } - } - - } - else - { - if(chat_mode == CHATMODE_NONE) - { - if(inp_key_down(config.key_chat)) - chat_mode = CHATMODE_ALL; - - if(inp_key_down(config.key_teamchat)) - chat_mode = CHATMODE_TEAM; - - if(inp_key_down(config.key_console)) - chat_mode = CHATMODE_CONSOLE; - - if(inp_key_down(config.key_remoteconsole)) - chat_mode = CHATMODE_REMOTECONSOLE; - - if(chat_mode != CHATMODE_NONE) - { - mem_zero(chat_input, sizeof(chat_input)); - chat_input_len = 0; - } - } - } - } - - if (!menu_active) - inp_clear(); - - // fetch new input - if(!menu_active && !emoticon_selector_active) - { - int x, y; - inp_mouse_relative(&x, &y); - mouse_pos += vec2(x, y); - if(!spectate) - { - float l = length(mouse_pos); - if(l > 600.0f) - mouse_pos = normalize(mouse_pos)*600.0f; - } - } - - // set listner pos - if(spectate) - { - local_target_pos = mouse_pos; - snd_set_listener_pos(mouse_pos.x, mouse_pos.y); - } - else - { - local_target_pos = local_character_pos + mouse_pos; - snd_set_listener_pos(local_character_pos.x, local_character_pos.y); - } - - // snap input - { - static player_input input = {0}; - - input.target_x = (int)mouse_pos.x; - input.target_y = (int)mouse_pos.y; - - if(chat_mode != CHATMODE_NONE) - input.state = STATE_CHATTING; - else if(menu_active) - input.state = STATE_IN_MENU; - else - { - input.state = STATE_PLAYING; - input.left = inp_key_state(config.key_move_left); - input.right = inp_key_state(config.key_move_right); - input.hook = inp_key_state(config.key_hook); - input.jump = inp_key_state(config.key_jump); - - if(!emoticon_selector_active) - do_input(&input.fire, config.key_fire); - - // weapon selection - do_input(&input.next_weapon, config.key_next_weapon); - do_input(&input.prev_weapon, config.key_prev_weapon); - - if(inp_key_presses(config.key_next_weapon) || inp_key_presses(config.key_prev_weapon)) - input.wanted_weapon = 0; - else if (config.cl_autoswitch_weapons && picked_up_weapon) - { - input.wanted_weapon = picked_up_weapon; - } - else - { - if(inp_key_presses(config.key_weapon1)) input.wanted_weapon = 1; - if(inp_key_presses(config.key_weapon2)) input.wanted_weapon = 2; - if(inp_key_presses(config.key_weapon3)) input.wanted_weapon = 3; - if(inp_key_presses(config.key_weapon4)) input.wanted_weapon = 4; - if(inp_key_presses(config.key_weapon5)) input.wanted_weapon = 5; - if(inp_key_presses(config.key_weapon6)) input.wanted_weapon = 6; - } - - picked_up_weapon = 0; - } - - // stress testing - if(config.dbg_stress) - { - float t = client_localtime(); - mem_zero(&input, sizeof(input)); - - input.left = ((int)t/2)&1; - input.right = ((int)t/2+1)&1; - input.jump = ((int)t); - input.fire = ((int)(t*10)); - input.hook = ((int)(t*2))&1; - input.wanted_weapon = ((int)t)%NUM_WEAPONS; - input.target_x = (int)(sinf(t*3)*100.0f); - input.target_y = (int)(cosf(t*3)*100.0f); - } - - snap_input(&input, sizeof(input)); - } - - // center at char but can be moved when mouse is far away - float offx = 0, offy = 0; - if (config.cl_dynamic_camera) - { - 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; - } - - // render the world - gfx_clear(0.65f,0.78f,0.9f); - if(spectate) - render_world(mouse_pos.x, mouse_pos.y, 1.0f); - else - { - render_world(local_character_pos.x+offx, local_character_pos.y+offy, 1.0f); - - // draw screen box - if(0) - { - gfx_texture_set(-1); - gfx_blend_normal(); - gfx_lines_begin(); - float cx = local_character_pos.x+offx; - float cy = local_character_pos.y+offy; - float w = 400*3/2; - float h = 300*3/2; - gfx_lines_draw(cx-w,cy-h,cx+w,cy-h); - gfx_lines_draw(cx+w,cy-h,cx+w,cy+h); - gfx_lines_draw(cx+w,cy+h,cx-w,cy+h); - gfx_lines_draw(cx-w,cy+h,cx-w,cy-h); - gfx_lines_end(); - } - } - - - // pseudo format - // ZOOM ZOOM - float zoom = 3.0; - if(local_character) - cl_effects.getzoom(client_tick(), client_intratick(), local_character); - - // DEBUG TESTING - if(zoom > 3.01f) - { - gfx_clear_mask(0); - - gfx_texture_set(-1); - gfx_blend_normal(); - - gfx_mask_op(MASK_NONE, 1); - - gfx_quads_begin(); - gfx_setcolor(0.65f,0.78f,0.9f,1.0f); - - float fov; - if (zoom > 3.01f) - fov = pi * (zoom - 3.0f) / 6.0f; - else - fov = pi / 6.0f; - - float fade = 0.7f; - - - float a = get_angle(normalize(vec2(mouse_pos.x, mouse_pos.y))); - vec2 d = get_dir(a); - vec2 d0 = get_dir(a-fov/2.0f); - vec2 d1 = get_dir(a+fov/2.0f); - - vec2 cd0 = get_dir(a-(fov*fade)/2.0f); // center direction - vec2 cd1 = get_dir(a+(fov*fade)/2.0f); - - vec2 p0n = local_character_pos + d0*32.0f; - vec2 p1n = local_character_pos + d1*32.0f; - vec2 p0f = local_character_pos + d0*1000.0f; - vec2 p1f = local_character_pos + d1*1000.0f; - - vec2 cn = local_character_pos + d*32.0f; - vec2 cf = local_character_pos + d*1000.0f; - - vec2 cp0n = local_character_pos + cd0*32.0f; - vec2 cp0f = local_character_pos + cd0*1000.0f; - vec2 cp1n = local_character_pos + cd1*32.0f; - vec2 cp1f = local_character_pos + cd1*1000.0f; - - gfx_quads_draw_freeform( - p0n.x,p0n.y, - p1n.x,p1n.y, - p0f.x,p0f.y, - p1f.x,p1f.y); - gfx_quads_end(); - - gfx_mask_op(MASK_SET, 0); - - render_world(local_character_pos.x+offx, local_character_pos.y+offy, 2.0f); - - gfx_mask_op(MASK_NONE, 0); - - mapscreen_to_world(local_character_pos.x+offx, local_character_pos.y+offy, 1.0f); - - gfx_texture_set(-1); - gfx_blend_normal(); - gfx_quads_begin(); - gfx_setcolor(0.5f,0.9f,0.5f,0.25f); - float r=0.5f, g=1.0f, b=0.5f; - float r2=r*0.25f, g2=g*0.25f, b2=b*0.25f; - - gfx_setcolor(r,g,b,0.2f); - gfx_quads_draw_freeform( - cn.x,cn.y, - cn.x,cn.y, - cp0f.x,cp0f.y, - cp1f.x,cp1f.y); - - gfx_setcolorvertex(0, r, g, b, 0.2f); - gfx_setcolorvertex(1, r2, g2, b2, 0.9f); - gfx_setcolorvertex(2, r, g, b, 0.2f); - gfx_setcolorvertex(3, r2, g2, b2, 0.9f); - gfx_quads_draw_freeform( - cn.x,cn.y, - p0n.x,p0n.y, - cp0f.x,cp0f.y, - p0f.x,p0f.y); - - gfx_quads_draw_freeform( - cn.x,cn.y, - p1n.x,p1n.y, - cp1f.x,cp1f.y, - p1f.x,p1f.y); - - gfx_quads_end(); - } - - if(local_character && !spectate && !(gameobj && gameobj->game_over)) - { - gfx_texture_set(data->images[IMAGE_GAME].id); - gfx_quads_begin(); - - // render cursor - if (!menu_active && !emoticon_selector_active) - { - select_sprite(data->weapons[local_character->weapon%data->num_weapons].sprite_cursor); - float cursorsize = 64; - draw_sprite(local_target_pos.x, local_target_pos.y, cursorsize); - } - - float x = 5; - float y = 5; - - // render ammo count - // render gui stuff - gfx_quads_end(); - gfx_quads_begin(); - gfx_mapscreen(0,0,400,300); - // if weaponstage is active, put a "glow" around the stage ammo - select_sprite(SPRITE_TEE_BODY); - for (int i = 0; i < local_character->weaponstage; i++) - gfx_quads_drawTL(x+local_character->ammocount * 12 -i*12, y+22, 11, 11); - select_sprite(data->weapons[local_character->weapon%data->num_weapons].sprite_proj); - for (int i = 0; i < local_character->ammocount; i++) - gfx_quads_drawTL(x+i*12,y+24,10,10); - - gfx_quads_end(); - - gfx_texture_set(data->images[IMAGE_GAME].id); - gfx_quads_begin(); - int h = 0; - - // render health - select_sprite(SPRITE_HEALTH_FULL); - for(; h < local_character->health; h++) - gfx_quads_drawTL(x+h*12,y,10,10); - - select_sprite(SPRITE_HEALTH_EMPTY); - for(; h < 10; h++) - gfx_quads_drawTL(x+h*12,y,10,10); - - // render armor meter - h = 0; - select_sprite(SPRITE_ARMOR_FULL); - for(; h < local_character->armor; h++) - gfx_quads_drawTL(x+h*12,y+12,10,10); - - select_sprite(SPRITE_ARMOR_EMPTY); - for(; h < 10; h++) - gfx_quads_drawTL(x+h*12,y+12,10,10); - gfx_quads_end(); - } - - // render kill messages - { - gfx_mapscreen(0, 0, width*1.5f, height*1.5f); - float startx = width*1.5f-10.0f; - float y = 20.0f; - - for(int i = 0; i < killmsg_max; i++) - { - - int r = (killmsg_current+i+1)%killmsg_max; - if(client_tick() > killmsgs[r].tick+50*10) - continue; - - float font_size = 48.0f; - float killername_w = gfx_pretty_text_width(font_size, client_datas[killmsgs[r].killer].name, -1); - float victimname_w = gfx_pretty_text_width(font_size, client_datas[killmsgs[r].victim].name, -1); - - float x = startx; - - // render victim name - x -= victimname_w; - gfx_pretty_text(x, y, font_size, client_datas[killmsgs[r].victim].name, -1); - - // render victim tee - x -= 24.0f; - - if(gameobj && gameobj->gametype == GAMETYPE_CTF) - { - if(killmsgs[r].mode_special&1) - { - gfx_blend_normal(); - gfx_texture_set(data->images[IMAGE_GAME].id); - gfx_quads_begin(); - - if(client_datas[killmsgs[r].victim].team == 0) select_sprite(SPRITE_FLAG_BLUE); - else select_sprite(SPRITE_FLAG_RED); - - float size = 56.0f; - gfx_quads_drawTL(x, y-16, size/2, size); - gfx_quads_end(); - } - } - - render_tee(&idlestate, &client_datas[killmsgs[r].victim].skin_info, EMOTE_PAIN, vec2(-1,0), vec2(x, y+28)); - x -= 32.0f; - - // render weapon - x -= 44.0f; - if (killmsgs[r].weapon >= 0) - { - gfx_texture_set(data->images[IMAGE_GAME].id); - gfx_quads_begin(); - select_sprite(data->weapons[killmsgs[r].weapon].sprite_body); - draw_sprite(x, y+28, 96); - gfx_quads_end(); - } - x -= 52.0f; - - if(killmsgs[r].victim != killmsgs[r].killer) - { - if(gameobj && gameobj->gametype == GAMETYPE_CTF) - { - if(killmsgs[r].mode_special&2) - { - gfx_blend_normal(); - gfx_texture_set(data->images[IMAGE_GAME].id); - gfx_quads_begin(); - - if(client_datas[killmsgs[r].killer].team == 0) select_sprite(SPRITE_FLAG_BLUE, SPRITE_FLAG_FLIP_X); - else select_sprite(SPRITE_FLAG_RED, SPRITE_FLAG_FLIP_X); - - float size = 56.0f; - gfx_quads_drawTL(x-56, y-16, size/2, size); - gfx_quads_end(); - } - } - - // render killer tee - x -= 24.0f; - render_tee(&idlestate, &client_datas[killmsgs[r].killer].skin_info, EMOTE_ANGRY, vec2(1,0), vec2(x, y+28)); - x -= 32.0f; - - // render killer name - x -= killername_w; - gfx_pretty_text(x, y, font_size, client_datas[killmsgs[r].killer].name, -1); - } - - y += 44; - } - } - - // render chat - { - gfx_mapscreen(0,0,400,300); - float x = 10.0f; - float y = 300.0f-50.0f; - float starty = -1; - if(chat_mode != CHATMODE_NONE) - { - // render chat input - char buf[sizeof(chat_input)+16]; - if(chat_mode == CHATMODE_ALL) - sprintf(buf, "All: %s_", chat_input); - else if(chat_mode == CHATMODE_TEAM) - sprintf(buf, "Team: %s_", chat_input); - else if(chat_mode == CHATMODE_CONSOLE) - sprintf(buf, "Console: %s_", chat_input); - else if(chat_mode == CHATMODE_REMOTECONSOLE) - sprintf(buf, "Rcon: %s_", chat_input); - else - sprintf(buf, "Chat: %s_", chat_input); - gfx_pretty_text(x, y, 10.0f, buf, 380); - starty = y; - } - - y -= 10; - - int i; - for(i = 0; i < chat_max_lines; i++) - { - int r = ((chat_current_line-i)+chat_max_lines)%chat_max_lines; - if(client_tick() > chat_lines[r].tick+50*15) - break; - - int lines = int(gfx_pretty_text_width(10, chat_lines[r].text, -1)) / 380 + 1; - - gfx_pretty_text_color(1,1,1,1); - if(chat_lines[r].client_id == -1) - gfx_pretty_text_color(1,1,0.5f,1); // system - else if(chat_lines[r].team) - gfx_pretty_text_color(0.5f,1,0.5f,1); // team message - - gfx_pretty_text(x, y - 8 * (lines - 1), 10, chat_lines[r].text, 380); - y -= 8 * lines; - } - - gfx_pretty_text_color(1,1,1,1); - } - - // render goals - if(gameobj) - { - gametype = gameobj->gametype; - gfx_mapscreen(0,0,400,300); - if(!gameobj->sudden_death) - { - char buf[32]; - int time = 0; - if(gameobj->time_limit) - { - time = gameobj->time_limit*60 - ((client_tick()-gameobj->round_start_tick)/client_tickspeed()); - - if(gameobj->game_over) - time = 0; - } - else - time = (client_tick()-gameobj->round_start_tick)/client_tickspeed(); - - sprintf(buf, "%d:%02d", time /60, time %60); - float w = gfx_pretty_text_width(16, buf, -1); - gfx_pretty_text(200-w/2, 2, 16, buf, -1); - } - - if(gameobj->sudden_death) - { - const char *text = "Sudden Death"; - float w = gfx_pretty_text_width(16, text, -1); - gfx_pretty_text(200-w/2, 2, 16, text, -1); - } - - // render small score hud - if(!(gameobj && gameobj->game_over) && (gametype == GAMETYPE_TDM || gametype == GAMETYPE_CTF)) - { - for(int t = 0; t < 2; t++) - { - gfx_blend_normal(); - gfx_texture_set(-1); - gfx_quads_begin(); - if(t == 0) - gfx_setcolor(1,0,0,0.25f); - else - gfx_setcolor(0,0,1,0.25f); - draw_round_rect(400-40, 300-40-15+t*20, 50, 18, 5.0f); - gfx_quads_end(); - - char buf[32]; - sprintf(buf, "%d", gameobj->teamscore[t]); - float w = gfx_pretty_text_width(14, buf, -1); - - if(gametype == GAMETYPE_CTF) - { - gfx_pretty_text(400-20-w/2+5, 300-40-15+t*20+2, 14, buf, -1); - if(flags[t]) - { - if(flags[t]->carried_by == -2 || (flags[t]->carried_by == -1 && ((client_tick()/10)&1))) - { - gfx_blend_normal(); - gfx_texture_set(data->images[IMAGE_GAME].id); - gfx_quads_begin(); - - if(t == 0) select_sprite(SPRITE_FLAG_RED); - else select_sprite(SPRITE_FLAG_BLUE); - - float size = 16; - gfx_quads_drawTL(400-40+5, 300-40-15+t*20+1, size/2, size); - gfx_quads_end(); - } - else if(flags[t]->carried_by >= 0) - { - int id = flags[t]->carried_by%MAX_CLIENTS; - const char *name = client_datas[id].name; - float w = gfx_pretty_text_width(10, name, -1); - gfx_pretty_text(400-40-5-w, 300-40-15+t*20+2, 10, name, -1); - tee_render_info info = client_datas[id].skin_info; - info.size = 18.0f; - - render_tee(&idlestate, &info, EMOTE_NORMAL, vec2(1,0), - vec2(400-40+10, 300-40-15+9+t*20+1)); - } - } - } - else - gfx_pretty_text(400-20-w/2, 300-40-15+t*20+2, 14, buf, -1); - } - } - - // render warmup timer - if(gameobj->warmup) - { - char buf[256]; - float w = gfx_pretty_text_width(24, "Warmup", -1); - gfx_pretty_text(200+-w/2, 50, 24, "Warmup", -1); - - int seconds = gameobj->warmup/SERVER_TICK_SPEED; - if(seconds < 5) - sprintf(buf, "%d.%d", seconds, (gameobj->warmup*10/SERVER_TICK_SPEED)%10); - else - sprintf(buf, "%d", seconds); - w = gfx_pretty_text_width(24, buf, -1); - gfx_pretty_text(200+-w/2, 75, 24, buf, -1); - } - } - - if (menu_active) - { - modmenu_render(); - return; - } - - if(chat_mode == CHATMODE_NONE && !menu_active && !spectate) - { - if(!emoticon_selector_active && inp_key_pressed(config.key_emoticon)) - { - emoticon_selector_active = true; - emoticon_selector_reset(); - } - } - else - emoticon_selector_active = false; - - if(emoticon_selector_active) - { - int emoticon = emoticon_selector_render(); - if (emoticon != -1) - { - send_emoticon(emoticon); - emoticon_selector_active = false; - } - } - - if(client_connection_problems()) - { - gfx_mapscreen(0, 0, 400, 300); - const char *text = "Connection Problems..."; - float w = gfx_pretty_text_width(24, text, -1); - gfx_pretty_text(200-w/2, 50, 24, text, -1); - } - - // render score board - if(inp_key_pressed(KEY_TAB) || // user requested - (!spectate && (!local_character || local_character->health < 0)) || // not spectating and is dead - (gameobj && gameobj->game_over) // game over - ) - { - gfx_mapscreen(0, 0, width, height); - - float w = 550.0f; - - if (gameobj && gameobj->gametype == GAMETYPE_DM) - { - render_scoreboard(width/2-w/2, 150.0f, w, -1, 0); - //render_scoreboard(gameobj, 0, 0, -1, 0); - } - else - { - - if(gameobj && gameobj->game_over) - { - const char *text = "DRAW!"; - if(gameobj->teamscore[0] > gameobj->teamscore[1]) - text = "Red Team Wins!"; - else if(gameobj->teamscore[1] > gameobj->teamscore[0]) - text = "Blue Team Wins!"; - - float w = gfx_pretty_text_width(92.0f, text, -1); - gfx_pretty_text(width/2-w/2, 45, 92.0f, text, -1); - } - - render_scoreboard(width/2-w-20, 150.0f, w, 0, "Red Team"); - render_scoreboard(width/2 + 20, 150.0f, w, 1, "Blue Team"); - } - - render_goals(width/2-w/2, 150+600+25, w); - - } -} - -extern "C" void modc_render() -{ - // this should be moved around abit - if(client_state() == CLIENTSTATE_ONLINE) - { - render_game(); - - // handle team switching - // TODO: FUGLY!!! - if(config.cl_team != -10) - { - msg_pack_start(MSG_SETTEAM, MSGFLAG_VITAL); - msg_pack_int(config.cl_team); - msg_pack_end(); - client_send_msg(); - } - } - else // if (client_state() != CLIENTSTATE_CONNECTING && client_state() != CLIENTSTATE_LOADING) - { - modmenu_render(); - } - - // - config.cl_team = -10; -} - - -void menu_do_disconnected(); -void menu_do_connecting(); -void menu_do_connected(); - -extern "C" void modc_statechange(int state, int old) -{ - clear_object_pointers(); - - if(state == CLIENTSTATE_OFFLINE) - { - menu_do_disconnected(); - menu_game_active = false; - } - else if(state == CLIENTSTATE_CONNECTING) - menu_do_connecting(); - else if (state == CLIENTSTATE_ONLINE) - { - menu_active = false; - menu_game_active = true; - menu_do_connected(); - } -} - -extern "C" void modc_message(int msg) -{ - if(msg == MSG_CHAT) - { - int cid = msg_unpack_int(); - int team = msg_unpack_int(); - const char *message = msg_unpack_string(); - dbg_msg("message", "chat cid=%d team=%d msg='%s'", cid, team, message); - chat_add_line(cid, team, message); - - if(cid >= 0) - snd_play(CHN_GUI, data->sounds[SOUND_CHAT_CLIENT].sounds[0].id, 0); - else - snd_play(CHN_GUI, data->sounds[SOUND_CHAT_SERVER].sounds[0].id, 0); - } - else if(msg == MSG_SETINFO) - { - int cid = msg_unpack_int(); - const char *name = msg_unpack_string(); - const char *skinname = msg_unpack_string(); - - strncpy(client_datas[cid].name, name, 64); - strncpy(client_datas[cid].skin_name, skinname, 64); - - int use_custom_color = msg_unpack_int(); - client_datas[cid].skin_info.color_body = skin_get_color(msg_unpack_int()); - client_datas[cid].skin_info.color_feet = skin_get_color(msg_unpack_int()); - client_datas[cid].skin_info.size = 64; - - // find new skin - client_datas[cid].skin_id = skin_find(client_datas[cid].skin_name); - if(client_datas[cid].skin_id < 0) - client_datas[cid].skin_id = 0; - - if(use_custom_color) - client_datas[cid].skin_info.texture = skin_get(client_datas[cid].skin_id)->color_texture; - else - { - client_datas[cid].skin_info.texture = skin_get(client_datas[cid].skin_id)->org_texture; - client_datas[cid].skin_info.color_body = vec4(1,1,1,1); - client_datas[cid].skin_info.color_feet = vec4(1,1,1,1); - } - } - else if(msg == MSG_WEAPON_PICKUP) - { - int weapon = msg_unpack_int(); - - picked_up_weapon = weapon+1; - } - else if(msg == MSG_READY_TO_ENTER) - { - client_entergame(); - } - else if(msg == MSG_KILLMSG) - { - killmsg_current = (killmsg_current+1)%killmsg_max; - killmsgs[killmsg_current].killer = msg_unpack_int(); - killmsgs[killmsg_current].victim = msg_unpack_int(); - killmsgs[killmsg_current].weapon = msg_unpack_int(); - killmsgs[killmsg_current].mode_special = msg_unpack_int(); - killmsgs[killmsg_current].tick = client_tick(); - } - else if (msg == MSG_EMOTICON) - { - int cid = msg_unpack_int(); - int emoticon = msg_unpack_int(); - client_datas[cid].emoticon = emoticon; - client_datas[cid].emoticon_start = client_tick(); - } - else if(msg == MSG_SOUND_GLOBAL) - { - int soundid = msg_unpack_int(); - snd_play_random(CHN_GLOBAL, soundid, 1.0f, vec2(0,0)); - } -} - -extern "C" void modc_connected() -{ - // init some stuff - col_init(32); - img_init(); - tilemap_init(); - chat_reset(); - - proj_particles.reset(); - - clear_object_pointers(); - last_new_predicted_tick = -1; - - for(int i = 0; i < MAX_CLIENTS; i++) - { - client_datas[i].name[0] = 0; - client_datas[i].team = 0; - client_datas[i].emoticon = 0; - client_datas[i].emoticon_start = -1; - } - - for(int i = 0; i < killmsg_max; i++) - killmsgs[i].tick = -100000; - - send_info(true); -} - -extern "C" const char *modc_net_version() { return TEEWARS_NETVERSION; } diff --git a/src/game/client/gc_client.cpp b/src/game/client/gc_client.cpp new file mode 100644 index 00000000..98275188 --- /dev/null +++ b/src/game/client/gc_client.cpp @@ -0,0 +1,3103 @@ +/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */ +#include +#include +#include +#include + +extern "C" { + #include + #include +}; + +#include "../g_game.h" +#include "../g_version.h" +#include "../g_mapres.h" +#include "gc_mapres_image.h" +#include "gc_mapres_tilemap.h" +#include "../generated/gc_data.h" +#include "gc_menu.h" +#include "gc_skin.h" +#include "gc_render.h" + +// sound channels +enum +{ + CHN_GUI=0, + CHN_MUSIC, + CHN_WORLD, + CHN_GLOBAL, +}; + +data_container *data = 0x0; + +int gametype = GAMETYPE_DM; + +extern void modmenu_render(); + +enum +{ + CHATMODE_NONE=0, + CHATMODE_ALL, + CHATMODE_TEAM, + CHATMODE_CONSOLE, + CHATMODE_REMOTECONSOLE, +}; + +typedef struct +{ + float x, y, w, h; +} RECT; +RECT *ui2_screen(); + +static int chat_mode = CHATMODE_NONE; +bool menu_active = false; +bool menu_game_active = false; +static bool emoticon_selector_active = false; + +static vec2 mouse_pos; +static vec2 local_character_pos; +static vec2 local_target_pos; +static const obj_player_character *local_character = 0; +static const obj_player_character *local_prev_character = 0; +const obj_player_info *local_info = 0; +static const obj_flag *flags[2] = {0,0}; +static const obj_game *gameobj = 0; + +static int picked_up_weapon = 0; + +static struct client_data +{ + char name[64]; + char skin_name[64]; + int skin_id; + int skin_color; + int team; + int emoticon; + int emoticon_start; + player_core predicted; + + tee_render_info skin_info; + +} client_datas[MAX_CLIENTS]; + +class client_effects +{ +public: + float zoom; + float currentzoom; + float stage; + int lastzoomin; + int lastincrease; + + client_effects() + { + currentzoom = zoom = 3.0f; + stage = 0.0f; + } + + float getorgzoom() { return zoom; } + + float getzoom(int tick, float intratick, const obj_player_character *player) + { + float currentstage = ((float)player->weaponstage) * 0.1f; + if (currentstage < stage) + { + if ((tick - lastincrease) > (client_tickspeed() / 2)) + stage = currentstage; + } + else + { + lastincrease = tick; + stage = currentstage; + } + + float targetzoom = 3.0f + stage; + currentzoom = LERP(currentzoom, targetzoom, 0.1); + return currentzoom; + } +}; + +client_effects cl_effects; + +inline float frandom() { return rand()/(float)(RAND_MAX); } + +void snd_play_random(int chn, int setid, float vol, vec2 pos) +{ + soundset *set = &data->sounds[setid]; + + if(!set->num_sounds) + return; + + if(set->num_sounds == 1) + { + snd_play_at(chn, set->sounds[0].id, 0, pos.x, pos.y); + return; + } + + // play a random one + int id; + do { + id = rand() % set->num_sounds; + } while(id == set->last); + snd_play_at(chn, set->sounds[id].id, 0, pos.x, pos.y); + set->last = id; +} + +// sound volume tweak +static const float stereo_separation = 0.001f; +static const float stereo_separation_deadzone = 200.0f; +static const float volume_distance_falloff = 200.0f; +static const float volume_distance_deadzone = 320.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; + +void sound_vol_pan(const vec2& p, float *vol, float *pan) +{ + vec2 player_to_ev = p - local_character_pos; + *pan = 0.0f; + *vol = 1.0f; + + if(fabs(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; + } +} + +enum +{ + SPRITE_FLAG_FLIP_Y=1, + SPRITE_FLAG_FLIP_X=2, +}; + +static float sprite_w_scale; +static float sprite_h_scale; + +static void select_sprite(sprite *spr, int flags=0, int sx=0, int sy=0) +{ + int x = spr->x+sx; + int y = spr->y+sy; + int w = spr->w; + int h = spr->h; + int cx = spr->set->gridx; + int cy = spr->set->gridy; + + float f = sqrtf(h*h + w*w); + sprite_w_scale = w/f; + sprite_h_scale = h/f; + + float x1 = x/(float)cx; + float x2 = (x+w)/(float)cx; + float y1 = y/(float)cy; + float y2 = (y+h)/(float)cy; + float temp = 0; + + if(flags&SPRITE_FLAG_FLIP_Y) + { + temp = y1; + y1 = y2; + y2 = temp; + } + + if(flags&SPRITE_FLAG_FLIP_X) + { + temp = x1; + x1 = x2; + x2 = temp; + } + + gfx_quads_setsubset(x1, y1, x2, y2); +} + +void select_sprite(int id, int flags=0, int sx=0, int sy=0) +{ + if(id < 0 || id > data->num_sprites) + return; + select_sprite(&data->sprites[id], flags, sx, sy); +} + +void draw_sprite(float x, float y, float size) +{ + gfx_quads_draw(x, y, size*sprite_w_scale, size*sprite_h_scale); +} + +class damage_indicators +{ +public: + int64 lastupdate; + struct item + { + vec2 pos; + vec2 dir; + float life; + float startangle; + }; + + enum + { + MAX_ITEMS=64, + }; + + damage_indicators() + { + lastupdate = 0; + num_items = 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, vec2 dir) + { + item *i = create_i(); + if (i) + { + i->pos = pos; + i->life = 0.75f; + i->dir = dir*-1; + i->startangle = (( (float)rand()/(float)RAND_MAX) - 1.0f) * 2.0f * pi; + } + } + + void render() + { + gfx_texture_set(data->images[IMAGE_GAME].id); + gfx_quads_begin(); + for(int i = 0; i < num_items;) + { + vec2 pos = mix(items[i].pos+items[i].dir*75.0f, items[i].pos, clamp((items[i].life-0.60f)/0.15f, 0.0f, 1.0f)); + + items[i].life -= client_frametime(); + if(items[i].life < 0.0f) + destroy_i(&items[i]); + else + { + gfx_setcolor(1.0f,1.0f,1.0f, items[i].life/0.1f); + gfx_quads_setrotation(items[i].startangle + items[i].life * 2.0f); + select_sprite(SPRITE_STAR1); + draw_sprite(pos.x, pos.y, 48.0f); + i++; + } + } + gfx_quads_end(); + } + +}; + +static damage_indicators damageind; + +class particle_system +{ +public: + struct particle + { + vec2 pos; + vec2 vel; + float life; + float max_life; + float size; + + float rot; + float rotspeed; + + float gravity; + float friction; + int iparticle; + + vec4 color; + }; + + enum + { + MAX_PARTICLES=1024, + }; + + particle particles[MAX_PARTICLES]; + int num_particles; + + particle_system() + { + num_particles = 0; + } + + void new_particle(vec2 pos, vec2 vel, float life, float size, float gravity, float friction, vec4 color=vec4(1,1,1,1)) + { + if (num_particles >= MAX_PARTICLES) + return; + + particles[num_particles].iparticle = rand() % data->num_particles; + particles[num_particles].pos = pos; + particles[num_particles].vel = vel; + particles[num_particles].life = life - (data->particles[particles[num_particles].iparticle].lifemod/100.0f) * life; + particles[num_particles].size = size; + particles[num_particles].max_life = life; + particles[num_particles].gravity = gravity; + particles[num_particles].friction = friction; + particles[num_particles].rot = frandom()*pi*2; + particles[num_particles].rotspeed = frandom() * 10.0f; + particles[num_particles].color = color; + num_particles++; + } + + void update(float time_passed) + { + for(int i = 0; i < num_particles; i++) + { + particles[i].vel.y += particles[i].gravity*time_passed; + particles[i].vel *= particles[i].friction; + vec2 vel = particles[i].vel*time_passed; + move_point(&particles[i].pos, &vel, 0.1f+0.9f*frandom(), NULL); + particles[i].vel = vel* (1.0f/time_passed); + particles[i].life += time_passed; + particles[i].rot += time_passed * particles[i].rotspeed; + + // check particle death + if(particles[i].life > particles[i].max_life) + { + num_particles--; + particles[i] = particles[num_particles]; + i--; + } + } + } + + void render() + { + gfx_blend_additive(); + gfx_texture_set(data->images[IMAGE_GAME].id); + gfx_quads_begin(); + + for(int i = 0; i < num_particles; i++) + { + int type = particles[i].iparticle; + select_sprite(data->particles[type].spr); + float a = 1 - particles[i].life / particles[i].max_life; + vec2 p = particles[i].pos; + + gfx_quads_setrotation(particles[i].rot); + + gfx_setcolor( + data->particles[type].color_r * particles[i].color.r, + data->particles[type].color_g * particles[i].color.g, + data->particles[type].color_b * particles[i].color.b, + pow(a, 0.75f) * particles[i].color.a); + + gfx_quads_draw(p.x, p.y,particles[i].size,particles[i].size); + } + gfx_quads_end(); + gfx_blend_normal(); + } +}; + +static particle_system temp_system; + +class projectile_particles +{ +public: + enum + { + LISTSIZE = 1000, + }; + // meh, just use size % + int lastadd[LISTSIZE]; + projectile_particles() + { + reset(); + } + + void reset() + { + for (int i = 0; i < LISTSIZE; i++) + lastadd[i] = -1000; + } + + void addparticle(int projectiletype, int projectileid, vec2 pos, vec2 vel) + { + int particlespersecond = data->projectileinfo[projectiletype].particlespersecond; + int lastaddtick = lastadd[projectileid % LISTSIZE]; + + if(!particlespersecond) + return; + + if ((client_tick() - lastaddtick) > (client_tickspeed() / particlespersecond)) + { + lastadd[projectileid % LISTSIZE] = client_tick(); + float life = data->projectileinfo[projectiletype].particlelife; + float size = data->projectileinfo[projectiletype].particlesize; + vec2 v = vel * 0.2f + normalize(vec2(frandom()-0.5f, -frandom()))*(32.0f+frandom()*32.0f); + + // add the particle (from projectiletype later on, but meh...) + temp_system.new_particle(pos, v, life, size, 0, 0.95f); + } + } +}; +static projectile_particles proj_particles; + +static char chat_input[512]; +static unsigned chat_input_len; +static const int chat_max_lines = 10; + +struct chatline +{ + int tick; + int client_id; + int team; + char text[512+64]; +}; + +chatline chat_lines[chat_max_lines]; +static int chat_current_line = 0; + +void chat_reset() +{ + for(int i = 0; i < chat_max_lines; i++) + chat_lines[i].tick = -1000000; + chat_current_line = 0; +} + +void chat_add_line(int client_id, int team, const char *line) +{ + chat_current_line = (chat_current_line+1)%chat_max_lines; + chat_lines[chat_current_line].tick = client_tick(); + chat_lines[chat_current_line].client_id = client_id; + chat_lines[chat_current_line].team = team; + + if(client_id == -1) // server message + sprintf(chat_lines[chat_current_line].text, "*** %s", line); + else + { + sprintf(chat_lines[chat_current_line].text, "%s: %s", client_datas[client_id].name, line); + } +} + +struct killmsg +{ + int weapon; + int victim; + int killer; + int mode_special; // for CTF, if the guy is carrying a flag for example + int tick; +}; + +static const int killmsg_max = 5; +killmsg killmsgs[killmsg_max]; +static int killmsg_current = 0; + +extern unsigned char internal_data[]; + +void create_air_jump_effect(vec2 pos) +{ + const int count = 12; + for(int i = 0; i <= count; i++) + { + float a = i/(float)count; + vec2 v = vec2((a-0.5f)*512.0f, 0); + temp_system.new_particle(pos+vec2(0,28), v, 0.4f, 16.0f, 0, 0.985f, vec4(0.25f,0.4f,1,1)); + } +} + + +extern void draw_round_rect(float x, float y, float w, float h, float r); +extern int render_popup(const char *caption, const char *text, const char *button_text); + +static void render_loading(float percent) +{ + gfx_clear(0.65f,0.78f,0.9f); + RECT screen = *ui2_screen(); + gfx_mapscreen(screen.x, screen.y, screen.w, screen.h); + + float tw; + + float w = 700; + float h = 200; + float x = screen.w/2-w/2; + float y = screen.h/2-h/2; + + gfx_blend_normal(); + + gfx_texture_set(-1); + gfx_quads_begin(); + gfx_setcolor(0,0,0,0.50f); + draw_round_rect(x, y, w, h, 40.0f); + gfx_quads_end(); + + const char *caption = "Loading"; + + tw = gfx_pretty_text_width(48.0f, caption, -1); + ui_do_label(x+w/2-tw/2, y+20, caption, 48.0f); + + gfx_texture_set(-1); + gfx_quads_begin(); + gfx_setcolor(1,1,1,1.0f); + draw_round_rect(x+40, y+h-75, (w-80)*percent, 25, 5.0f); + gfx_quads_end(); + + gfx_swap(); +} + +extern "C" void modc_init() +{ + // setup sound channels + snd_set_channel(CHN_GUI, 1.0f, 0.0f); + snd_set_channel(CHN_MUSIC, 1.0f, 0.0f); + snd_set_channel(CHN_WORLD, 0.9f, 1.0f); + snd_set_channel(CHN_GLOBAL, 1.0f, 0.0f); + + // load the data container + data = load_data_from_memory(internal_data); + + // TODO: should be removed + snd_set_listener_pos(0.0f, 0.0f); + + float total = data->num_sounds+data->num_images; + float current = 0; + + // load sounds + for(int s = 0; s < data->num_sounds; s++) + { + render_loading(current/total); + for(int i = 0; i < data->sounds[s].num_sounds; i++) + { + int id; + //if (strcmp(data->sounds[s].sounds[i].filename + strlen(data->sounds[s].sounds[i].filename) - 3, ".wv") == 0) + id = snd_load_wv(data->sounds[s].sounds[i].filename); + //else + // id = snd_load_wav(data->sounds[s].sounds[i].filename); + + data->sounds[s].sounds[i].id = id; + } + + current++; + } + + // load textures + for(int i = 0; i < data->num_images; i++) + { + render_loading(current/total); + data->images[i].id = gfx_load_texture(data->images[i].filename); + current++; + } + + skin_init(); +} + +extern "C" void modc_entergame() +{ +} + +extern "C" void modc_shutdown() +{ + // shutdown the menu +} + +static void process_events(int s) +{ + int num = snap_num_items(s); + for(int index = 0; index < num; index++) + { + SNAP_ITEM item; + const void *data = snap_get_item(s, index, &item); + + if(item.type == EVENT_DAMAGEINDICATION) + { + ev_damageind *ev = (ev_damageind *)data; + damageind.create(vec2(ev->x, ev->y), get_direction(ev->angle)); + } + else if(item.type == EVENT_AIR_JUMP) + { + ev_common *ev = (ev_common *)data; + create_air_jump_effect(vec2(ev->x, ev->y)); + } + 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_SPAWN) + { + 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_DEATH) + { + ev_explosion *ev = (ev_explosion *)data; + vec2 p(ev->x, ev->y); + vec4 c(0.5f, 0.1f, 0.1f, 1.0f); + + // center explosion + vec2 v = normalize(vec2(frandom()-0.5f, -frandom()))*(32.0f+frandom()*32.0f); + temp_system.new_particle(p, v, 1.2f, 64.0f, 0, 0.95f, c); + v = normalize(vec2(frandom()-0.5f, -frandom()))*(128.0f+frandom()*128.0f); + temp_system.new_particle(p, v, 1.2f, 32.0f, 0, 0.95f, c); + v = normalize(vec2(frandom()-0.5f, -frandom()))*(128.0f+frandom()*128.0f); + temp_system.new_particle(p, v, 1.2f, 16.0f, 0, 0.95f, c); + + for(int i = 0; i < 8; i++) + { + vec2 v = normalize(vec2(frandom()-0.5f, frandom()-0.5f))*(64.0f+frandom()*64.0f); + temp_system.new_particle(p, v, 0.5f+0.5f*frandom(), 16.0f, 0, 0.985f, c); + } + + for(int i = 0; i < 8; i++) + { + vec2 v = normalize(vec2(frandom()-0.5f, frandom()-0.5f))*(128.0f+frandom()*256.0f); + temp_system.new_particle(p, v, 0.5f+0.5f*frandom(), 16.0f, 128.0f, 0.985f, c); + } + } + else if(item.type == EVENT_SOUND_WORLD) + { + ev_sound *ev = (ev_sound *)data; + if(ev->sound >= 0 && ev->sound < NUM_SOUNDS) + snd_play_random(CHN_WORLD, ev->sound, 1.0f, vec2(ev->x, ev->y)); + } + } +} + +static player_core predicted_prev_player; +static player_core predicted_player; +static int predicted_tick = 0; +static int last_new_predicted_tick = -1; + +extern "C" void modc_predict() +{ + player_core before_prev_player = predicted_prev_player; + player_core before_player = predicted_player; + + + // repredict player + world_core world; + int local_cid = -1; + + // search for players + for(int i = 0; i < snap_num_items(SNAP_CURRENT); i++) + { + SNAP_ITEM item; + const void *data = snap_get_item(SNAP_CURRENT, i, &item); + int client_id = item.id; + + if(item.type == OBJTYPE_PLAYER_CHARACTER) + { + const obj_player_character *character = (const obj_player_character *)data; + client_datas[client_id].predicted.world = &world; + world.players[client_id] = &client_datas[client_id].predicted; + + client_datas[client_id].predicted.read(character); + } + else if(item.type == OBJTYPE_PLAYER_INFO) + { + const obj_player_info *info = (const obj_player_info *)data; + if(info->local) + local_cid = client_id; + } + } + + // predict + for(int tick = client_tick()+1; tick <= client_predtick(); tick++) + { + // fetch the local + if(tick == client_predtick() && world.players[local_cid]) + predicted_prev_player = *world.players[local_cid]; + + // first calculate where everyone should move + for(int c = 0; c < MAX_CLIENTS; c++) + { + if(!world.players[c]) + continue; + + mem_zero(&world.players[c]->input, sizeof(world.players[c]->input)); + if(local_cid == c) + { + // apply player input + int *input = client_get_input(tick); + if(input) + world.players[c]->input = *((player_input*)input); + } + + world.players[c]->tick(); + } + + // move all players and quantize their data + for(int c = 0; c < MAX_CLIENTS; c++) + { + if(!world.players[c]) + continue; + + world.players[c]->move(); + world.players[c]->quantize(); + } + + if(tick > last_new_predicted_tick) + { + last_new_predicted_tick = tick; + + if(local_cid != -1 && world.players[local_cid]) + { + vec2 pos = world.players[local_cid]->pos; + int events = world.players[local_cid]->triggered_events; + if(events&COREEVENT_GROUND_JUMP) snd_play_random(CHN_WORLD, SOUND_PLAYER_JUMP, 1.0f, pos); + if(events&COREEVENT_AIR_JUMP) + { + create_air_jump_effect(pos); + snd_play_random(CHN_WORLD, SOUND_PLAYER_JUMP, 1.0f, pos); + } + //if(events&COREEVENT_HOOK_LAUNCH) snd_play_random(CHN_WORLD, SOUND_HOOK_LOOP, 1.0f, pos); + if(events&COREEVENT_HOOK_ATTACH_PLAYER) snd_play_random(CHN_WORLD, SOUND_HOOK_ATTACH_PLAYER, 1.0f, pos); + if(events&COREEVENT_HOOK_ATTACH_GROUND) snd_play_random(CHN_WORLD, SOUND_HOOK_ATTACH_GROUND, 1.0f, pos); + //if(events&COREEVENT_HOOK_RETRACT) snd_play_random(CHN_WORLD, SOUND_PLAYER_JUMP, 1.0f, pos); + } + + + /* + dbg_msg("predict", "%d %d %d", tick, + (int)world.players[c]->pos.x, (int)world.players[c]->pos.y, + (int)world.players[c]->vel.x, (int)world.players[c]->vel.y);*/ + } + + if(tick == client_predtick() && world.players[local_cid]) + predicted_player = *world.players[local_cid]; + } + + if(config.debug && predicted_tick == client_predtick()) + { + if(predicted_player.pos.x != before_player.pos.x || + predicted_player.pos.y != before_player.pos.y) + { + dbg_msg("client", "prediction error, (%d %d) (%d %d)", + (int)before_player.pos.x, (int)before_player.pos.y, + (int)predicted_player.pos.x, (int)predicted_player.pos.y); + } + + if(predicted_prev_player.pos.x != before_prev_player.pos.x || + predicted_prev_player.pos.y != before_prev_player.pos.y) + { + dbg_msg("client", "prediction error, prev (%d %d) (%d %d)", + (int)before_prev_player.pos.x, (int)before_prev_player.pos.y, + (int)predicted_prev_player.pos.x, (int)predicted_prev_player.pos.y); + } + } + + predicted_tick = client_predtick(); +} + +static void clear_object_pointers() +{ + // clear out the invalid pointers + local_character = 0; + local_prev_character = 0; + local_info = 0; + flags[0] = 0; + flags[1] = 0; + gameobj = 0; +} + +extern "C" void modc_newsnapshot() +{ + process_events(SNAP_CURRENT); + + if(config.dbg_stress) + { + if((client_tick()%250) == 0) + { + msg_pack_start(MSG_SAY, MSGFLAG_VITAL); + msg_pack_int(-1); + msg_pack_string("galenskap!!!!", 512); + msg_pack_end(); + client_send_msg(); + } + } + + clear_object_pointers(); + + // 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; + const void *data = snap_get_item(SNAP_CURRENT, i, &item); + + if(item.type == OBJTYPE_PLAYER_INFO) + { + const obj_player_info *info = (const obj_player_info *)data; + if(info->local) + { + local_info = info; + const void *data = snap_find_item(SNAP_CURRENT, OBJTYPE_PLAYER_CHARACTER, item.id); + if(data) + { + local_character = (const obj_player_character *)data; + local_character_pos = vec2(local_character->x, local_character->y); + + const void *p = snap_find_item(SNAP_PREV, OBJTYPE_PLAYER_CHARACTER, item.id); + if(p) + local_prev_character = (obj_player_character *)p; + } + } + } + else if(item.type == OBJTYPE_GAME) + gameobj = (obj_game *)data; + else if(item.type == OBJTYPE_FLAG) + { + flags[item.id%2] = (const obj_flag *)data; + } + } + } +} + +void send_info(bool start) +{ + if(start) + msg_pack_start(MSG_STARTINFO, MSGFLAG_VITAL); + else + msg_pack_start(MSG_CHANGEINFO, MSGFLAG_VITAL); + msg_pack_string(config.player_name, 64); + msg_pack_string(config.player_skin, 64); + msg_pack_int(config.player_use_custom_color); + msg_pack_int(config.player_color_body); + msg_pack_int(config.player_color_feet); + msg_pack_end(); + client_send_msg(); +} + +void send_emoticon(int emoticon) +{ + msg_pack_start(MSG_EMOTICON, MSGFLAG_VITAL); + msg_pack_int(emoticon); + msg_pack_end(); + client_send_msg(); +} + +static void render_projectile(const obj_projectile *prev, const obj_projectile *current, int itemid) +{ + gfx_texture_set(data->images[IMAGE_GAME].id); + gfx_quads_begin(); + + // get positions + float gravity = -400; + if(current->type != WEAPON_ROCKET) + gravity = -100; + + float ct = (client_tick()-current->start_tick)/(float)SERVER_TICK_SPEED + client_intratick()*1/(float)SERVER_TICK_SPEED; + vec2 startpos(current->x, current->y); + vec2 startvel(current->vx, current->vy); + vec2 pos = calc_pos(startpos, startvel, gravity, ct); + vec2 prevpos = calc_pos(startpos, startvel, gravity, ct-0.001f); + + select_sprite(data->weapons[current->type%data->num_weapons].sprite_proj); + vec2 vel = pos-prevpos; + //vec2 pos = mix(vec2(prev->x, prev->y), vec2(current->x, current->y), client_intratick()); + + // add particle for this projectile + proj_particles.addparticle(current->type, itemid, pos, vel); + + if(length(vel) > 0.00001f) + gfx_quads_setrotation(get_angle(vel)); + else + gfx_quads_setrotation(0); + + // TODO: do this, but nice + //temp_system.new_particle(pos, vec2(0,0), 0.3f, 14.0f, 0, 0.95f); + + gfx_quads_draw(pos.x, pos.y, 32, 32); + gfx_quads_setrotation(0); + gfx_quads_end(); +} + +static void render_powerup(const obj_powerup *prev, const obj_powerup *current) +{ + gfx_texture_set(data->images[IMAGE_GAME].id); + gfx_quads_begin(); + vec2 pos = mix(vec2(prev->x, prev->y), vec2(current->x, current->y), client_intratick()); + float angle = 0.0f; + float size = 64.0f; + if (current->type == POWERUP_WEAPON) + { + angle = 0; //-pi/6;//-0.25f * pi * 2.0f; + select_sprite(data->weapons[current->subtype%data->num_weapons].sprite_body); + size = data->weapons[current->subtype%data->num_weapons].visual_size; + } + else + { + const int c[] = { + SPRITE_POWERUP_HEALTH, + SPRITE_POWERUP_ARMOR, + SPRITE_POWERUP_WEAPON, + SPRITE_POWERUP_NINJA, + SPRITE_POWERUP_TIMEFIELD + }; + select_sprite(c[current->type]); + + if(c[current->type] == SPRITE_POWERUP_NINJA) + { + proj_particles.addparticle(0, 0, + pos+vec2((frandom()-0.5f)*80.0f, (frandom()-0.5f)*20.0f), + vec2((frandom()-0.5f)*10.0f, (frandom()-0.5f)*10.0f)); + size *= 2.0f; + pos.x += 10.0f; + } + } + + gfx_quads_setrotation(angle); + + float offset = pos.y/32.0f + pos.x/32.0f; + pos.x += cosf(client_localtime()*2.0f+offset)*2.5f; + pos.y += sinf(client_localtime()*2.0f+offset)*2.5f; + draw_sprite(pos.x, pos.y, size); + gfx_quads_end(); +} + +static void render_flag(const obj_flag *prev, const obj_flag *current) +{ + float angle = 0.0f; + float size = 42.0f; + + gfx_blend_normal(); + gfx_texture_set(data->images[IMAGE_GAME].id); + gfx_quads_begin(); + + if(current->team == 0) // red team + select_sprite(SPRITE_FLAG_RED); + else + select_sprite(SPRITE_FLAG_BLUE); + + gfx_quads_setrotation(angle); + + vec2 pos = mix(vec2(prev->x, prev->y), vec2(current->x, current->y), client_intratick()); + + if(local_info && current->carried_by == local_info->clientid) + pos = local_character_pos; + + gfx_setcolor(current->team ? 0 : 1,0,current->team ? 1 : 0,1); + //draw_sprite(pos.x, pos.y, size); + gfx_quads_draw(pos.x, pos.y-size*0.75f, size, size*2); + gfx_quads_end(); +} + +void anim_seq_eval(sequence *seq, float time, keyframe *frame) +{ + if(seq->num_frames == 0) + { + frame->time = 0; + frame->x = 0; + frame->y = 0; + frame->angle = 0; + } + else if(seq->num_frames == 1) + { + *frame = seq->frames[0]; + } + else + { + //time = max(0.0f, min(1.0f, time / duration)); // TODO: use clamp + keyframe *frame1 = 0; + keyframe *frame2 = 0; + float blend = 0.0f; + + // TODO: make this smarter.. binary search + for (int i = 1; i < seq->num_frames; i++) + { + if (seq->frames[i-1].time <= time && seq->frames[i].time >= time) + { + frame1 = &seq->frames[i-1]; + frame2 = &seq->frames[i]; + blend = (time - frame1->time) / (frame2->time - frame1->time); + break; + } + } + + if (frame1 && frame2) + { + frame->time = time; + frame->x = mix(frame1->x, frame2->x, blend); + frame->y = mix(frame1->y, frame2->y, blend); + frame->angle = mix(frame1->angle, frame2->angle, blend); + } + } +} + +void anim_eval(animation *anim, float time, animstate *state) +{ + anim_seq_eval(&anim->body, time, &state->body); + anim_seq_eval(&anim->back_foot, time, &state->back_foot); + anim_seq_eval(&anim->front_foot, time, &state->front_foot); + anim_seq_eval(&anim->attach, time, &state->attach); +} + +void anim_add_keyframe(keyframe *seq, keyframe *added, float amount) +{ + seq->x += added->x*amount; + seq->y += added->y*amount; + seq->angle += added->angle*amount; +} + +void anim_add(animstate *state, animstate *added, float amount) +{ + anim_add_keyframe(&state->body, &added->body, amount); + anim_add_keyframe(&state->back_foot, &added->back_foot, amount); + anim_add_keyframe(&state->front_foot, &added->front_foot, amount); + anim_add_keyframe(&state->attach, &added->attach, amount); +} + +void anim_eval_add(animstate *state, animation *anim, float time, float amount) +{ + animstate add; + anim_eval(anim, time, &add); + anim_add(state, &add, amount); +} + +static void render_hand(int skin_id, vec2 center_pos, vec2 dir, float angle_offset, vec2 post_rot_offset) +{ + // for drawing hand + const skin *s = skin_get(skin_id); + + float basesize = 10.0f; + //dir = normalize(hook_pos-pos); + + vec2 hand_pos = center_pos + dir; + float angle = get_angle(dir); + if (dir.x < 0) + angle -= angle_offset; + else + angle += angle_offset; + + vec2 dirx = dir; + vec2 diry(-dir.y,dir.x); + + if (dir.x < 0) + diry = -diry; + + hand_pos += dirx * post_rot_offset.x; + hand_pos += diry * post_rot_offset.y; + + //gfx_texture_set(data->images[IMAGE_CHAR_DEFAULT].id); + gfx_texture_set(s->color_texture); + gfx_quads_begin(); + + // two passes + for (int i = 0; i < 2; i++) + { + bool outline = i == 0; + + select_sprite(outline?SPRITE_TEE_HAND_OUTLINE:SPRITE_TEE_HAND, 0, 0, 0); + gfx_quads_setrotation(angle); + gfx_quads_draw(hand_pos.x, hand_pos.y, 2*basesize, 2*basesize); + } + + gfx_quads_setrotation(0); + gfx_quads_end(); +} + +void render_tee(animstate *anim, tee_render_info *info, int emote, vec2 dir, vec2 pos) +{ + vec2 direction = dir; + vec2 position = pos; + + //gfx_texture_set(data->images[IMAGE_CHAR_DEFAULT].id); + gfx_texture_set(info->texture); + gfx_quads_begin(); + //gfx_quads_draw(pos.x, pos.y-128, 128, 128); + + // first pass we draw the outline + // second pass we draw the filling + for(int p = 0; p < 2; p++) + { + int outline = p==0 ? 1 : 0; + + for(int f = 0; f < 2; f++) + { + float animscale = info->size * 1.0f/64.0f; + float basesize = info->size; + if(f == 1) + { + gfx_quads_setrotation(anim->body.angle*pi*2); + + // draw body + gfx_setcolor(info->color_body.r, info->color_body.g, info->color_body.b, info->color_body.a); + vec2 body_pos = position + vec2(anim->body.x, anim->body.y)*animscale; + select_sprite(outline?SPRITE_TEE_BODY_OUTLINE:SPRITE_TEE_BODY, 0, 0, 0); + gfx_quads_draw(body_pos.x, body_pos.y, basesize, basesize); + + // draw eyes + if(p == 1) + { + switch (emote) + { + case EMOTE_PAIN: + select_sprite(SPRITE_TEE_EYE_PAIN, 0, 0, 0); + break; + case EMOTE_HAPPY: + select_sprite(SPRITE_TEE_EYE_HAPPY, 0, 0, 0); + break; + case EMOTE_SURPRISE: + select_sprite(SPRITE_TEE_EYE_SURPRISE, 0, 0, 0); + break; + case EMOTE_ANGRY: + select_sprite(SPRITE_TEE_EYE_ANGRY, 0, 0, 0); + break; + default: + select_sprite(SPRITE_TEE_EYE_NORMAL, 0, 0, 0); + break; + } + + float eyescale = basesize*0.40f; + float h = emote == EMOTE_BLINK ? basesize*0.15f : eyescale; + float eyeseparation = (0.075f - 0.010f*fabs(direction.x))*basesize; + vec2 offset = vec2(direction.x*0.125f, -0.05f+direction.y*0.10f)*basesize; + gfx_quads_draw(body_pos.x-eyeseparation+offset.x, body_pos.y+offset.y, eyescale, h); + gfx_quads_draw(body_pos.x+eyeseparation+offset.x, body_pos.y+offset.y, -eyescale, h); + } + } + + // draw feet + gfx_setcolor(info->color_feet.r, info->color_feet.g, info->color_feet.b, info->color_feet.a); + select_sprite(outline?SPRITE_TEE_FOOT_OUTLINE:SPRITE_TEE_FOOT, 0, 0, 0); + + keyframe *foot = f ? &anim->front_foot : &anim->back_foot; + + float w = basesize; + float h = basesize/2; + + gfx_quads_setrotation(foot->angle*pi*2); + gfx_quads_draw(position.x+foot->x*animscale, position.y+foot->y*animscale, w, h); + } + } + + gfx_quads_end(); +} + +void draw_circle(float x, float y, float r, int segments) +{ + float f_segments = (float)segments; + for(int i = 0; i < segments; i+=2) + { + float a1 = i/f_segments * 2*pi; + float a2 = (i+1)/f_segments * 2*pi; + float a3 = (i+2)/f_segments * 2*pi; + float ca1 = cosf(a1); + float ca2 = cosf(a2); + float ca3 = cosf(a3); + float sa1 = sinf(a1); + float sa2 = sinf(a2); + float sa3 = sinf(a3); + + gfx_quads_draw_freeform( + x, y, + x+ca1*r, y+sa1*r, + x+ca3*r, y+sa3*r, + x+ca2*r, y+sa2*r); + } +} + +void draw_round_rect_ext(float x, float y, float w, float h, float r, int corners) +{ + int num = 8; + for(int i = 0; i < num; i+=2) + { + float a1 = i/(float)num * pi/2; + float a2 = (i+1)/(float)num * pi/2; + float a3 = (i+2)/(float)num * pi/2; + float ca1 = cosf(a1); + float ca2 = cosf(a2); + float ca3 = cosf(a3); + float sa1 = sinf(a1); + float sa2 = sinf(a2); + float sa3 = sinf(a3); + + if(corners&1) // TL + gfx_quads_draw_freeform( + x+r, y+r, + x+(1-ca1)*r, y+(1-sa1)*r, + x+(1-ca3)*r, y+(1-sa3)*r, + x+(1-ca2)*r, y+(1-sa2)*r); + + if(corners&2) // TR + gfx_quads_draw_freeform( + x+w-r, y+r, + x+w-r+ca1*r, y+(1-sa1)*r, + x+w-r+ca3*r, y+(1-sa3)*r, + x+w-r+ca2*r, y+(1-sa2)*r); + + if(corners&4) // BL + gfx_quads_draw_freeform( + x+r, y+h-r, + x+(1-ca1)*r, y+h-r+sa1*r, + x+(1-ca3)*r, y+h-r+sa3*r, + x+(1-ca2)*r, y+h-r+sa2*r); + + if(corners&8) // BR + gfx_quads_draw_freeform( + x+w-r, y+h-r, + x+w-r+ca1*r, y+h-r+sa1*r, + x+w-r+ca3*r, y+h-r+sa3*r, + x+w-r+ca2*r, y+h-r+sa2*r); + } + + gfx_quads_drawTL(x+r, y+r, w-r*2, h-r*2); // center + gfx_quads_drawTL(x+r, y, w-r*2, r); // top + gfx_quads_drawTL(x+r, y+h-r, w-r*2, r); // bottom + gfx_quads_drawTL(x, y+r, r, h-r*2); // left + gfx_quads_drawTL(x+w-r, y+r, r, h-r*2); // right + + if(!(corners&1)) gfx_quads_drawTL(x, y, r, r); // TL + if(!(corners&2)) gfx_quads_drawTL(x+w, y, -r, r); // TR + if(!(corners&4)) gfx_quads_drawTL(x, y+h, r, -r); // BL + if(!(corners&8)) gfx_quads_drawTL(x+w, y+h, -r, -r); // BR +} + +void draw_round_rect(float x, float y, float w, float h, float r) +{ + draw_round_rect_ext(x,y,w,h,r,0xf); +} + + +static void render_player( + const obj_player_character *prev_char, + const obj_player_character *player_char, + const obj_player_info *prev_info, + const obj_player_info *player_info + ) +{ + obj_player_character prev; + obj_player_character player; + prev = *prev_char; + player = *player_char; + + obj_player_info info = *player_info; + + float intratick = client_intratick(); + + if(player.health < 0) // dont render dead players + return; + + if(info.local && config.cl_predict) + { + if(!local_character || (local_character->health < 0) || (gameobj && gameobj->game_over)) + { + } + else + { + // apply predicted results + predicted_player.write(&player); + predicted_prev_player.write(&prev); + intratick = client_intrapredtick(); + } + } + + // TODO: proper skin selection + int skin_id = client_datas[info.clientid].skin_id; //charids[info.clientid]; + //if(gametype != GAMETYPE_DM) + //skin_id = info.team*9; // 0 or 9 + + vec2 direction = get_direction(player.angle); + float angle = player.angle/256.0f; + vec2 position = mix(vec2(prev.x, prev.y), vec2(player.x, player.y), intratick); + + if(prev.health < 0) // Don't flicker from previous position + position = vec2(player.x, player.y); + + bool stationary = player.vx < 1 && player.vx > -1; + bool inair = col_check_point(player.x, player.y+16) == 0; + + // evaluate animation + float walk_time = fmod(position.x, 100.0f)/100.0f; + animstate state; + anim_eval(&data->animations[ANIM_BASE], 0, &state); + + if(inair) + anim_eval_add(&state, &data->animations[ANIM_INAIR], 0, 1.0f); // TODO: some sort of time here + else if(stationary) + anim_eval_add(&state, &data->animations[ANIM_IDLE], 0, 1.0f); // TODO: some sort of time here + else + anim_eval_add(&state, &data->animations[ANIM_WALK], walk_time, 1.0f); + + if (player.weapon == WEAPON_HAMMER) + { + float a = clamp((client_tick()-player.attacktick+intratick)/10.0f, 0.0f, 1.0f); + anim_eval_add(&state, &data->animations[ANIM_HAMMER_SWING], a, 1.0f); + } + if (player.weapon == WEAPON_NINJA) + { + float a = clamp((client_tick()-player.attacktick+intratick)/40.0f, 0.0f, 1.0f); + anim_eval_add(&state, &data->animations[ANIM_NINJA_SWING], a, 1.0f); + } + + // draw hook + if (prev.hook_state>0 && player.hook_state>0) + { + gfx_texture_set(data->images[IMAGE_GAME].id); + 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), intratick); + + float d = distance(pos, hook_pos); + vec2 dir = normalize(pos-hook_pos); + + gfx_quads_setrotation(get_angle(dir)+pi); + + // render head + select_sprite(SPRITE_HOOK_HEAD); + gfx_quads_draw(hook_pos.x, hook_pos.y, 24,16); + + // render chain + select_sprite(SPRITE_HOOK_CHAIN); + 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(); + + render_hand(skin_id, position, normalize(hook_pos-pos), -pi/2, vec2(20, 0)); + } + + // draw gun + { + gfx_texture_set(data->images[IMAGE_GAME].id); + gfx_quads_begin(); + gfx_quads_setrotation(state.attach.angle*pi*2+angle); + + // normal weapons + int iw = clamp(player.weapon, 0, NUM_WEAPONS-1); + select_sprite(data->weapons[iw].sprite_body, direction.x < 0 ? SPRITE_FLAG_FLIP_Y : 0); + + vec2 dir = direction; + float recoil = 0.0f; + vec2 p; + if (player.weapon == WEAPON_HAMMER) + { + // Static position for hammer + p = position; + p.y += data->weapons[iw].offsety; + // if attack is under way, bash stuffs + if(direction.x < 0) + { + gfx_quads_setrotation(-pi/2-state.attach.angle*pi*2); + p.x -= data->weapons[iw].offsetx; + } + else + { + gfx_quads_setrotation(-pi/2+state.attach.angle*pi*2); + } + draw_sprite(p.x, p.y, data->weapons[iw].visual_size); + } + else if (player.weapon == WEAPON_NINJA) + { + p = position; + p.y += data->weapons[iw].offsety; + + if(direction.x < 0) + { + gfx_quads_setrotation(-pi/2-state.attach.angle*pi*2); + p.x -= data->weapons[iw].offsetx; + } + else + { + gfx_quads_setrotation(-pi/2+state.attach.angle*pi*2); + } + draw_sprite(p.x, p.y, data->weapons[iw].visual_size); + + // HADOKEN + if ((client_tick()-player.attacktick) <= (SERVER_TICK_SPEED / 6) && data->weapons[iw].nummuzzlesprites) + { + int itex = rand() % data->weapons[iw].nummuzzlesprites; + float alpha = 1.0f; + if (alpha > 0.0f && data->weapons[iw].sprite_muzzle[itex].psprite) + { + vec2 dir = vec2(player_char->x,player_char->y) - vec2(prev_char->x, prev_char->y); + dir = normalize(dir); + float hadokenangle = get_angle(dir); + gfx_quads_setrotation(hadokenangle); + //float offsety = -data->weapons[iw].muzzleoffsety; + select_sprite(data->weapons[iw].sprite_muzzle[itex].psprite, 0); + vec2 diry(-dir.y,dir.x); + p = position; + float offsetx = data->weapons[iw].muzzleoffsetx; + p -= dir * offsetx; + draw_sprite(p.x, p.y, 160.0f); + } + } + } + else + { + // TODO: should be an animation + recoil = 0; + float a = (client_tick()-player.attacktick+intratick)/5.0f; + if(a < 1) + recoil = sinf(a*pi); + p = position + dir * data->weapons[iw].offsetx - dir*recoil*10.0f; + p.y += data->weapons[iw].offsety; + draw_sprite(p.x, p.y, data->weapons[iw].visual_size); + } + + if (player.weapon == WEAPON_GUN || player.weapon == WEAPON_SHOTGUN) + { + // check if we're firing stuff + if (true)//prev.attackticks) + { + float alpha = 0.0f; + int phase1tick = (client_tick() - player.attacktick); + if (phase1tick < (data->weapons[iw].muzzleduration + 3)) + { + float t = ((((float)phase1tick) + intratick)/(float)data->weapons[iw].muzzleduration); + alpha = LERP(2.0, 0.0f, min(1.0f,max(0.0f,t))); + } + + int itex = rand() % data->weapons[iw].nummuzzlesprites; + if (alpha > 0.0f && data->weapons[iw].sprite_muzzle[itex].psprite) + { + float offsety = -data->weapons[iw].muzzleoffsety; + select_sprite(data->weapons[iw].sprite_muzzle[itex].psprite, direction.x < 0 ? SPRITE_FLAG_FLIP_Y : 0); + if(direction.x < 0) + offsety = -offsety; + + vec2 diry(-dir.y,dir.x); + vec2 muzzlepos = p + dir * data->weapons[iw].muzzleoffsetx + diry * offsety; + + draw_sprite(muzzlepos.x, muzzlepos.y, data->weapons[iw].visual_size); + /*gfx_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,muzzleparams[player.weapon].sizex, muzzleparams[player.weapon].sizey);*/ + } + } + } + gfx_quads_end(); + + switch (player.weapon) + { + case WEAPON_GUN: render_hand(skin_id, p, direction, -3*pi/4, vec2(-15, 4)); break; + case WEAPON_SHOTGUN: render_hand(skin_id, p, direction, -pi/2, vec2(-5, 4)); break; + case WEAPON_ROCKET: render_hand(skin_id, p, direction, -pi/2, vec2(-4, 7)); break; + } + + } + + // render the "shadow" tee + if(info.local && config.debug) + { + vec2 ghost_position = mix(vec2(prev_char->x, prev_char->y), vec2(player_char->x, player_char->y), client_intratick()); + tee_render_info ghost = client_datas[info.clientid].skin_info; + ghost.color_body.a = 0.5f; + ghost.color_feet.a = 0.5f; + render_tee(&state, &ghost, player.emote, direction, ghost_position); // render ghost + } + + // render the tee + render_tee(&state, &client_datas[info.clientid].skin_info, player.emote, direction, position); + + if(player.state == STATE_CHATTING) + { + gfx_texture_set(data->images[IMAGE_EMOTICONS].id); + gfx_quads_begin(); + select_sprite(SPRITE_DOTDOT); + gfx_quads_draw(position.x + 24, position.y - 40, 64,64); + gfx_quads_end(); + } + + if (client_datas[info.clientid].emoticon_start != -1 && client_datas[info.clientid].emoticon_start + 2 * client_tickspeed() > client_tick()) + { + gfx_texture_set(data->images[IMAGE_EMOTICONS].id); + gfx_quads_begin(); + + int since_start = client_tick() - client_datas[info.clientid].emoticon_start; + int from_end = client_datas[info.clientid].emoticon_start + 2 * client_tickspeed() - client_tick(); + + float a = 1; + + if (from_end < client_tickspeed() / 5) + a = from_end / (client_tickspeed() / 5.0); + + float h = 1; + if (since_start < client_tickspeed() / 10) + h = since_start / (client_tickspeed() / 10.0); + + float wiggle = 0; + if (since_start < client_tickspeed() / 5) + wiggle = since_start / (client_tickspeed() / 5.0); + + float wiggle_angle = sin(5*wiggle); + + gfx_quads_setrotation(pi/6*wiggle_angle); + + gfx_setcolor(1.0f,1.0f,1.0f,a); + // client_datas::emoticon is an offset from the first emoticon + select_sprite(SPRITE_OOP + client_datas[info.clientid].emoticon); + gfx_quads_draw(position.x, position.y - 23 - 32*h, 64, 64*h); + gfx_quads_end(); + } + + // render name plate + if(!info.local && config.cl_nameplates) + { + //gfx_pretty_text_color + float a = 1; + if(config.cl_nameplates_always == 0) + a = clamp(1-powf(distance(local_target_pos, position)/200.0f,16.0f), 0.0f, 1.0f); + + const char *name = client_datas[info.clientid].name; + float tw = gfx_pretty_text_width(28.0f, name, -1); + gfx_pretty_text_color(1,1,1,a); + gfx_pretty_text(position.x-tw/2.0f, position.y-60, 28.0f, name, -1); + gfx_pretty_text_color(1,1,1,1); + } +} + +void render_moon(float x, float y) +{ + gfx_texture_set(data->images[IMAGE_MOON].id); + gfx_quads_begin(); + gfx_quads_draw(x, y, 512, 512); + gfx_quads_end(); +} + +void render_stars() +{ + struct star + { + vec2 p; + float tingle; + float rot; + float size; + }; + + static const int NUM_STARS = 100; + static star stars[NUM_STARS]; + static bool init = true; + if(init) + { + for(int i = 0; i < NUM_STARS; i++) + { + stars[i].p.x = (frandom()-0.5f)*800*3; + stars[i].p.y = (frandom()-0.5f)*600*3; + stars[i].tingle = frandom(); + stars[i].rot = frandom()*pi; + stars[i].size = 10.0f+frandom()*10.0f; + } + + init = false; + } + + int64 now = time_get(); + int64 freq = time_freq()*5; + float t = (now%freq)/(float)freq; + gfx_texture_set(data->images[IMAGE_STARS].id); + gfx_quads_begin(); + gfx_quads_setsubset(0,0,0.5f,1); + for(int i = 0; i < NUM_STARS; i++) + { + float a = fmod(t+stars[i].tingle, 1.0f); + gfx_quads_setrotation(stars[i].rot); + gfx_setcolor(1,1,1,0.25f+sinf(a*pi)*0.75f); + gfx_quads_draw(stars[i].p.x, stars[i].p.y, stars[i].size, stars[i].size); + } + + gfx_quads_end(); +} + +void render_snow() +{ + vec2 tl, br; + gfx_getscreen(&tl.x, &tl.y, &br.x, &br.y); + tl.x += 1000; // this is here to fix positions below 0,0 + tl.y += 1000; + br.x += 1000; + br.y += 1000; + + struct flake + { + vec2 p; + float tingle; + float rot; + float size; + float yspeed; + float xspeed; + }; + + static const int NUM_FLAKES = 100; + static flake flakes[NUM_FLAKES]; + static bool init = true; + + float w = br.x-tl.x; + float h = br.y-tl.y; + + if(init) + { + for(int i = 0; i < NUM_FLAKES; i++) + { + flakes[i].p.x = frandom()*w; + flakes[i].p.y = frandom()*h; + flakes[i].tingle = frandom(); + flakes[i].rot = frandom()*pi; + flakes[i].size = 50.0f+frandom()*10.0f; + flakes[i].yspeed = 50+frandom()*20.0f; + flakes[i].xspeed = flakes[i].yspeed * (0.4+frandom()*0.4f); + } + + init = false; + } + + int basex = (int)(tl.x/w); + float splitx = tl.x-basex*w; + int basey = (int)(tl.y/h); + float splity = tl.y-basey*h; + + float f = client_frametime(); + gfx_texture_set(data->images[IMAGE_SNOW].id); + gfx_quads_begin(); + for(int i = 0; i < NUM_FLAKES; i++) + { + flakes[i].p.x -= f*flakes[i].xspeed; + flakes[i].p.y += f*flakes[i].yspeed; + if(flakes[i].p.x < 0) + flakes[i].p.x += w; + if(flakes[i].p.y > h) + flakes[i].p.y -= h; + + float x = flakes[i].p.x + basex*w; + float y = flakes[i].p.y + basey*h; + + if(flakes[i].p.x < splitx) + x += w; + if(flakes[i].p.y < splity) + y += h; + + x -= 1000; + y -= 1000; + + gfx_quads_setrotation(flakes[i].rot); + gfx_quads_draw(x, y, flakes[i].size, flakes[i].size); + } + + gfx_quads_end(); +} + +void render_sun(float x, float y) +{ + vec2 pos(x, y); + + gfx_texture_set(-1); + gfx_blend_additive(); + gfx_quads_begin(); + const int rays = 10; + gfx_setcolor(1.0f,1.0f,1.0f,0.025f); + for(int r = 0; r < rays; r++) + { + float a = r/(float)rays + client_localtime()*0.025f; + 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_setcolorvertex(0, 1.0f,1.0f,1.0f,0.025f); + gfx_setcolorvertex(1, 1.0f,1.0f,1.0f,0.025f); + gfx_setcolorvertex(2, 1.0f,1.0f,1.0f,0.0f); + gfx_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(data->images[IMAGE_SUN].id); + gfx_quads_begin(); + gfx_quads_draw(pos.x, pos.y, 256, 256); + gfx_quads_end(); +} + +static vec2 emoticon_selector_mouse; + +void emoticon_selector_reset() +{ + emoticon_selector_mouse = vec2(0, 0); +} + +int emoticon_selector_render() +{ + int x, y; + inp_mouse_relative(&x, &y); + + emoticon_selector_mouse.x += x; + emoticon_selector_mouse.y += y; + + if (length(emoticon_selector_mouse) > 140) + emoticon_selector_mouse = normalize(emoticon_selector_mouse) * 140; + + float selected_angle = get_angle(emoticon_selector_mouse) + 2*pi/24; + if (selected_angle < 0) + selected_angle += 2*pi; + + bool return_now = false; + int selected_emoticon = -1; + + if (length(emoticon_selector_mouse) > 100) + selected_emoticon = (int)(selected_angle / (2*pi) * 12.0f); + + if(!inp_key_pressed(config.key_emoticon)) + { + return_now = true; + emoticon_selector_active = false; + } + + RECT screen = *ui2_screen(); + + gfx_mapscreen(screen.x, screen.y, screen.w, screen.h); + + gfx_blend_normal(); + + gfx_texture_set(-1); + gfx_quads_begin(); + gfx_setcolor(0,0,0,0.3f); + draw_circle(screen.w/2, screen.h/2, 160, 64); + gfx_quads_end(); + + gfx_texture_set(data->images[IMAGE_EMOTICONS].id); + gfx_quads_begin(); + + for (int i = 0; i < 12; i++) + { + float angle = 2*pi*i/12.0; + if (angle > pi) + angle -= 2*pi; + + bool selected = selected_emoticon == i; + + float size = selected ? 96 : 64; + + float nudge_x = 120 * cos(angle); + float nudge_y = 120 * sin(angle); + select_sprite(SPRITE_OOP + i); + gfx_quads_draw(screen.w/2 + nudge_x, screen.h/2 + nudge_y, size, size); + } + + gfx_quads_end(); + + gfx_texture_set(data->images[IMAGE_CURSOR].id); + gfx_quads_begin(); + gfx_setcolor(1,1,1,1); + gfx_quads_drawTL(emoticon_selector_mouse.x+screen.w/2,emoticon_selector_mouse.y+screen.h/2,24,24); + gfx_quads_end(); + + return return_now ? selected_emoticon : -1; +} + +void render_goals(float x, float y, float w) +{ + float h = 50.0f; + + gfx_blend_normal(); + gfx_texture_set(-1); + gfx_quads_begin(); + gfx_setcolor(0,0,0,0.5f); + draw_round_rect(x-10.f, y-10.f, w, h, 10.0f); + gfx_quads_end(); + + // render goals + //y = ystart+h-54; + if(gameobj && gameobj->time_limit) + { + char buf[64]; + sprintf(buf, "Time Limit: %d min", gameobj->time_limit); + gfx_pretty_text(x+w/2, y, 32, buf, -1); + } + if(gameobj && gameobj->score_limit) + { + char buf[64]; + sprintf(buf, "Score Limit: %d", gameobj->score_limit); + gfx_pretty_text(x+40, y, 32, buf, -1); + } + +} + +void render_scoreboard(float x, float y, float w, int team, const char *title) +{ + //float w = 550.0f; + //float x = width/2-w/2; + //; + //float y = ystart; + //float w = 550.0f; + + animstate idlestate; + anim_eval(&data->animations[ANIM_BASE], 0, &idlestate); + anim_eval_add(&idlestate, &data->animations[ANIM_IDLE], 0, 1.0f); + + //float ystart = y; + float h = 600.0f; + + gfx_blend_normal(); + gfx_texture_set(-1); + gfx_quads_begin(); + gfx_setcolor(0,0,0,0.5f); + draw_round_rect(x-10.f, y-10.f, w, h, 40.0f); + gfx_quads_end(); + + // render title + if(!title) + { + if(gameobj->game_over) + title = "Game Over"; + else + title = "Score Board"; + } + + float tw = gfx_pretty_text_width( 64, title, -1); + + if(team == -1) + { + gfx_pretty_text(x+w/2-tw/2, y, 64, title, -1); + } + else + { + gfx_pretty_text(x+10, y, 64, title, -1); + + if(gameobj) + { + char buf[128]; + sprintf(buf, "%d", gameobj->teamscore[team&1]); + tw = gfx_pretty_text_width(64, buf, -1); + gfx_pretty_text(x+w-tw-40, y, 64, buf, -1); + } + } + + y += 64.0f; + + /* + if(team) + { + char buf[128]; + sprintf(buf, "%4d", gameobj->teamscore[team&1]); + gfx_pretty_text(x+w/2-tw/2, y, 32, buf, -1); + }*/ + + + // find players + const obj_player_info *players[MAX_CLIENTS] = {0}; + int num_players = 0; + for(int i = 0; i < snap_num_items(SNAP_CURRENT); i++) + { + SNAP_ITEM item; + const void *data = snap_get_item(SNAP_CURRENT, i, &item); + + if(item.type == OBJTYPE_PLAYER_INFO) + { + players[num_players] = (const obj_player_info *)data; + num_players++; + } + } + + // sort players + for(int k = 0; k < num_players; k++) // ffs, bubblesort + { + for(int i = 0; i < num_players-k-1; i++) + { + if(players[i]->score < players[i+1]->score) + { + const obj_player_info *tmp = players[i]; + players[i] = players[i+1]; + players[i+1] = tmp; + } + } + } + + // render headlines + gfx_pretty_text(x+10, y, 32, "Score", -1); + gfx_pretty_text(x+125, y, 32, "Name", -1); + gfx_pretty_text(x+w-70, y, 32, "Ping", -1); + y += 38.0f; + + // render player scores + for(int i = 0; i < num_players; i++) + { + const obj_player_info *info = players[i]; + + // make sure that we render the correct team + if(team != -1 && info->team != team) + continue; + + char buf[128]; + float font_size = 46.0f; + if(info->local) + { + // background so it's easy to find the local player + gfx_texture_set(-1); + gfx_quads_begin(); + gfx_setcolor(1,1,1,0.25f); + draw_round_rect(x, y, w-20, 48, 20.0f); + gfx_quads_end(); + } + + sprintf(buf, "%4d", info->score); + gfx_pretty_text(x+60-gfx_pretty_text_width(font_size,buf,-1), y, font_size, buf, -1); + gfx_pretty_text(x+128, y, font_size, client_datas[info->clientid].name, -1); + + sprintf(buf, "%4d", info->latency); + float tw = gfx_pretty_text_width(font_size, buf, -1); + gfx_pretty_text(x+w-tw-35, y, font_size, buf, -1); + + // render avatar + render_tee(&idlestate, &client_datas[info->clientid].skin_info, EMOTE_NORMAL, vec2(1,0), vec2(x+90, y+28)); + y += 50.0f; + } +} + +void mapscreen_to_world(float center_x, float center_y, float zoom) +{ + RECT screen = *ui2_screen(); + + const float default_zoom = 1.5f; + float width = screen.w*default_zoom*zoom; + float height = screen.h*default_zoom*zoom; + gfx_mapscreen(center_x-width/2, center_y-height/2, center_x+width/2, center_y+height/2); +} + +// renders the complete game world +void render_world(float center_x, float center_y, float zoom) +{ + mapscreen_to_world(center_x, center_y, zoom); + //gfx_mapscreen(center_x-width/2, center_y-height/2, center_x+width/2, center_y+height/2); + + // render background environment + int theme_id = 0; + mapres_theme *t = (mapres_theme *)map_find_item(MAPRES_TEMP_THEME, 0); + if(t) + theme_id = t->id; + + if(config.gfx_high_detail) + { + if(theme_id == 1) + { + // Winter night + gfx_mapscreen(0,0,1,1); + gfx_texture_set(-1); + gfx_quads_begin(); + vec4 top(0x11/(float)0xff, 0x1a/(float)0xff, 0x21/(float)0xff, 1.0f); + vec4 bottom(0x2a/(float)0xff, 0x40/(float)0xff, 0x52/(float)0xff, 1.0f); + gfx_setcolorvertex(0, top.r, top.g, top.b, top.a); + gfx_setcolorvertex(1, top.r, top.g, top.b, top.a); + gfx_setcolorvertex(2, bottom.r, bottom.g, bottom.b, bottom.a); + gfx_setcolorvertex(3, bottom.r, bottom.g, bottom.b, bottom.a); + gfx_quads_drawTL(0, 0, 1, 1); + gfx_quads_end(); + + mapscreen_to_world(center_x*0.1f, center_y*0.1f, zoom); + render_stars(); + + mapscreen_to_world(center_x, center_y, zoom); + + render_moon(center_x*0.8f, center_y*0.8f); + + mapscreen_to_world(center_x, center_y, zoom); + } + else + { + // Summer day + render_sun(20+center_x*0.6f, 20+center_y*0.6f); + + // draw clouds + static vec2 cloud_pos[6] = {vec2(-500,0),vec2(-500,200),vec2(-500,400)}; + static float cloud_speed[6] = {30, 20, 10}; + static int cloud_sprites[6] = {SPRITE_CLOUD1, SPRITE_CLOUD2, SPRITE_CLOUD3}; + + gfx_texture_set(data->images[IMAGE_CLOUDS].id); + gfx_quads_begin(); + for(int i = 0; i < 3; i++) + { + float parallax_amount = 0.55f; + select_sprite(cloud_sprites[i]); + draw_sprite((cloud_pos[i].x+fmod(client_localtime()*cloud_speed[i]+i*100.0f, 3000.0f))+center_x*parallax_amount, + cloud_pos[i].y+center_y*parallax_amount, 300); + } + gfx_quads_end(); + + // draw backdrop + gfx_texture_set(data->images[IMAGE_BACKDROP].id); + gfx_quads_begin(); + float parallax_amount = 0.25f; + for(int x = -1; x < 3; x++) + gfx_quads_drawTL(1024*x+center_x*parallax_amount, (center_y)*parallax_amount+150+512, 1024, 512); + gfx_quads_end(); + } + } + + // render background tilemaps + tilemap_render(32.0f, 0); + + // render items + { + int num = snap_num_items(SNAP_CURRENT); + for(int i = 0; i < num; i++) + { + SNAP_ITEM item; + const void *data = snap_get_item(SNAP_CURRENT, i, &item); + + if(item.type == OBJTYPE_PROJECTILE) + { + const void *prev = snap_find_item(SNAP_PREV, item.type, item.id); + if(prev) + render_projectile((const obj_projectile *)prev, (const obj_projectile *)data, item.id); + } + else if(item.type == OBJTYPE_POWERUP) + { + const void *prev = snap_find_item(SNAP_PREV, item.type, item.id); + if(prev) + render_powerup((const obj_powerup *)prev, (const obj_powerup *)data); + } + else if(item.type == OBJTYPE_FLAG) + { + const void *prev = snap_find_item(SNAP_PREV, item.type, item.id); + if (prev) + render_flag((const obj_flag *)prev, (const obj_flag *)data); + } + } + } + + // render players above all + { + int num = snap_num_items(SNAP_CURRENT); + for(int i = 0; i < num; i++) + { + SNAP_ITEM item; + const void *data = snap_get_item(SNAP_CURRENT, i, &item); + + if(item.type == OBJTYPE_PLAYER_CHARACTER) + { + const void *prev = snap_find_item(SNAP_PREV, item.type, item.id); + const void *prev_info = snap_find_item(SNAP_PREV, OBJTYPE_PLAYER_INFO, item.id); + const void *info = snap_find_item(SNAP_CURRENT, OBJTYPE_PLAYER_INFO, item.id); + if(prev && prev_info && info) + { + client_datas[((const obj_player_info *)info)->clientid].team = ((const obj_player_info *)info)->team; + render_player( + (const obj_player_character *)prev, + (const obj_player_character *)data, + (const obj_player_info *)prev_info, + (const obj_player_info *)info + ); + } + } + } + } + + // render particles + temp_system.update(client_frametime()); + temp_system.render(); + + // render foreground tilemaps + tilemap_render(32.0f, 1); + + // render front environment effects + if(config.gfx_high_detail) + { + if(theme_id == 1) + { + //mapscreen_to_world(center_x, center_y, zoom); + render_snow(); + } + } + + // render damage indications + damageind.render(); +} + +static void do_input(int *v, int key) +{ + *v += inp_key_presses(key) + inp_key_releases(key); + if((*v&1) != inp_key_state(key)) + (*v)++; + *v &= INPUT_STATE_MASK; +} + +void render_game() +{ + float width = 400*3.0f; + float height = 300*3.0f; + + bool spectate = false; + + if(config.cl_predict) + { + if(!local_character || (local_character->health < 0) || (gameobj && gameobj->game_over)) + { + // don't use predicted + } + else + local_character_pos = mix(predicted_prev_player.pos, predicted_player.pos, client_intrapredtick()); + } + else if(local_character && local_prev_character) + { + local_character_pos = mix( + vec2(local_prev_character->x, local_prev_character->y), + vec2(local_character->x, local_character->y), client_intratick()); + } + + if(local_info && local_info->team == -1) + spectate = true; + + animstate idlestate; + anim_eval(&data->animations[ANIM_BASE], 0, &idlestate); + anim_eval_add(&idlestate, &data->animations[ANIM_IDLE], 0, 1.0f); + + if (inp_key_down(KEY_ESC)) + { + if (chat_mode) + chat_mode = CHATMODE_NONE; + else + { + menu_active = !menu_active; + if(menu_active) + menu_game_active = true; + } + } + + // make sure to send our info again if the menu closes + static bool menu_was_active = false; + if(menu_active) + menu_was_active = true; + else if(menu_was_active) + { + send_info(false); + menu_was_active = false; + } + + // handle chat input + if (!menu_active) + { + if(chat_mode != CHATMODE_NONE) + { + if(inp_key_down(KEY_ENTER)) + { + // send message + if(chat_input_len) + { + if(chat_mode == CHATMODE_CONSOLE) + config_set(chat_input); + else if(chat_mode == CHATMODE_REMOTECONSOLE) + client_rcon(chat_input); + else + { + // send chat message + msg_pack_start(MSG_SAY, MSGFLAG_VITAL); + if(chat_mode == CHATMODE_ALL) + msg_pack_int(0); + else + msg_pack_int(1); + msg_pack_string(chat_input, 512); + msg_pack_end(); + client_send_msg(); + } + } + + chat_mode = CHATMODE_NONE; + } + + int c = inp_last_char(); + int k = inp_last_key(); + + if (!(c >= 0 && c < 32)) + { + if (chat_input_len < sizeof(chat_input) - 1) + { + chat_input[chat_input_len] = c; + chat_input[chat_input_len+1] = 0; + chat_input_len++; + } + } + + if(k == KEY_BACKSPACE) + { + if(chat_input_len > 0) + { + chat_input[chat_input_len-1] = 0; + chat_input_len--; + } + } + + } + else + { + if(chat_mode == CHATMODE_NONE) + { + if(inp_key_down(config.key_chat)) + chat_mode = CHATMODE_ALL; + + if(inp_key_down(config.key_teamchat)) + chat_mode = CHATMODE_TEAM; + + if(inp_key_down(config.key_console)) + chat_mode = CHATMODE_CONSOLE; + + if(inp_key_down(config.key_remoteconsole)) + chat_mode = CHATMODE_REMOTECONSOLE; + + if(chat_mode != CHATMODE_NONE) + { + mem_zero(chat_input, sizeof(chat_input)); + chat_input_len = 0; + } + } + } + } + + if (!menu_active) + inp_clear(); + + // fetch new input + if(!menu_active && !emoticon_selector_active) + { + int x, y; + inp_mouse_relative(&x, &y); + mouse_pos += vec2(x, y); + if(!spectate) + { + float l = length(mouse_pos); + if(l > 600.0f) + mouse_pos = normalize(mouse_pos)*600.0f; + } + } + + // set listner pos + if(spectate) + { + local_target_pos = mouse_pos; + snd_set_listener_pos(mouse_pos.x, mouse_pos.y); + } + else + { + local_target_pos = local_character_pos + mouse_pos; + snd_set_listener_pos(local_character_pos.x, local_character_pos.y); + } + + // snap input + { + static player_input input = {0}; + + input.target_x = (int)mouse_pos.x; + input.target_y = (int)mouse_pos.y; + + if(chat_mode != CHATMODE_NONE) + input.state = STATE_CHATTING; + else if(menu_active) + input.state = STATE_IN_MENU; + else + { + input.state = STATE_PLAYING; + input.left = inp_key_state(config.key_move_left); + input.right = inp_key_state(config.key_move_right); + input.hook = inp_key_state(config.key_hook); + input.jump = inp_key_state(config.key_jump); + + if(!emoticon_selector_active) + do_input(&input.fire, config.key_fire); + + // weapon selection + do_input(&input.next_weapon, config.key_next_weapon); + do_input(&input.prev_weapon, config.key_prev_weapon); + + if(inp_key_presses(config.key_next_weapon) || inp_key_presses(config.key_prev_weapon)) + input.wanted_weapon = 0; + else if (config.cl_autoswitch_weapons && picked_up_weapon) + { + input.wanted_weapon = picked_up_weapon; + } + else + { + if(inp_key_presses(config.key_weapon1)) input.wanted_weapon = 1; + if(inp_key_presses(config.key_weapon2)) input.wanted_weapon = 2; + if(inp_key_presses(config.key_weapon3)) input.wanted_weapon = 3; + if(inp_key_presses(config.key_weapon4)) input.wanted_weapon = 4; + if(inp_key_presses(config.key_weapon5)) input.wanted_weapon = 5; + if(inp_key_presses(config.key_weapon6)) input.wanted_weapon = 6; + } + + picked_up_weapon = 0; + } + + // stress testing + if(config.dbg_stress) + { + float t = client_localtime(); + mem_zero(&input, sizeof(input)); + + input.left = ((int)t/2)&1; + input.right = ((int)t/2+1)&1; + input.jump = ((int)t); + input.fire = ((int)(t*10)); + input.hook = ((int)(t*2))&1; + input.wanted_weapon = ((int)t)%NUM_WEAPONS; + input.target_x = (int)(sinf(t*3)*100.0f); + input.target_y = (int)(cosf(t*3)*100.0f); + } + + snap_input(&input, sizeof(input)); + } + + // center at char but can be moved when mouse is far away + float offx = 0, offy = 0; + if (config.cl_dynamic_camera) + { + 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; + } + + // render the world + gfx_clear(0.65f,0.78f,0.9f); + if(spectate) + render_world(mouse_pos.x, mouse_pos.y, 1.0f); + else + { + render_world(local_character_pos.x+offx, local_character_pos.y+offy, 1.0f); + + // draw screen box + if(0) + { + gfx_texture_set(-1); + gfx_blend_normal(); + gfx_lines_begin(); + float cx = local_character_pos.x+offx; + float cy = local_character_pos.y+offy; + float w = 400*3/2; + float h = 300*3/2; + gfx_lines_draw(cx-w,cy-h,cx+w,cy-h); + gfx_lines_draw(cx+w,cy-h,cx+w,cy+h); + gfx_lines_draw(cx+w,cy+h,cx-w,cy+h); + gfx_lines_draw(cx-w,cy+h,cx-w,cy-h); + gfx_lines_end(); + } + } + + + // pseudo format + // ZOOM ZOOM + float zoom = 3.0; + if(local_character) + cl_effects.getzoom(client_tick(), client_intratick(), local_character); + + // DEBUG TESTING + if(zoom > 3.01f) + { + gfx_clear_mask(0); + + gfx_texture_set(-1); + gfx_blend_normal(); + + gfx_mask_op(MASK_NONE, 1); + + gfx_quads_begin(); + gfx_setcolor(0.65f,0.78f,0.9f,1.0f); + + float fov; + if (zoom > 3.01f) + fov = pi * (zoom - 3.0f) / 6.0f; + else + fov = pi / 6.0f; + + float fade = 0.7f; + + + float a = get_angle(normalize(vec2(mouse_pos.x, mouse_pos.y))); + vec2 d = get_dir(a); + vec2 d0 = get_dir(a-fov/2.0f); + vec2 d1 = get_dir(a+fov/2.0f); + + vec2 cd0 = get_dir(a-(fov*fade)/2.0f); // center direction + vec2 cd1 = get_dir(a+(fov*fade)/2.0f); + + vec2 p0n = local_character_pos + d0*32.0f; + vec2 p1n = local_character_pos + d1*32.0f; + vec2 p0f = local_character_pos + d0*1000.0f; + vec2 p1f = local_character_pos + d1*1000.0f; + + vec2 cn = local_character_pos + d*32.0f; + vec2 cf = local_character_pos + d*1000.0f; + + vec2 cp0n = local_character_pos + cd0*32.0f; + vec2 cp0f = local_character_pos + cd0*1000.0f; + vec2 cp1n = local_character_pos + cd1*32.0f; + vec2 cp1f = local_character_pos + cd1*1000.0f; + + gfx_quads_draw_freeform( + p0n.x,p0n.y, + p1n.x,p1n.y, + p0f.x,p0f.y, + p1f.x,p1f.y); + gfx_quads_end(); + + gfx_mask_op(MASK_SET, 0); + + render_world(local_character_pos.x+offx, local_character_pos.y+offy, 2.0f); + + gfx_mask_op(MASK_NONE, 0); + + mapscreen_to_world(local_character_pos.x+offx, local_character_pos.y+offy, 1.0f); + + gfx_texture_set(-1); + gfx_blend_normal(); + gfx_quads_begin(); + gfx_setcolor(0.5f,0.9f,0.5f,0.25f); + float r=0.5f, g=1.0f, b=0.5f; + float r2=r*0.25f, g2=g*0.25f, b2=b*0.25f; + + gfx_setcolor(r,g,b,0.2f); + gfx_quads_draw_freeform( + cn.x,cn.y, + cn.x,cn.y, + cp0f.x,cp0f.y, + cp1f.x,cp1f.y); + + gfx_setcolorvertex(0, r, g, b, 0.2f); + gfx_setcolorvertex(1, r2, g2, b2, 0.9f); + gfx_setcolorvertex(2, r, g, b, 0.2f); + gfx_setcolorvertex(3, r2, g2, b2, 0.9f); + gfx_quads_draw_freeform( + cn.x,cn.y, + p0n.x,p0n.y, + cp0f.x,cp0f.y, + p0f.x,p0f.y); + + gfx_quads_draw_freeform( + cn.x,cn.y, + p1n.x,p1n.y, + cp1f.x,cp1f.y, + p1f.x,p1f.y); + + gfx_quads_end(); + } + + if(local_character && !spectate && !(gameobj && gameobj->game_over)) + { + gfx_texture_set(data->images[IMAGE_GAME].id); + gfx_quads_begin(); + + // render cursor + if (!menu_active && !emoticon_selector_active) + { + select_sprite(data->weapons[local_character->weapon%data->num_weapons].sprite_cursor); + float cursorsize = 64; + draw_sprite(local_target_pos.x, local_target_pos.y, cursorsize); + } + + float x = 5; + float y = 5; + + // render ammo count + // render gui stuff + gfx_quads_end(); + gfx_quads_begin(); + gfx_mapscreen(0,0,400,300); + // if weaponstage is active, put a "glow" around the stage ammo + select_sprite(SPRITE_TEE_BODY); + for (int i = 0; i < local_character->weaponstage; i++) + gfx_quads_drawTL(x+local_character->ammocount * 12 -i*12, y+22, 11, 11); + select_sprite(data->weapons[local_character->weapon%data->num_weapons].sprite_proj); + for (int i = 0; i < local_character->ammocount; i++) + gfx_quads_drawTL(x+i*12,y+24,10,10); + + gfx_quads_end(); + + gfx_texture_set(data->images[IMAGE_GAME].id); + gfx_quads_begin(); + int h = 0; + + // render health + select_sprite(SPRITE_HEALTH_FULL); + for(; h < local_character->health; h++) + gfx_quads_drawTL(x+h*12,y,10,10); + + select_sprite(SPRITE_HEALTH_EMPTY); + for(; h < 10; h++) + gfx_quads_drawTL(x+h*12,y,10,10); + + // render armor meter + h = 0; + select_sprite(SPRITE_ARMOR_FULL); + for(; h < local_character->armor; h++) + gfx_quads_drawTL(x+h*12,y+12,10,10); + + select_sprite(SPRITE_ARMOR_EMPTY); + for(; h < 10; h++) + gfx_quads_drawTL(x+h*12,y+12,10,10); + gfx_quads_end(); + } + + // render kill messages + { + gfx_mapscreen(0, 0, width*1.5f, height*1.5f); + float startx = width*1.5f-10.0f; + float y = 20.0f; + + for(int i = 0; i < killmsg_max; i++) + { + + int r = (killmsg_current+i+1)%killmsg_max; + if(client_tick() > killmsgs[r].tick+50*10) + continue; + + float font_size = 48.0f; + float killername_w = gfx_pretty_text_width(font_size, client_datas[killmsgs[r].killer].name, -1); + float victimname_w = gfx_pretty_text_width(font_size, client_datas[killmsgs[r].victim].name, -1); + + float x = startx; + + // render victim name + x -= victimname_w; + gfx_pretty_text(x, y, font_size, client_datas[killmsgs[r].victim].name, -1); + + // render victim tee + x -= 24.0f; + + if(gameobj && gameobj->gametype == GAMETYPE_CTF) + { + if(killmsgs[r].mode_special&1) + { + gfx_blend_normal(); + gfx_texture_set(data->images[IMAGE_GAME].id); + gfx_quads_begin(); + + if(client_datas[killmsgs[r].victim].team == 0) select_sprite(SPRITE_FLAG_BLUE); + else select_sprite(SPRITE_FLAG_RED); + + float size = 56.0f; + gfx_quads_drawTL(x, y-16, size/2, size); + gfx_quads_end(); + } + } + + render_tee(&idlestate, &client_datas[killmsgs[r].victim].skin_info, EMOTE_PAIN, vec2(-1,0), vec2(x, y+28)); + x -= 32.0f; + + // render weapon + x -= 44.0f; + if (killmsgs[r].weapon >= 0) + { + gfx_texture_set(data->images[IMAGE_GAME].id); + gfx_quads_begin(); + select_sprite(data->weapons[killmsgs[r].weapon].sprite_body); + draw_sprite(x, y+28, 96); + gfx_quads_end(); + } + x -= 52.0f; + + if(killmsgs[r].victim != killmsgs[r].killer) + { + if(gameobj && gameobj->gametype == GAMETYPE_CTF) + { + if(killmsgs[r].mode_special&2) + { + gfx_blend_normal(); + gfx_texture_set(data->images[IMAGE_GAME].id); + gfx_quads_begin(); + + if(client_datas[killmsgs[r].killer].team == 0) select_sprite(SPRITE_FLAG_BLUE, SPRITE_FLAG_FLIP_X); + else select_sprite(SPRITE_FLAG_RED, SPRITE_FLAG_FLIP_X); + + float size = 56.0f; + gfx_quads_drawTL(x-56, y-16, size/2, size); + gfx_quads_end(); + } + } + + // render killer tee + x -= 24.0f; + render_tee(&idlestate, &client_datas[killmsgs[r].killer].skin_info, EMOTE_ANGRY, vec2(1,0), vec2(x, y+28)); + x -= 32.0f; + + // render killer name + x -= killername_w; + gfx_pretty_text(x, y, font_size, client_datas[killmsgs[r].killer].name, -1); + } + + y += 44; + } + } + + // render chat + { + gfx_mapscreen(0,0,400,300); + float x = 10.0f; + float y = 300.0f-50.0f; + float starty = -1; + if(chat_mode != CHATMODE_NONE) + { + // render chat input + char buf[sizeof(chat_input)+16]; + if(chat_mode == CHATMODE_ALL) + sprintf(buf, "All: %s_", chat_input); + else if(chat_mode == CHATMODE_TEAM) + sprintf(buf, "Team: %s_", chat_input); + else if(chat_mode == CHATMODE_CONSOLE) + sprintf(buf, "Console: %s_", chat_input); + else if(chat_mode == CHATMODE_REMOTECONSOLE) + sprintf(buf, "Rcon: %s_", chat_input); + else + sprintf(buf, "Chat: %s_", chat_input); + gfx_pretty_text(x, y, 10.0f, buf, 380); + starty = y; + } + + y -= 10; + + int i; + for(i = 0; i < chat_max_lines; i++) + { + int r = ((chat_current_line-i)+chat_max_lines)%chat_max_lines; + if(client_tick() > chat_lines[r].tick+50*15) + break; + + int lines = int(gfx_pretty_text_width(10, chat_lines[r].text, -1)) / 380 + 1; + + gfx_pretty_text_color(1,1,1,1); + if(chat_lines[r].client_id == -1) + gfx_pretty_text_color(1,1,0.5f,1); // system + else if(chat_lines[r].team) + gfx_pretty_text_color(0.5f,1,0.5f,1); // team message + + gfx_pretty_text(x, y - 8 * (lines - 1), 10, chat_lines[r].text, 380); + y -= 8 * lines; + } + + gfx_pretty_text_color(1,1,1,1); + } + + // render goals + if(gameobj) + { + gametype = gameobj->gametype; + gfx_mapscreen(0,0,400,300); + if(!gameobj->sudden_death) + { + char buf[32]; + int time = 0; + if(gameobj->time_limit) + { + time = gameobj->time_limit*60 - ((client_tick()-gameobj->round_start_tick)/client_tickspeed()); + + if(gameobj->game_over) + time = 0; + } + else + time = (client_tick()-gameobj->round_start_tick)/client_tickspeed(); + + sprintf(buf, "%d:%02d", time /60, time %60); + float w = gfx_pretty_text_width(16, buf, -1); + gfx_pretty_text(200-w/2, 2, 16, buf, -1); + } + + if(gameobj->sudden_death) + { + const char *text = "Sudden Death"; + float w = gfx_pretty_text_width(16, text, -1); + gfx_pretty_text(200-w/2, 2, 16, text, -1); + } + + // render small score hud + if(!(gameobj && gameobj->game_over) && (gametype == GAMETYPE_TDM || gametype == GAMETYPE_CTF)) + { + for(int t = 0; t < 2; t++) + { + gfx_blend_normal(); + gfx_texture_set(-1); + gfx_quads_begin(); + if(t == 0) + gfx_setcolor(1,0,0,0.25f); + else + gfx_setcolor(0,0,1,0.25f); + draw_round_rect(400-40, 300-40-15+t*20, 50, 18, 5.0f); + gfx_quads_end(); + + char buf[32]; + sprintf(buf, "%d", gameobj->teamscore[t]); + float w = gfx_pretty_text_width(14, buf, -1); + + if(gametype == GAMETYPE_CTF) + { + gfx_pretty_text(400-20-w/2+5, 300-40-15+t*20+2, 14, buf, -1); + if(flags[t]) + { + if(flags[t]->carried_by == -2 || (flags[t]->carried_by == -1 && ((client_tick()/10)&1))) + { + gfx_blend_normal(); + gfx_texture_set(data->images[IMAGE_GAME].id); + gfx_quads_begin(); + + if(t == 0) select_sprite(SPRITE_FLAG_RED); + else select_sprite(SPRITE_FLAG_BLUE); + + float size = 16; + gfx_quads_drawTL(400-40+5, 300-40-15+t*20+1, size/2, size); + gfx_quads_end(); + } + else if(flags[t]->carried_by >= 0) + { + int id = flags[t]->carried_by%MAX_CLIENTS; + const char *name = client_datas[id].name; + float w = gfx_pretty_text_width(10, name, -1); + gfx_pretty_text(400-40-5-w, 300-40-15+t*20+2, 10, name, -1); + tee_render_info info = client_datas[id].skin_info; + info.size = 18.0f; + + render_tee(&idlestate, &info, EMOTE_NORMAL, vec2(1,0), + vec2(400-40+10, 300-40-15+9+t*20+1)); + } + } + } + else + gfx_pretty_text(400-20-w/2, 300-40-15+t*20+2, 14, buf, -1); + } + } + + // render warmup timer + if(gameobj->warmup) + { + char buf[256]; + float w = gfx_pretty_text_width(24, "Warmup", -1); + gfx_pretty_text(200+-w/2, 50, 24, "Warmup", -1); + + int seconds = gameobj->warmup/SERVER_TICK_SPEED; + if(seconds < 5) + sprintf(buf, "%d.%d", seconds, (gameobj->warmup*10/SERVER_TICK_SPEED)%10); + else + sprintf(buf, "%d", seconds); + w = gfx_pretty_text_width(24, buf, -1); + gfx_pretty_text(200+-w/2, 75, 24, buf, -1); + } + } + + if (menu_active) + { + modmenu_render(); + return; + } + + if(chat_mode == CHATMODE_NONE && !menu_active && !spectate) + { + if(!emoticon_selector_active && inp_key_pressed(config.key_emoticon)) + { + emoticon_selector_active = true; + emoticon_selector_reset(); + } + } + else + emoticon_selector_active = false; + + if(emoticon_selector_active) + { + int emoticon = emoticon_selector_render(); + if (emoticon != -1) + { + send_emoticon(emoticon); + emoticon_selector_active = false; + } + } + + if(client_connection_problems()) + { + gfx_mapscreen(0, 0, 400, 300); + const char *text = "Connection Problems..."; + float w = gfx_pretty_text_width(24, text, -1); + gfx_pretty_text(200-w/2, 50, 24, text, -1); + } + + // render score board + if(inp_key_pressed(KEY_TAB) || // user requested + (!spectate && (!local_character || local_character->health < 0)) || // not spectating and is dead + (gameobj && gameobj->game_over) // game over + ) + { + gfx_mapscreen(0, 0, width, height); + + float w = 550.0f; + + if (gameobj && gameobj->gametype == GAMETYPE_DM) + { + render_scoreboard(width/2-w/2, 150.0f, w, -1, 0); + //render_scoreboard(gameobj, 0, 0, -1, 0); + } + else + { + + if(gameobj && gameobj->game_over) + { + const char *text = "DRAW!"; + if(gameobj->teamscore[0] > gameobj->teamscore[1]) + text = "Red Team Wins!"; + else if(gameobj->teamscore[1] > gameobj->teamscore[0]) + text = "Blue Team Wins!"; + + float w = gfx_pretty_text_width(92.0f, text, -1); + gfx_pretty_text(width/2-w/2, 45, 92.0f, text, -1); + } + + render_scoreboard(width/2-w-20, 150.0f, w, 0, "Red Team"); + render_scoreboard(width/2 + 20, 150.0f, w, 1, "Blue Team"); + } + + render_goals(width/2-w/2, 150+600+25, w); + + } +} + +extern "C" void modc_render() +{ + // this should be moved around abit + if(client_state() == CLIENTSTATE_ONLINE) + { + render_game(); + + // handle team switching + // TODO: FUGLY!!! + if(config.cl_team != -10) + { + msg_pack_start(MSG_SETTEAM, MSGFLAG_VITAL); + msg_pack_int(config.cl_team); + msg_pack_end(); + client_send_msg(); + } + } + else // if (client_state() != CLIENTSTATE_CONNECTING && client_state() != CLIENTSTATE_LOADING) + { + modmenu_render(); + } + + // + config.cl_team = -10; +} + + +void menu_do_disconnected(); +void menu_do_connecting(); +void menu_do_connected(); + +extern "C" void modc_statechange(int state, int old) +{ + clear_object_pointers(); + + if(state == CLIENTSTATE_OFFLINE) + { + menu_do_disconnected(); + menu_game_active = false; + } + else if(state == CLIENTSTATE_CONNECTING) + menu_do_connecting(); + else if (state == CLIENTSTATE_ONLINE) + { + menu_active = false; + menu_game_active = true; + menu_do_connected(); + } +} + +extern "C" void modc_message(int msg) +{ + if(msg == MSG_CHAT) + { + int cid = msg_unpack_int(); + int team = msg_unpack_int(); + const char *message = msg_unpack_string(); + dbg_msg("message", "chat cid=%d team=%d msg='%s'", cid, team, message); + chat_add_line(cid, team, message); + + if(cid >= 0) + snd_play(CHN_GUI, data->sounds[SOUND_CHAT_CLIENT].sounds[0].id, 0); + else + snd_play(CHN_GUI, data->sounds[SOUND_CHAT_SERVER].sounds[0].id, 0); + } + else if(msg == MSG_SETINFO) + { + int cid = msg_unpack_int(); + const char *name = msg_unpack_string(); + const char *skinname = msg_unpack_string(); + + strncpy(client_datas[cid].name, name, 64); + strncpy(client_datas[cid].skin_name, skinname, 64); + + int use_custom_color = msg_unpack_int(); + client_datas[cid].skin_info.color_body = skin_get_color(msg_unpack_int()); + client_datas[cid].skin_info.color_feet = skin_get_color(msg_unpack_int()); + client_datas[cid].skin_info.size = 64; + + // find new skin + client_datas[cid].skin_id = skin_find(client_datas[cid].skin_name); + if(client_datas[cid].skin_id < 0) + client_datas[cid].skin_id = 0; + + if(use_custom_color) + client_datas[cid].skin_info.texture = skin_get(client_datas[cid].skin_id)->color_texture; + else + { + client_datas[cid].skin_info.texture = skin_get(client_datas[cid].skin_id)->org_texture; + client_datas[cid].skin_info.color_body = vec4(1,1,1,1); + client_datas[cid].skin_info.color_feet = vec4(1,1,1,1); + } + } + else if(msg == MSG_WEAPON_PICKUP) + { + int weapon = msg_unpack_int(); + + picked_up_weapon = weapon+1; + } + else if(msg == MSG_READY_TO_ENTER) + { + client_entergame(); + } + else if(msg == MSG_KILLMSG) + { + killmsg_current = (killmsg_current+1)%killmsg_max; + killmsgs[killmsg_current].killer = msg_unpack_int(); + killmsgs[killmsg_current].victim = msg_unpack_int(); + killmsgs[killmsg_current].weapon = msg_unpack_int(); + killmsgs[killmsg_current].mode_special = msg_unpack_int(); + killmsgs[killmsg_current].tick = client_tick(); + } + else if (msg == MSG_EMOTICON) + { + int cid = msg_unpack_int(); + int emoticon = msg_unpack_int(); + client_datas[cid].emoticon = emoticon; + client_datas[cid].emoticon_start = client_tick(); + } + else if(msg == MSG_SOUND_GLOBAL) + { + int soundid = msg_unpack_int(); + snd_play_random(CHN_GLOBAL, soundid, 1.0f, vec2(0,0)); + } +} + +extern "C" void modc_connected() +{ + // init some stuff + col_init(32); + img_init(); + tilemap_init(); + chat_reset(); + + proj_particles.reset(); + + clear_object_pointers(); + last_new_predicted_tick = -1; + + for(int i = 0; i < MAX_CLIENTS; i++) + { + client_datas[i].name[0] = 0; + client_datas[i].team = 0; + client_datas[i].emoticon = 0; + client_datas[i].emoticon_start = -1; + } + + for(int i = 0; i < killmsg_max; i++) + killmsgs[i].tick = -100000; + + send_info(true); +} + +extern "C" const char *modc_net_version() { return TEEWARS_NETVERSION; } diff --git a/src/game/client/gc_mapres_image.cpp b/src/game/client/gc_mapres_image.cpp new file mode 100644 index 00000000..cc9a8143 --- /dev/null +++ b/src/game/client/gc_mapres_image.cpp @@ -0,0 +1,125 @@ +/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */ +#include +#include +#include "gc_mapres_image.h" +#include "../g_mapres.h" + +static int map_textures[64] = {0}; +static int count = 0; +/* +static void calc_mipmaps(void *data_in, unsigned width, unsigned height, void *data_out) +{ + unsigned char *src = (unsigned char*)data_in; + unsigned char *dst = (unsigned char*)data_out; + unsigned mip_w = width; + unsigned mip_h = height; + unsigned prev_w; + unsigned prev_h; + + // Highest level - no mod + for(unsigned x = 0; x < mip_w; x++) + { + for(unsigned y = 0; y < mip_h; y++) + { + unsigned i = (y * mip_w + x)<<2; + for(unsigned j = 0; j < 4; j++) + dst[i+j] = src[i+j]; + } + } + + src = dst; + dst += mip_w * mip_h * 4; + prev_w = mip_w; + prev_h = mip_h; + mip_w = mip_w>>1; + mip_h = mip_h>>1; + + while(mip_w > 0 && mip_h > 0) + { + for(unsigned x = 0; x < mip_w; x++) + { + for(unsigned y = 0; y < mip_h; y++) + { + unsigned i = (y * mip_w + x)<<2; + + unsigned r = 0; + unsigned g = 0; + unsigned b = 0; + unsigned a = 0; + + + r += src[(((y<<1) * prev_w + (x<<1))<<2)]; + g += src[(((y<<1) * prev_w + (x<<1))<<2)+1]; + b += src[(((y<<1) * prev_w + (x<<1))<<2)+2]; + a += src[(((y<<1) * prev_w + (x<<1))<<2)+3]; + + r += src[(((y<<1) * prev_w + ((x+1)<<1))<<2)]; + g += src[(((y<<1) * prev_w + ((x+1)<<1))<<2)+1]; + b += src[(((y<<1) * prev_w + ((x+1)<<1))<<2)+2]; + a += src[(((y<<1) * prev_w + ((x+1)<<1))<<2)+3]; + + r += src[((((y+1)<<1) * prev_w + (x<<1))<<2)]; + g += src[((((y+1)<<1) * prev_w + (x<<1))<<2)+1]; + b += src[((((y+1)<<1) * prev_w + (x<<1))<<2)+2]; + a += src[((((y+1)<<1) * prev_w + (x<<1))<<2)+3]; + + r += src[((((y+1)<<1) * prev_w + ((x+1)<<1))<<2)]; + g += src[((((y+1)<<1) * prev_w + ((x+1)<<1))<<2)+1]; + b += src[((((y+1)<<1) * prev_w + ((x+1)<<1))<<2)+2]; + a += src[((((y+1)<<1) * prev_w + ((x+1)<<1))<<2)+3]; + + dst[i] = r>>2; + dst[i+1] = g>>2; + dst[i+2] = b>>2; + dst[i+3] = a>>2; + } + } + + src = dst; + dst = dst + mip_w*mip_h*4; + prev_w = mip_w; + prev_h = mip_h; + mip_w = mip_w>>1; + mip_h = mip_h>>1; + } +} +*/ +extern int DEBUGTEST_MAPIMAGE; + +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; + } + } + + //void *data_res = (void*)mem_alloc(1024*1024*4*2, 16); + 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); + //calc_mipmaps(data, img->width, img->height, data_res); + map_textures[i] = gfx_load_texture_raw(img->width, img->height, IMG_RGBA, data); + map_unload_data(img->image_data); + } + + //mem_free(data_res); + return count; +} + +int img_num() +{ + return count; +} + +int img_get(int index) +{ + return map_textures[index]; +} diff --git a/src/game/client/gc_mapres_image.h b/src/game/client/gc_mapres_image.h new file mode 100644 index 00000000..f841ca53 --- /dev/null +++ b/src/game/client/gc_mapres_image.h @@ -0,0 +1,19 @@ +/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */ + +// 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/gc_mapres_tilemap.cpp b/src/game/client/gc_mapres_tilemap.cpp new file mode 100644 index 00000000..6e687495 --- /dev/null +++ b/src/game/client/gc_mapres_tilemap.cpp @@ -0,0 +1,102 @@ +/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */ +#include +#include +#include "gc_mapres_tilemap.h" +#include "gc_mapres_image.h" +#include "../g_mapres.h" + +int tilemap_init() +{ + return 0; +} + +void tilemap_render(float scale, int fg) +{ + if(!map_is_loaded()) + return; + + float screen_x0, screen_y0, screen_x1, screen_y1; + gfx_getscreen(&screen_x0, &screen_y0, &screen_x1, &screen_y1); + + // 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)) + { + if(!config.gfx_high_detail && !tmap->main) + continue; + gfx_texture_set(img_get(tmap->image)); + + gfx_quads_begin(); + + int starty = (int)(screen_y0/scale)-1; + int startx = (int)(screen_x0/scale)-1; + int endy = (int)(screen_y1/scale)+1; + int endx = (int)(screen_x1/scale)+1; + + float frac = (1.25f/1024.0f);//2.0f; //2.0f; + float texsize = 1024.0f; + float nudge = 0.5f/texsize; + for(int y = starty; y < endy; y++) + for(int x = startx; x < endx; x++) + { + int mx = x; + int my = y; + if(mx<0) mx = 0; + if(mx>=tmap->width) mx = tmap->width-1; + if(my<0) my = 0; + if(my>=tmap->height) my = tmap->height-1; + + int c = mx + my*tmap->width; + + unsigned char d = data[c*2]; + unsigned char f = data[c*2+1]; + if(d) + { + int tx = d%16; + int ty = d/16; + int px0 = tx*(1024/16); + int py0 = ty*(1024/16); + int px1 = (tx+1)*(1024/16)-1; + int py1 = (ty+1)*(1024/16)-1; + + float u0 = nudge + px0/texsize+frac; + float v0 = nudge + py0/texsize+frac; + float u1 = nudge + px1/texsize-frac; + float v1 = nudge + py1/texsize-frac; + + if(f&TILEFLAG_VFLIP) + { + float tmp = u0; + u0 = u1; + u1 = tmp; + } + + if(f&TILEFLAG_HFLIP) + { + float tmp = v0; + v0 = v1; + v1 = tmp; + } + + gfx_quads_setsubset(u0,v0,u1,v1); + + gfx_quads_drawTL(x*scale, y*scale, scale, scale); + } + } + + gfx_quads_end(); + } + } +} diff --git a/src/game/client/gc_mapres_tilemap.h b/src/game/client/gc_mapres_tilemap.h new file mode 100644 index 00000000..a13495ed --- /dev/null +++ b/src/game/client/gc_mapres_tilemap.h @@ -0,0 +1,26 @@ +/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */ + +// dependencies: image + +// +int tilemap_init(); + +// renders the tilemaps +void tilemap_render(float scale, int fg); + +enum +{ + TILEFLAG_VFLIP=1, + TILEFLAG_HFLIP=2, +}; + +struct mapres_tilemap +{ + int image; + int width; + int height; + int x, y; + int scale; + int data; + int main; +}; diff --git a/src/game/client/gc_menu.cpp b/src/game/client/gc_menu.cpp new file mode 100644 index 00000000..de9047df --- /dev/null +++ b/src/game/client/gc_menu.cpp @@ -0,0 +1,1893 @@ +/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */ +#include +#include +#include +#include + +#include +#include + +extern "C" { + #include + #include + #include + #include +} + +#include "../g_mapres.h" +#include "../g_version.h" +#include "../g_protocol.h" + +#include "gc_mapres_image.h" +#include "gc_mapres_tilemap.h" + +#include "../generated/gc_data.h" +#include "gc_render.h" +#include "gc_skin.h" +#include + +extern data_container *data; + +// abit uglyness +extern const obj_player_info *local_info; +extern bool menu_active; +extern bool menu_game_active; + +enum +{ + POPUP_NONE=0, + POPUP_CONNECTING, + POPUP_DISCONNECTED, + POPUP_PASSWORD, + POPUP_QUIT, +}; + +static int popup = POPUP_NONE; + +//static vec4 gui_color(0.9f,0.78f,0.65f, 0.5f); +//static vec4 gui_color(0.78f,0.9f,0.65f, 0.5f); + +static vec4 gui_color(0.65f,0.78f,0.9f, 0.5f); + +static vec4 color_tabbar_inactive_outgame(0,0,0,0.25f); +static vec4 color_tabbar_active_outgame(0,0,0,0.5f); + +static float color_ingame_scale_i = 0.5f; +static float color_ingame_scale_a = 0.2f; +static vec4 color_tabbar_inactive_ingame(gui_color.r*color_ingame_scale_i, gui_color.g*color_ingame_scale_i, gui_color.b*color_ingame_scale_i,0.75f); +static vec4 color_tabbar_active_ingame(gui_color.r*color_ingame_scale_a, gui_color.g*color_ingame_scale_a, gui_color.b*color_ingame_scale_a,0.85f); +//static vec4 color_tabbar_inactive_ingame(0.2f,0.2f,0.2f,0.5f); +//static vec4 color_tabbar_active_ingame(0.2f,0.2f,0.2f,0.75f); + +static vec4 color_tabbar_inactive = color_tabbar_inactive_outgame; +static vec4 color_tabbar_active = color_tabbar_active_outgame; + +enum +{ + CORNER_TL=1, + CORNER_TR=2, + CORNER_BL=4, + CORNER_BR=8, + + CORNER_T=CORNER_TL|CORNER_TR, + CORNER_B=CORNER_BL|CORNER_BR, + CORNER_R=CORNER_TR|CORNER_BR, + CORNER_L=CORNER_TL|CORNER_BL, + + CORNER_ALL=CORNER_T|CORNER_B, + + PAGE_NEWS=0, + PAGE_INTERNET, + PAGE_LAN, + PAGE_FAVORITES, + PAGE_SETTINGS, + //PAGE_GAME, // not a real page + PAGE_SYSTEM, +}; + +typedef struct +{ + float x, y, w, h; +} RECT; + +static RECT screen = { 0.0f, 0.0f, 848.0f, 480.0f }; + +extern void select_sprite(int id, int flags=0, int sx=0, int sy=0); + +RECT *ui2_screen() +{ + float aspect = gfx_screenaspect(); + float w, h; + + h = 600; + w = aspect*h; + + screen.w = w; + screen.h = h; + + return &screen; +} + +void ui2_set_scale(float s) +{ + config.ui_scale = (int)(s*100.0f); +} + +float ui2_scale() +{ + return config.ui_scale/100.0f; +} + +void ui2_hsplit_t(const RECT *original, float cut, RECT *top, RECT *bottom) +{ + RECT r = *original; + cut *= ui2_scale(); + + if (top) + { + top->x = r.x; + top->y = r.y; + top->w = r.w; + top->h = cut; + } + + if (bottom) + { + bottom->x = r.x; + bottom->y = r.y + cut; + bottom->w = r.w; + bottom->h = r.h - cut; + } +} + +void ui2_hsplit_b(const RECT *original, float cut, RECT *top, RECT *bottom) +{ + RECT r = *original; + cut *= ui2_scale(); + + if (top) + { + top->x = r.x; + top->y = r.y; + top->w = r.w; + top->h = r.h - cut; + } + + if (bottom) + { + bottom->x = r.x; + bottom->y = r.y + r.h - cut; + bottom->w = r.w; + bottom->h = cut; + } +} + +void ui2_vsplit_l(const RECT *original, float cut, RECT *left, RECT *right) +{ + RECT r = *original; + cut *= ui2_scale(); + + if (left) + { + left->x = r.x; + left->y = r.y; + left->w = cut; + left->h = r.h; + } + + if (right) + { + right->x = r.x + cut; + right->y = r.y; + right->w = r.w - cut; + right->h = r.h; + } +} + +void ui2_vsplit_r(const RECT *original, float cut, RECT *left, RECT *right) +{ + RECT r = *original; + cut *= ui2_scale(); + + if (left) + { + left->x = r.x; + left->y = r.y; + left->w = r.w - cut; + left->h = r.h; + } + + if (right) + { + right->x = r.x + r.w - cut; + right->y = r.y; + right->w = cut; + right->h = r.h; + } +} + +void ui2_margin(const RECT *original, float cut, RECT *other_rect) +{ + RECT r = *original; + cut *= ui2_scale(); + + other_rect->x = r.x + cut; + other_rect->y = r.y + cut; + other_rect->w = r.w - 2*cut; + other_rect->h = r.h - 2*cut; +} + +void ui2_vmargin(const RECT *original, float cut, RECT *other_rect) +{ + RECT r = *original; + cut *= ui2_scale(); + + other_rect->x = r.x + cut; + other_rect->y = r.y; + other_rect->w = r.w - 2*cut; + other_rect->h = r.h; +} + +void ui2_hmargin(const RECT *original, float cut, RECT *other_rect) +{ + RECT r = *original; + cut *= ui2_scale(); + + other_rect->x = r.x; + other_rect->y = r.y + cut; + other_rect->w = r.w; + other_rect->h = r.h - 2*cut; +} + +typedef void (*ui2_draw_button_func)(const void *id, const char *text, int checked, const RECT *r, void *extra); + +int ui2_do_button(const void *id, const char *text, int checked, const RECT *r, ui2_draw_button_func draw_func, void *extra) +{ + /* logic */ + int ret = 0; + int inside = ui_mouse_inside(r->x,r->y,r->w,r->h); + + if(ui_active_item() == id) + { + if(!ui_mouse_button(0)) + { + if(inside) + ret = 1; + ui_set_active_item(0); + } + } + else if(ui_hot_item() == id) + { + if(ui_mouse_button(0)) + ui_set_active_item(id); + } + + if(inside) + ui_set_hot_item(id); + + if(draw_func) + draw_func(id, text, checked, r, extra); + return ret; +} + + +void ui2_do_label(const RECT *r, const char *text, float size, int align) +{ + gfx_blend_normal(); + size *= ui2_scale(); + if(align == 0) + { + float tw = gfx_pretty_text_width(size, text, -1); + gfx_pretty_text(r->x + r->w/2-tw/2, r->y, size, text, -1); + } + else if(align < 0) + gfx_pretty_text(r->x, r->y, size, text, -1); + else if(align > 0) + { + float tw = gfx_pretty_text_width(size, text, -1); + gfx_pretty_text(r->x + r->w-tw, r->y, size, text, -1); + } +} + + +extern void draw_round_rect_ext(float x, float y, float w, float h, float r, int corners); +extern void draw_round_rect(float x, float y, float w, float h, float r); + +static void ui2_draw_rect(const RECT *r, vec4 color, int corners, float rounding) +{ + gfx_texture_set(-1); + gfx_quads_begin(); + gfx_setcolor(color.r, color.g, color.b, color.a); + draw_round_rect_ext(r->x,r->y,r->w,r->h,rounding*ui2_scale(), corners); + gfx_quads_end(); +} + +static void ui2_draw_browse_icon(int what, const RECT *r) +{ + gfx_texture_set(data->images[IMAGE_BROWSEICONS].id); + gfx_quads_begin(); + select_sprite(SPRITE_BROWSE_PROGRESS1); // default + if(what <= 100) + { + if(what < 66) + select_sprite(SPRITE_BROWSE_PROGRESS2); + else + select_sprite(SPRITE_BROWSE_PROGRESS3); + } + else if(what&0x100) + { + select_sprite(SPRITE_BROWSE_LOCK); + } + gfx_quads_drawTL(r->x,r->y,r->w,r->h); + gfx_quads_end(); +} + +static void ui2_draw_menu_button(const void *id, const char *text, int checked, const RECT *r, void *extra) +{ + ui2_draw_rect(r, vec4(1,1,1,0.5f), CORNER_ALL, 5.0f); + ui2_do_label(r, text, 24, 0); +} + + +static void ui2_draw_keyselect_button(const void *id, const char *text, int checked, const RECT *r, void *extra) +{ + ui2_draw_rect(r, vec4(1,1,1,0.5f), CORNER_ALL, 5.0f); + ui2_do_label(r, text, 18, 0); +} + +static void ui2_draw_menu_tab_button(const void *id, const char *text, int checked, const RECT *r, void *extra) +{ + if(checked) + ui2_draw_rect(r, color_tabbar_active, CORNER_T, 10.0f); + else + ui2_draw_rect(r, color_tabbar_inactive, CORNER_T, 10.0f); + ui2_do_label(r, text, 26, 0); +} + + +static void ui2_draw_settings_tab_button(const void *id, const char *text, int checked, const RECT *r, void *extra) +{ + if(checked) + ui2_draw_rect(r, color_tabbar_active, CORNER_R, 10.0f); + else + ui2_draw_rect(r, color_tabbar_inactive, CORNER_R, 10.0f); + ui2_do_label(r, text, 24, 0); +} + +static void ui2_draw_grid_header(const void *id, const char *text, int checked, const RECT *r, void *extra) +{ + if(checked) + ui2_draw_rect(r, vec4(1,1,1,0.5f), CORNER_T, 5.0f); + //else + // ui2_draw_rect(r, vec4(1,1,1,0.1f), CORNER_T, 5.0f); + RECT t; + ui2_vsplit_l(r, 5.0f, 0, &t); + ui2_do_label(&t, text, 18, -1); +} +/* +static void ui2_draw_grid_cell_l(const void *id, const char *text, int checked, const RECT *r, void *extra) +{ + ui2_do_label(r, text, 18, -1); +} + +static void ui2_draw_grid_cell_r(const void *id, const char *text, int checked, const RECT *r, void *extra) +{ + ui2_do_label(r, text, 18, 1); +}*/ + +static void ui2_draw_list_row(const void *id, const char *text, int checked, const RECT *r, void *extra) +{ + if(checked) + { + RECT sr = *r; + ui2_margin(&sr, 1.5f, &sr); + ui2_draw_rect(&sr, vec4(1,1,1,0.5f), CORNER_ALL, 4.0f); + } + ui2_do_label(r, text, 18, -1); +} + +static void ui2_draw_checkbox_common(const void *id, const char *text, const char *boxtext, const RECT *r) +{ + RECT c = *r; + RECT t = *r; + c.w = c.h; + t.x += c.w; + t.w -= c.w; + ui2_vsplit_l(&t, 5.0f, 0, &t); + + ui2_margin(&c, 2.0f, &c); + ui2_draw_rect(&c, vec4(1,1,1,0.25f), CORNER_ALL, 3.0f); + ui2_do_label(&c, boxtext, 16, 0); + ui2_do_label(&t, text, 18, -1); +} + +static void ui2_draw_checkbox(const void *id, const char *text, int checked, const RECT *r, void *extra) +{ + ui2_draw_checkbox_common(id, text, checked?"X":"", r); +} + +static void ui2_draw_checkbox_number(const void *id, const char *text, int checked, const RECT *r, void *extra) +{ + char buf[16]; + sprintf(buf, "%d", checked); + ui2_draw_checkbox_common(id, text, buf, r); +} + +int ui2_do_edit_box(void *id, const RECT *rect, char *str, int str_size, bool hidden=false) +{ + int inside = ui_mouse_inside(rect->x,rect->y,rect->w,rect->h); + int r = 0; + static int at_index = 0; + + if(ui_last_active_item() == id) + { + int c = inp_last_char(); + int k = inp_last_key(); + int len = strlen(str); + + if (inside && ui_mouse_button(0)) + { + int mx_rel = (int)(ui_mouse_x() - rect->x); + + for (int i = 1; i <= len; i++) + { + if (gfx_pretty_text_width(18.0f, str, i) + 10 > mx_rel) + { + at_index = i - 1; + break; + } + + if (i == len) + at_index = len; + } + } + + if (at_index > len) + at_index = len; + + if (!(c >= 0 && c < 32)) + { + if (len < str_size - 1 && at_index < str_size - 1) + { + memmove(str + at_index + 1, str + at_index, len - at_index + 1); + str[at_index] = c; + at_index++; + } + } + + if (k == KEY_BACKSPACE && at_index > 0) + { + memmove(str + at_index - 1, str + at_index, len - at_index + 1); + at_index--; + } + else if (k == KEY_DEL && at_index < len) + memmove(str + at_index, str + at_index + 1, len - at_index); + else if (k == KEY_ENTER) + ui_clear_last_active_item(); + else if (k == KEY_LEFT && at_index > 0) + at_index--; + else if (k == KEY_RIGHT && at_index < len) + at_index++; + else if (k == KEY_HOME) + at_index = 0; + else if (k == KEY_END) + at_index = len; + + r = 1; + } + + int box_type; + if (ui_active_item() == id || ui_hot_item() == id || ui_last_active_item() == id) + box_type = GUI_BOX_SCREEN_INFO; + else + box_type = GUI_BOX_SCREEN_TEXTBOX; + + bool just_got_active = false; + + if(ui_active_item() == id) + { + if(!ui_mouse_button(0)) + ui_set_active_item(0); + } + else if(ui_hot_item() == id) + { + if(ui_mouse_button(0)) + { + if (ui_last_active_item() != id) + just_got_active = true; + ui_set_active_item(id); + } + } + + if(inside) + ui_set_hot_item(id); + + RECT textbox = *rect; + ui2_draw_rect(&textbox, vec4(1,1,1,0.5f), CORNER_ALL, 5.0f); + ui2_vmargin(&textbox, 5.0f, &textbox); + + const char *display_str = str; + char stars[128]; + + if(hidden) + { + unsigned s = strlen(str); + if(s >= sizeof(stars)) + s = sizeof(stars)-1; + memset(stars, '*', s); + stars[s] = 0; + display_str = stars; + } + + ui2_do_label(&textbox, display_str, 18, -1); + + if (ui_last_active_item() == id && !just_got_active) + { + float w = gfx_pretty_text_width(18.0f, display_str, at_index); + textbox.x += w*ui2_scale(); + ui2_do_label(&textbox, "_", 18, -1); + } + + return r; +} + +float ui2_do_scrollbar_v(const void *id, const RECT *rect, float current) +{ + RECT handle; + static float offset_y; + ui2_hsplit_t(rect, 33, &handle, 0); + + handle.y += (rect->h-handle.h)*current; + + /* logic */ + float ret = current; + int inside = ui_mouse_inside(handle.x,handle.y,handle.w,handle.h); + + if(ui_active_item() == id) + { + if(!ui_mouse_button(0)) + ui_set_active_item(0); + + float min = rect->y; + float max = rect->h-handle.h; + float cur = ui_mouse_y()-offset_y; + ret = (cur-min)/max; + if(ret < 0.0f) ret = 0.0f; + if(ret > 1.0f) ret = 1.0f; + } + else if(ui_hot_item() == id) + { + if(ui_mouse_button(0)) + { + ui_set_active_item(id); + offset_y = ui_mouse_y()-handle.y; + } + } + + if(inside) + ui_set_hot_item(id); + + // render + RECT rail; + ui2_vmargin(rect, 5.0f, &rail); + ui2_draw_rect(&rail, vec4(1,1,1,0.25f), 0, 0.0f); + + RECT slider = handle; + slider.w = rail.x-slider.x; + ui2_draw_rect(&slider, vec4(1,1,1,0.25f), CORNER_L, 2.5f); + slider.x = rail.x+rail.w; + ui2_draw_rect(&slider, vec4(1,1,1,0.25f), CORNER_R, 2.5f); + + slider = handle; + ui2_margin(&slider, 5.0f, &slider); + ui2_draw_rect(&slider, vec4(1,1,1,0.25f), CORNER_ALL, 2.5f); + + return ret; +} + + + +float ui2_do_scrollbar_h(const void *id, const RECT *rect, float current) +{ + RECT handle; + static float offset_x; + ui2_vsplit_l(rect, 33, &handle, 0); + + handle.x += (rect->w-handle.w)*current; + + /* logic */ + float ret = current; + int inside = ui_mouse_inside(handle.x,handle.y,handle.w,handle.h); + + if(ui_active_item() == id) + { + if(!ui_mouse_button(0)) + ui_set_active_item(0); + + float min = rect->x; + float max = rect->w-handle.w; + float cur = ui_mouse_x()-offset_x; + ret = (cur-min)/max; + if(ret < 0.0f) ret = 0.0f; + if(ret > 1.0f) ret = 1.0f; + } + else if(ui_hot_item() == id) + { + if(ui_mouse_button(0)) + { + ui_set_active_item(id); + offset_x = ui_mouse_x()-handle.x; + } + } + + if(inside) + ui_set_hot_item(id); + + // render + RECT rail; + ui2_hmargin(rect, 5.0f, &rail); + ui2_draw_rect(&rail, vec4(1,1,1,0.25f), 0, 0.0f); + + RECT slider = handle; + slider.h = rail.y-slider.y; + ui2_draw_rect(&slider, vec4(1,1,1,0.25f), CORNER_T, 2.5f); + slider.y = rail.y+rail.h; + ui2_draw_rect(&slider, vec4(1,1,1,0.25f), CORNER_B, 2.5f); + + slider = handle; + ui2_margin(&slider, 5.0f, &slider); + ui2_draw_rect(&slider, vec4(1,1,1,0.25f), CORNER_ALL, 2.5f); + + return ret; +} + +int ui2_do_key_reader(void *id, const RECT *rect, int key) +{ + // process + static bool mouse_released = true; + int inside = ui_mouse_inside(rect->x, rect->y, rect->w, rect->h); + int new_key = key; + + if(!ui_mouse_button(0)) + mouse_released = true; + + if(ui_active_item() == id) + { + int k = inp_last_key(); + if (k) + { + new_key = k; + ui_set_active_item(0); + mouse_released = false; + } + } + else if(ui_hot_item() == id) + { + if(ui_mouse_button(0) && mouse_released) + ui_set_active_item(id); + } + + if(inside) + ui_set_hot_item(id); + + // draw + if (ui_active_item() == id) + ui2_draw_keyselect_button(id, "???", 0, rect, 0); + else + ui2_draw_keyselect_button(id, inp_key_name(key), 0, rect, 0); + return new_key; +} + + +static int menu2_render_menubar(RECT r) +{ + RECT box = r; + RECT button; + + int active_page = config.ui_page; + int new_page = -1; + if(menu_game_active) + active_page = -1; + + if(client_state() == CLIENTSTATE_OFFLINE) + { + if(0) // this is not done yet + { + ui2_vsplit_l(&box, 90.0f, &button, &box); + static int news_button=0; + if (ui2_do_button(&news_button, "News", active_page==PAGE_NEWS, &button, ui2_draw_menu_tab_button, 0)) + new_page = PAGE_NEWS; + ui2_vsplit_l(&box, 30.0f, 0, &box); + } + } + else + { + ui2_vsplit_l(&box, 90.0f, &button, &box); + static int game_button=0; + if (ui2_do_button(&game_button, "Game", menu_game_active, &button, ui2_draw_menu_tab_button, 0)) + menu_game_active = true; + + ui2_vsplit_l(&box, 30.0f, 0, &box); + } + + ui2_vsplit_l(&box, 110.0f, &button, &box); + static int internet_button=0; + if (ui2_do_button(&internet_button, "Internet", active_page==PAGE_INTERNET, &button, ui2_draw_menu_tab_button, 0)) + { + client_serverbrowse_refresh(0); + new_page = PAGE_INTERNET; + } + + ui2_vsplit_l(&box, 4.0f, 0, &box); + ui2_vsplit_l(&box, 90.0f, &button, &box); + static int lan_button=0; + if (ui2_do_button(&lan_button, "LAN", active_page==PAGE_LAN, &button, ui2_draw_menu_tab_button, 0)) + { + client_serverbrowse_refresh(1); + new_page = PAGE_LAN; + } + + if(0) // this one is not done yet + { + ui2_vsplit_l(&box, 4.0f, 0, &box); + ui2_vsplit_l(&box, 120.0f, &button, &box); + static int favorites_button=0; + if (ui2_do_button(&favorites_button, "Favorites", active_page==PAGE_FAVORITES, &button, ui2_draw_menu_tab_button, 0)) + new_page = PAGE_FAVORITES; + } + + /* + ui2_vsplit_r(&box, 110.0f, &box, &button); + static int system_button=0; + if (ui2_do_button(&system_button, "System", config.ui_page==PAGE_SYSTEM, &button, ui2_draw_menu_tab_button, 0)) + config.ui_page = PAGE_SYSTEM; + + ui2_vsplit_r(&box, 30.0f, &box, 0); + */ + + ui2_vsplit_r(&box, 110.0f, &box, &button); + static int quit_button=0; + if (ui2_do_button(&quit_button, "Quit", 0, &button, ui2_draw_menu_tab_button, 0)) + popup = POPUP_QUIT; + + ui2_vsplit_r(&box, 10.0f, &box, &button); + ui2_vsplit_r(&box, 110.0f, &box, &button); + static int settings_button=0; + if (ui2_do_button(&settings_button, "Settings", active_page==PAGE_SETTINGS, &button, ui2_draw_menu_tab_button, 0)) + new_page = PAGE_SETTINGS; + + if(new_page != -1) + { + config.ui_page = new_page; + menu_game_active = false; + } + + return 0; +} + +static void menu2_render_background() +{ + //gfx_clear(0.65f,0.78f,0.9f); + gfx_clear(gui_color.r, gui_color.g, gui_color.b); + //gfx_clear(0.78f,0.9f,0.65f); + + gfx_texture_set(data->images[IMAGE_BANNER].id); + gfx_quads_begin(); + gfx_setcolor(0,0,0,0.05f); + gfx_quads_setrotation(-pi/4+0.15f); + gfx_quads_draw(400, 300, 1000, 250); + gfx_quads_end(); +} + +static void menu2_render_serverbrowser(RECT main_view) +{ + ui2_draw_rect(&main_view, color_tabbar_active, CORNER_ALL, 10.0f); + + RECT view; + ui2_margin(&main_view, 10.0f, &view); + + RECT headers; + RECT filters; + RECT status; + RECT toolbox; + + //ui2_hsplit_t(&view, 20.0f, &status, &view); + ui2_hsplit_t(&view, 20.0f, &headers, &view); + ui2_hsplit_b(&view, 90.0f, &view, &filters); + ui2_hsplit_b(&view, 5.0f, &view, 0); + ui2_hsplit_b(&view, 20.0f, &view, &status); + + ui2_vsplit_r(&filters, 300.0f, &filters, &toolbox); + ui2_vsplit_r(&filters, 150.0f, &filters, 0); + + // split of the scrollbar + ui2_draw_rect(&headers, vec4(1,1,1,0.25f), CORNER_T, 5.0f); + ui2_vsplit_r(&headers, 20.0f, &headers, 0); + + struct column + { + int id; + int sort; + const char *caption; + int direction; + float width; + int flags; + RECT rect; + RECT spacer; + }; + + enum + { + FIXED=1, + SPACER=2, + + COL_FLAGS=0, + COL_NAME, + COL_GAMETYPE, + COL_MAP, + COL_PLAYERS, + COL_PING, + COL_PROGRESS, + }; + + static column cols[] = { + {-1, -1, " ", -1, 10.0f, 0, {0}, {0}}, + {COL_FLAGS, -1, " ", -1, 20.0f, 0, {0}, {0}}, + {COL_NAME, BROWSESORT_NAME, "Name", 0, 300.0f, 0, {0}, {0}}, + {COL_GAMETYPE, BROWSESORT_GAMETYPE, "Type", 1, 50.0f, 0, {0}, {0}}, + {COL_MAP, BROWSESORT_MAP, "Map", 1, 100.0f, 0, {0}, {0}}, + {COL_PLAYERS, BROWSESORT_NUMPLAYERS, "Players", 1, 60.0f, 0, {0}, {0}}, + {-1, -1, " ", 1, 10.0f, 0, {0}, {0}}, + {COL_PROGRESS, BROWSESORT_PROGRESSION, "%", 1, 20.0f, FIXED, {0}, {0}}, + {COL_PING, BROWSESORT_PING, "Ping", 1, 40.0f, FIXED, {0}, {0}}, + }; + + int num_cols = sizeof(cols)/sizeof(column); + + // do layout + for(int i = 0; i < num_cols; i++) + { + if(cols[i].direction == -1) + { + ui2_vsplit_l(&headers, cols[i].width, &cols[i].rect, &headers); + + if(i+1 < num_cols) + { + //cols[i].flags |= SPACER; + ui2_vsplit_l(&headers, 2, &cols[i].spacer, &headers); + } + } + } + + for(int i = num_cols-1; i >= 0; i--) + { + if(cols[i].direction == 1) + { + ui2_vsplit_r(&headers, cols[i].width, &headers, &cols[i].rect); + ui2_vsplit_r(&headers, 2, &headers, &cols[i].spacer); + } + } + + for(int i = 0; i < num_cols; i++) + { + if(cols[i].direction == 0) + cols[i].rect = headers; + } + + // do headers + for(int i = 0; i < num_cols; i++) + { + if(ui2_do_button(cols[i].caption, cols[i].caption, config.b_sort == cols[i].sort, &cols[i].rect, ui2_draw_grid_header, 0)) + { + if(cols[i].sort != -1) + config.b_sort = cols[i].sort; + } + } + + ui2_draw_rect(&view, vec4(0,0,0,0.15f), 0, 0); + + RECT scroll; + ui2_vsplit_r(&view, 15, &view, &scroll); + + int num_servers = client_serverbrowse_sorted_num(); + + int num = (int)(view.h/cols[0].rect.h); + static int scrollbar = 0; + static float scrollvalue = 0; + static int selected_index = -1; + ui2_hmargin(&scroll, 5.0f, &scroll); + scrollvalue = ui2_do_scrollbar_v(&scrollbar, &scroll, scrollvalue); + + int start = (int)((num_servers-num)*scrollvalue); + if(start < 0) + start = 0; + + //int r = -1; + int new_selected = selected_index; + + for (int i = start, k = 0; i < num_servers && k < num; i++, k++) + { + int item_index = i; + SERVER_INFO *item = client_serverbrowse_sorted_get(item_index); + RECT row; + + int l = selected_index==item_index; + + if(l) + { + // selected server, draw the players on it + RECT whole; + int h = (item->num_players+2)/3; + + ui2_hsplit_t(&view, 25.0f+h*15.0f, &whole, &view); + + RECT r = whole; + ui2_margin(&r, 1.5f, &r); + ui2_draw_rect(&r, vec4(1,1,1,0.5f), CORNER_ALL, 4.0f); + + ui2_hsplit_t(&whole, 20.0f, &row, &whole); + ui2_vsplit_l(&whole, 50.0f, 0, &whole); + + for(int p = 0; p < item->num_players; p+=3) + { + RECT player_row; + RECT player_rect; + RECT player_score; + RECT player_name; + ui2_hsplit_t(&whole, 15.0f, &player_row, &whole); + + for(int a = 0; a < 3; a++) + { + if(p+a >= item->num_players) + break; + + ui2_vsplit_l(&player_row, 170.0f, &player_rect, &player_row); + ui2_vsplit_l(&player_rect, 30.0f, &player_score, &player_name); + ui2_vsplit_l(&player_name, 10.0f, 0, &player_name); + char buf[32]; + sprintf(buf, "%d", item->player_scores[p+a]); + ui2_do_label(&player_score, buf, 16.0f, 1); + ui2_do_label(&player_name, item->player_names[p+a], 16.0f, -1); + } + } + + k += h*3/4; + } + else + ui2_hsplit_t(&view, 20.0f, &row, &view); + + if(ui2_do_button(item, "", l, &row, 0, 0)) + { + new_selected = item_index; + dbg_msg("dbg", "addr = %s", item->address); + strncpy(config.ui_server_address, item->address, sizeof(config.ui_server_address)); + if(inp_mouse_doubleclick()) + client_connect(config.ui_server_address); + } + + for(int c = 0; c < num_cols; c++) + { + RECT button; + char temp[64]; + button.x = cols[c].rect.x; + button.y = row.y; + button.h = row.h; + button.w = cols[c].rect.w; + + //int s = 0; + int id = cols[c].id; + + //s = ui2_do_button(item, "L", l, &button, ui2_draw_browse_icon, 0); + + if(id == COL_FLAGS) + { + if(item->flags&1) + ui2_draw_browse_icon(0x100, &button); + } + else if(id == COL_NAME) + ui2_do_label(&button, item->name, 20.0f, -1); + else if(id == COL_MAP) + ui2_do_label(&button, item->map, 20.0f, -1); + else if(id == COL_PLAYERS) + { + sprintf(temp, "%i/%i", item->num_players, item->max_players); + ui2_do_label(&button, temp, 20.0f, 1); + } + else if(id == COL_PING) + { + sprintf(temp, "%i", item->latency); + ui2_do_label(&button, temp, 20.0f, 1); + } + else if(id == COL_PROGRESS) + { + ui2_draw_browse_icon(item->progression, &button); + } + else if(id == COL_GAMETYPE) + { + const char *type = "???"; + if(item->game_type == GAMETYPE_DM) type = "DM"; + else if(item->game_type == GAMETYPE_TDM) type = "TDM"; + else if(item->game_type == GAMETYPE_CTF) type = "CTF"; + ui2_do_label(&button, type, 20.0f, 0); + } + /* + if(s) + { + new_selected = item_index; + dbg_msg("dbg", "addr = %s", item->address); + strncpy(config.ui_server_address, item->address, sizeof(config.ui_server_address)); + }*/ + } + } + + selected_index = new_selected; + + + // render quick search + RECT button; + ui2_hsplit_t(&filters, 20.0f, &button, &filters); + ui2_do_label(&button, "Quick search: ", 18, -1); + ui2_vsplit_l(&button, 95.0f, 0, &button); + ui2_do_edit_box(&config.b_filter_string, &button, config.b_filter_string, sizeof(config.b_filter_string)); + + // render filters + ui2_hsplit_t(&filters, 20.0f, &button, &filters); + if (ui2_do_button(&config.b_filter_empty, "Has people playing", config.b_filter_empty, &button, ui2_draw_checkbox, 0)) + config.b_filter_empty ^= 1; + + ui2_hsplit_t(&filters, 20.0f, &button, &filters); + if (ui2_do_button(&config.b_filter_full, "Server not full", config.b_filter_full, &button, ui2_draw_checkbox, 0)) + config.b_filter_full ^= 1; + + ui2_hsplit_t(&filters, 20.0f, &button, &filters); + if (ui2_do_button(&config.b_filter_pw, "Is not password protected", config.b_filter_pw, &button, ui2_draw_checkbox, 0)) + config.b_filter_pw ^= 1; + + + // render status + ui2_draw_rect(&status, vec4(1,1,1,0.25f), CORNER_B, 5.0f); + ui2_vmargin(&status, 50.0f, &status); + char buf[128]; + sprintf(buf, "%d of %d servers", client_serverbrowse_sorted_num(), client_serverbrowse_num()); + ui2_do_label(&status, buf, 18.0f, -1); + + // render toolbox + { + RECT buttons, button; + ui2_hsplit_b(&toolbox, 25.0f, &toolbox, &buttons); + + ui2_vsplit_r(&buttons, 100.0f, &buttons, &button); + ui2_vmargin(&button, 2.0f, &button); + static int join_button = 0; + if(ui2_do_button(&join_button, "Connect", 0, &button, ui2_draw_menu_button, 0)) + client_connect(config.ui_server_address); + + ui2_vsplit_r(&buttons, 20.0f, &buttons, &button); + ui2_vsplit_r(&buttons, 100.0f, &buttons, &button); + ui2_vmargin(&button, 2.0f, &button); + static int refresh_button = 0; + if(ui2_do_button(&refresh_button, "Refresh", 0, &button, ui2_draw_menu_button, 0)) + { + if(config.ui_page == PAGE_INTERNET) + client_serverbrowse_refresh(0); + else if(config.ui_page == PAGE_LAN) + client_serverbrowse_refresh(1); + } + + ui2_hsplit_t(&toolbox, 20.0f, &button, &toolbox); + ui2_do_label(&button, "Host address:", 18, -1); + ui2_vsplit_l(&button, 100.0f, 0, &button); + ui2_do_edit_box(&config.ui_server_address, &button, config.ui_server_address, sizeof(config.ui_server_address)); + } +} + +static void menu2_render_settings_player(RECT main_view) +{ + RECT button; + RECT skinselection; + ui2_vsplit_l(&main_view, 300.0f, &main_view, &skinselection); + + + ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); + + // render settings + { + ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); + ui2_do_label(&button, "Name:", 18.0, -1); + ui2_vsplit_l(&button, 80.0f, 0, &button); + ui2_vsplit_l(&button, 180.0f, &button, 0); + ui2_do_edit_box(config.player_name, &button, config.player_name, sizeof(config.player_name)); + + ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); + if (ui2_do_button(&config.cl_dynamic_camera, "Dynamic camera", config.cl_dynamic_camera, &button, ui2_draw_checkbox, 0)) + config.cl_dynamic_camera ^= 1; + + ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); + if (ui2_do_button(&config.cl_autoswitch_weapons, "Switch weapon on pickup", config.cl_autoswitch_weapons, &button, ui2_draw_checkbox, 0)) + config.cl_autoswitch_weapons ^= 1; + + ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); + if (ui2_do_button(&config.cl_nameplates, "Show name plates", config.cl_nameplates, &button, ui2_draw_checkbox, 0)) + config.cl_nameplates ^= 1; + + if(config.cl_nameplates) + { + ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); + ui2_vsplit_l(&button, 15.0f, 0, &button); + if (ui2_do_button(&config.cl_nameplates_always, "Always show name plates", config.cl_nameplates_always, &button, ui2_draw_checkbox, 0)) + config.cl_nameplates_always ^= 1; + } + + ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); + + ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); + if (ui2_do_button(&config.player_color_body, "Custom colors", config.player_use_custom_color, &button, ui2_draw_checkbox, 0)) + config.player_use_custom_color = config.player_use_custom_color?0:1; + + if(config.player_use_custom_color) + { + int *colors[2]; + colors[0] = &config.player_color_body; + colors[1] = &config.player_color_feet; + + const char *parts[] = {"Body", "Feet"}; + const char *labels[] = {"Hue", "Sat.", "Lht."}; + static int color_slider[2][3] = {{0}}; + //static float v[2][3] = {{0, 0.5f, 0.25f}, {0, 0.5f, 0.25f}}; + + for(int i = 0; i < 2; i++) + { + RECT text; + ui2_hsplit_t(&main_view, 20.0f, &text, &main_view); + ui2_vsplit_l(&text, 15.0f, 0, &text); + ui2_do_label(&text, parts[i], 18, -1); + + int prevcolor = *colors[i]; + int color = 0; + for(int s = 0; s < 3; s++) + { + RECT text; + ui2_hsplit_t(&main_view, 19.0f, &button, &main_view); + ui2_vsplit_l(&button, 30.0f, 0, &button); + ui2_vsplit_l(&button, 30.0f, &text, &button); + ui2_vsplit_r(&button, 5.0f, &button, 0); + ui2_hsplit_t(&button, 4.0f, 0, &button); + + float k = ((prevcolor>>((2-s)*8))&0xff) / 255.0f; + k = ui2_do_scrollbar_h(&color_slider[i][s], &button, k); + color <<= 8; + color += clamp((int)(k*255), 0, 255); + ui2_do_label(&text, labels[s], 20, -1); + + } + + *colors[i] = color; + ui2_hsplit_t(&main_view, 5.0f, 0, &main_view); + } + } + } + + // draw header + RECT header, footer; + ui2_hsplit_t(&skinselection, 20, &header, &skinselection); + ui2_draw_rect(&header, vec4(1,1,1,0.25f), CORNER_T, 5.0f); + ui2_do_label(&header, "Skins", 18.0f, 0); + + // draw footers + ui2_hsplit_b(&skinselection, 20, &skinselection, &footer); + ui2_draw_rect(&footer, vec4(1,1,1,0.25f), CORNER_B, 5.0f); + ui2_vsplit_l(&footer, 10.0f, 0, &footer); + + // modes + ui2_draw_rect(&skinselection, vec4(0,0,0,0.15f), 0, 0); + + RECT scroll; + ui2_vsplit_r(&skinselection, 15, &skinselection, &scroll); + + RECT list = skinselection; + ui2_hsplit_t(&list, 50, &button, &list); + + int num = (int)(skinselection.h/button.h); + static float scrollvalue = 0; + static int scrollbar = 0; + ui2_hmargin(&scroll, 5.0f, &scroll); + scrollvalue = ui2_do_scrollbar_v(&scrollbar, &scroll, scrollvalue); + + int start = (int)((skin_num()-num)*scrollvalue); + if(start < 0) + start = 0; + + animstate state; + anim_eval(&data->animations[ANIM_BASE], 0, &state); + anim_eval_add(&state, &data->animations[ANIM_IDLE], 0, 1.0f); + //anim_eval_add(&state, &data->animations[ANIM_WALK], fmod(client_localtime(), 1.0f), 1.0f); + + for(int i = start; i < start+num && i < skin_num(); i++) + { + const skin *s = skin_get(i); + char buf[128]; + sprintf(buf, "%s", s->name); + int selected = 0; + if(strcmp(s->name, config.player_skin) == 0) + selected = 1; + + tee_render_info info; + info.texture = s->org_texture; + info.color_body = vec4(1,1,1,1); + info.color_feet = vec4(1,1,1,1); + if(config.player_use_custom_color) + { + info.color_body = skin_get_color(config.player_color_body); + info.color_feet = skin_get_color(config.player_color_feet); + info.texture = s->color_texture; + } + + info.size = ui2_scale()*50.0f; + + RECT icon; + RECT text; + ui2_vsplit_l(&button, 50.0f, &icon, &text); + + if(ui2_do_button(s, "", selected, &button, ui2_draw_list_row, 0)) + config_set_player_skin(&config, s->name); + + ui2_hsplit_t(&text, 12.0f, 0, &text); // some margin from the top + ui2_do_label(&text, buf, 24, 0); + + ui2_hsplit_t(&icon, 5.0f, 0, &icon); // some margin from the top + render_tee(&state, &info, 0, vec2(1, 0), vec2(icon.x+icon.w/2, icon.y+icon.h/2)); + + ui2_hsplit_t(&list, 50, &button, &list); + } +} + +typedef void (*assign_func_callback)(CONFIGURATION *config, int value); + +static void menu2_render_settings_controls(RECT main_view) +{ + ui2_vsplit_l(&main_view, 300.0f, &main_view, 0); + + { + RECT button, label; + ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); + ui2_vsplit_l(&button, 110.0f, &label, &button); + ui2_do_label(&label, "Mouse sens.", 18.0f, -1); + ui2_hmargin(&button, 2.0f, &button); + config.inp_mousesens = (int)(ui2_do_scrollbar_h(&config.inp_mousesens, &button, config.inp_mousesens/500.0f)*500.0f); + //*key.key = ui2_do_key_reader(key.key, &button, *key.key); + ui2_hsplit_t(&main_view, 20.0f, 0, &main_view); + } + + typedef struct + { + char name[32]; + int *key; + } KEYINFO; + + const KEYINFO keys[] = + { + { "Move Left:", &config.key_move_left }, + { "Move Right:", &config.key_move_right }, + { "Jump:", &config.key_jump }, + { "Fire:", &config.key_fire }, + { "Hook:", &config.key_hook }, + { "Hammer:", &config.key_weapon1 }, + { "Pistol:", &config.key_weapon2 }, + { "Shotgun:", &config.key_weapon3 }, + { "Grenade:", &config.key_weapon4 }, + { "Next Weapon:", &config.key_next_weapon }, + { "Prev. Weapon:", &config.key_prev_weapon }, + { "Emoticon:", &config.key_emoticon }, + { "Chat:", &config.key_chat }, + { "Team Chat:", &config.key_teamchat }, + { "Console:", &config.key_console }, + { "Remote Console:", &config.key_remoteconsole }, + { "Screenshot:", &config.key_screenshot }, + }; + + const int key_count = sizeof(keys) / sizeof(KEYINFO); + + for (int i = 0; i < key_count; i++) + { + KEYINFO key = keys[i]; + RECT button, label; + ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); + ui2_vsplit_l(&button, 110.0f, &label, &button); + + ui2_do_label(&label, key.name, 18.0f, -1); + *key.key = ui2_do_key_reader(key.key, &button, *key.key); + ui2_hsplit_t(&main_view, 5.0f, 0, &main_view); + } +} + +static void menu2_render_settings_graphics(RECT main_view) +{ + RECT button; + char buf[128]; + + static const int MAX_RESOLUTIONS = 256; + static VIDEO_MODE modes[MAX_RESOLUTIONS]; + static int num_modes = -1; + + if(num_modes == -1) + num_modes = gfx_get_video_modes(modes, MAX_RESOLUTIONS); + + RECT modelist; + ui2_vsplit_l(&main_view, 300.0f, &main_view, &modelist); + + // draw allmodes switch + RECT header, footer; + ui2_hsplit_t(&modelist, 20, &button, &modelist); + if (ui2_do_button(&config.gfx_display_all_modes, "Show only supported", config.gfx_display_all_modes^1, &button, ui2_draw_checkbox, 0)) + { + config.gfx_display_all_modes ^= 1; + num_modes = gfx_get_video_modes(modes, MAX_RESOLUTIONS); + } + + // draw header + ui2_hsplit_t(&modelist, 20, &header, &modelist); + ui2_draw_rect(&header, vec4(1,1,1,0.25f), CORNER_T, 5.0f); + ui2_do_label(&header, "Display Modes", 18.0f, 0); + + // draw footers + ui2_hsplit_b(&modelist, 20, &modelist, &footer); + sprintf(buf, "Current: %dx%d %d bit", config.gfx_screen_width, config.gfx_screen_height, config.gfx_color_depth); + ui2_draw_rect(&footer, vec4(1,1,1,0.25f), CORNER_B, 5.0f); + ui2_vsplit_l(&footer, 10.0f, 0, &footer); + ui2_do_label(&footer, buf, 18.0f, -1); + + // modes + ui2_draw_rect(&modelist, vec4(0,0,0,0.15f), 0, 0); + + RECT scroll; + ui2_vsplit_r(&modelist, 15, &modelist, &scroll); + + RECT list = modelist; + ui2_hsplit_t(&list, 20, &button, &list); + + int num = (int)(modelist.h/button.h); + static float scrollvalue = 0; + static int scrollbar = 0; + ui2_hmargin(&scroll, 5.0f, &scroll); + scrollvalue = ui2_do_scrollbar_v(&scrollbar, &scroll, scrollvalue); + + int start = (int)((num_modes-num)*scrollvalue); + if(start < 0) + start = 0; + + for(int i = start; i < start+num && i < num_modes; i++) + { + int depth = modes[i].red+modes[i].green+modes[i].blue; + if(depth < 16) + depth = 16; + else if(depth > 16) + depth = 24; + + int selected = 0; + if(config.gfx_color_depth == depth && + config.gfx_screen_width == modes[i].width && + config.gfx_screen_height == modes[i].height) + { + selected = 1; + } + + sprintf(buf, " %dx%d %d bit", modes[i].width, modes[i].height, depth); + if(ui2_do_button(&modes[i], buf, selected, &button, ui2_draw_list_row, 0)) + { + config.gfx_color_depth = depth; + config.gfx_screen_width = modes[i].width; + config.gfx_screen_height = modes[i].height; + } + + ui2_hsplit_t(&list, 20, &button, &list); + } + + + // switches + ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); + if (ui2_do_button(&config.gfx_fullscreen, "Fullscreen", config.gfx_fullscreen, &button, ui2_draw_checkbox, 0)) + config.gfx_fullscreen ^= 1; + + ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); + if (ui2_do_button(&config.gfx_vsync, "V-Sync", config.gfx_vsync, &button, ui2_draw_checkbox, 0)) + config.gfx_vsync ^= 1; + + ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); + if (ui2_do_button(&config.gfx_fsaa_samples, "FSAA samples", config.gfx_fsaa_samples, &button, ui2_draw_checkbox_number, 0)) + { + if(config.gfx_fsaa_samples < 2) config.gfx_fsaa_samples = 2; + else if(config.gfx_fsaa_samples < 4) config.gfx_fsaa_samples = 4; + else if(config.gfx_fsaa_samples < 6) config.gfx_fsaa_samples = 6; + else if(config.gfx_fsaa_samples < 8) config.gfx_fsaa_samples = 8; + else if(config.gfx_fsaa_samples < 16) config.gfx_fsaa_samples = 16; + else if(config.gfx_fsaa_samples >= 16) config.gfx_fsaa_samples = 0; + } + + ui2_hsplit_t(&main_view, 40.0f, &button, &main_view); + ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); + if (ui2_do_button(&config.gfx_texture_quality, "Quality Textures", config.gfx_texture_quality, &button, ui2_draw_checkbox, 0)) + config.gfx_texture_quality ^= 1; + + ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); + if (ui2_do_button(&config.gfx_texture_compression, "Texture Compression", config.gfx_texture_compression, &button, ui2_draw_checkbox, 0)) + config.gfx_texture_compression ^= 1; + + ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); + if (ui2_do_button(&config.gfx_high_detail, "High Detail", config.gfx_high_detail, &button, ui2_draw_checkbox, 0)) + config.gfx_high_detail ^= 1; + + // + + RECT text; + ui2_hsplit_t(&main_view, 20.0f, 0, &main_view); + ui2_hsplit_t(&main_view, 20.0f, &text, &main_view); + //ui2_vsplit_l(&text, 15.0f, 0, &text); + ui2_do_label(&text, "UI Color", 18, -1); + + const char *labels[] = {"Hue", "Sat.", "Lht.", "Alpha"}; + int *color_slider[4] = {&config.ui_color_hue, &config.ui_color_sat, &config.ui_color_lht, &config.ui_color_alpha}; + for(int s = 0; s < 4; s++) + { + RECT text; + ui2_hsplit_t(&main_view, 19.0f, &button, &main_view); + ui2_vmargin(&button, 15.0f, &button); + ui2_vsplit_l(&button, 30.0f, &text, &button); + ui2_vsplit_r(&button, 5.0f, &button, 0); + ui2_hsplit_t(&button, 4.0f, 0, &button); + + float k = (*color_slider[s]) / 255.0f; + k = ui2_do_scrollbar_h(color_slider[s], &button, k); + *color_slider[s] = (int)(k*255.0f); + ui2_do_label(&text, labels[s], 20, -1); + } +} + +static void menu2_render_settings_sound(RECT main_view) +{ + RECT button; + ui2_vsplit_l(&main_view, 300.0f, &main_view, 0); + + ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); + if (ui2_do_button(&config.snd_enable, "Use Sounds", config.snd_enable, &button, ui2_draw_checkbox, 0)) + config.snd_enable ^= 1; + + if(!config.snd_enable) + return; + + // sample rate box + { + char buf[64]; + sprintf(buf, "%d", config.snd_rate); + ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); + ui2_do_label(&button, "Sample Rate", 18.0, -1); + ui2_vsplit_l(&button, 110.0f, 0, &button); + ui2_vsplit_l(&button, 180.0f, &button, 0); + ui2_do_edit_box(&config.snd_rate, &button, buf, sizeof(buf)); + config.snd_rate = atoi(buf); + + if(config.snd_rate < 1) + config.snd_rate = 1; + } + + // volume slider + { + RECT button, label; + ui2_hsplit_t(&main_view, 5.0f, &button, &main_view); + ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); + ui2_vsplit_l(&button, 110.0f, &label, &button); + ui2_hmargin(&button, 2.0f, &button); + ui2_do_label(&label, "Sound Volume", 18.0f, -1); + config.snd_volume = (int)(ui2_do_scrollbar_h(&config.snd_volume, &button, config.snd_volume/100.0f)*100.0f); + ui2_hsplit_t(&main_view, 20.0f, 0, &main_view); + } +} + + +static void menu2_render_settings_network(RECT main_view) +{ + RECT button; + ui2_vsplit_l(&main_view, 300.0f, &main_view, 0); + + { + ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); + ui2_do_label(&button, "Rcon Password", 18.0, -1); + ui2_vsplit_l(&button, 110.0f, 0, &button); + ui2_vsplit_l(&button, 180.0f, &button, 0); + ui2_do_edit_box(&config.rcon_password, &button, config.rcon_password, sizeof(config.rcon_password), true); + } +} + +static void menu2_render_settings(RECT main_view) +{ + static int settings_page = 0; + + // render background + RECT temp, tabbar; + ui2_vsplit_r(&main_view, 120.0f, &main_view, &tabbar); + ui2_draw_rect(&main_view, color_tabbar_active, CORNER_B|CORNER_TL, 10.0f); + ui2_hsplit_t(&tabbar, 50.0f, &temp, &tabbar); + ui2_draw_rect(&temp, color_tabbar_active, CORNER_R, 10.0f); + + ui2_hsplit_t(&main_view, 10.0f, 0, &main_view); + + RECT button; + + const char *tabs[] = {"Player", "Controls", "Network", "Graphics", "Sound"}; + int num_tabs = (int)(sizeof(tabs)/sizeof(*tabs)); + + for(int i = 0; i < num_tabs; i++) + { + ui2_hsplit_t(&tabbar, 10, &button, &tabbar); + ui2_hsplit_t(&tabbar, 26, &button, &tabbar); + if(ui2_do_button(tabs[i], tabs[i], settings_page == i, &button, ui2_draw_settings_tab_button, 0)) + settings_page = i; + } + + ui2_margin(&main_view, 10.0f, &main_view); + + if(settings_page == 0) + menu2_render_settings_player(main_view); + else if(settings_page == 1) + menu2_render_settings_controls(main_view); + else if(settings_page == 2) + menu2_render_settings_network(main_view); + else if(settings_page == 3) + menu2_render_settings_graphics(main_view); + else if(settings_page == 4) + menu2_render_settings_sound(main_view); +} + +static void menu2_render_news(RECT main_view) +{ + ui2_draw_rect(&main_view, color_tabbar_active, CORNER_ALL, 10.0f); +} + + +static void menu2_render_game(RECT main_view) +{ + RECT button; + ui2_hsplit_t(&main_view, 45.0f, &main_view, 0); + ui2_draw_rect(&main_view, color_tabbar_active, CORNER_ALL, 10.0f); + + ui2_hsplit_t(&main_view, 10.0f, 0, &main_view); + ui2_hsplit_t(&main_view, 25.0f, &main_view, 0); + ui2_vmargin(&main_view, 10.0f, &main_view); + + ui2_vsplit_r(&main_view, 120.0f, &main_view, &button); + static int disconnect_button = 0; + if(ui2_do_button(&disconnect_button, "Disconnect", 0, &button, ui2_draw_menu_button, 0)) + client_disconnect(); + + if(local_info) + { + if(local_info->team != -1) + { + ui2_vsplit_l(&main_view, 10.0f, &button, &main_view); + ui2_vsplit_l(&main_view, 120.0f, &button, &main_view); + static int spectate_button = 0; + if(ui2_do_button(&spectate_button, "Spectate", 0, &button, ui2_draw_menu_button, 0)) + { + config.cl_team = -1; + menu_active = false; + } + } + + if(local_info->team != 0) + { + ui2_vsplit_l(&main_view, 10.0f, &button, &main_view); + ui2_vsplit_l(&main_view, 120.0f, &button, &main_view); + static int spectate_button = 0; + if(ui2_do_button(&spectate_button, "Join Red", 0, &button, ui2_draw_menu_button, 0)) + { + config.cl_team = 0; + menu_active = false; + } + } + + if(local_info->team != 1) + { + ui2_vsplit_l(&main_view, 10.0f, &button, &main_view); + ui2_vsplit_l(&main_view, 120.0f, &button, &main_view); + static int spectate_button = 0; + if(ui2_do_button(&spectate_button, "Join Blue", 0, &button, ui2_draw_menu_button, 0)) + { + config.cl_team = 1; + menu_active = false; + } + } + } +} + +void menu_do_disconnected() +{ + popup = POPUP_NONE; + if(client_error_string() && client_error_string()[0] != 0) + { + if(strstr(client_error_string(), "password")) + { + popup = POPUP_PASSWORD; + ui_set_hot_item(&config.password); + ui_set_active_item(&config.password); + } + else + popup = POPUP_DISCONNECTED; + } +} + +void menu_do_connecting() +{ + popup = POPUP_CONNECTING; +} + +void menu_do_connected() +{ + popup = POPUP_NONE; +} + +int menu2_render() +{ + if(0) + { + gfx_mapscreen(0,0,10*4/3.0f,10); + gfx_clear(gui_color.r, gui_color.g, gui_color.b); + + animstate state; + anim_eval(&data->animations[ANIM_BASE], 0, &state); + anim_eval_add(&state, &data->animations[ANIM_IDLE], 0, 1.0f); + //anim_eval_add(&state, &data->animations[ANIM_WALK], fmod(client_localtime(), 1.0f), 1.0f); + + for(int i = 0; i < skin_num(); i++) + { + float x = (i/8)*3; + float y = (i%8); + for(int c = 0; c < 2; c++) + { + //int colors[2] = {54090, 10998628}; + //int colors[2] = {65432, 9895832}; // NEW + int colors[2] = {65387, 10223467}; // NEW + + tee_render_info info; + info.texture = skin_get(i)->color_texture; + info.color_feet = info.color_body = skin_get_color(colors[c]); + //info.color_feet = info.color_body = vec4(1,1,1,1); + info.size = 1.0f; //ui2_scale()*16.0f; + //render_tee(&state, &info, 0, vec2(sinf(client_localtime()*3), cosf(client_localtime()*3)), vec2(1+x+c,1+y)); + render_tee(&state, &info, 0, vec2(1,0), vec2(1+x+c,1+y)); + } + } + + return 0; + } + + RECT screen = *ui2_screen(); + gfx_mapscreen(screen.x, screen.y, screen.w, screen.h); + + static bool first = true; + if(first) + { + if(config.ui_page == PAGE_INTERNET) + client_serverbrowse_refresh(0); + else if(config.ui_page == PAGE_LAN) + client_serverbrowse_refresh(1); + first = false; + } + + if(client_state() == CLIENTSTATE_ONLINE) + { + color_tabbar_inactive = color_tabbar_inactive_ingame; + color_tabbar_active = color_tabbar_active_ingame; + } + else + { + menu2_render_background(); + color_tabbar_inactive = color_tabbar_inactive_outgame; + color_tabbar_active = color_tabbar_active_outgame; + } + + RECT tab_bar; + RECT main_view; + + // some margin around the screen + ui2_margin(&screen, 10.0f, &screen); + + if(popup == POPUP_NONE) + { + // do tab bar + ui2_hsplit_t(&screen, 26.0f, &tab_bar, &main_view); + ui2_vmargin(&tab_bar, 20.0f, &tab_bar); + menu2_render_menubar(tab_bar); + + // render current page + if(menu_game_active) + menu2_render_game(main_view); + else if(config.ui_page == PAGE_NEWS) + menu2_render_news(main_view); + else if(config.ui_page == PAGE_INTERNET) + menu2_render_serverbrowser(main_view); + else if(config.ui_page == PAGE_LAN) + menu2_render_serverbrowser(main_view); + else if(config.ui_page == PAGE_FAVORITES) + menu2_render_serverbrowser(main_view); + else if(config.ui_page == PAGE_SETTINGS) + menu2_render_settings(main_view); + } + else + { + // make sure that other windows doesn't do anything funnay! + //ui_set_hot_item(0); + //ui_set_active_item(0); + const char *title = ""; + const char *extra_text = ""; + const char *button_text = ""; + + if(popup == POPUP_CONNECTING) + { + title = "Connecting to"; + extra_text = config.ui_server_address; // TODO: query the client about the address + button_text = "Abort"; + } + else if(popup == POPUP_DISCONNECTED) + { + title = "Disconnected"; + extra_text = client_error_string(); + button_text = "Ok"; + } + else if(popup == POPUP_PASSWORD) + { + title = "Password Error"; + extra_text = client_error_string(); + button_text = "Try Again"; + } + else if(popup == POPUP_QUIT) + { + title = "Quit"; + extra_text = "Are you sure that you want to quit?"; + } + + + RECT box, part; + box = screen; + ui2_vmargin(&box, 150.0f, &box); + ui2_hmargin(&box, 150.0f, &box); + + // render the box + ui2_draw_rect(&box, vec4(0,0,0,0.5f), CORNER_ALL, 15.0f); + + ui2_hsplit_t(&box, 20.f, &part, &box); + ui2_hsplit_t(&box, 24.f, &part, &box); + ui2_do_label(&part, title, 24.f, 0); + ui2_hsplit_t(&box, 20.f, &part, &box); + ui2_hsplit_t(&box, 24.f, &part, &box); + ui2_do_label(&part, extra_text, 20.f, 0); + + if(popup == POPUP_QUIT) + { + RECT tryagain, abort; + ui2_hsplit_b(&box, 20.f, &box, &part); + ui2_hsplit_b(&box, 24.f, &box, &part); + ui2_vmargin(&part, 120.0f, &part); + + ui2_vsplit_l(&part, 100.0f, &abort, &part); + ui2_vsplit_r(&part, 100.0f, 0, &tryagain); + + static int button_abort = 0; + if(ui2_do_button(&button_abort, "No", 0, &abort, ui2_draw_menu_button, 0) || inp_key_down(KEY_ESC)) + popup = POPUP_NONE; + + static int button_tryagain = 0; + if(ui2_do_button(&button_tryagain, "Yes", 0, &tryagain, ui2_draw_menu_button, 0) || inp_key_down(KEY_ENTER)) + client_quit(); + } + else if(popup == POPUP_PASSWORD) + { + RECT label, textbox, tryagain, abort; + + ui2_hsplit_b(&box, 20.f, &box, &part); + ui2_hsplit_b(&box, 24.f, &box, &part); + ui2_vmargin(&part, 120.0f, &part); + + ui2_vsplit_l(&part, 100.0f, &abort, &part); + ui2_vsplit_r(&part, 100.0f, 0, &tryagain); + + static int button_abort = 0; + if(ui2_do_button(&button_abort, "Abort", 0, &abort, ui2_draw_menu_button, 0) || inp_key_down(KEY_ESC)) + popup = POPUP_NONE; + + static int button_tryagain = 0; + if(ui2_do_button(&button_tryagain, "Try again", 0, &tryagain, ui2_draw_menu_button, 0) || inp_key_down(KEY_ENTER)) + { + client_connect(config.ui_server_address); + } + + ui2_hsplit_b(&box, 60.f, &box, &part); + ui2_hsplit_b(&box, 24.f, &box, &part); + + ui2_vsplit_l(&part, 60.0f, 0, &label); + ui2_vsplit_l(&label, 100.0f, 0, &textbox); + ui2_vsplit_l(&textbox, 20.0f, 0, &textbox); + ui2_vsplit_r(&textbox, 60.0f, &textbox, 0); + ui2_do_label(&label, "Password:", 20, -1); + ui2_do_edit_box(&config.password, &textbox, config.password, sizeof(config.password), true); + } + else + { + ui2_hsplit_b(&box, 20.f, &box, &part); + ui2_hsplit_b(&box, 24.f, &box, &part); + ui2_vmargin(&part, 120.0f, &part); + + static int button = 0; + if(ui2_do_button(&button, button_text, 0, &part, ui2_draw_menu_button, 0) || inp_key_down(KEY_ESC) || inp_key_down(KEY_ENTER)) + { + if(popup == POPUP_CONNECTING) + client_disconnect(); + popup = POPUP_NONE; + } + } + } + + return 0; +} + +void modmenu_render() +{ + static int mouse_x = 0; + static int mouse_y = 0; + + // update colors + + vec3 rgb = hsl_to_rgb(vec3(config.ui_color_hue/255.0f, config.ui_color_sat/255.0f, config.ui_color_lht/255.0f)); + gui_color = vec4(rgb.r, rgb.g, rgb.b, config.ui_color_alpha/255.0f); + + color_tabbar_inactive_outgame = vec4(0,0,0,0.25f); + color_tabbar_active_outgame = vec4(0,0,0,0.5f); + + color_ingame_scale_i = 0.5f; + color_ingame_scale_a = 0.2f; + color_tabbar_inactive_ingame = vec4( + gui_color.r*color_ingame_scale_i, + gui_color.g*color_ingame_scale_i, + gui_color.b*color_ingame_scale_i, + gui_color.a*0.8f); + + color_tabbar_active_ingame = vec4( + gui_color.r*color_ingame_scale_a, + gui_color.g*color_ingame_scale_a, + gui_color.b*color_ingame_scale_a, + gui_color.a); + + + // handle mouse movement + float mx, my; + { + 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 + RECT *screen = ui2_screen(); + mx = (mouse_x/(float)gfx_screenwidth())*screen->w; + my = (mouse_y/(float)gfx_screenheight())*screen->h; + + int buttons = 0; + if(inp_key_pressed(KEY_MOUSE_1)) buttons |= 1; + if(inp_key_pressed(KEY_MOUSE_2)) buttons |= 2; + if(inp_key_pressed(KEY_MOUSE_3)) buttons |= 4; + + ui_update(mx,my,mx*3.0f,my*3.0f,buttons); + } + + menu2_render(); + + gfx_texture_set(data->images[IMAGE_CURSOR].id); + gfx_quads_begin(); + gfx_setcolor(1,1,1,1); + gfx_quads_drawTL(mx,my,24,24); + gfx_quads_end(); + + inp_clear(); +} diff --git a/src/game/client/gc_menu.h b/src/game/client/gc_menu.h new file mode 100644 index 00000000..5c68c53d --- /dev/null +++ b/src/game/client/gc_menu.h @@ -0,0 +1,16 @@ +/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */ +#ifndef __MENU_H +#define __MENU_H + +void draw_image_button(void *id, const char *text, int checked, float x, float y, float w, float h, void *extra); +void draw_single_part_button(void *id, const char *text, int checked, float x, float y, float w, float h, void *extra); +void draw_menu_button(void *id, const char *text, int checked, float x, float y, float w, float h, void *extra); +void draw_teewars_button(void *id, const char *text, int checked, float x, float y, float w, float h, void *extra); +int ui_do_key_reader(void *id, float x, float y, float w, float h, int key); +int ui_do_combo_box(void *id, float x, float y, float w, char *lines, int line_count, int selected_index); +int ui_do_edit_box(void *id, float x, float y, float w, float h, char *str, int str_size); +int ui_do_check_box(void *id, float x, float y, float w, float h, int value); +int do_scroll_bar_horiz(void *id, float x, float y, float width, int steps, int last_index); +int do_scroll_bar_vert(void *id, float x, float y, float height, int steps, int last_index); + +#endif diff --git a/src/game/client/gc_render.h b/src/game/client/gc_render.h new file mode 100644 index 00000000..fc85d49a --- /dev/null +++ b/src/game/client/gc_render.h @@ -0,0 +1,24 @@ +/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */ +struct animstate +{ + keyframe body; + keyframe back_foot; + keyframe front_foot; + keyframe attach; +}; + +void anim_seq_eval(sequence *seq, float time, keyframe *frame); +void anim_eval(animation *anim, float time, animstate *state); +void anim_add_keyframe(keyframe *seq, keyframe *added, float amount); +void anim_add(animstate *state, animstate *added, float amount); +void anim_eval_add(animstate *state, animation *anim, float time, float amount); + +struct tee_render_info +{ + int texture; + vec4 color_body; + vec4 color_feet; + float size; +}; + +void render_tee(animstate *anim, tee_render_info *info, int emote, vec2 dir, vec2 pos); diff --git a/src/game/client/gc_skin.cpp b/src/game/client/gc_skin.cpp new file mode 100644 index 00000000..cc5699e4 --- /dev/null +++ b/src/game/client/gc_skin.cpp @@ -0,0 +1,167 @@ +/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */ +#include +#include +#include +#include +#include "gc_skin.h" +#include "../g_math.h" + +enum +{ + MAX_SKINS=256, +}; + +static skin skins[MAX_SKINS] = {{0}}; +static int num_skins = 0; + +static void skinscan(const char *name, int is_dir, void *user) +{ + int l = strlen(name); + if(l < 4 || is_dir || num_skins == MAX_SKINS) + return; + if(strcmp(name+l-4, ".png") != 0) + return; + + char buf[512]; + sprintf(buf, "data/skins/%s", name); + IMAGE_INFO info; + if(!gfx_load_png(&info, buf)) + { + dbg_msg("game", "failed to load skin from %s", name); + return; + } + + skins[num_skins].org_texture = gfx_load_texture_raw(info.width, info.height, info.format, info.data); + + // create colorless version + unsigned char *d = (unsigned char *)info.data; + int step = info.format == IMG_RGBA ? 4 : 3; + + for(int i = 0; i < info.width*info.height; i++) + { + int v = (d[i*step]+d[i*step+1]+d[i*step+2])/3; + d[i*step] = v; + d[i*step+1] = v; + d[i*step+2] = v; + } + + if(1) + { + int bs = 96; // body size + int pitch = info.width*4; + int freq[256] = {0}; + + for(int y = 0; y < bs; y++) + for(int x = 0; x < bs; x++) + { + if(d[y*pitch+x*4+3] > 128) + freq[d[y*pitch+x*4]]++; + } + + int org_weight = 0; + int new_weight = 192; + for(int i = 1; i < 256; i++) + { + if(freq[org_weight] < freq[i]) + org_weight = i; + } + + int inv_org_weight = 255-org_weight; + int inv_new_weight = 255-new_weight; + for(int y = 0; y < bs; y++) + for(int x = 0; x < bs; x++) + { + int v = d[y*pitch+x*4]; + if(v <= org_weight) + v = (int)(((v/(float)org_weight) * new_weight)); + else + v = (int)(((v-org_weight)/(float)inv_org_weight)*inv_new_weight + new_weight); + d[y*pitch+x*4] = v; + d[y*pitch+x*4+1] = v; + d[y*pitch+x*4+2] = v; + } + } + + skins[num_skins].color_texture = gfx_load_texture_raw(info.width, info.height, info.format, info.data); + mem_free(info.data); + + // set skin data + strncpy(skins[num_skins].name, name, min((int)sizeof(skins[num_skins].name),l-4)); + dbg_msg("game", "load skin %s", skins[num_skins].name); + num_skins++; +} + + +void skin_init() +{ + // load skins + fs_listdir("data/skins", skinscan, 0); +} + +int skin_num() +{ + return num_skins; +} + +const skin *skin_get(int index) +{ + return &skins[index%num_skins]; +} + +int skin_find(const char *name) +{ + for(int i = 0; i < num_skins; i++) + { + if(strcmp(skins[i].name, name) == 0) + return i; + } + return -1; +} + + + + +// these converter functions were nicked from some random internet pages +static float hue_to_rgb(float v1, float v2, float h) +{ + if(h < 0) h += 1; + if(h > 1) h -= 1; + if((6 * h) < 1) return v1 + ( v2 - v1 ) * 6 * h; + if((2 * h) < 1) return v2; + if((3 * h) < 2) return v1 + ( v2 - v1 ) * ((2.0f/3.0f) - h) * 6; + return v1; +} + +vec3 hsl_to_rgb(vec3 in) +{ + float v1, v2; + vec3 out; + + if(in.s == 0) + { + out.r = in.l; + out.g = in.l; + out.b = in.l; + } + else + { + if(in.l < 0.5f) + v2 = in.l * (1 + in.s); + else + v2 = (in.l+in.s) - (in.s*in.l); + + v1 = 2 * in.l - v2; + + out.r = hue_to_rgb(v1, v2, in.h + (1.0f/3.0f)); + out.g = hue_to_rgb(v1, v2, in.h); + out.b = hue_to_rgb(v1, v2, in.h - (1.0f/3.0f)); + } + + return out; +} + +vec4 skin_get_color(int v) +{ + vec3 r = hsl_to_rgb(vec3((v>>16)/255.0f, ((v>>8)&0xff)/255.0f, 0.5f+(v&0xff)/255.0f*0.5f)); + return vec4(r.r, r.g, r.b, 1.0f); +} diff --git a/src/game/client/gc_skin.h b/src/game/client/gc_skin.h new file mode 100644 index 00000000..3742d04e --- /dev/null +++ b/src/game/client/gc_skin.h @@ -0,0 +1,20 @@ +/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */ +#include "../g_vmath.h" + +// do this better and nicer +typedef struct +{ + int org_texture; + int color_texture; + char name[31]; + char term[1]; +} skin; + +vec4 skin_get_color(int v); +void skin_init(); +int skin_num(); +const skin *skin_get(int index); +int skin_find(const char *name); + + +vec3 hsl_to_rgb(vec3 in); diff --git a/src/game/client/mapres_image.cpp b/src/game/client/mapres_image.cpp deleted file mode 100644 index 1ef1617c..00000000 --- a/src/game/client/mapres_image.cpp +++ /dev/null @@ -1,125 +0,0 @@ -/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */ -#include -#include -#include "mapres_image.h" -#include "../mapres.h" - -static int map_textures[64] = {0}; -static int count = 0; -/* -static void calc_mipmaps(void *data_in, unsigned width, unsigned height, void *data_out) -{ - unsigned char *src = (unsigned char*)data_in; - unsigned char *dst = (unsigned char*)data_out; - unsigned mip_w = width; - unsigned mip_h = height; - unsigned prev_w; - unsigned prev_h; - - // Highest level - no mod - for(unsigned x = 0; x < mip_w; x++) - { - for(unsigned y = 0; y < mip_h; y++) - { - unsigned i = (y * mip_w + x)<<2; - for(unsigned j = 0; j < 4; j++) - dst[i+j] = src[i+j]; - } - } - - src = dst; - dst += mip_w * mip_h * 4; - prev_w = mip_w; - prev_h = mip_h; - mip_w = mip_w>>1; - mip_h = mip_h>>1; - - while(mip_w > 0 && mip_h > 0) - { - for(unsigned x = 0; x < mip_w; x++) - { - for(unsigned y = 0; y < mip_h; y++) - { - unsigned i = (y * mip_w + x)<<2; - - unsigned r = 0; - unsigned g = 0; - unsigned b = 0; - unsigned a = 0; - - - r += src[(((y<<1) * prev_w + (x<<1))<<2)]; - g += src[(((y<<1) * prev_w + (x<<1))<<2)+1]; - b += src[(((y<<1) * prev_w + (x<<1))<<2)+2]; - a += src[(((y<<1) * prev_w + (x<<1))<<2)+3]; - - r += src[(((y<<1) * prev_w + ((x+1)<<1))<<2)]; - g += src[(((y<<1) * prev_w + ((x+1)<<1))<<2)+1]; - b += src[(((y<<1) * prev_w + ((x+1)<<1))<<2)+2]; - a += src[(((y<<1) * prev_w + ((x+1)<<1))<<2)+3]; - - r += src[((((y+1)<<1) * prev_w + (x<<1))<<2)]; - g += src[((((y+1)<<1) * prev_w + (x<<1))<<2)+1]; - b += src[((((y+1)<<1) * prev_w + (x<<1))<<2)+2]; - a += src[((((y+1)<<1) * prev_w + (x<<1))<<2)+3]; - - r += src[((((y+1)<<1) * prev_w + ((x+1)<<1))<<2)]; - g += src[((((y+1)<<1) * prev_w + ((x+1)<<1))<<2)+1]; - b += src[((((y+1)<<1) * prev_w + ((x+1)<<1))<<2)+2]; - a += src[((((y+1)<<1) * prev_w + ((x+1)<<1))<<2)+3]; - - dst[i] = r>>2; - dst[i+1] = g>>2; - dst[i+2] = b>>2; - dst[i+3] = a>>2; - } - } - - src = dst; - dst = dst + mip_w*mip_h*4; - prev_w = mip_w; - prev_h = mip_h; - mip_w = mip_w>>1; - mip_h = mip_h>>1; - } -} -*/ -extern int DEBUGTEST_MAPIMAGE; - -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; - } - } - - //void *data_res = (void*)mem_alloc(1024*1024*4*2, 16); - 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); - //calc_mipmaps(data, img->width, img->height, data_res); - map_textures[i] = gfx_load_texture_raw(img->width, img->height, IMG_RGBA, data); - map_unload_data(img->image_data); - } - - //mem_free(data_res); - 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 deleted file mode 100644 index f841ca53..00000000 --- a/src/game/client/mapres_image.h +++ /dev/null @@ -1,19 +0,0 @@ -/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */ - -// 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 deleted file mode 100644 index 6bee4081..00000000 --- a/src/game/client/mapres_tilemap.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */ -#include -#include -#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; - - float screen_x0, screen_y0, screen_x1, screen_y1; - gfx_getscreen(&screen_x0, &screen_y0, &screen_x1, &screen_y1); - - // 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)) - { - if(!config.gfx_high_detail && !tmap->main) - continue; - gfx_texture_set(img_get(tmap->image)); - - gfx_quads_begin(); - - int starty = (int)(screen_y0/scale)-1; - int startx = (int)(screen_x0/scale)-1; - int endy = (int)(screen_y1/scale)+1; - int endx = (int)(screen_x1/scale)+1; - - float frac = (1.25f/1024.0f);//2.0f; //2.0f; - float texsize = 1024.0f; - float nudge = 0.5f/texsize; - for(int y = starty; y < endy; y++) - for(int x = startx; x < endx; x++) - { - int mx = x; - int my = y; - if(mx<0) mx = 0; - if(mx>=tmap->width) mx = tmap->width-1; - if(my<0) my = 0; - if(my>=tmap->height) my = tmap->height-1; - - int c = mx + my*tmap->width; - - unsigned char d = data[c*2]; - unsigned char f = data[c*2+1]; - if(d) - { - int tx = d%16; - int ty = d/16; - int px0 = tx*(1024/16); - int py0 = ty*(1024/16); - int px1 = (tx+1)*(1024/16)-1; - int py1 = (ty+1)*(1024/16)-1; - - float u0 = nudge + px0/texsize+frac; - float v0 = nudge + py0/texsize+frac; - float u1 = nudge + px1/texsize-frac; - float v1 = nudge + py1/texsize-frac; - - if(f&TILEFLAG_VFLIP) - { - float tmp = u0; - u0 = u1; - u1 = tmp; - } - - if(f&TILEFLAG_HFLIP) - { - float tmp = v0; - v0 = v1; - v1 = tmp; - } - - gfx_quads_setsubset(u0,v0,u1,v1); - - 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 deleted file mode 100644 index a13495ed..00000000 --- a/src/game/client/mapres_tilemap.h +++ /dev/null @@ -1,26 +0,0 @@ -/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */ - -// dependencies: image - -// -int tilemap_init(); - -// renders the tilemaps -void tilemap_render(float scale, int fg); - -enum -{ - TILEFLAG_VFLIP=1, - TILEFLAG_HFLIP=2, -}; - -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 deleted file mode 100644 index 10dafc39..00000000 --- a/src/game/client/menu.cpp +++ /dev/null @@ -1,1865 +0,0 @@ -/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */ -#if 0 - -#include -#include -#include -#include - -#include - -extern "C" { - #include - #include - #include - #include -} - -#include "../mapres.h" -#include "../version.h" - -#include "mapres_image.h" -#include "mapres_tilemap.h" - -#include "data.h" -#include - -extern data_container *data; - -/******************************************************** - MENU -*********************************************************/ - -enum gui_tileset_enum -{ - tileset_regular, - tileset_hot, - tileset_active, - tileset_inactive -}; - -void draw_area(gui_tileset_enum tileset, int areax, int areay, int areaw, int areah, float x, float y, float w, float h) -{ -/* - const float tex_w = 512.0, tex_h = 512.0; - - switch (tileset) - { - case tileset_regular: - break; - case tileset_hot: - areax += 192; areay += 192; break; - case tileset_active: - areay += 192; break; - case tileset_inactive: - areax += 192; break; - default: - dbg_msg("menu", "invalid tileset given to draw_part"); - } - - float ts_x = areax / tex_w; - float ts_y = areay / tex_h; - float te_x = (areax + areaw) / tex_w; - float te_y = (areay + areah) / tex_h; - - gfx_blend_normal(); - gfx_texture_set(data->images[IMAGE_GUI_WIDGETS].id); - gfx_quads_begin(); - gfx_setcolor(1,1,1,1); - gfx_quads_setsubset( - ts_x, // startx - ts_y, // starty - te_x, // endx - te_y); // endy - gfx_quads_drawTL(x,y,w,h); - gfx_quads_end(); - */ -} - -void draw_part(int part_type, gui_tileset_enum tileset, float x, float y, float w, float h) -{ - gui_box part = data->gui.misc[part_type]; - - draw_area(tileset, part.x, part.y, part.w, part.h, x, y, w, h); - - //draw_part(parts[part], tileset, x, y, w, h); -} - -void draw_part(int part_type, gui_tileset_enum tileset, float x, float y) -{ - gui_box part = data->gui.misc[part_type]; - - draw_part(part_type, tileset, x, y, part.w, part.h); -} - -void draw_box(int box_type, gui_tileset_enum tileset, float x, float y, float w, float h) -{ - gui_compositebox box = data->gui.boxes[box_type]; - - /* A composite box consists of 9 parts. To get the coordinates for all corners, we need A, B, C and D: - * A----+----+----+ - * | tl | tm | tr | - * +----B----+----+ - * | ml | mm | mr | - * +----+----C----+ - * | bl | bm | br | - * +----+----+----D - */ - - int ax = box.rect.x; - int ay = box.rect.y; - - int bx = box.center.x; - int by = box.center.y; - - int cx = box.center.x + box.center.w; - int cy = box.center.y + box.center.h; - - int dx = box.rect.x + box.rect.w; - int dy = box.rect.y + box.rect.h; - - draw_area(tileset, ax, ay, bx-ax, by-ay, x, y, bx-ax, by-ay); - draw_area(tileset, bx, ay, cx-bx, by-ay, x+bx-ax, y, w-(bx-ax)-(dx-cx), by-ay); - draw_area(tileset, cx, ay, dx-cx, by-ay, x+w-(dx-cx), y, dx-cx, by-ay); - - draw_area(tileset, ax, by, bx-ax, min(int(h-(by-ay)-(dy-cy)), cy-by), x, y+(by-ay), bx-ax, h-(by-ay)-(dy-cy)); - draw_area(tileset, bx, by, cx-bx, cy-by, x+bx-ax, y+(by-ay), w-(bx-ax)-(dx-cx), h-(by-ay)-(dy-cy)); - draw_area(tileset, cx, by, dx-cx, min(int(h-(by-ay)-(dy-cy)), cy-by), x+w-(dx-cx), y+(by-ay), dx-cx, h-(by-ay)-(dy-cy)); - - draw_area(tileset, ax, cy, bx-ax, dy-cy, x, y+h-(dy-cy), bx-ax, dy-cy); - draw_area(tileset, bx, cy, cx-bx, dy-cy, x+bx-ax, y+h-(dy-cy), w-(bx-ax)-(dx-cx), dy-cy); - draw_area(tileset, cx, cy, dx-cx, dy-cy, x+w-(dx-cx), y+h-(dy-cy), dx-cx, dy-cy); -} - -extern "C" -{ - -struct pretty_font -{ - float m_CharStartTable[256]; - float m_CharEndTable[256]; - int font_texture; -}; - -extern pretty_font *current_font; - -} - -extern void render_sun(float x, float y); -extern void select_sprite(int id, int flags=0, int sx=0, int sy=0); -extern void draw_sprite(float x, float y, float size); - -void draw_background(float t) -{ - // background color - gfx_clear(0.65f,0.78f,0.9f); - - gfx_blend_normal(); - - render_sun(170, 170); - - gfx_texture_set(data->images[IMAGE_CLOUDS].id); - gfx_quads_begin(); - select_sprite(SPRITE_CLOUD1); - draw_sprite(3500 - fmod(t * 20 + 2000, 4524), 250, 512); - select_sprite(SPRITE_CLOUD2); - draw_sprite(3000 - fmod(t * 50 + 2000, 4024), 150+250, 512); - select_sprite(SPRITE_CLOUD3); - draw_sprite(4000 - fmod(t * 60 + 500, 4512), 300+130, 256); - gfx_quads_end(); - - /* - gfx_texture_set(data->images[IMAGE_MENU_BACKGROUND].id); - gfx_quads_begin(); - gfx_quads_drawTL(0, 430, 1600, 1600/2); - gfx_quads_end(); - */ - -/* - int frame = int(t * 10) % 3; - - //float x_path = -t - - float x_nudge = 3*cos(t*10); - float y_nudge = 8*sin(t*3); - - x_nudge += 150 * cos(t/3); - y_nudge += 30 * sin(t/3); - - float angl = t/3; - angl = fmod(angl, 2*pi); - - bool flip = angl > pi; - - gfx_texture_set(data->images[IMAGE_MENU_BUTTERFLY].id); - gfx_quads_begin(); - gfx_setcolor(1, 1, 1, 1); - gfx_quads_setsubset( - flip ? (frame + 1) * 0.25f : frame * 0.25f, // startx - 0.0f, // starty - flip ? frame * 0.25f : (frame + 1) * 0.25f, // endx - 0.5f); // endy - gfx_quads_drawTL(1250 + x_nudge, 480 + y_nudge, 64, 64); - gfx_quads_end(); - */ -} - -void draw_image_button(const 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); -} - -void draw_single_part_button(const void *id, const char *text, int checked, float x, float y, float w, float h, void *extra) -{ - gui_tileset_enum tileset; - - if (ui_active_item() == id && ui_hot_item() == id) - tileset = tileset_active; - else if (ui_hot_item() == id) - tileset = tileset_hot; - else - tileset = tileset_regular; - - - draw_part((int)((char*)extra-(char*)0), tileset, x, y, w, h); -} - -void draw_menu_button(const void *id, const char *text, int checked, float x, float y, float w, float h, void *extra) -{ - int box_type; - if ((int)((char*)extra-(char*)0)) - box_type = GUI_BOX_SCREEN_INFO; - else - box_type = GUI_BOX_SCREEN_LIST; - draw_box(box_type, tileset_regular, x, y, w, h); - - ui_do_label(x + 10, y, text, 28); -} - -void draw_teewars_button(const void *id, const char *text, int checked, float x, float y, float w, float h, void *extra) -{ - const float font_size = h-6.0f;//42.0f; - - float text_width = gfx_pretty_text_width(font_size, text, -1); - gui_tileset_enum tileset; - - if (ui_active_item() == id) - { - int inside = ui_mouse_inside(x, y, w, h); - tileset = inside ? tileset_active : tileset_hot; - } - else if (ui_hot_item() == id) - tileset = tileset_hot; - else - tileset = tileset_regular; - - if ((int)((char*)extra-(char*)0) == 1) - tileset = tileset_inactive; - - draw_box(GUI_BOX_BUTTON, tileset, x, y, w, h); - - ui_do_label(x + w/2 - text_width/2, y + 2, text, font_size); -} - -/* -struct server_info -{ - int version; - int players; - int max_players; - netaddr4 address; - char name[129]; - char map[65]; -};*/ - -struct server_list -{ - int active_count, info_count; - int scroll_index; - int selected_index; -}; - -int ui_do_key_reader(void *id, float x, float y, float w, float h, int key) -{ - // process - static bool mouse_released = true; - int inside = ui_mouse_inside(x, y, w, h); - int new_key = key; - - if(!ui_mouse_button(0)) - mouse_released = true; - - if(ui_active_item() == id) - { - int k = inp_last_key(); - if (k) - { - new_key = k; - ui_set_active_item(0); - mouse_released = false; - } - } - else if(ui_hot_item() == id) - { - if(ui_mouse_button(0) && mouse_released) - ui_set_active_item(id); - } - - if(inside) - ui_set_hot_item(id); - - // draw - int box_type; - if (ui_active_item() == id || ui_hot_item() == id) - box_type = GUI_BOX_SCREEN_INFO; - else - box_type = GUI_BOX_SCREEN_TEXTBOX; - draw_box(box_type, tileset_regular, x, y, w, h); - - const char *str = inp_key_name(key); - ui_do_label(x + 10, y, str, 36); - if (ui_active_item() == id) - { - float w = gfx_pretty_text_width(36.0f, str, -1); - ui_do_label(x + 10 + w, y, "_", 36); - } - - return new_key; -} - -int ui_do_combo_box(void *id, float x, float y, float w, const char **lines, int line_count, int selected_index) -{ - float line_height = 36.0f; - float height = line_count * line_height; - - int inside = (ui_active_item() == id) ? ui_mouse_inside(x, y, w, height) : ui_mouse_inside(x, y, w, line_height); - int hover_index = (int)((ui_mouse_y() - y) / line_height); - - if (ui_active_item() == id) - { - if (!ui_mouse_button(0)) - { - ui_set_active_item(0); - - if (inside) - selected_index = hover_index; - } - } - else if(ui_hot_item() == id) - { - if (ui_mouse_button(0)) - { - ui_set_active_item(id); - } - } - - if (inside) - { - ui_set_hot_item(id); - } - - if (ui_active_item() == id) - { - for (int i = 0; i < line_count; i++) - { - int box_type; - if (inside && hover_index == i) - box_type = GUI_BOX_SCREEN_INFO; - else - box_type = GUI_BOX_SCREEN_LIST; - - draw_box(box_type, tileset_regular, x, y + i * line_height, w, line_height); - ui_do_label(x + 10 + 10, y + i * line_height, lines[i], 36); - if (selected_index == i) - ui_do_label(x + 10, y + i * line_height, "-", 36); - } - } - else - { - int box_type; - if (ui_active_item() == id || ui_hot_item() == id) - box_type = GUI_BOX_SCREEN_INFO; - else - box_type = GUI_BOX_SCREEN_TEXTBOX; - draw_box(box_type, tileset_regular, x, y, w, line_height); - ui_do_label(x + 10, y, lines[selected_index], 36); - } - - return selected_index; -} - -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; - static int at_index = 0; - - if(ui_last_active_item() == id) - { - int c = inp_last_char(); - int k = inp_last_key(); - int len = strlen(str); - - if (inside && ui_mouse_button(0)) - { - int mx_rel = (int)(ui_mouse_x() - x); - - for (int i = 1; i <= len; i++) - { - if (gfx_pretty_text_width(36.0f, str, i) + 10 > mx_rel) - { - at_index = i - 1; - break; - } - - if (i == len) - at_index = len; - } - } - - if (at_index > len) - at_index = len; - - if (!(c >= 0 && c < 32)) - { - if (len < str_size - 1 && at_index < str_size - 1) - { - memmove(str + at_index + 1, str + at_index, len - at_index + 1); - str[at_index] = c; - at_index++; - } - } - - if (k == KEY_BACKSPACE && at_index > 0) - { - memmove(str + at_index - 1, str + at_index, len - at_index + 1); - at_index--; - } - else if (k == KEY_DEL && at_index < len) - memmove(str + at_index, str + at_index + 1, len - at_index); - else if (k == KEY_ENTER) - ui_clear_last_active_item(); - else if (k == KEY_LEFT && at_index > 0) - at_index--; - else if (k == KEY_RIGHT && at_index < len) - at_index++; - else if (k == KEY_HOME) - at_index = 0; - else if (k == KEY_END) - at_index = len; - - r = 1; - } - - int box_type; - if (ui_active_item() == id || ui_hot_item() == id || ui_last_active_item() == id) - box_type = GUI_BOX_SCREEN_INFO; - else - box_type = GUI_BOX_SCREEN_TEXTBOX; - - bool just_got_active = false; - - if(ui_active_item() == id) - { - if(!ui_mouse_button(0)) - ui_set_active_item(0); - } - else if(ui_hot_item() == id) - { - if(ui_mouse_button(0)) - { - if (ui_last_active_item() != id) - just_got_active = true; - ui_set_active_item(id); - } - } - - if(inside) - ui_set_hot_item(id); - - draw_box(box_type, tileset_regular, x, y, w, h); - - ui_do_label(x + 10, y, str, 36); - - if (ui_last_active_item() == id && !just_got_active) - { - float w = gfx_pretty_text_width(36.0f, str, at_index); - ui_do_label(x + 10 + w, y, "_", 36); - } - - return r; -} - -int ui_do_check_box(void *id, float x, float y, float w, float h, int value) -{ - int inside = ui_mouse_inside(x, y, w, h); - int r = value; - - if(ui_active_item() == id) - { - if(!ui_mouse_button(0)) - { - ui_set_active_item(0); - r = r ? 0 : 1; - } - } - else if(ui_hot_item() == id) - { - if(ui_mouse_button(0)) - ui_set_active_item(id); - } - - if(inside) - ui_set_hot_item(id); - - // render - gui_tileset_enum tileset; - int part_type; - if (ui_active_item() == id) - tileset = tileset_active; - else if (ui_hot_item() == id) - tileset = tileset_hot; - else - tileset = tileset_regular; - - part_type = r ? GUI_MISC_RADIO_CHECKED : GUI_MISC_RADIO_UNCHECKED; - - draw_part(part_type, tileset, x, y, w, h); - - return r; -} - -int do_scroll_bar_horiz(void *id, float x, float y, float width, int steps, int last_index) -{ - int r = last_index; - - static int up_button; - static int down_button; - - if (ui_do_button(&up_button, "", 0, x, y + 8, 16, 16, draw_single_part_button, (void *)GUI_MISC_SLIDER_BIG_ARROW_LEFT)) - { - if (r > 0) - --r; - } - if (ui_do_button(&down_button, "", 0, x + width - 16, y + 8, 16, 16, draw_single_part_button, (void *)GUI_MISC_SLIDER_BIG_ARROW_RIGHT)) - { - if (r < steps) - ++r; - } - if (steps > 0) // only if there's actually stuff to scroll through - { - int inside = ui_mouse_inside(x + 16, y, width - 32, 32); - 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_x() - x - 16; - float perc = pos / (width - 32); - - r = (int)((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); - } - - draw_part(GUI_MISC_SLIDER_BIG_HORIZ_BEGIN, tileset_regular, x + 16, y + 8, 16, 16); - draw_part(GUI_MISC_SLIDER_BIG_HORIZ_MID, tileset_regular, x + 32, y + 8, width - 32 - 32, 16); - draw_part(GUI_MISC_SLIDER_BIG_HORIZ_END, tileset_regular, x + width - 32, y + 8, 16, 16); - - draw_part(GUI_MISC_SLIDER_BIG_HANDLE_HORIZ, tileset_regular, x + 16 + r * ((width - 64) / steps), y + 8, 32, 16); - - return r; -} - -int do_scroll_bar_vert(void *id, float x, float y, float height, int steps, int last_index) -{ - int r = last_index; - - static int up_button; - static int down_button; - - if (ui_do_button(&up_button, "", 0, x + 8, y, 16, 16, draw_single_part_button, (void *)GUI_MISC_SLIDER_BIG_ARROW_UP)) - { - if (r > 0) - --r; - } - if (ui_do_button(&down_button, "", 0, x + 8, y + height - 16, 16, 16, draw_single_part_button, (void *)GUI_MISC_SLIDER_BIG_ARROW_DOWN)) - { - if (r < steps) - ++r; - } - if (steps > 0) // only if there's actually stuff to scroll through - { - int inside = ui_mouse_inside(x, y + 16, 16, height - 32); - 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 - 32; - float perc = pos / (height - 32); - - r = (int)((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); - } - - draw_part(GUI_MISC_SLIDER_BIG_VERT_BEGIN, tileset_regular, x + 8, y + 16, 16, 16); - draw_part(GUI_MISC_SLIDER_BIG_VERT_MID, tileset_regular, x + 8, y + 32, 16, height - 32 - 32); - draw_part(GUI_MISC_SLIDER_BIG_VERT_END, tileset_regular, x + 8, y + height - 32, 16, 16); - - draw_part(GUI_MISC_SLIDER_BIG_HANDLE_VERT, tileset_regular, x + 8, y + 16 + r * ((height - 64) / steps), 16, 32); - - return r; -} - -int ui_do_button_rect(const void *id, const char *text, int checked, const struct rect *r, draw_button_callback draw_func, void *extra) -{ - return ui_do_button((void *)id, text, checked, r->x, r->y, r->w, r->h, draw_func, extra); -} - -void ui_do_label_rect(const struct rect *r, char *str) -{ - float size = r->h; - ui_do_label(r->x + 3, r->y + r->h/2 - size/2, str, size); -} - -void ui_do_edit_box_rect(const void *id, const struct rect *r, char *buffer, int bufferSize) -{ - ui_do_edit_box((void *)id, r->x, r->y, r->w, r->h, buffer, bufferSize); -} - -int ui_do_check_box_rect(const void *id, const struct rect *r, int checked) -{ - return ui_do_check_box((void *)id, r->x, r->y, 32, 32, checked); -} - -int ui_do_key_reader_rect(const void *id, const struct rect *r, int key) -{ - return ui_do_key_reader((void *)id, r->x, r->y, r->w, r->h, key); -} - -int do_scroll_bar_horiz_rect(const void *id, const struct rect *r, int steps, int last_index) -{ - return do_scroll_bar_horiz((void *)id, r->x, r->y, r->w, steps, last_index); - //return do_scroll_bar_horiz((void *)id, r->x, r->y, r->w, r->h, steps, last_index); -} - - -static int do_server_list(float x, float y, int *scroll_index, int *selected_index, int visible_items) -{ - const float spacing = 3.f; - const float item_height = 28; - const float item_width = 728; - const float real_width = item_width + 20; - const float real_height = item_height * visible_items + spacing * (visible_items - 1); - - int num_servers = client_serverbrowse_sorted_num(); - - int r = -1; - - for (int i = 0; i < visible_items; i++) - { - int item_index = i + *scroll_index; - if (item_index >= num_servers) - ; - //ui_do_image(empty_item_texture, x, y + i * item_height + i * spacing, item_width, item_height); - else - { - SERVER_INFO *item = client_serverbrowse_sorted_get(item_index); - - bool clicked = false; - clicked = ui_do_button(item, item->name, 0, x, y + i * item_height + i * spacing, item_width, item_height, - draw_menu_button, (*selected_index == item_index) ? (void *)1 : 0); - - char temp[64]; // plenty of extra room so we don't get sad :o - sprintf(temp, "%i/%i %3d", item->num_players, item->max_players, item->latency); - - ui_do_label(x + 600, y + i * item_height + i * spacing, temp, item_height); - ui_do_label(x + 360, y + i * item_height + i * spacing, item->map, item_height); - - if (clicked) - { - r = item_index; - *selected_index = item_index; - } - } - } - - *scroll_index = do_scroll_bar_vert(scroll_index, x + real_width - 16, y, real_height, - max(num_servers - visible_items, 0), *scroll_index); - - return r; -} - -enum -{ - SCREEN_SERVERS, - SCREEN_NEWS, - SCREEN_HOST, - SCREEN_DISCONNECTED, - SCREEN_CONNECTING, - SCREEN_SETTINGS_GENERAL, - SCREEN_SETTINGS_CONTROLS, - SCREEN_SETTINGS_VIDEO, - SCREEN_SETTINGS_VIDEO_SELECT_MODE, - SCREEN_SETTINGS_VIDEO_CUSTOM, - SCREEN_SETTINGS_SOUND, - SCREEN_KERNING -}; - -static int screen = SCREEN_SERVERS; -static CONFIGURATION config_copy; - -const float column1_x = 250; -const float column2_x = column1_x + 170; -const float column3_x = column2_x + 170; -const float row1_y = 180; -const float row2_y = row1_y + 40; -const float row3_y = row2_y + 40; -const float row4_y = row3_y + 40; -const float row5_y = row4_y + 40; -const float row6_y = row5_y + 40; -const float row7_y = row6_y + 40; - -static char address[128] = "localhost:8303"; - -static float colors[7][3] = -{ - { 0, 0, 1 }, - { 0, 1, 0 }, - { 0, 1, 1 }, - { 1, 0, 0 }, - { 1, 0, 1 }, - { 1, 1, 0 }, - { 1, 1, 1 }, -}; - -static void draw_rect(const struct rect *r) -{ - float *color = colors[rand()%7]; - gfx_setcolor(color[0], color[1], color[2], 1); - - gfx_lines_draw(r->x, r->y, r->x+r->w, r->y); - gfx_lines_draw(r->x+r->w, r->y, r->x+r->w, r->y+r->h); - gfx_lines_draw(r->x+r->w, r->y+r->h, r->x, r->y+r->h); - gfx_lines_draw(r->x, r->y+r->h, r->x, r->y); -} - -void ui_settings_general_render(const struct rect *r) -{ - static struct rect row1; - static struct rect row2; - static struct rect rest; - - static struct rect cells[4]; - - ui_hsplit_t(r, 50, &row1, &rest); - ui_hsplit_t(&rest, 50, &row2, &rest); - - ui_vsplit_l(&row1, 100, &cells[0], &cells[1]); - ui_vsplit_l(&row2, 100, &cells[2], &cells[3]); - - // NAME - ui_do_label_rect(&cells[0], "Name:"); - ui_do_edit_box_rect(config_copy.player_name, &cells[1], config_copy.player_name, sizeof(config_copy.player_name)); - - // Dynamic camera - ui_do_label_rect(&cells[2], "Dynamic Camera:"); - config_set_dynamic_camera(&config_copy, ui_do_check_box_rect(&config_copy.dynamic_camera, &cells[3], config_copy.dynamic_camera)); -} - -typedef void (*assign_func_callback)(CONFIGURATION *config, int value); - -struct key_thing -{ - char name[32]; - int *key; - assign_func_callback assign_func; -}; - -static void ui_settings_controls_render(const struct rect *r) -{ - static int scroll_index = 0; - - const key_thing keys[] = - { - { "Move Left:", &config_copy.key_move_left, config_set_key_move_left }, - { "Move Right:", &config_copy.key_move_right, config_set_key_move_right }, - { "Jump:", &config_copy.key_jump, config_set_key_jump }, - { "Fire:", &config_copy.key_fire, config_set_key_fire }, - { "Hook:", &config_copy.key_hook, config_set_key_hook }, - { "Hammer:", &config_copy.key_weapon1, config_set_key_weapon1 }, - { "Pistol:", &config_copy.key_weapon2, config_set_key_weapon2 }, - { "Shotgun:", &config_copy.key_weapon3, config_set_key_weapon3 }, - { "Grenade:", &config_copy.key_weapon4, config_set_key_weapon4 }, - { "Next Weapon:", &config_copy.key_next_weapon, config_set_key_next_weapon }, - { "Prev. Weapon:", &config_copy.key_prev_weapon, config_set_key_prev_weapon }, - { "Emoticon:", &config_copy.key_emoticon, config_set_key_emoticon }, - { "Screenshot:", &config_copy.key_screenshot, config_set_key_screenshot }, - }; - - const int key_count = sizeof(keys) / sizeof(key_thing); - - struct rect rest = *r; - - for (int i = 0; i < key_count; i++) - { - struct rect row; - struct rect left, right; - - ui_hsplit_t(&rest, 32, &row, &rest); - ui_vsplit_l(&row, 128, &left, &right); - - key_thing key = keys[i + scroll_index]; - - ui_do_label_rect(&left, key.name); - key.assign_func(&config_copy, ui_do_key_reader_rect(key.key, &right, *key.key)); - } -} - -void ui_settings_video_render(const struct rect *r) -{ -} - -void ui_settings_video_render_select_mode(const struct rect *r) -{ -} - -void ui_settings_video_render_custom(const struct rect *r) -{ -} - -void ui_settings_sound_render(const struct rect *r) -{ - struct rect row; - struct rect left, right; - - ui_hsplit_t(r, 32, &row, 0x0); - ui_vsplit_l(&row, 128, &left, &right); - - ui_do_label_rect(&left, "Volume:"); - - config_set_volume(&config_copy, do_scroll_bar_horiz_rect(&config_copy.volume, &right, 256, config_copy.volume)); - snd_set_master_volume(config_copy.volume / 255.0f); -} - -static void tab_menu_button_render(const struct rect *r, char *name, int s) -{ - if (ui_do_button_rect(r, name, 0, r, draw_teewars_button, 0)) - screen = s; -} - -static void tab_menu_render(const struct rect *r) -{ - static struct rect button_news; - static struct rect button_servers; - static struct rect button_host; - static struct rect button_settings; - static struct rect rest; - - ui_vsplit_l(r, 130, &button_news, &rest); - ui_vsplit_l(&rest, 130, &button_servers, &rest); - ui_vsplit_l(&rest, 130, &button_host, &rest); - ui_vsplit_l(&rest, 130, &button_settings, &rest); - - tab_menu_button_render(&button_news, "News", SCREEN_NEWS); - tab_menu_button_render(&button_servers, "Servers", SCREEN_SERVERS); - tab_menu_button_render(&button_host, "Host", SCREEN_HOST); - tab_menu_button_render(&button_settings, "Settings", SCREEN_SETTINGS_GENERAL); -} - -static void settings_tab_menu_render(const struct rect *r) -{ - static struct rect button_general; - static struct rect button_controls; - static struct rect button_video; - static struct rect button_sound; - static struct rect rest; - - ui_hsplit_t(r, 60, &button_general, &rest); - ui_hsplit_t(&rest, 60, &button_controls, &rest); - ui_hsplit_t(&rest, 60, &button_video, &rest); - ui_hsplit_t(&rest, 60, &button_sound, &rest); - - tab_menu_button_render(&button_general, "General", SCREEN_SETTINGS_GENERAL); - tab_menu_button_render(&button_controls, "Controls", SCREEN_SETTINGS_CONTROLS); - tab_menu_button_render(&button_video, "Video", SCREEN_SETTINGS_VIDEO); - tab_menu_button_render(&button_sound, "Sound", SCREEN_SETTINGS_SOUND); -} - -static void ui_settings_render(const struct rect *r) -{ - static struct rect sub_menu_selector; - static struct rect center; - - ui_vsplit_l(r, 100, &sub_menu_selector, ¢er); - - settings_tab_menu_render(&sub_menu_selector); - - switch (screen) - { - case SCREEN_SETTINGS_GENERAL: ui_settings_general_render(¢er); break; - case SCREEN_SETTINGS_CONTROLS: ui_settings_controls_render(¢er); break; - case SCREEN_SETTINGS_VIDEO: ui_settings_video_render(¢er); break; - case SCREEN_SETTINGS_VIDEO_SELECT_MODE: ui_settings_video_render_select_mode(¢er); break; - case SCREEN_SETTINGS_VIDEO_CUSTOM: ui_settings_video_render_custom(¢er); break; - case SCREEN_SETTINGS_SOUND: ui_settings_sound_render(¢er); break; - } -} - -static void middle_render(const struct rect *r) -{ - bool ingame = false; - - switch (screen) - { - case SCREEN_SERVERS: - { - if (ingame) - {} - //return ingame_main_render(); - else - { - static struct rect browser; - static bool inited = false; - - ui_margin(r, 5, &browser); - - { - struct rect button_row; - static struct rect button_refresh, button_connect; - - ui_hsplit_b(&browser, 30, &browser, &button_row); - ui_vsplit_l(&button_row, 100, &button_refresh, &button_row); - ui_vsplit_l(&button_row, 100, &button_connect, &button_row); - - if (ui_do_button_rect(&button_refresh, "Refresh", 0, &button_refresh, draw_teewars_button, 0)) - client_serverbrowse_refresh(0); - - if (ui_do_button_rect(&button_connect, "Connect", 0, &button_connect, draw_teewars_button, 0)) - {} - - } - - if (!inited) - { - client_serverbrowse_refresh(0); - inited = true; - } - - { - int server_count = client_serverbrowse_sorted_num(); - int i; - - struct rect rest = browser; - - struct rect button_row; - - static struct rect button_name, button_players, button_players_max, button_map, button_latency, button_progression; - - ui_hsplit_t(&rest, 32, &button_row, &rest); - ui_margin(&button_row, 1, &button_row); - - ui_vsplit_l(&button_row, 400, &button_name, &button_row); - ui_vsplit_l(&button_row, 40, &button_players, &button_row); - ui_vsplit_l(&button_row, 40, &button_players_max, &button_row); - ui_vsplit_l(&button_row, 80, &button_map, &button_row); - ui_vsplit_l(&button_row, 40, &button_latency, &button_row); - ui_vsplit_l(&button_row, 40, &button_progression, &button_row); - - if (ui_do_button_rect(&button_name, "Name", 0, &button_name, draw_teewars_button, 0)) - config.b_sort = BROWSESORT_NAME; - if (ui_do_button_rect(&button_players, "Players", 0, &button_players, draw_teewars_button, 0)) - config.b_sort = BROWSESORT_NUMPLAYERS; - if (ui_do_button_rect(&button_players_max, "Max Players", 0, &button_players_max, draw_teewars_button, 0)) - config.b_sort = BROWSESORT_NUMPLAYERS; // TODO: real enum here - if (ui_do_button_rect(&button_map, "Map", 0, &button_map, draw_teewars_button, 0)) - config.b_sort = BROWSESORT_MAP; - if (ui_do_button_rect(&button_latency, "Ping", 0, &button_latency, draw_teewars_button, 0)) - config.b_sort = BROWSESORT_PING; - if (ui_do_button_rect(&button_progression, "Progression", 0, &button_progression, draw_teewars_button, 0)) - config.b_sort = BROWSESORT_PING; // TODO: real enum here - - for (i = 0; i < server_count; i++) - { - SERVER_INFO *info = client_serverbrowse_sorted_get(i); - struct rect row; - struct rect col_name, col_players, col_players_max, col_map, col_latency, col_progression; - char temp[16]; - - - ui_hsplit_t(&rest, 32, &row, &rest); - - if (rest.h < 0) - break; - - ui_margin(&row, 1, &row); - - ui_vsplit_l(&row, 400, &col_name, &row); - ui_vsplit_l(&row, 40, &col_players, &row); - ui_vsplit_l(&row, 40, &col_players_max, &row); - ui_vsplit_l(&row, 80, &col_map, &row); - ui_vsplit_l(&row, 40, &col_latency, &row); - ui_vsplit_l(&row, 40, &col_progression, &row); - - ui_do_label_rect(&col_name, info->name); - - sprintf(temp, "%i", info->num_players); - ui_do_label_rect(&col_players, temp); - sprintf(temp, "%i", info->max_players); - ui_do_label_rect(&col_players_max, temp); - ui_do_label_rect(&col_map, info->map); - - sprintf(temp, "%i", info->latency); - ui_do_label_rect(&col_latency, temp); - sprintf(temp, "%i", info->progression); - ui_do_label_rect(&col_progression, temp); - } - } - } - break; - } - case SCREEN_NEWS: - { - break; - } - case SCREEN_HOST: - { - break; - //return disconnected_render(); - } - case SCREEN_CONNECTING: - { - break; - //return connecting_render(); - } - case SCREEN_SETTINGS_GENERAL: - case SCREEN_SETTINGS_CONTROLS: - case SCREEN_SETTINGS_VIDEO: - case SCREEN_SETTINGS_VIDEO_SELECT_MODE: - case SCREEN_SETTINGS_VIDEO_CUSTOM: - case SCREEN_SETTINGS_SOUND: - { - ui_settings_render(r); - break; - } - case SCREEN_KERNING: - { - break; - } - default: dbg_msg("menu", "invalid screen selected..."); break; - } -} - -static int ui_menu_render(const struct rect *r) -{ - static struct rect top; - static struct rect middle; - static struct rect bottom; - - ui_hsplit_t(r, 48, &top, &middle); - ui_hsplit_b(&middle, 32, &middle, &bottom); - tab_menu_render(&top); - middle_render(&middle); - - return -ui_do_button_rect(&bottom, "Quit", 0, &bottom, draw_teewars_button, 0); -} - -static int main_render() -{ - static bool inited = false; - - if (!inited) - { - inited = true; - client_serverbrowse_refresh(0); - } - - static int scoll_index = 0, selected_index = -1; - int last_selected_index = selected_index; - do_server_list(20, 160, &scoll_index, &selected_index, 8); - - ui_do_edit_box(address, 280, 425, 300, 36, address, sizeof(address)); - - if (last_selected_index != selected_index && selected_index != -1) - { - SERVER_INFO *server; - server = client_serverbrowse_get(selected_index); - - strcpy(address, server->address); - } - - static int refresh_button, join_button, quit_button; - static int use_lan = 0; - - - if (ui_do_button(&refresh_button, "Refresh", 0, 20, 460, 170, 48, draw_teewars_button, 0)) - client_serverbrowse_refresh(use_lan); - - ui_do_label(60, 420, "Search LAN ", 36); - int last_lan = use_lan; - use_lan = ui_do_check_box(&use_lan, 20, 424, 32, 32, use_lan); - if (use_lan != last_lan) - client_serverbrowse_refresh(use_lan); - - if (ui_do_button(&join_button, "Join", 0, 620, 420, 128, 48, draw_teewars_button, 0)) - { - client_connect(address); - - return 1; - } - - if (ui_do_button(&quit_button, "Quit", 0, 620, 490, 128, 48, draw_teewars_button, 0)) - return -1; - - static int settings_button; - if (ui_do_button(&settings_button, "Settings", 0, 400, 490, 170, 48, draw_teewars_button, 0)) - { - config_copy = config; - screen = SCREEN_SETTINGS_GENERAL; - } - - // render status text - if(client_serverbrowse_num_requests()) - { - char buf[512]; - sprintf(buf, "Refreshing %d servers...", client_serverbrowse_num_requests()); - ui_do_label(20, 400, buf, 28); - } - else - { - char buf[512]; - sprintf(buf, "%d of %d servers", client_serverbrowse_sorted_num(), client_serverbrowse_num()); - ui_do_label(20, 400, buf, 28); - } - - ui_do_edit_box(&config.b_filter_string, 20+150, 600-80, 200, 36, config.b_filter_string, sizeof(config.b_filter_string)); - config.b_filter_empty = ui_do_check_box(&config.b_filter_empty, 20, 600-80, 32, 32, config.b_filter_empty); - config.b_filter_full = ui_do_check_box(&config.b_filter_full, 20+50, 600-80, 32, 32, config.b_filter_full); - config.b_filter_pw = ui_do_check_box(&config.b_filter_pw, 20+100, 600-80, 32, 32, config.b_filter_pw); - - - return 0; -} - - -static int settings_general_render() -{ - // NAME - ui_do_label(column1_x, row1_y, "Name:", 36); - ui_do_edit_box(config_copy.player_name, column2_x, row1_y, 300, 36, config_copy.player_name, sizeof(config_copy.player_name)); - - // Dynamic camera - ui_do_label(column1_x, row2_y, "Dynamic Camera:", 36); - config_set_dynamic_camera(&config_copy, ui_do_check_box(&config_copy.dynamic_camera, column2_x + 55, row2_y + 4, 32, 32, config_copy.dynamic_camera)); - - return 0; -} - -static int settings_controls_render() -{ - static int scroll_index = 0; - - const key_thing keys[] = - { - { "Move Left:", &config_copy.key_move_left, config_set_key_move_left }, - { "Move Right:", &config_copy.key_move_right, config_set_key_move_right }, - { "Jump:", &config_copy.key_jump, config_set_key_jump }, - { "Fire:", &config_copy.key_fire, config_set_key_fire }, - { "Hook:", &config_copy.key_hook, config_set_key_hook }, - { "Hammer:", &config_copy.key_weapon1, config_set_key_weapon1 }, - { "Pistol:", &config_copy.key_weapon2, config_set_key_weapon2 }, - { "Shotgun:", &config_copy.key_weapon3, config_set_key_weapon3 }, - { "Grenade:", &config_copy.key_weapon4, config_set_key_weapon4 }, - { "Next Weapon:", &config_copy.key_next_weapon, config_set_key_next_weapon }, - { "Prev. Weapon:", &config_copy.key_prev_weapon, config_set_key_prev_weapon }, - { "Emoticon:", &config_copy.key_emoticon, config_set_key_emoticon }, - { "Screenshot:", &config_copy.key_screenshot, config_set_key_screenshot }, - }; - - const int key_count = sizeof(keys) / sizeof(key_thing); - - for (int i = 0; i < 6; i++) - { - key_thing key = keys[i + scroll_index]; - - ui_do_label(column1_x, row1_y + 40 * i, key.name, 36); - key.assign_func(&config_copy, ui_do_key_reader(key.key, column2_x, row1_y + 40 * i, 150, 36, *key.key)); - } - - scroll_index = do_scroll_bar_vert(&scroll_index, 600, row1_y, 40 * 6, key_count - 6, scroll_index); - - ui_do_label(column1_x, row1_y + 40 * 6, "Scroll wheel weapon switch", 22); - config_set_scroll_weapon(&config_copy, ui_do_check_box(&config_copy.scroll_weapon, column2_x + 50, row1_y + 40 * 6, 22, 22, config_copy.scroll_weapon)); - - return 0; -} - -static const int MAX_RESOLUTIONS = 128; -static int settings_video_render_select_mode() -{ - static VIDEO_MODE modes[MAX_RESOLUTIONS]; - static int num_modes = -1; - - if(num_modes == -1) - num_modes = gfx_get_video_modes(modes, MAX_RESOLUTIONS); - - static int scroll_index = 0; - scroll_index = do_scroll_bar_vert(&scroll_index, 500, row1_y, 40 * 7, num_modes - 7, scroll_index); - - for (int i = 0; i < 7; i++) - { - int index = i + scroll_index; - if(index >= num_modes) - break; - - //key_thing key = keys[i + scroll_index]; - int depth = modes[index].red+modes[index].green+modes[index].blue; - if(depth < 16) - depth = 16; - else if(depth > 16) - depth = 24; - - char buf[128]; - int s = 0; - if(modes[index].width == config_copy.gfx_screen_width && - modes[index].height == config_copy.gfx_screen_height && - depth == config_copy.gfx_color_depth) - { - s = 1; - } - - sprintf(buf, "%c %dx%d %d bit %c", s?'>':' ', modes[index].width, modes[index].height, depth, s?'<':' '); - - if(ui_do_button((void*)&modes[index], buf, 0, - column1_x, row1_y + 40 * i, 250, 32.0f, draw_teewars_button, 0)) - { - // select - config_set_gfx_color_depth(&config_copy, depth); - config_set_gfx_screen_width(&config_copy, modes[index].width); - config_set_gfx_screen_height(&config_copy, modes[index].height); - screen = SCREEN_SETTINGS_VIDEO; - } - } - - static int back_button = 0; - if(ui_do_button(&back_button, "Back", 0, column3_x, row7_y, 150, 32, draw_teewars_button, 0)) - screen = SCREEN_SETTINGS_VIDEO; - - return 0; -} - -static int settings_video_render_custom() -{ - ui_do_label(column1_x, row1_y, "Quality Textures:", 36); - config_set_gfx_texture_quality(&config_copy, ui_do_check_box(&config_copy.gfx_texture_quality, column3_x, row1_y + 5, 32, 32, config_copy.gfx_texture_quality)); - - ui_do_label(column1_x, row2_y, "Texture Compression:", 36); - config_set_gfx_texture_compression(&config_copy, ui_do_check_box(&config_copy.gfx_texture_compression, column3_x, row2_y + 5, 32, 32, config_copy.gfx_texture_compression)); - - ui_do_label(column1_x, row3_y, "High Detail:", 36); - config_set_gfx_high_detail(&config_copy, ui_do_check_box(&config_copy.gfx_high_detail, column3_x, row3_y + 5, 32, 32, config_copy.gfx_high_detail)); - - static int back_button = 0; - if(ui_do_button(&back_button, "Back", 0, column3_x, row7_y, 150, 32, draw_teewars_button, 0)) - screen = SCREEN_SETTINGS_VIDEO; - - return 0; -} - -static int settings_video_render() -{ - - ui_do_label(column1_x, row1_y, "Mode:", 36); - - char buf[128]; - sprintf(buf, "%dx%d %d bit", config_copy.gfx_screen_width, config_copy.gfx_screen_height, config_copy.gfx_color_depth); - static int select_button = 0; - if(ui_do_button(&select_button, buf, 0, column2_x, row1_y, 300, 32, draw_teewars_button, 0)) - screen = SCREEN_SETTINGS_VIDEO_SELECT_MODE; - - // we need to draw these bottom up, to make overlapping work correctly - - ui_do_label(column1_x, row2_y, "Fullscreen:", 36); - config_set_gfx_fullscreen(&config_copy, ui_do_check_box(&config_copy.gfx_fullscreen, column2_x, row2_y + 5, 32, 32, config_copy.gfx_fullscreen)); - - ui_do_label(column1_x, row3_y, "V-sync:", 36); - config_set_gfx_vsync(&config_copy, ui_do_check_box(&config_copy.gfx_vsync, column2_x, row3_y + 5, 32, 32, config_copy.gfx_vsync)); - - - int current_level = - (config_copy.gfx_texture_quality<<8)| - (config_copy.gfx_texture_compression<<4)| - (config_copy.gfx_high_detail); - - static const int opt_levels[3] = {0x101,0x001,0x010}; - static const char *opts[] = { - "High", - "Medium", - "Low", - "Custom"}; - - int selected = 0; // custom per default - for(; selected < 3; selected++) - { - if(current_level == opt_levels[selected]) - break; - } - - ui_do_label(column1_x, row4_y, "Quality:", 36); - int new_level = ui_do_combo_box(&config_copy.gfx_texture_quality, column2_x, row4_y, 150, opts, 4, selected); - if(new_level < 3) - { - config_set_gfx_texture_quality(&config_copy, (opt_levels[new_level]>>8)&1); - config_set_gfx_texture_compression(&config_copy, (opt_levels[new_level]>>4)&1); - config_set_gfx_high_detail(&config_copy, opt_levels[new_level]&1); - } - - static int custom_button=0; - if(ui_do_button(&custom_button, "Customize", 0, column3_x, row4_y, 130, 32, draw_teewars_button, 0)) - screen = SCREEN_SETTINGS_VIDEO_CUSTOM; - - ui_do_label(column1_x, row6_y + 50, "(A restart of the game is required for these settings to take effect.)", 20); - - return 0; -} - -static int settings_sound_render() -{ - ui_do_label(column1_x, row1_y, "Volume:", 36); - - config_set_volume(&config_copy, do_scroll_bar_horiz(&config_copy.volume, column2_x, row1_y, 200, 255, config_copy.volume)); - snd_set_master_volume(config_copy.volume / 255.0f); - - return 0; -} - -extern void draw_round_rect(float x, float y, float w, float h, float r); -extern void send_info(bool); - -static int settings_render(bool ingame) -{ - if (ingame) - { - gfx_blend_normal(); - - gfx_texture_set(-1); - gfx_quads_begin(); - gfx_setcolor(0,0,0,0.5f); - draw_round_rect(10, 120, 780, 460, 30.0f); - gfx_quads_end(); - } - - static int general_button, controls_button, video_button, sound_button; - - if (ui_do_button(&general_button, "General", 0, 30, 200, 170, 48, draw_teewars_button, 0)) - screen = SCREEN_SETTINGS_GENERAL; - if (ui_do_button(&controls_button, "Controls", 0, 30, 250, 170, 48, draw_teewars_button, 0)) - screen = SCREEN_SETTINGS_CONTROLS; - if (ui_do_button(&video_button, "Video", 0, 30, 300, 170, 48, draw_teewars_button, 0)) - screen = SCREEN_SETTINGS_VIDEO; - if (ui_do_button(&sound_button, "Sound", 0, 30, 350, 170, 48, draw_teewars_button, 0)) - screen = SCREEN_SETTINGS_SOUND; - - switch (screen) - { - case SCREEN_SETTINGS_GENERAL: settings_general_render(); break; - case SCREEN_SETTINGS_CONTROLS: settings_controls_render(); break; - case SCREEN_SETTINGS_VIDEO: settings_video_render(); break; - case SCREEN_SETTINGS_VIDEO_SELECT_MODE: settings_video_render_select_mode(); break; - case SCREEN_SETTINGS_VIDEO_CUSTOM: settings_video_render_custom(); break; - case SCREEN_SETTINGS_SOUND: settings_sound_render(); break; - } - - // SAVE BUTTON - static int save_button; - if (ui_do_button(&save_button, "Save", 0, 482, 490, 128, 48, draw_teewars_button, 0)) - { - // did we change our name? - bool name_changed = strcmp(config.player_name, config_copy.player_name) != 0; - - config = config_copy; - - if (ingame && name_changed) - send_info(false); - -#ifdef CONF_PLATFORM_MACOSX - config_save("~/.teewars"); -#else - config_save("default.cfg"); -#endif - screen = SCREEN_SERVERS; - } - - // CANCEL BUTTON - static int cancel_button; - if (ui_do_button(&cancel_button, "Cancel", 0, 620, 490, 150, 48, draw_teewars_button, 0)) - { - snd_set_master_volume(config.volume / 255.0f); - screen = SCREEN_SERVERS; - } - - return 0; -} - -extern int gametype; -static int ingame_main_render() -{ - static int menu_resume, menu_quit, menu_settings; - /*if (gametype == GAMETYPE_TDM) - { - char buf[128]; - // Switch team - ui_do_label(100,100,"Switch Team",40); - sprintf(buf,"Team: %s",local_player->team ? "A" : "B"); - if (ui_do_button(&menu_team, buf, 0, 30, 150, 170, 48, draw_teewars_button)) - { - msg_pack_start(MSG_SWITCHTEAM, MSGFLAG_VITAL); - msg_pack_end(); - client_send_msg(); - menu_active = false; - } - }*/ - - const int column1_x = 275; - const int row1_y = 200; - const int row2_y = row1_y + 60; - const int row3_y = row2_y + 60; - const int row4_y = row3_y + 60; - - gfx_blend_normal(); - - gfx_texture_set(-1); - gfx_quads_begin(); - gfx_setcolor(0,0,0,0.5f); - draw_round_rect(170, 120, 460, 360, 30.0f); - gfx_quads_end(); - - ui_do_image(data->images[IMAGE_BANNER].id, 214, 150, 384, 96); - - if (ui_do_button(&menu_resume, "Resume Game", 0, column1_x, row2_y, 250, 48, draw_teewars_button, 0)) - { - return 1; - } - - if (ui_do_button(&menu_quit, "Disconnect", 0, column1_x, row4_y, 250, 48, draw_teewars_button, 0)) - { - client_disconnect(); - return 1; - } - - if (ui_do_button(&menu_settings, "Settings", 0, column1_x, row3_y, 250, 48, draw_teewars_button, 0)) - { - config_copy = config; - screen = SCREEN_SETTINGS_GENERAL; - } - - return 0; -} - -extern "C" double extra_kerning[256*256]; - -static int kerning_render() -{ - static bool loaded = false; - static char text[32] = {0}; - - if (!loaded) - { - // TODO: fix me - /* - file_stream file; - - if (file.open_r("kerning.txt")) - { - line_stream lstream(&file); - int i = 0; - char *line; - - while ((line = lstream.get_line())) - extra_kerning[i++] = atof(line); - - file.close(); - } - - if (file.open_r("tracking.txt")) - { - line_stream lstream(&file); - char *line; - - for (int i = 0; i < 256; i++) - { - line = lstream.get_line(); - current_font->m_CharStartTable[i] = atof(line); - line = lstream.get_line(); - current_font->m_CharEndTable[i] = atof(line); - } - - file.close(); - } - */ - - loaded = true; - } - - ui_do_edit_box(text, 160, 20, 300, 36, text, sizeof(text)); - - ui_do_label(160, 250, text, 70); - - int len = strlen(text); - - for (int i = 0; i < len-1; i++) - { - char s[3] = {0}; - s[0] = text[i]; - s[1] = text[i+1]; - ui_do_label(10, 30 * i + 10, s, 45); - - int index = s[0] + s[1] * 256; - - // less - if (ui_do_button((void *)(100 + i * 2), "", 0, 50, 30 * i + 10 + 20, 16, 16, draw_single_part_button, (void *)GUI_MISC_SLIDER_BIG_ARROW_LEFT)) - { - extra_kerning[index] -= 0.01; - } - - // more - if (ui_do_button((void *)(100 + i * 2 + 1), "", 0, 66, 30 * i + 10 + 20, 16, 16, draw_single_part_button, (void *)GUI_MISC_SLIDER_BIG_ARROW_RIGHT)) - { - extra_kerning[index] += 0.01; - } - - char num[16]; - sprintf(num, "(%f)", extra_kerning[index]); - ui_do_label(84, 30 * i + 30, num, 12); - } - - for (int i = 0; i < len; i++) - { - char s[2] = {0}; - s[0] = text[i]; - - ui_do_label(700, 35 * i + 10, s, 45); - - gfx_blend_normal(); - gfx_texture_set(-1); - gfx_quads_begin(); - gfx_setcolor(0,0,0,0.5); - gfx_quads_drawTL(700,35*i+20,1,30); - gfx_quads_drawTL(700+45*(current_font->m_CharEndTable[(int)s[0]]-current_font->m_CharStartTable[(int)s[0]]),35*i+20,1,30); - gfx_quads_end(); - // less - if (ui_do_button((void *)(200 + i * 2), "", 0, 650, 35 * i + 10 + 15, 16, 16, draw_single_part_button, (void *)GUI_MISC_SLIDER_BIG_ARROW_LEFT)) - { - current_font->m_CharStartTable[(int)s[0]] -= 0.01f; - } - - // more - if (ui_do_button((void *)(200 + i * 2 + 1), "", 0, 666, 35 * i + 10 + 15, 16, 16, draw_single_part_button, (void *)GUI_MISC_SLIDER_BIG_ARROW_RIGHT)) - { - current_font->m_CharStartTable[(int)s[0]] += 0.01f; - } - - char num[16]; - sprintf(num, "(%f)", current_font->m_CharStartTable[(int)s[0]]); - ui_do_label(645, 35 * i + 40, num, 12); - - - - - // less - if (ui_do_button((void *)(300 + i * 2), "", 0, 750, 35 * i + 10 + 15, 16, 16, draw_single_part_button, (void *)GUI_MISC_SLIDER_BIG_ARROW_LEFT)) - { - current_font->m_CharEndTable[(int)s[0]] -= 0.01f; - } - - // more - if (ui_do_button((void *)(300 + i * 2 + 1), "", 0, 766, 35 * i + 10 + 15, 16, 16, draw_single_part_button, (void *)GUI_MISC_SLIDER_BIG_ARROW_RIGHT)) - { - current_font->m_CharEndTable[(int)s[0]] += 0.01f; - } - - sprintf(num, "(%f)", current_font->m_CharEndTable[(int)s[0]]); - ui_do_label(745, 35 * i + 40, num, 12); - - } - - // SAVE BUTTON - static int save_button; - if (ui_do_button(&save_button, "Save", 0, 482, 520, 128, 48, draw_teewars_button, 0)) - { - // TODO: fix or remove me - /* - file_stream file; - - if (file.open_w("kerning.txt")) - { - char t[16]; - - for (int i = 0; i < 256*256; i++) - { - sprintf(t, "%f\n", extra_kerning[i]); - file.write(t, strlen(t)); - } - - file.close(); - } - - if (file.open_w("tracking.txt")) - { - char t[16]; - - for (int i = 0; i < 256; i++) - { - sprintf(t, "%f\n", current_font->m_CharStartTable[i]); - file.write(t, strlen(t)); - sprintf(t, "%f\n", current_font->m_CharEndTable[i]); - file.write(t, strlen(t)); - } - - file.close(); - } - */ - - //screen = 0; - } - - // CANCEL BUTTON - static int cancel_button; - if (ui_do_button(&cancel_button, "Cancel", 0, 620, 520, 150, 48, draw_teewars_button, 0)) - screen = SCREEN_SERVERS; - - return 0; -} - - -int render_popup(const char *caption, const char *text, const char *button_text) -{ - float tw; - - float w = 700; - float h = 300; - float x = 800/2-w/2; - float y = 600/2-h/2; - - gfx_blend_normal(); - - gfx_texture_set(-1); - gfx_quads_begin(); - gfx_setcolor(0,0,0,0.50f); - draw_round_rect(x, y, w, h, 40.0f); - gfx_quads_end(); - - tw = gfx_pretty_text_width(48.0f, caption, -1); - ui_do_label(x+w/2-tw/2, y+20, caption, 48.0f); - - tw = gfx_pretty_text_width(32.0f, text, -1); - gfx_pretty_text(x+w/2-tw/2, y+130, 32.0f, text, -1); - - if(button_text) - { - static int back_button = 0; - if(ui_do_button(&back_button, button_text, 0, x+w/2-100, y+220, 200, 48, draw_teewars_button, 0)) - return 1; - if(inp_key_down(KEY_ESC) || inp_key_down(KEY_ENTER)) - return 1; - } - - return 0; -} - -static int disconnected_render() -{ - if(strlen(client_error_string()) == 0) - screen = SCREEN_SERVERS; - else - { - if(render_popup("Disconnected", client_error_string(), "Back")) - screen = SCREEN_SERVERS; - } - return 0; -} - -static int connecting_render() -{ - char buf[256]; - sprintf(buf, "Server: %s", address); - if(render_popup("Connecting", buf, "Abort")) - { - client_disconnect(); - screen = SCREEN_SERVERS; - } - return 0; -} - - -void menu_do_disconnected() -{ - screen = SCREEN_DISCONNECTED; -} - - -void menu_do_connecting() -{ - screen = SCREEN_CONNECTING; -} - -void menu_do_connected() -{ - screen = SCREEN_SERVERS; -} - -static int menu_render(bool ingame) -{ - if (!ingame) - { - // background color - gfx_clear(0.65f,0.78f,0.9f); - //gfx_clear(89/255.f,122/255.f,0.0); - - // GUI coordsys - gfx_mapscreen(0,0,800.0f,600.0f); - - static int64 start = time_get(); - - float t = double(time_get() - start) / double(time_freq()); - gfx_mapscreen(0,0,1600.0f,1200.0f); - draw_background(t); - gfx_mapscreen(0,0,800.0f,600.0f); - - if (screen != SCREEN_KERNING) - { - ui_do_image(data->images[IMAGE_BANNER].id, 200, 20, 512, 128); - ui_do_label(20.0f, 600.0f-40.0f, "Version: " TEEWARS_VERSION, 36); - if(config.debug) - ui_do_label(20.0f, 600.0f-60.0f, "Nethash: " TEEWARS_NETVERSION_HASH, 24); - } - } - else - { - gfx_mapscreen(0, 0, 800, 600); - } - - if(config.dbg_new_gui) - { - struct rect *screen = ui_screen(); - - static float scale = 1.0f; - - if (inp_key_pressed('I')) - scale += 0.01; - if (inp_key_pressed('O')) - scale -= 0.01; - - ui_scale(scale); - int retn = ui_menu_render(screen); - - /*gfx_texture_set(-1); - gfx_lines_begin(); - ui_foreach_rect(draw_rect); - gfx_lines_end();*/ - - return retn; - } - else - { - switch (screen) - { - case SCREEN_SERVERS: return ingame ? ingame_main_render() : main_render(); - case SCREEN_DISCONNECTED: return disconnected_render(); - case SCREEN_CONNECTING: return connecting_render(); - case SCREEN_SETTINGS_GENERAL: - case SCREEN_SETTINGS_CONTROLS: - case SCREEN_SETTINGS_VIDEO: - case SCREEN_SETTINGS_VIDEO_SELECT_MODE: - case SCREEN_SETTINGS_VIDEO_CUSTOM: - case SCREEN_SETTINGS_SOUND: return settings_render(ingame); - case SCREEN_KERNING: return kerning_render(); - default: dbg_msg("menu", "invalid screen selected..."); return 0; - } - } -} - -extern "C" void modmenu_init() // TODO: nastyness -{ - // TODO: should be removed - current_font->font_texture = gfx_load_texture("data/big_font.png"); -} - -void modmenu_shutdown() -{ -} - -extern int menu2_render(); - -extern "C" int modmenu_render(int ingame) // TODO: nastyness -{ - static int mouse_x = 0; - static int mouse_y = 0; - - // handle mouse movement - float mx, my; - { - 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())*800.0f; - my = (mouse_y/(float)gfx_screenheight())*600.0f; - - int buttons = 0; - if(inp_key_pressed(KEY_MOUSE_1)) buttons |= 1; - if(inp_key_pressed(KEY_MOUSE_2)) buttons |= 2; - if(inp_key_pressed(KEY_MOUSE_3)) buttons |= 4; - - ui_update(mx,my,mx*3.0f,my*3.0f,buttons); - } - - //int r = menu_render(server_address, str, max_len); - //int r = menu2_render(ingame); - (void)menu_render; - int r = menu2_render(); - - gfx_texture_set(data->images[IMAGE_CURSOR].id); - gfx_quads_begin(); - gfx_setcolor(1,1,1,1); - gfx_quads_drawTL(mx,my,24,24); - gfx_quads_end(); - - inp_clear(); - - return r; -} - -#endif diff --git a/src/game/client/menu.h b/src/game/client/menu.h deleted file mode 100644 index 5c68c53d..00000000 --- a/src/game/client/menu.h +++ /dev/null @@ -1,16 +0,0 @@ -/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */ -#ifndef __MENU_H -#define __MENU_H - -void draw_image_button(void *id, const char *text, int checked, float x, float y, float w, float h, void *extra); -void draw_single_part_button(void *id, const char *text, int checked, float x, float y, float w, float h, void *extra); -void draw_menu_button(void *id, const char *text, int checked, float x, float y, float w, float h, void *extra); -void draw_teewars_button(void *id, const char *text, int checked, float x, float y, float w, float h, void *extra); -int ui_do_key_reader(void *id, float x, float y, float w, float h, int key); -int ui_do_combo_box(void *id, float x, float y, float w, char *lines, int line_count, int selected_index); -int ui_do_edit_box(void *id, float x, float y, float w, float h, char *str, int str_size); -int ui_do_check_box(void *id, float x, float y, float w, float h, int value); -int do_scroll_bar_horiz(void *id, float x, float y, float width, int steps, int last_index); -int do_scroll_bar_vert(void *id, float x, float y, float height, int steps, int last_index); - -#endif diff --git a/src/game/client/menu2.cpp b/src/game/client/menu2.cpp deleted file mode 100644 index 04ed48b0..00000000 --- a/src/game/client/menu2.cpp +++ /dev/null @@ -1,1893 +0,0 @@ -/* copyright (c) 2007 magnus auvinen, see licence.txt for more info */ -#include -#include -#include -#include - -#include -#include - -extern "C" { - #include - #include - #include - #include -} - -#include "../mapres.h" -#include "../version.h" -#include "../game_protocol.h" - -#include "mapres_image.h" -#include "mapres_tilemap.h" - -#include "data.h" -#include "cl_render.h" -#include "cl_skin.h" -#include - -extern data_container *data; - -// abit uglyness -extern const obj_player_info *local_info; -extern bool menu_active; -extern bool menu_game_active; - -enum -{ - POPUP_NONE=0, - POPUP_CONNECTING, - POPUP_DISCONNECTED, - POPUP_PASSWORD, - POPUP_QUIT, -}; - -static int popup = POPUP_NONE; - -//static vec4 gui_color(0.9f,0.78f,0.65f, 0.5f); -//static vec4 gui_color(0.78f,0.9f,0.65f, 0.5f); - -static vec4 gui_color(0.65f,0.78f,0.9f, 0.5f); - -static vec4 color_tabbar_inactive_outgame(0,0,0,0.25f); -static vec4 color_tabbar_active_outgame(0,0,0,0.5f); - -static float color_ingame_scale_i = 0.5f; -static float color_ingame_scale_a = 0.2f; -static vec4 color_tabbar_inactive_ingame(gui_color.r*color_ingame_scale_i, gui_color.g*color_ingame_scale_i, gui_color.b*color_ingame_scale_i,0.75f); -static vec4 color_tabbar_active_ingame(gui_color.r*color_ingame_scale_a, gui_color.g*color_ingame_scale_a, gui_color.b*color_ingame_scale_a,0.85f); -//static vec4 color_tabbar_inactive_ingame(0.2f,0.2f,0.2f,0.5f); -//static vec4 color_tabbar_active_ingame(0.2f,0.2f,0.2f,0.75f); - -static vec4 color_tabbar_inactive = color_tabbar_inactive_outgame; -static vec4 color_tabbar_active = color_tabbar_active_outgame; - -enum -{ - CORNER_TL=1, - CORNER_TR=2, - CORNER_BL=4, - CORNER_BR=8, - - CORNER_T=CORNER_TL|CORNER_TR, - CORNER_B=CORNER_BL|CORNER_BR, - CORNER_R=CORNER_TR|CORNER_BR, - CORNER_L=CORNER_TL|CORNER_BL, - - CORNER_ALL=CORNER_T|CORNER_B, - - PAGE_NEWS=0, - PAGE_INTERNET, - PAGE_LAN, - PAGE_FAVORITES, - PAGE_SETTINGS, - //PAGE_GAME, // not a real page - PAGE_SYSTEM, -}; - -typedef struct -{ - float x, y, w, h; -} RECT; - -static RECT screen = { 0.0f, 0.0f, 848.0f, 480.0f }; - -extern void select_sprite(int id, int flags=0, int sx=0, int sy=0); - -RECT *ui2_screen() -{ - float aspect = gfx_screenaspect(); - float w, h; - - h = 600; - w = aspect*h; - - screen.w = w; - screen.h = h; - - return &screen; -} - -void ui2_set_scale(float s) -{ - config.ui_scale = (int)(s*100.0f); -} - -float ui2_scale() -{ - return config.ui_scale/100.0f; -} - -void ui2_hsplit_t(const RECT *original, float cut, RECT *top, RECT *bottom) -{ - RECT r = *original; - cut *= ui2_scale(); - - if (top) - { - top->x = r.x; - top->y = r.y; - top->w = r.w; - top->h = cut; - } - - if (bottom) - { - bottom->x = r.x; - bottom->y = r.y + cut; - bottom->w = r.w; - bottom->h = r.h - cut; - } -} - -void ui2_hsplit_b(const RECT *original, float cut, RECT *top, RECT *bottom) -{ - RECT r = *original; - cut *= ui2_scale(); - - if (top) - { - top->x = r.x; - top->y = r.y; - top->w = r.w; - top->h = r.h - cut; - } - - if (bottom) - { - bottom->x = r.x; - bottom->y = r.y + r.h - cut; - bottom->w = r.w; - bottom->h = cut; - } -} - -void ui2_vsplit_l(const RECT *original, float cut, RECT *left, RECT *right) -{ - RECT r = *original; - cut *= ui2_scale(); - - if (left) - { - left->x = r.x; - left->y = r.y; - left->w = cut; - left->h = r.h; - } - - if (right) - { - right->x = r.x + cut; - right->y = r.y; - right->w = r.w - cut; - right->h = r.h; - } -} - -void ui2_vsplit_r(const RECT *original, float cut, RECT *left, RECT *right) -{ - RECT r = *original; - cut *= ui2_scale(); - - if (left) - { - left->x = r.x; - left->y = r.y; - left->w = r.w - cut; - left->h = r.h; - } - - if (right) - { - right->x = r.x + r.w - cut; - right->y = r.y; - right->w = cut; - right->h = r.h; - } -} - -void ui2_margin(const RECT *original, float cut, RECT *other_rect) -{ - RECT r = *original; - cut *= ui2_scale(); - - other_rect->x = r.x + cut; - other_rect->y = r.y + cut; - other_rect->w = r.w - 2*cut; - other_rect->h = r.h - 2*cut; -} - -void ui2_vmargin(const RECT *original, float cut, RECT *other_rect) -{ - RECT r = *original; - cut *= ui2_scale(); - - other_rect->x = r.x + cut; - other_rect->y = r.y; - other_rect->w = r.w - 2*cut; - other_rect->h = r.h; -} - -void ui2_hmargin(const RECT *original, float cut, RECT *other_rect) -{ - RECT r = *original; - cut *= ui2_scale(); - - other_rect->x = r.x; - other_rect->y = r.y + cut; - other_rect->w = r.w; - other_rect->h = r.h - 2*cut; -} - -typedef void (*ui2_draw_button_func)(const void *id, const char *text, int checked, const RECT *r, void *extra); - -int ui2_do_button(const void *id, const char *text, int checked, const RECT *r, ui2_draw_button_func draw_func, void *extra) -{ - /* logic */ - int ret = 0; - int inside = ui_mouse_inside(r->x,r->y,r->w,r->h); - - if(ui_active_item() == id) - { - if(!ui_mouse_button(0)) - { - if(inside) - ret = 1; - ui_set_active_item(0); - } - } - else if(ui_hot_item() == id) - { - if(ui_mouse_button(0)) - ui_set_active_item(id); - } - - if(inside) - ui_set_hot_item(id); - - if(draw_func) - draw_func(id, text, checked, r, extra); - return ret; -} - - -void ui2_do_label(const RECT *r, const char *text, float size, int align) -{ - gfx_blend_normal(); - size *= ui2_scale(); - if(align == 0) - { - float tw = gfx_pretty_text_width(size, text, -1); - gfx_pretty_text(r->x + r->w/2-tw/2, r->y, size, text, -1); - } - else if(align < 0) - gfx_pretty_text(r->x, r->y, size, text, -1); - else if(align > 0) - { - float tw = gfx_pretty_text_width(size, text, -1); - gfx_pretty_text(r->x + r->w-tw, r->y, size, text, -1); - } -} - - -extern void draw_round_rect_ext(float x, float y, float w, float h, float r, int corners); -extern void draw_round_rect(float x, float y, float w, float h, float r); - -static void ui2_draw_rect(const RECT *r, vec4 color, int corners, float rounding) -{ - gfx_texture_set(-1); - gfx_quads_begin(); - gfx_setcolor(color.r, color.g, color.b, color.a); - draw_round_rect_ext(r->x,r->y,r->w,r->h,rounding*ui2_scale(), corners); - gfx_quads_end(); -} - -static void ui2_draw_browse_icon(int what, const RECT *r) -{ - gfx_texture_set(data->images[IMAGE_BROWSEICONS].id); - gfx_quads_begin(); - select_sprite(SPRITE_BROWSE_PROGRESS1); // default - if(what <= 100) - { - if(what < 66) - select_sprite(SPRITE_BROWSE_PROGRESS2); - else - select_sprite(SPRITE_BROWSE_PROGRESS3); - } - else if(what&0x100) - { - select_sprite(SPRITE_BROWSE_LOCK); - } - gfx_quads_drawTL(r->x,r->y,r->w,r->h); - gfx_quads_end(); -} - -static void ui2_draw_menu_button(const void *id, const char *text, int checked, const RECT *r, void *extra) -{ - ui2_draw_rect(r, vec4(1,1,1,0.5f), CORNER_ALL, 5.0f); - ui2_do_label(r, text, 24, 0); -} - - -static void ui2_draw_keyselect_button(const void *id, const char *text, int checked, const RECT *r, void *extra) -{ - ui2_draw_rect(r, vec4(1,1,1,0.5f), CORNER_ALL, 5.0f); - ui2_do_label(r, text, 18, 0); -} - -static void ui2_draw_menu_tab_button(const void *id, const char *text, int checked, const RECT *r, void *extra) -{ - if(checked) - ui2_draw_rect(r, color_tabbar_active, CORNER_T, 10.0f); - else - ui2_draw_rect(r, color_tabbar_inactive, CORNER_T, 10.0f); - ui2_do_label(r, text, 26, 0); -} - - -static void ui2_draw_settings_tab_button(const void *id, const char *text, int checked, const RECT *r, void *extra) -{ - if(checked) - ui2_draw_rect(r, color_tabbar_active, CORNER_R, 10.0f); - else - ui2_draw_rect(r, color_tabbar_inactive, CORNER_R, 10.0f); - ui2_do_label(r, text, 24, 0); -} - -static void ui2_draw_grid_header(const void *id, const char *text, int checked, const RECT *r, void *extra) -{ - if(checked) - ui2_draw_rect(r, vec4(1,1,1,0.5f), CORNER_T, 5.0f); - //else - // ui2_draw_rect(r, vec4(1,1,1,0.1f), CORNER_T, 5.0f); - RECT t; - ui2_vsplit_l(r, 5.0f, 0, &t); - ui2_do_label(&t, text, 18, -1); -} -/* -static void ui2_draw_grid_cell_l(const void *id, const char *text, int checked, const RECT *r, void *extra) -{ - ui2_do_label(r, text, 18, -1); -} - -static void ui2_draw_grid_cell_r(const void *id, const char *text, int checked, const RECT *r, void *extra) -{ - ui2_do_label(r, text, 18, 1); -}*/ - -static void ui2_draw_list_row(const void *id, const char *text, int checked, const RECT *r, void *extra) -{ - if(checked) - { - RECT sr = *r; - ui2_margin(&sr, 1.5f, &sr); - ui2_draw_rect(&sr, vec4(1,1,1,0.5f), CORNER_ALL, 4.0f); - } - ui2_do_label(r, text, 18, -1); -} - -static void ui2_draw_checkbox_common(const void *id, const char *text, const char *boxtext, const RECT *r) -{ - RECT c = *r; - RECT t = *r; - c.w = c.h; - t.x += c.w; - t.w -= c.w; - ui2_vsplit_l(&t, 5.0f, 0, &t); - - ui2_margin(&c, 2.0f, &c); - ui2_draw_rect(&c, vec4(1,1,1,0.25f), CORNER_ALL, 3.0f); - ui2_do_label(&c, boxtext, 16, 0); - ui2_do_label(&t, text, 18, -1); -} - -static void ui2_draw_checkbox(const void *id, const char *text, int checked, const RECT *r, void *extra) -{ - ui2_draw_checkbox_common(id, text, checked?"X":"", r); -} - -static void ui2_draw_checkbox_number(const void *id, const char *text, int checked, const RECT *r, void *extra) -{ - char buf[16]; - sprintf(buf, "%d", checked); - ui2_draw_checkbox_common(id, text, buf, r); -} - -int ui2_do_edit_box(void *id, const RECT *rect, char *str, int str_size, bool hidden=false) -{ - int inside = ui_mouse_inside(rect->x,rect->y,rect->w,rect->h); - int r = 0; - static int at_index = 0; - - if(ui_last_active_item() == id) - { - int c = inp_last_char(); - int k = inp_last_key(); - int len = strlen(str); - - if (inside && ui_mouse_button(0)) - { - int mx_rel = (int)(ui_mouse_x() - rect->x); - - for (int i = 1; i <= len; i++) - { - if (gfx_pretty_text_width(18.0f, str, i) + 10 > mx_rel) - { - at_index = i - 1; - break; - } - - if (i == len) - at_index = len; - } - } - - if (at_index > len) - at_index = len; - - if (!(c >= 0 && c < 32)) - { - if (len < str_size - 1 && at_index < str_size - 1) - { - memmove(str + at_index + 1, str + at_index, len - at_index + 1); - str[at_index] = c; - at_index++; - } - } - - if (k == KEY_BACKSPACE && at_index > 0) - { - memmove(str + at_index - 1, str + at_index, len - at_index + 1); - at_index--; - } - else if (k == KEY_DEL && at_index < len) - memmove(str + at_index, str + at_index + 1, len - at_index); - else if (k == KEY_ENTER) - ui_clear_last_active_item(); - else if (k == KEY_LEFT && at_index > 0) - at_index--; - else if (k == KEY_RIGHT && at_index < len) - at_index++; - else if (k == KEY_HOME) - at_index = 0; - else if (k == KEY_END) - at_index = len; - - r = 1; - } - - int box_type; - if (ui_active_item() == id || ui_hot_item() == id || ui_last_active_item() == id) - box_type = GUI_BOX_SCREEN_INFO; - else - box_type = GUI_BOX_SCREEN_TEXTBOX; - - bool just_got_active = false; - - if(ui_active_item() == id) - { - if(!ui_mouse_button(0)) - ui_set_active_item(0); - } - else if(ui_hot_item() == id) - { - if(ui_mouse_button(0)) - { - if (ui_last_active_item() != id) - just_got_active = true; - ui_set_active_item(id); - } - } - - if(inside) - ui_set_hot_item(id); - - RECT textbox = *rect; - ui2_draw_rect(&textbox, vec4(1,1,1,0.5f), CORNER_ALL, 5.0f); - ui2_vmargin(&textbox, 5.0f, &textbox); - - const char *display_str = str; - char stars[128]; - - if(hidden) - { - unsigned s = strlen(str); - if(s >= sizeof(stars)) - s = sizeof(stars)-1; - memset(stars, '*', s); - stars[s] = 0; - display_str = stars; - } - - ui2_do_label(&textbox, display_str, 18, -1); - - if (ui_last_active_item() == id && !just_got_active) - { - float w = gfx_pretty_text_width(18.0f, display_str, at_index); - textbox.x += w*ui2_scale(); - ui2_do_label(&textbox, "_", 18, -1); - } - - return r; -} - -float ui2_do_scrollbar_v(const void *id, const RECT *rect, float current) -{ - RECT handle; - static float offset_y; - ui2_hsplit_t(rect, 33, &handle, 0); - - handle.y += (rect->h-handle.h)*current; - - /* logic */ - float ret = current; - int inside = ui_mouse_inside(handle.x,handle.y,handle.w,handle.h); - - if(ui_active_item() == id) - { - if(!ui_mouse_button(0)) - ui_set_active_item(0); - - float min = rect->y; - float max = rect->h-handle.h; - float cur = ui_mouse_y()-offset_y; - ret = (cur-min)/max; - if(ret < 0.0f) ret = 0.0f; - if(ret > 1.0f) ret = 1.0f; - } - else if(ui_hot_item() == id) - { - if(ui_mouse_button(0)) - { - ui_set_active_item(id); - offset_y = ui_mouse_y()-handle.y; - } - } - - if(inside) - ui_set_hot_item(id); - - // render - RECT rail; - ui2_vmargin(rect, 5.0f, &rail); - ui2_draw_rect(&rail, vec4(1,1,1,0.25f), 0, 0.0f); - - RECT slider = handle; - slider.w = rail.x-slider.x; - ui2_draw_rect(&slider, vec4(1,1,1,0.25f), CORNER_L, 2.5f); - slider.x = rail.x+rail.w; - ui2_draw_rect(&slider, vec4(1,1,1,0.25f), CORNER_R, 2.5f); - - slider = handle; - ui2_margin(&slider, 5.0f, &slider); - ui2_draw_rect(&slider, vec4(1,1,1,0.25f), CORNER_ALL, 2.5f); - - return ret; -} - - - -float ui2_do_scrollbar_h(const void *id, const RECT *rect, float current) -{ - RECT handle; - static float offset_x; - ui2_vsplit_l(rect, 33, &handle, 0); - - handle.x += (rect->w-handle.w)*current; - - /* logic */ - float ret = current; - int inside = ui_mouse_inside(handle.x,handle.y,handle.w,handle.h); - - if(ui_active_item() == id) - { - if(!ui_mouse_button(0)) - ui_set_active_item(0); - - float min = rect->x; - float max = rect->w-handle.w; - float cur = ui_mouse_x()-offset_x; - ret = (cur-min)/max; - if(ret < 0.0f) ret = 0.0f; - if(ret > 1.0f) ret = 1.0f; - } - else if(ui_hot_item() == id) - { - if(ui_mouse_button(0)) - { - ui_set_active_item(id); - offset_x = ui_mouse_x()-handle.x; - } - } - - if(inside) - ui_set_hot_item(id); - - // render - RECT rail; - ui2_hmargin(rect, 5.0f, &rail); - ui2_draw_rect(&rail, vec4(1,1,1,0.25f), 0, 0.0f); - - RECT slider = handle; - slider.h = rail.y-slider.y; - ui2_draw_rect(&slider, vec4(1,1,1,0.25f), CORNER_T, 2.5f); - slider.y = rail.y+rail.h; - ui2_draw_rect(&slider, vec4(1,1,1,0.25f), CORNER_B, 2.5f); - - slider = handle; - ui2_margin(&slider, 5.0f, &slider); - ui2_draw_rect(&slider, vec4(1,1,1,0.25f), CORNER_ALL, 2.5f); - - return ret; -} - -int ui2_do_key_reader(void *id, const RECT *rect, int key) -{ - // process - static bool mouse_released = true; - int inside = ui_mouse_inside(rect->x, rect->y, rect->w, rect->h); - int new_key = key; - - if(!ui_mouse_button(0)) - mouse_released = true; - - if(ui_active_item() == id) - { - int k = inp_last_key(); - if (k) - { - new_key = k; - ui_set_active_item(0); - mouse_released = false; - } - } - else if(ui_hot_item() == id) - { - if(ui_mouse_button(0) && mouse_released) - ui_set_active_item(id); - } - - if(inside) - ui_set_hot_item(id); - - // draw - if (ui_active_item() == id) - ui2_draw_keyselect_button(id, "???", 0, rect, 0); - else - ui2_draw_keyselect_button(id, inp_key_name(key), 0, rect, 0); - return new_key; -} - - -static int menu2_render_menubar(RECT r) -{ - RECT box = r; - RECT button; - - int active_page = config.ui_page; - int new_page = -1; - if(menu_game_active) - active_page = -1; - - if(client_state() == CLIENTSTATE_OFFLINE) - { - if(0) // this is not done yet - { - ui2_vsplit_l(&box, 90.0f, &button, &box); - static int news_button=0; - if (ui2_do_button(&news_button, "News", active_page==PAGE_NEWS, &button, ui2_draw_menu_tab_button, 0)) - new_page = PAGE_NEWS; - ui2_vsplit_l(&box, 30.0f, 0, &box); - } - } - else - { - ui2_vsplit_l(&box, 90.0f, &button, &box); - static int game_button=0; - if (ui2_do_button(&game_button, "Game", menu_game_active, &button, ui2_draw_menu_tab_button, 0)) - menu_game_active = true; - - ui2_vsplit_l(&box, 30.0f, 0, &box); - } - - ui2_vsplit_l(&box, 110.0f, &button, &box); - static int internet_button=0; - if (ui2_do_button(&internet_button, "Internet", active_page==PAGE_INTERNET, &button, ui2_draw_menu_tab_button, 0)) - { - client_serverbrowse_refresh(0); - new_page = PAGE_INTERNET; - } - - ui2_vsplit_l(&box, 4.0f, 0, &box); - ui2_vsplit_l(&box, 90.0f, &button, &box); - static int lan_button=0; - if (ui2_do_button(&lan_button, "LAN", active_page==PAGE_LAN, &button, ui2_draw_menu_tab_button, 0)) - { - client_serverbrowse_refresh(1); - new_page = PAGE_LAN; - } - - if(0) // this one is not done yet - { - ui2_vsplit_l(&box, 4.0f, 0, &box); - ui2_vsplit_l(&box, 120.0f, &button, &box); - static int favorites_button=0; - if (ui2_do_button(&favorites_button, "Favorites", active_page==PAGE_FAVORITES, &button, ui2_draw_menu_tab_button, 0)) - new_page = PAGE_FAVORITES; - } - - /* - ui2_vsplit_r(&box, 110.0f, &box, &button); - static int system_button=0; - if (ui2_do_button(&system_button, "System", config.ui_page==PAGE_SYSTEM, &button, ui2_draw_menu_tab_button, 0)) - config.ui_page = PAGE_SYSTEM; - - ui2_vsplit_r(&box, 30.0f, &box, 0); - */ - - ui2_vsplit_r(&box, 110.0f, &box, &button); - static int quit_button=0; - if (ui2_do_button(&quit_button, "Quit", 0, &button, ui2_draw_menu_tab_button, 0)) - popup = POPUP_QUIT; - - ui2_vsplit_r(&box, 10.0f, &box, &button); - ui2_vsplit_r(&box, 110.0f, &box, &button); - static int settings_button=0; - if (ui2_do_button(&settings_button, "Settings", active_page==PAGE_SETTINGS, &button, ui2_draw_menu_tab_button, 0)) - new_page = PAGE_SETTINGS; - - if(new_page != -1) - { - config.ui_page = new_page; - menu_game_active = false; - } - - return 0; -} - -static void menu2_render_background() -{ - //gfx_clear(0.65f,0.78f,0.9f); - gfx_clear(gui_color.r, gui_color.g, gui_color.b); - //gfx_clear(0.78f,0.9f,0.65f); - - gfx_texture_set(data->images[IMAGE_BANNER].id); - gfx_quads_begin(); - gfx_setcolor(0,0,0,0.05f); - gfx_quads_setrotation(-pi/4+0.15f); - gfx_quads_draw(400, 300, 1000, 250); - gfx_quads_end(); -} - -static void menu2_render_serverbrowser(RECT main_view) -{ - ui2_draw_rect(&main_view, color_tabbar_active, CORNER_ALL, 10.0f); - - RECT view; - ui2_margin(&main_view, 10.0f, &view); - - RECT headers; - RECT filters; - RECT status; - RECT toolbox; - - //ui2_hsplit_t(&view, 20.0f, &status, &view); - ui2_hsplit_t(&view, 20.0f, &headers, &view); - ui2_hsplit_b(&view, 90.0f, &view, &filters); - ui2_hsplit_b(&view, 5.0f, &view, 0); - ui2_hsplit_b(&view, 20.0f, &view, &status); - - ui2_vsplit_r(&filters, 300.0f, &filters, &toolbox); - ui2_vsplit_r(&filters, 150.0f, &filters, 0); - - // split of the scrollbar - ui2_draw_rect(&headers, vec4(1,1,1,0.25f), CORNER_T, 5.0f); - ui2_vsplit_r(&headers, 20.0f, &headers, 0); - - struct column - { - int id; - int sort; - const char *caption; - int direction; - float width; - int flags; - RECT rect; - RECT spacer; - }; - - enum - { - FIXED=1, - SPACER=2, - - COL_FLAGS=0, - COL_NAME, - COL_GAMETYPE, - COL_MAP, - COL_PLAYERS, - COL_PING, - COL_PROGRESS, - }; - - static column cols[] = { - {-1, -1, " ", -1, 10.0f, 0, {0}, {0}}, - {COL_FLAGS, -1, " ", -1, 20.0f, 0, {0}, {0}}, - {COL_NAME, BROWSESORT_NAME, "Name", 0, 300.0f, 0, {0}, {0}}, - {COL_GAMETYPE, BROWSESORT_GAMETYPE, "Type", 1, 50.0f, 0, {0}, {0}}, - {COL_MAP, BROWSESORT_MAP, "Map", 1, 100.0f, 0, {0}, {0}}, - {COL_PLAYERS, BROWSESORT_NUMPLAYERS, "Players", 1, 60.0f, 0, {0}, {0}}, - {-1, -1, " ", 1, 10.0f, 0, {0}, {0}}, - {COL_PROGRESS, BROWSESORT_PROGRESSION, "%", 1, 20.0f, FIXED, {0}, {0}}, - {COL_PING, BROWSESORT_PING, "Ping", 1, 40.0f, FIXED, {0}, {0}}, - }; - - int num_cols = sizeof(cols)/sizeof(column); - - // do layout - for(int i = 0; i < num_cols; i++) - { - if(cols[i].direction == -1) - { - ui2_vsplit_l(&headers, cols[i].width, &cols[i].rect, &headers); - - if(i+1 < num_cols) - { - //cols[i].flags |= SPACER; - ui2_vsplit_l(&headers, 2, &cols[i].spacer, &headers); - } - } - } - - for(int i = num_cols-1; i >= 0; i--) - { - if(cols[i].direction == 1) - { - ui2_vsplit_r(&headers, cols[i].width, &headers, &cols[i].rect); - ui2_vsplit_r(&headers, 2, &headers, &cols[i].spacer); - } - } - - for(int i = 0; i < num_cols; i++) - { - if(cols[i].direction == 0) - cols[i].rect = headers; - } - - // do headers - for(int i = 0; i < num_cols; i++) - { - if(ui2_do_button(cols[i].caption, cols[i].caption, config.b_sort == cols[i].sort, &cols[i].rect, ui2_draw_grid_header, 0)) - { - if(cols[i].sort != -1) - config.b_sort = cols[i].sort; - } - } - - ui2_draw_rect(&view, vec4(0,0,0,0.15f), 0, 0); - - RECT scroll; - ui2_vsplit_r(&view, 15, &view, &scroll); - - int num_servers = client_serverbrowse_sorted_num(); - - int num = (int)(view.h/cols[0].rect.h); - static int scrollbar = 0; - static float scrollvalue = 0; - static int selected_index = -1; - ui2_hmargin(&scroll, 5.0f, &scroll); - scrollvalue = ui2_do_scrollbar_v(&scrollbar, &scroll, scrollvalue); - - int start = (int)((num_servers-num)*scrollvalue); - if(start < 0) - start = 0; - - //int r = -1; - int new_selected = selected_index; - - for (int i = start, k = 0; i < num_servers && k < num; i++, k++) - { - int item_index = i; - SERVER_INFO *item = client_serverbrowse_sorted_get(item_index); - RECT row; - - int l = selected_index==item_index; - - if(l) - { - // selected server, draw the players on it - RECT whole; - int h = (item->num_players+2)/3; - - ui2_hsplit_t(&view, 25.0f+h*15.0f, &whole, &view); - - RECT r = whole; - ui2_margin(&r, 1.5f, &r); - ui2_draw_rect(&r, vec4(1,1,1,0.5f), CORNER_ALL, 4.0f); - - ui2_hsplit_t(&whole, 20.0f, &row, &whole); - ui2_vsplit_l(&whole, 50.0f, 0, &whole); - - for(int p = 0; p < item->num_players; p+=3) - { - RECT player_row; - RECT player_rect; - RECT player_score; - RECT player_name; - ui2_hsplit_t(&whole, 15.0f, &player_row, &whole); - - for(int a = 0; a < 3; a++) - { - if(p+a >= item->num_players) - break; - - ui2_vsplit_l(&player_row, 170.0f, &player_rect, &player_row); - ui2_vsplit_l(&player_rect, 30.0f, &player_score, &player_name); - ui2_vsplit_l(&player_name, 10.0f, 0, &player_name); - char buf[32]; - sprintf(buf, "%d", item->player_scores[p+a]); - ui2_do_label(&player_score, buf, 16.0f, 1); - ui2_do_label(&player_name, item->player_names[p+a], 16.0f, -1); - } - } - - k += h*3/4; - } - else - ui2_hsplit_t(&view, 20.0f, &row, &view); - - if(ui2_do_button(item, "", l, &row, 0, 0)) - { - new_selected = item_index; - dbg_msg("dbg", "addr = %s", item->address); - strncpy(config.ui_server_address, item->address, sizeof(config.ui_server_address)); - if(inp_mouse_doubleclick()) - client_connect(config.ui_server_address); - } - - for(int c = 0; c < num_cols; c++) - { - RECT button; - char temp[64]; - button.x = cols[c].rect.x; - button.y = row.y; - button.h = row.h; - button.w = cols[c].rect.w; - - //int s = 0; - int id = cols[c].id; - - //s = ui2_do_button(item, "L", l, &button, ui2_draw_browse_icon, 0); - - if(id == COL_FLAGS) - { - if(item->flags&1) - ui2_draw_browse_icon(0x100, &button); - } - else if(id == COL_NAME) - ui2_do_label(&button, item->name, 20.0f, -1); - else if(id == COL_MAP) - ui2_do_label(&button, item->map, 20.0f, -1); - else if(id == COL_PLAYERS) - { - sprintf(temp, "%i/%i", item->num_players, item->max_players); - ui2_do_label(&button, temp, 20.0f, 1); - } - else if(id == COL_PING) - { - sprintf(temp, "%i", item->latency); - ui2_do_label(&button, temp, 20.0f, 1); - } - else if(id == COL_PROGRESS) - { - ui2_draw_browse_icon(item->progression, &button); - } - else if(id == COL_GAMETYPE) - { - const char *type = "???"; - if(item->game_type == GAMETYPE_DM) type = "DM"; - else if(item->game_type == GAMETYPE_TDM) type = "TDM"; - else if(item->game_type == GAMETYPE_CTF) type = "CTF"; - ui2_do_label(&button, type, 20.0f, 0); - } - /* - if(s) - { - new_selected = item_index; - dbg_msg("dbg", "addr = %s", item->address); - strncpy(config.ui_server_address, item->address, sizeof(config.ui_server_address)); - }*/ - } - } - - selected_index = new_selected; - - - // render quick search - RECT button; - ui2_hsplit_t(&filters, 20.0f, &button, &filters); - ui2_do_label(&button, "Quick search: ", 18, -1); - ui2_vsplit_l(&button, 95.0f, 0, &button); - ui2_do_edit_box(&config.b_filter_string, &button, config.b_filter_string, sizeof(config.b_filter_string)); - - // render filters - ui2_hsplit_t(&filters, 20.0f, &button, &filters); - if (ui2_do_button(&config.b_filter_empty, "Has people playing", config.b_filter_empty, &button, ui2_draw_checkbox, 0)) - config.b_filter_empty ^= 1; - - ui2_hsplit_t(&filters, 20.0f, &button, &filters); - if (ui2_do_button(&config.b_filter_full, "Server not full", config.b_filter_full, &button, ui2_draw_checkbox, 0)) - config.b_filter_full ^= 1; - - ui2_hsplit_t(&filters, 20.0f, &button, &filters); - if (ui2_do_button(&config.b_filter_pw, "Is not password protected", config.b_filter_pw, &button, ui2_draw_checkbox, 0)) - config.b_filter_pw ^= 1; - - - // render status - ui2_draw_rect(&status, vec4(1,1,1,0.25f), CORNER_B, 5.0f); - ui2_vmargin(&status, 50.0f, &status); - char buf[128]; - sprintf(buf, "%d of %d servers", client_serverbrowse_sorted_num(), client_serverbrowse_num()); - ui2_do_label(&status, buf, 18.0f, -1); - - // render toolbox - { - RECT buttons, button; - ui2_hsplit_b(&toolbox, 25.0f, &toolbox, &buttons); - - ui2_vsplit_r(&buttons, 100.0f, &buttons, &button); - ui2_vmargin(&button, 2.0f, &button); - static int join_button = 0; - if(ui2_do_button(&join_button, "Connect", 0, &button, ui2_draw_menu_button, 0)) - client_connect(config.ui_server_address); - - ui2_vsplit_r(&buttons, 20.0f, &buttons, &button); - ui2_vsplit_r(&buttons, 100.0f, &buttons, &button); - ui2_vmargin(&button, 2.0f, &button); - static int refresh_button = 0; - if(ui2_do_button(&refresh_button, "Refresh", 0, &button, ui2_draw_menu_button, 0)) - { - if(config.ui_page == PAGE_INTERNET) - client_serverbrowse_refresh(0); - else if(config.ui_page == PAGE_LAN) - client_serverbrowse_refresh(1); - } - - ui2_hsplit_t(&toolbox, 20.0f, &button, &toolbox); - ui2_do_label(&button, "Host address:", 18, -1); - ui2_vsplit_l(&button, 100.0f, 0, &button); - ui2_do_edit_box(&config.ui_server_address, &button, config.ui_server_address, sizeof(config.ui_server_address)); - } -} - -static void menu2_render_settings_player(RECT main_view) -{ - RECT button; - RECT skinselection; - ui2_vsplit_l(&main_view, 300.0f, &main_view, &skinselection); - - - ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); - - // render settings - { - ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); - ui2_do_label(&button, "Name:", 18.0, -1); - ui2_vsplit_l(&button, 80.0f, 0, &button); - ui2_vsplit_l(&button, 180.0f, &button, 0); - ui2_do_edit_box(config.player_name, &button, config.player_name, sizeof(config.player_name)); - - ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); - if (ui2_do_button(&config.cl_dynamic_camera, "Dynamic camera", config.cl_dynamic_camera, &button, ui2_draw_checkbox, 0)) - config.cl_dynamic_camera ^= 1; - - ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); - if (ui2_do_button(&config.cl_autoswitch_weapons, "Switch weapon on pickup", config.cl_autoswitch_weapons, &button, ui2_draw_checkbox, 0)) - config.cl_autoswitch_weapons ^= 1; - - ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); - if (ui2_do_button(&config.cl_nameplates, "Show name plates", config.cl_nameplates, &button, ui2_draw_checkbox, 0)) - config.cl_nameplates ^= 1; - - if(config.cl_nameplates) - { - ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); - ui2_vsplit_l(&button, 15.0f, 0, &button); - if (ui2_do_button(&config.cl_nameplates_always, "Always show name plates", config.cl_nameplates_always, &button, ui2_draw_checkbox, 0)) - config.cl_nameplates_always ^= 1; - } - - ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); - - ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); - if (ui2_do_button(&config.player_color_body, "Custom colors", config.player_use_custom_color, &button, ui2_draw_checkbox, 0)) - config.player_use_custom_color = config.player_use_custom_color?0:1; - - if(config.player_use_custom_color) - { - int *colors[2]; - colors[0] = &config.player_color_body; - colors[1] = &config.player_color_feet; - - const char *parts[] = {"Body", "Feet"}; - const char *labels[] = {"Hue", "Sat.", "Lht."}; - static int color_slider[2][3] = {{0}}; - //static float v[2][3] = {{0, 0.5f, 0.25f}, {0, 0.5f, 0.25f}}; - - for(int i = 0; i < 2; i++) - { - RECT text; - ui2_hsplit_t(&main_view, 20.0f, &text, &main_view); - ui2_vsplit_l(&text, 15.0f, 0, &text); - ui2_do_label(&text, parts[i], 18, -1); - - int prevcolor = *colors[i]; - int color = 0; - for(int s = 0; s < 3; s++) - { - RECT text; - ui2_hsplit_t(&main_view, 19.0f, &button, &main_view); - ui2_vsplit_l(&button, 30.0f, 0, &button); - ui2_vsplit_l(&button, 30.0f, &text, &button); - ui2_vsplit_r(&button, 5.0f, &button, 0); - ui2_hsplit_t(&button, 4.0f, 0, &button); - - float k = ((prevcolor>>((2-s)*8))&0xff) / 255.0f; - k = ui2_do_scrollbar_h(&color_slider[i][s], &button, k); - color <<= 8; - color += clamp((int)(k*255), 0, 255); - ui2_do_label(&text, labels[s], 20, -1); - - } - - *colors[i] = color; - ui2_hsplit_t(&main_view, 5.0f, 0, &main_view); - } - } - } - - // draw header - RECT header, footer; - ui2_hsplit_t(&skinselection, 20, &header, &skinselection); - ui2_draw_rect(&header, vec4(1,1,1,0.25f), CORNER_T, 5.0f); - ui2_do_label(&header, "Skins", 18.0f, 0); - - // draw footers - ui2_hsplit_b(&skinselection, 20, &skinselection, &footer); - ui2_draw_rect(&footer, vec4(1,1,1,0.25f), CORNER_B, 5.0f); - ui2_vsplit_l(&footer, 10.0f, 0, &footer); - - // modes - ui2_draw_rect(&skinselection, vec4(0,0,0,0.15f), 0, 0); - - RECT scroll; - ui2_vsplit_r(&skinselection, 15, &skinselection, &scroll); - - RECT list = skinselection; - ui2_hsplit_t(&list, 50, &button, &list); - - int num = (int)(skinselection.h/button.h); - static float scrollvalue = 0; - static int scrollbar = 0; - ui2_hmargin(&scroll, 5.0f, &scroll); - scrollvalue = ui2_do_scrollbar_v(&scrollbar, &scroll, scrollvalue); - - int start = (int)((skin_num()-num)*scrollvalue); - if(start < 0) - start = 0; - - animstate state; - anim_eval(&data->animations[ANIM_BASE], 0, &state); - anim_eval_add(&state, &data->animations[ANIM_IDLE], 0, 1.0f); - //anim_eval_add(&state, &data->animations[ANIM_WALK], fmod(client_localtime(), 1.0f), 1.0f); - - for(int i = start; i < start+num && i < skin_num(); i++) - { - const skin *s = skin_get(i); - char buf[128]; - sprintf(buf, "%s", s->name); - int selected = 0; - if(strcmp(s->name, config.player_skin) == 0) - selected = 1; - - tee_render_info info; - info.texture = s->org_texture; - info.color_body = vec4(1,1,1,1); - info.color_feet = vec4(1,1,1,1); - if(config.player_use_custom_color) - { - info.color_body = skin_get_color(config.player_color_body); - info.color_feet = skin_get_color(config.player_color_feet); - info.texture = s->color_texture; - } - - info.size = ui2_scale()*50.0f; - - RECT icon; - RECT text; - ui2_vsplit_l(&button, 50.0f, &icon, &text); - - if(ui2_do_button(s, "", selected, &button, ui2_draw_list_row, 0)) - config_set_player_skin(&config, s->name); - - ui2_hsplit_t(&text, 12.0f, 0, &text); // some margin from the top - ui2_do_label(&text, buf, 24, 0); - - ui2_hsplit_t(&icon, 5.0f, 0, &icon); // some margin from the top - render_tee(&state, &info, 0, vec2(1, 0), vec2(icon.x+icon.w/2, icon.y+icon.h/2)); - - ui2_hsplit_t(&list, 50, &button, &list); - } -} - -typedef void (*assign_func_callback)(CONFIGURATION *config, int value); - -static void menu2_render_settings_controls(RECT main_view) -{ - ui2_vsplit_l(&main_view, 300.0f, &main_view, 0); - - { - RECT button, label; - ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); - ui2_vsplit_l(&button, 110.0f, &label, &button); - ui2_do_label(&label, "Mouse sens.", 18.0f, -1); - ui2_hmargin(&button, 2.0f, &button); - config.inp_mousesens = (int)(ui2_do_scrollbar_h(&config.inp_mousesens, &button, config.inp_mousesens/500.0f)*500.0f); - //*key.key = ui2_do_key_reader(key.key, &button, *key.key); - ui2_hsplit_t(&main_view, 20.0f, 0, &main_view); - } - - typedef struct - { - char name[32]; - int *key; - } KEYINFO; - - const KEYINFO keys[] = - { - { "Move Left:", &config.key_move_left }, - { "Move Right:", &config.key_move_right }, - { "Jump:", &config.key_jump }, - { "Fire:", &config.key_fire }, - { "Hook:", &config.key_hook }, - { "Hammer:", &config.key_weapon1 }, - { "Pistol:", &config.key_weapon2 }, - { "Shotgun:", &config.key_weapon3 }, - { "Grenade:", &config.key_weapon4 }, - { "Next Weapon:", &config.key_next_weapon }, - { "Prev. Weapon:", &config.key_prev_weapon }, - { "Emoticon:", &config.key_emoticon }, - { "Chat:", &config.key_chat }, - { "Team Chat:", &config.key_teamchat }, - { "Console:", &config.key_console }, - { "Remote Console:", &config.key_remoteconsole }, - { "Screenshot:", &config.key_screenshot }, - }; - - const int key_count = sizeof(keys) / sizeof(KEYINFO); - - for (int i = 0; i < key_count; i++) - { - KEYINFO key = keys[i]; - RECT button, label; - ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); - ui2_vsplit_l(&button, 110.0f, &label, &button); - - ui2_do_label(&label, key.name, 18.0f, -1); - *key.key = ui2_do_key_reader(key.key, &button, *key.key); - ui2_hsplit_t(&main_view, 5.0f, 0, &main_view); - } -} - -static void menu2_render_settings_graphics(RECT main_view) -{ - RECT button; - char buf[128]; - - static const int MAX_RESOLUTIONS = 256; - static VIDEO_MODE modes[MAX_RESOLUTIONS]; - static int num_modes = -1; - - if(num_modes == -1) - num_modes = gfx_get_video_modes(modes, MAX_RESOLUTIONS); - - RECT modelist; - ui2_vsplit_l(&main_view, 300.0f, &main_view, &modelist); - - // draw allmodes switch - RECT header, footer; - ui2_hsplit_t(&modelist, 20, &button, &modelist); - if (ui2_do_button(&config.gfx_display_all_modes, "Show only supported", config.gfx_display_all_modes^1, &button, ui2_draw_checkbox, 0)) - { - config.gfx_display_all_modes ^= 1; - num_modes = gfx_get_video_modes(modes, MAX_RESOLUTIONS); - } - - // draw header - ui2_hsplit_t(&modelist, 20, &header, &modelist); - ui2_draw_rect(&header, vec4(1,1,1,0.25f), CORNER_T, 5.0f); - ui2_do_label(&header, "Display Modes", 18.0f, 0); - - // draw footers - ui2_hsplit_b(&modelist, 20, &modelist, &footer); - sprintf(buf, "Current: %dx%d %d bit", config.gfx_screen_width, config.gfx_screen_height, config.gfx_color_depth); - ui2_draw_rect(&footer, vec4(1,1,1,0.25f), CORNER_B, 5.0f); - ui2_vsplit_l(&footer, 10.0f, 0, &footer); - ui2_do_label(&footer, buf, 18.0f, -1); - - // modes - ui2_draw_rect(&modelist, vec4(0,0,0,0.15f), 0, 0); - - RECT scroll; - ui2_vsplit_r(&modelist, 15, &modelist, &scroll); - - RECT list = modelist; - ui2_hsplit_t(&list, 20, &button, &list); - - int num = (int)(modelist.h/button.h); - static float scrollvalue = 0; - static int scrollbar = 0; - ui2_hmargin(&scroll, 5.0f, &scroll); - scrollvalue = ui2_do_scrollbar_v(&scrollbar, &scroll, scrollvalue); - - int start = (int)((num_modes-num)*scrollvalue); - if(start < 0) - start = 0; - - for(int i = start; i < start+num && i < num_modes; i++) - { - int depth = modes[i].red+modes[i].green+modes[i].blue; - if(depth < 16) - depth = 16; - else if(depth > 16) - depth = 24; - - int selected = 0; - if(config.gfx_color_depth == depth && - config.gfx_screen_width == modes[i].width && - config.gfx_screen_height == modes[i].height) - { - selected = 1; - } - - sprintf(buf, " %dx%d %d bit", modes[i].width, modes[i].height, depth); - if(ui2_do_button(&modes[i], buf, selected, &button, ui2_draw_list_row, 0)) - { - config.gfx_color_depth = depth; - config.gfx_screen_width = modes[i].width; - config.gfx_screen_height = modes[i].height; - } - - ui2_hsplit_t(&list, 20, &button, &list); - } - - - // switches - ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); - if (ui2_do_button(&config.gfx_fullscreen, "Fullscreen", config.gfx_fullscreen, &button, ui2_draw_checkbox, 0)) - config.gfx_fullscreen ^= 1; - - ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); - if (ui2_do_button(&config.gfx_vsync, "V-Sync", config.gfx_vsync, &button, ui2_draw_checkbox, 0)) - config.gfx_vsync ^= 1; - - ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); - if (ui2_do_button(&config.gfx_fsaa_samples, "FSAA samples", config.gfx_fsaa_samples, &button, ui2_draw_checkbox_number, 0)) - { - if(config.gfx_fsaa_samples < 2) config.gfx_fsaa_samples = 2; - else if(config.gfx_fsaa_samples < 4) config.gfx_fsaa_samples = 4; - else if(config.gfx_fsaa_samples < 6) config.gfx_fsaa_samples = 6; - else if(config.gfx_fsaa_samples < 8) config.gfx_fsaa_samples = 8; - else if(config.gfx_fsaa_samples < 16) config.gfx_fsaa_samples = 16; - else if(config.gfx_fsaa_samples >= 16) config.gfx_fsaa_samples = 0; - } - - ui2_hsplit_t(&main_view, 40.0f, &button, &main_view); - ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); - if (ui2_do_button(&config.gfx_texture_quality, "Quality Textures", config.gfx_texture_quality, &button, ui2_draw_checkbox, 0)) - config.gfx_texture_quality ^= 1; - - ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); - if (ui2_do_button(&config.gfx_texture_compression, "Texture Compression", config.gfx_texture_compression, &button, ui2_draw_checkbox, 0)) - config.gfx_texture_compression ^= 1; - - ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); - if (ui2_do_button(&config.gfx_high_detail, "High Detail", config.gfx_high_detail, &button, ui2_draw_checkbox, 0)) - config.gfx_high_detail ^= 1; - - // - - RECT text; - ui2_hsplit_t(&main_view, 20.0f, 0, &main_view); - ui2_hsplit_t(&main_view, 20.0f, &text, &main_view); - //ui2_vsplit_l(&text, 15.0f, 0, &text); - ui2_do_label(&text, "UI Color", 18, -1); - - const char *labels[] = {"Hue", "Sat.", "Lht.", "Alpha"}; - int *color_slider[4] = {&config.ui_color_hue, &config.ui_color_sat, &config.ui_color_lht, &config.ui_color_alpha}; - for(int s = 0; s < 4; s++) - { - RECT text; - ui2_hsplit_t(&main_view, 19.0f, &button, &main_view); - ui2_vmargin(&button, 15.0f, &button); - ui2_vsplit_l(&button, 30.0f, &text, &button); - ui2_vsplit_r(&button, 5.0f, &button, 0); - ui2_hsplit_t(&button, 4.0f, 0, &button); - - float k = (*color_slider[s]) / 255.0f; - k = ui2_do_scrollbar_h(color_slider[s], &button, k); - *color_slider[s] = (int)(k*255.0f); - ui2_do_label(&text, labels[s], 20, -1); - } -} - -static void menu2_render_settings_sound(RECT main_view) -{ - RECT button; - ui2_vsplit_l(&main_view, 300.0f, &main_view, 0); - - ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); - if (ui2_do_button(&config.snd_enable, "Use Sounds", config.snd_enable, &button, ui2_draw_checkbox, 0)) - config.snd_enable ^= 1; - - if(!config.snd_enable) - return; - - // sample rate box - { - char buf[64]; - sprintf(buf, "%d", config.snd_rate); - ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); - ui2_do_label(&button, "Sample Rate", 18.0, -1); - ui2_vsplit_l(&button, 110.0f, 0, &button); - ui2_vsplit_l(&button, 180.0f, &button, 0); - ui2_do_edit_box(&config.snd_rate, &button, buf, sizeof(buf)); - config.snd_rate = atoi(buf); - - if(config.snd_rate < 1) - config.snd_rate = 1; - } - - // volume slider - { - RECT button, label; - ui2_hsplit_t(&main_view, 5.0f, &button, &main_view); - ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); - ui2_vsplit_l(&button, 110.0f, &label, &button); - ui2_hmargin(&button, 2.0f, &button); - ui2_do_label(&label, "Sound Volume", 18.0f, -1); - config.snd_volume = (int)(ui2_do_scrollbar_h(&config.snd_volume, &button, config.snd_volume/100.0f)*100.0f); - ui2_hsplit_t(&main_view, 20.0f, 0, &main_view); - } -} - - -static void menu2_render_settings_network(RECT main_view) -{ - RECT button; - ui2_vsplit_l(&main_view, 300.0f, &main_view, 0); - - { - ui2_hsplit_t(&main_view, 20.0f, &button, &main_view); - ui2_do_label(&button, "Rcon Password", 18.0, -1); - ui2_vsplit_l(&button, 110.0f, 0, &button); - ui2_vsplit_l(&button, 180.0f, &button, 0); - ui2_do_edit_box(&config.rcon_password, &button, config.rcon_password, sizeof(config.rcon_password), true); - } -} - -static void menu2_render_settings(RECT main_view) -{ - static int settings_page = 0; - - // render background - RECT temp, tabbar; - ui2_vsplit_r(&main_view, 120.0f, &main_view, &tabbar); - ui2_draw_rect(&main_view, color_tabbar_active, CORNER_B|CORNER_TL, 10.0f); - ui2_hsplit_t(&tabbar, 50.0f, &temp, &tabbar); - ui2_draw_rect(&temp, color_tabbar_active, CORNER_R, 10.0f); - - ui2_hsplit_t(&main_view, 10.0f, 0, &main_view); - - RECT button; - - const char *tabs[] = {"Player", "Controls", "Network", "Graphics", "Sound"}; - int num_tabs = (int)(sizeof(tabs)/sizeof(*tabs)); - - for(int i = 0; i < num_tabs; i++) - { - ui2_hsplit_t(&tabbar, 10, &button, &tabbar); - ui2_hsplit_t(&tabbar, 26, &button, &tabbar); - if(ui2_do_button(tabs[i], tabs[i], settings_page == i, &button, ui2_draw_settings_tab_button, 0)) - settings_page = i; - } - - ui2_margin(&main_view, 10.0f, &main_view); - - if(settings_page == 0) - menu2_render_settings_player(main_view); - else if(settings_page == 1) - menu2_render_settings_controls(main_view); - else if(settings_page == 2) - menu2_render_settings_network(main_view); - else if(settings_page == 3) - menu2_render_settings_graphics(main_view); - else if(settings_page == 4) - menu2_render_settings_sound(main_view); -} - -static void menu2_render_news(RECT main_view) -{ - ui2_draw_rect(&main_view, color_tabbar_active, CORNER_ALL, 10.0f); -} - - -static void menu2_render_game(RECT main_view) -{ - RECT button; - ui2_hsplit_t(&main_view, 45.0f, &main_view, 0); - ui2_draw_rect(&main_view, color_tabbar_active, CORNER_ALL, 10.0f); - - ui2_hsplit_t(&main_view, 10.0f, 0, &main_view); - ui2_hsplit_t(&main_view, 25.0f, &main_view, 0); - ui2_vmargin(&main_view, 10.0f, &main_view); - - ui2_vsplit_r(&main_view, 120.0f, &main_view, &button); - static int disconnect_button = 0; - if(ui2_do_button(&disconnect_button, "Disconnect", 0, &button, ui2_draw_menu_button, 0)) - client_disconnect(); - - if(local_info) - { - if(local_info->team != -1) - { - ui2_vsplit_l(&main_view, 10.0f, &button, &main_view); - ui2_vsplit_l(&main_view, 120.0f, &button, &main_view); - static int spectate_button = 0; - if(ui2_do_button(&spectate_button, "Spectate", 0, &button, ui2_draw_menu_button, 0)) - { - config.cl_team = -1; - menu_active = false; - } - } - - if(local_info->team != 0) - { - ui2_vsplit_l(&main_view, 10.0f, &button, &main_view); - ui2_vsplit_l(&main_view, 120.0f, &button, &main_view); - static int spectate_button = 0; - if(ui2_do_button(&spectate_button, "Join Red", 0, &button, ui2_draw_menu_button, 0)) - { - config.cl_team = 0; - menu_active = false; - } - } - - if(local_info->team != 1) - { - ui2_vsplit_l(&main_view, 10.0f, &button, &main_view); - ui2_vsplit_l(&main_view, 120.0f, &button, &main_view); - static int spectate_button = 0; - if(ui2_do_button(&spectate_button, "Join Blue", 0, &button, ui2_draw_menu_button, 0)) - { - config.cl_team = 1; - menu_active = false; - } - } - } -} - -void menu_do_disconnected() -{ - popup = POPUP_NONE; - if(client_error_string() && client_error_string()[0] != 0) - { - if(strstr(client_error_string(), "password")) - { - popup = POPUP_PASSWORD; - ui_set_hot_item(&config.password); - ui_set_active_item(&config.password); - } - else - popup = POPUP_DISCONNECTED; - } -} - -void menu_do_connecting() -{ - popup = POPUP_CONNECTING; -} - -void menu_do_connected() -{ - popup = POPUP_NONE; -} - -int menu2_render() -{ - if(0) - { - gfx_mapscreen(0,0,10*4/3.0f,10); - gfx_clear(gui_color.r, gui_color.g, gui_color.b); - - animstate state; - anim_eval(&data->animations[ANIM_BASE], 0, &state); - anim_eval_add(&state, &data->animations[ANIM_IDLE], 0, 1.0f); - //anim_eval_add(&state, &data->animations[ANIM_WALK], fmod(client_localtime(), 1.0f), 1.0f); - - for(int i = 0; i < skin_num(); i++) - { - float x = (i/8)*3; - float y = (i%8); - for(int c = 0; c < 2; c++) - { - //int colors[2] = {54090, 10998628}; - //int colors[2] = {65432, 9895832}; // NEW - int colors[2] = {65387, 10223467}; // NEW - - tee_render_info info; - info.texture = skin_get(i)->color_texture; - info.color_feet = info.color_body = skin_get_color(colors[c]); - //info.color_feet = info.color_body = vec4(1,1,1,1); - info.size = 1.0f; //ui2_scale()*16.0f; - //render_tee(&state, &info, 0, vec2(sinf(client_localtime()*3), cosf(client_localtime()*3)), vec2(1+x+c,1+y)); - render_tee(&state, &info, 0, vec2(1,0), vec2(1+x+c,1+y)); - } - } - - return 0; - } - - RECT screen = *ui2_screen(); - gfx_mapscreen(screen.x, screen.y, screen.w, screen.h); - - static bool first = true; - if(first) - { - if(config.ui_page == PAGE_INTERNET) - client_serverbrowse_refresh(0); - else if(config.ui_page == PAGE_LAN) - client_serverbrowse_refresh(1); - first = false; - } - - if(client_state() == CLIENTSTATE_ONLINE) - { - color_tabbar_inactive = color_tabbar_inactive_ingame; - color_tabbar_active = color_tabbar_active_ingame; - } - else - { - menu2_render_background(); - color_tabbar_inactive = color_tabbar_inactive_outgame; - color_tabbar_active = color_tabbar_active_outgame; - } - - RECT tab_bar; - RECT main_view; - - // some margin around the screen - ui2_margin(&screen, 10.0f, &screen); - - if(popup == POPUP_NONE) - { - // do tab bar - ui2_hsplit_t(&screen, 26.0f, &tab_bar, &main_view); - ui2_vmargin(&tab_bar, 20.0f, &tab_bar); - menu2_render_menubar(tab_bar); - - // render current page - if(menu_game_active) - menu2_render_game(main_view); - else if(config.ui_page == PAGE_NEWS) - menu2_render_news(main_view); - else if(config.ui_page == PAGE_INTERNET) - menu2_render_serverbrowser(main_view); - else if(config.ui_page == PAGE_LAN) - menu2_render_serverbrowser(main_view); - else if(config.ui_page == PAGE_FAVORITES) - menu2_render_serverbrowser(main_view); - else if(config.ui_page == PAGE_SETTINGS) - menu2_render_settings(main_view); - } - else - { - // make sure that other windows doesn't do anything funnay! - //ui_set_hot_item(0); - //ui_set_active_item(0); - const char *title = ""; - const char *extra_text = ""; - const char *button_text = ""; - - if(popup == POPUP_CONNECTING) - { - title = "Connecting to"; - extra_text = config.ui_server_address; // TODO: query the client about the address - button_text = "Abort"; - } - else if(popup == POPUP_DISCONNECTED) - { - title = "Disconnected"; - extra_text = client_error_string(); - button_text = "Ok"; - } - else if(popup == POPUP_PASSWORD) - { - title = "Password Error"; - extra_text = client_error_string(); - button_text = "Try Again"; - } - else if(popup == POPUP_QUIT) - { - title = "Quit"; - extra_text = "Are you sure that you want to quit?"; - } - - - RECT box, part; - box = screen; - ui2_vmargin(&box, 150.0f, &box); - ui2_hmargin(&box, 150.0f, &box); - - // render the box - ui2_draw_rect(&box, vec4(0,0,0,0.5f), CORNER_ALL, 15.0f); - - ui2_hsplit_t(&box, 20.f, &part, &box); - ui2_hsplit_t(&box, 24.f, &part, &box); - ui2_do_label(&part, title, 24.f, 0); - ui2_hsplit_t(&box, 20.f, &part, &box); - ui2_hsplit_t(&box, 24.f, &part, &box); - ui2_do_label(&part, extra_text, 20.f, 0); - - if(popup == POPUP_QUIT) - { - RECT tryagain, abort; - ui2_hsplit_b(&box, 20.f, &box, &part); - ui2_hsplit_b(&box, 24.f, &box, &part); - ui2_vmargin(&part, 120.0f, &part); - - ui2_vsplit_l(&part, 100.0f, &abort, &part); - ui2_vsplit_r(&part, 100.0f, 0, &tryagain); - - static int button_abort = 0; - if(ui2_do_button(&button_abort, "No", 0, &abort, ui2_draw_menu_button, 0) || inp_key_down(KEY_ESC)) - popup = POPUP_NONE; - - static int button_tryagain = 0; - if(ui2_do_button(&button_tryagain, "Yes", 0, &tryagain, ui2_draw_menu_button, 0) || inp_key_down(KEY_ENTER)) - client_quit(); - } - else if(popup == POPUP_PASSWORD) - { - RECT label, textbox, tryagain, abort; - - ui2_hsplit_b(&box, 20.f, &box, &part); - ui2_hsplit_b(&box, 24.f, &box, &part); - ui2_vmargin(&part, 120.0f, &part); - - ui2_vsplit_l(&part, 100.0f, &abort, &part); - ui2_vsplit_r(&part, 100.0f, 0, &tryagain); - - static int button_abort = 0; - if(ui2_do_button(&button_abort, "Abort", 0, &abort, ui2_draw_menu_button, 0) || inp_key_down(KEY_ESC)) - popup = POPUP_NONE; - - static int button_tryagain = 0; - if(ui2_do_button(&button_tryagain, "Try again", 0, &tryagain, ui2_draw_menu_button, 0) || inp_key_down(KEY_ENTER)) - { - client_connect(config.ui_server_address); - } - - ui2_hsplit_b(&box, 60.f, &box, &part); - ui2_hsplit_b(&box, 24.f, &box, &part); - - ui2_vsplit_l(&part, 60.0f, 0, &label); - ui2_vsplit_l(&label, 100.0f, 0, &textbox); - ui2_vsplit_l(&textbox, 20.0f, 0, &textbox); - ui2_vsplit_r(&textbox, 60.0f, &textbox, 0); - ui2_do_label(&label, "Password:", 20, -1); - ui2_do_edit_box(&config.password, &textbox, config.password, sizeof(config.password), true); - } - else - { - ui2_hsplit_b(&box, 20.f, &box, &part); - ui2_hsplit_b(&box, 24.f, &box, &part); - ui2_vmargin(&part, 120.0f, &part); - - static int button = 0; - if(ui2_do_button(&button, button_text, 0, &part, ui2_draw_menu_button, 0) || inp_key_down(KEY_ESC) || inp_key_down(KEY_ENTER)) - { - if(popup == POPUP_CONNECTING) - client_disconnect(); - popup = POPUP_NONE; - } - } - } - - return 0; -} - -void modmenu_render() -{ - static int mouse_x = 0; - static int mouse_y = 0; - - // update colors - - vec3 rgb = hsl_to_rgb(vec3(config.ui_color_hue/255.0f, config.ui_color_sat/255.0f, config.ui_color_lht/255.0f)); - gui_color = vec4(rgb.r, rgb.g, rgb.b, config.ui_color_alpha/255.0f); - - color_tabbar_inactive_outgame = vec4(0,0,0,0.25f); - color_tabbar_active_outgame = vec4(0,0,0,0.5f); - - color_ingame_scale_i = 0.5f; - color_ingame_scale_a = 0.2f; - color_tabbar_inactive_ingame = vec4( - gui_color.r*color_ingame_scale_i, - gui_color.g*color_ingame_scale_i, - gui_color.b*color_ingame_scale_i, - gui_color.a*0.8f); - - color_tabbar_active_ingame = vec4( - gui_color.r*color_ingame_scale_a, - gui_color.g*color_ingame_scale_a, - gui_color.b*color_ingame_scale_a, - gui_color.a); - - - // handle mouse movement - float mx, my; - { - 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 - RECT *screen = ui2_screen(); - mx = (mouse_x/(float)gfx_screenwidth())*screen->w; - my = (mouse_y/(float)gfx_screenheight())*screen->h; - - int buttons = 0; - if(inp_key_pressed(KEY_MOUSE_1)) buttons |= 1; - if(inp_key_pressed(KEY_MOUSE_2)) buttons |= 2; - if(inp_key_pressed(KEY_MOUSE_3)) buttons |= 4; - - ui_update(mx,my,mx*3.0f,my*3.0f,buttons); - } - - menu2_render(); - - gfx_texture_set(data->images[IMAGE_CURSOR].id); - gfx_quads_begin(); - gfx_setcolor(1,1,1,1); - gfx_quads_drawTL(mx,my,24,24); - gfx_quads_end(); - - inp_clear(); -} -- cgit 1.4.1