diff options
| author | Magnus Auvinen <magnus.auvinen@gmail.com> | 2007-10-28 11:30:25 +0000 |
|---|---|---|
| committer | Magnus Auvinen <magnus.auvinen@gmail.com> | 2007-10-28 11:30:25 +0000 |
| commit | a3ce2eb90cd26fe87042344175e5c9669adb7dcd (patch) | |
| tree | d936a8ffafe366caea08c5bb384794034c590322 | |
| parent | eba83b7e194cc6b4ba76fd5e048d81279becfc35 (diff) | |
| download | zcatch-a3ce2eb90cd26fe87042344175e5c9669adb7dcd.tar.gz zcatch-a3ce2eb90cd26fe87042344175e5c9669adb7dcd.zip | |
major update. splitted the player information into two diffrent network items
| -rw-r--r-- | src/engine/client/client.c | 8 | ||||
| -rw-r--r-- | src/engine/client/gfx.c | 7 | ||||
| -rw-r--r-- | src/engine/client/snd.c | 13 | ||||
| -rw-r--r-- | src/engine/config_variables.h | 2 | ||||
| -rw-r--r-- | src/engine/network.c | 16 | ||||
| -rw-r--r-- | src/engine/protocol.h | 2 | ||||
| -rw-r--r-- | src/engine/server/server.c | 15 | ||||
| -rw-r--r-- | src/engine/snapshot.c | 17 | ||||
| -rw-r--r-- | src/engine/system.c | 1 | ||||
| -rw-r--r-- | src/game/client/game_client.cpp | 716 | ||||
| -rw-r--r-- | src/game/game.cpp | 23 | ||||
| -rw-r--r-- | src/game/game_protocol.h | 64 | ||||
| -rw-r--r-- | src/game/server/game_server.cpp | 384 | ||||
| -rw-r--r-- | src/game/server/srv_ctf.cpp | 7 |
14 files changed, 698 insertions, 577 deletions
diff --git a/src/engine/client/client.c b/src/engine/client/client.c index f8ccf6e5..c6a9252f 100644 --- a/src/engine/client/client.c +++ b/src/engine/client/client.c @@ -1007,6 +1007,14 @@ static void client_run(const char *direct_connect_server) int editor_main(int argc, char **argv); /*client main_client; */ +/* +const char *user_directory() +{ + static char path[512] = {0}; + +}*/ + + int main(int argc, char **argv) { diff --git a/src/engine/client/gfx.c b/src/engine/client/gfx.c index 13c35a39..fe72f4c7 100644 --- a/src/engine/client/gfx.c +++ b/src/engine/client/gfx.c @@ -531,9 +531,14 @@ int gfx_load_texture_raw(int w, int h, int format, const void *data) unsigned char *texdata = (unsigned char *)data; unsigned char *tmpdata = 0; int oglformat = 0; + int tex = 0; + + /* don't waste memory on texture if we are stress testing */ + if(config.stress) + return -1; /* grab texture */ - int tex = first_free_texture; + tex = first_free_texture; first_free_texture = textures[tex].next; textures[tex].next = -1; diff --git a/src/engine/client/snd.c b/src/engine/client/snd.c index 79121584..725bc569 100644 --- a/src/engine/client/snd.c +++ b/src/engine/client/snd.c @@ -334,14 +334,23 @@ int snd_load_wv(const char *filename) int sid = -1; char error[100]; WavpackContext *context; + + /* don't waste memory on sound when we are stress testing */ + if(config.stress) + return -1; + + file = fopen(filename, "rb"); /* TODO: use system.h stuff for this */ + if(!file) + { + dbg_msg("sound/wv", "failed to open %s", filename); + return -1; + } sid = snd_alloc_id(); if(sid < 0) return -1; snd = &samples[sid]; - file = fopen(filename, "rb"); /* TODO: use system.h stuff for this */ - context = WavpackOpenFileInput(read_data, error); if (context) { diff --git a/src/engine/config_variables.h b/src/engine/config_variables.h index dfe638d0..4ef8958e 100644 --- a/src/engine/config_variables.h +++ b/src/engine/config_variables.h @@ -46,3 +46,5 @@ MACRO_CONFIG_STR(sv_map, 128, "dm1") MACRO_CONFIG_INT(sv_max_clients, 8, 1, 16) +MACRO_CONFIG_INT(sv_bandwidth_mode, 0, 0, 2) + diff --git a/src/engine/network.c b/src/engine/network.c index 05779831..1005bbf2 100644 --- a/src/engine/network.c +++ b/src/engine/network.c @@ -17,7 +17,8 @@ enum NETWORK_VERSION = 1, NETWORK_HEADER_SIZE = 6, - NETWORK_MAX_PACKET_SIZE = 1024, + NETWORK_MAX_PAYLOAD = 1024, + NETWORK_MAX_PACKET_SIZE = NETWORK_HEADER_SIZE+NETWORK_MAX_PAYLOAD, NETWORK_MAX_CLIENTS = 16, NETWORK_CONNSTATE_OFFLINE=0, @@ -738,6 +739,8 @@ int netserver_recv(NETSERVER *s, NETPACKET *packet) int netserver_send(NETSERVER *s, NETPACKET *packet) { + dbg_assert(packet->data_size < NETWORK_MAX_PAYLOAD, "packet payload too big"); + if(packet->flags&PACKETFLAG_CONNLESS) { /* send connectionless packet */ @@ -775,9 +778,12 @@ void netserver_stats(NETSERVER *s, NETSTATS *stats) for(c = 0; c < s->max_clients; c++) { - int *sstats = (int *)(&(s->slots[c].conn.stats)); - for(i = 0; i < num_stats; i++) - istats[i] += sstats[i]; + if(s->slots[c].conn.state != NETWORK_CONNSTATE_OFFLINE) + { + int *sstats = (int *)(&(s->slots[c].conn.stats)); + for(i = 0; i < num_stats; i++) + istats[i] += sstats[i]; + } } } @@ -869,6 +875,8 @@ int netclient_recv(NETCLIENT *c, NETPACKET *packet) int netclient_send(NETCLIENT *c, NETPACKET *packet) { + dbg_assert(packet->data_size < NETWORK_MAX_PAYLOAD, "packet payload too big"); + if(packet->flags&PACKETFLAG_CONNLESS) { /* send connectionless packet */ diff --git a/src/engine/protocol.h b/src/engine/protocol.h index b9aba258..96ad1e6b 100644 --- a/src/engine/protocol.h +++ b/src/engine/protocol.h @@ -30,5 +30,5 @@ enum MAX_NAME_LENGTH=32, MAX_CLANNAME_LENGTH=32, MAX_INPUT_SIZE=128, - MAX_SNAPSHOT_PACKSIZE=1200 + MAX_SNAPSHOT_PACKSIZE=900 }; diff --git a/src/engine/server/server.c b/src/engine/server/server.c index afbcc0dd..0262c65f 100644 --- a/src/engine/server/server.c +++ b/src/engine/server/server.c @@ -739,6 +739,10 @@ static int server_run() } /* snap game */ + if(config.sv_bandwidth_mode == 0 || + (config.sv_bandwidth_mode == 1 && current_tick%2) || + (config.sv_bandwidth_mode == 2 && (current_tick%3) == 0 )) + /* if(current_tick&1) */ { int64 start = time_get(); server_do_snap(); @@ -765,12 +769,21 @@ static int server_run() { if(config.debug) { - dbg_msg("server", "sim=%.02fms snap=%.02fms net=%.02fms total=%.02fms load=%.02f%%", + static NETSTATS prev_stats; + NETSTATS stats; + netserver_stats(net, &stats); + dbg_msg("server", "sim=%.02fms snap=%.02fms net=%.02fms tot=%.02fms load=%.02f%%", (simulationtime/reportinterval)/(double)time_freq()*1000, (snaptime/reportinterval)/(double)time_freq()*1000, (networktime/reportinterval)/(double)time_freq()*1000, (totaltime/reportinterval)/(double)time_freq()*1000, (totaltime)/reportinterval/(double)time_freq()*100.0f); + + dbg_msg("server", "send=%8d recv=%8d", + (stats.send_bytes - prev_stats.send_bytes)/reportinterval, + (stats.recv_bytes - prev_stats.recv_bytes)/reportinterval); + + prev_stats = stats; } simulationtime = 0; diff --git a/src/engine/snapshot.c b/src/engine/snapshot.c index 84f0416b..40bad21e 100644 --- a/src/engine/snapshot.c +++ b/src/engine/snapshot.c @@ -94,26 +94,11 @@ void snapshot_debug_dump(SNAPSHOT *snap) static int diff_item(int *past, int *current, int *out, int size) { - /* int needed = 0; while(size) { *out = *current-*past; - if(*out) - needed = 1; - out++; - current++; - past++; - size--; - }*/ - - int needed = 0; - while(size) - { - *out = *current-*past; - if(*out) - needed = 1; - + needed |= *out; out++; past++; current++; diff --git a/src/engine/system.c b/src/engine/system.c index 67e84b74..71f5b545 100644 --- a/src/engine/system.c +++ b/src/engine/system.c @@ -81,6 +81,7 @@ void dbg_msg(const char *sys, const char *fmt, ...) vprintf(fmt, args); va_end(args); printf("\n"); + fflush(stdout); } int memory_alloced = 0; diff --git a/src/game/client/game_client.cpp b/src/game/client/game_client.cpp index 55c98bc1..d31b1b3e 100644 --- a/src/game/client/game_client.cpp +++ b/src/game/client/game_client.cpp @@ -46,8 +46,10 @@ static bool menu_active = false; static bool emoticon_selector_active = false; static vec2 mouse_pos; -static vec2 local_player_pos; -static obj_player *local_player; +static vec2 local_character_pos; +static const obj_player_character *local_character = 0; +static const obj_player_info *local_info = 0; +static const obj_game *gameobj = 0; struct client_data { @@ -74,8 +76,8 @@ public: } float getorgzoom() { return zoom; } - - float getzoom(int tick, float intratick, obj_player* player) + + float getzoom(int tick, float intratick, const obj_player_character *player) { float currentstage = ((float)player->weaponstage) * 0.1f; if (currentstage < stage) @@ -102,16 +104,16 @@ 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 { @@ -133,7 +135,7 @@ static const float volume_music = 0.8f; void sound_vol_pan(const vec2& p, float *vol, float *pan) { - vec2 player_to_ev = p - local_player_pos; + vec2 player_to_ev = p - local_character_pos; *pan = 0.0f; *vol = 1.0f; @@ -170,11 +172,11 @@ static void select_sprite(sprite *spr, int flags=0, int sx=0, int sy=0) 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; - + if(flags&SPRITE_FLAG_FLIP_Y) gfx_quads_setsubset(x/(float)cx,(y+h)/(float)cy,(x+w)/(float)cx,y/(float)cy); else @@ -204,7 +206,7 @@ public: float life; float startangle; }; - + enum { MAX_ITEMS=64, @@ -215,10 +217,10 @@ public: lastupdate = 0; num_items = 0; } - + item items[MAX_ITEMS]; int num_items; - + item *create_i() { if (num_items < MAX_ITEMS) @@ -229,13 +231,13 @@ public: } return 0; } - + void destroy_i(item *i) { num_items--; *i = items[num_items]; } - + void create(vec2 pos, vec2 dir) { item *i = create_i(); @@ -247,7 +249,7 @@ public: i->startangle = (( (float)rand()/(float)RAND_MAX) - 1.0f) * 2.0f * pi; } } - + void render() { gfx_texture_set(data->images[IMAGE_GAME].id); @@ -255,7 +257,7 @@ public: 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]); @@ -270,7 +272,7 @@ public: } gfx_quads_end(); } - + }; static damage_indicators damageind; @@ -285,14 +287,14 @@ public: float life; float max_life; float size; - + float rot; float rotspeed; - + float gravity; float friction; int iparticle; - + vec4 color; }; @@ -300,15 +302,15 @@ public: { MAX_PARTICLES=1024, }; - + particle particles[MAX_PARTICLES]; int num_particles; - + particle_system() { num_particles = 0; } - + void new_particle(vec2 pos, vec2 vel, float life, float size, float gravity, float friction) { if (num_particles >= MAX_PARTICLES) @@ -326,7 +328,7 @@ public: particles[num_particles].rotspeed = frandom() * 10.0f; num_particles++; } - + void update(float time_passed) { for(int i = 0; i < num_particles; i++) @@ -338,7 +340,7 @@ public: 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) { @@ -348,31 +350,31 @@ public: } } } - + 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, data->particles[type].color_g, data->particles[type].color_b, pow(a, 0.75f)); - + gfx_quads_draw(p.x, p.y,particles[i].size,particles[i].size); } - gfx_quads_end(); + gfx_quads_end(); gfx_blend_normal(); } }; @@ -386,13 +388,13 @@ public: { LISTSIZE = 1000, }; - // meh, just use size % + // meh, just use size % int lastadd[LISTSIZE]; projectile_particles() { reset(); } - + void reset() { for (int i = 0; i < LISTSIZE; i++) @@ -403,24 +405,24 @@ public: { 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; @@ -489,7 +491,7 @@ static void render_loading(float percent) float y = 600/2-h/2; gfx_blend_normal(); - + gfx_texture_set(-1); gfx_quads_begin(); gfx_setcolor(0,0,0,0.50f); @@ -497,7 +499,7 @@ static void render_loading(float percent) 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); @@ -516,7 +518,7 @@ extern "C" void modc_init() snd_set_channel(CHN_GUI, 1.0f, 0.0f); snd_set_channel(CHN_MUSIC, 1.0f, 0.0f); snd_set_channel(CHN_WORLD, 1.0f, 1.0f); - + // load the data container data = load_data_from_memory(internal_data); @@ -541,10 +543,10 @@ extern "C" void modc_init() data->sounds[s].sounds[i].id = id; } - + current++; } - + // load textures for(int i = 0; i < data->num_images; i++) { @@ -560,9 +562,9 @@ extern "C" void modc_entergame() img_init(); tilemap_init(); chat_reset(); - + proj_particles.reset(); - + for(int i = 0; i < MAX_CLIENTS; i++) { client_datas[i].name[0] = 0; @@ -570,7 +572,7 @@ extern "C" void modc_entergame() client_datas[i].emoticon = 0; client_datas[i].emoticon_start = -1; } - + for(int i = 0; i < killmsg_max; i++) killmsgs[i].tick = -100000; } @@ -588,7 +590,7 @@ static void process_events(int s) { SNAP_ITEM item; const void *data = snap_get_item(s, index, &item); - + if(item.type == EVENT_DAMAGEINDICATION) { ev_damageind *ev = (ev_damageind *)data; @@ -598,19 +600,19 @@ static void process_events(int s) { 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); @@ -627,7 +629,7 @@ static void process_events(int s) { 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); @@ -635,13 +637,13 @@ static void process_events(int s) 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); @@ -652,7 +654,7 @@ static void process_events(int s) { 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); @@ -660,13 +662,13 @@ static void process_events(int s) 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); @@ -677,7 +679,7 @@ static void process_events(int s) { 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); @@ -685,13 +687,13 @@ static void process_events(int s) 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); @@ -707,7 +709,7 @@ static void process_events(int s) //bool bstoploop = (ev->sound & SOUND_LOOPFLAG_STOPLOOP) != 0; //float vol, pan; //sound_vol_pan(p, &vol, &pan); - + if(soundid >= 0 && soundid < NUM_SOUNDS) { // TODO: we need to control the volume of the diffrent sounds @@ -716,7 +718,7 @@ static void process_events(int s) } } } - + must_process_events = false; } @@ -729,25 +731,30 @@ extern "C" void modc_predict() { 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); - - if(item.type == OBJTYPE_PLAYER) + int client_id = item.id; + + if(item.type == OBJTYPE_PLAYER_CHARACTER) { - const obj_player *player = (const obj_player *)data; - client_datas[player->clientid].predicted.world = &world; - world.players[player->clientid] = &client_datas[player->clientid].predicted; - - client_datas[player->clientid].predicted.read(player); - if(player->local) - local_cid = player->clientid; + 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(); tick <= client_predtick(); tick++) { @@ -756,7 +763,7 @@ extern "C" void modc_predict() { if(!world.players[c]) continue; - + mem_zero(&world.players[c]->input, sizeof(world.players[c]->input)); if(local_cid == c) { @@ -765,23 +772,23 @@ extern "C" void modc_predict() 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(); } } - + // get the data from the local player - if(local_cid != -1) + if(local_cid != -1 && world.players[local_cid]) { predicted_prev_player = predicted_player; predicted_player = *world.players[local_cid]; @@ -794,7 +801,7 @@ extern "C" void modc_newsnapshot() if(must_process_events) process_events(SNAP_PREV); must_process_events = true; - + if(config.stress) { if((client_tick()%250) == 0) @@ -806,6 +813,47 @@ extern "C" void modc_newsnapshot() client_send_msg(); } } + + // clear out the invalid pointers + local_character = 0; + local_info = 0; + gameobj = 0; + + // 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_character_pos = mix(vec2(((obj_player_character *)p)->x, ((obj_player_character *)p)->y), + local_character_pos, client_intratick()); + } + } + } + } + else if(item.type == OBJTYPE_GAME) + gameobj = (obj_game *)data; + } + } } void send_changename_request(const char *name) @@ -828,22 +876,22 @@ static void render_projectile(const obj_projectile *prev, const obj_projectile * { gfx_texture_set(data->images[IMAGE_GAME].id); gfx_quads_begin(); - + select_sprite(data->weapons[current->type%data->num_weapons].sprite_proj); vec2 vel = mix(vec2(prev->vx, prev->vy), vec2(current->vx, current->vy), client_intratick()); 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(); @@ -872,7 +920,7 @@ static void render_powerup(const obj_powerup *prev, const obj_powerup *current) SPRITE_POWERUP_TIMEFIELD }; select_sprite(c[current->type]); - + if(c[current->type] == SPRITE_POWERUP_NINJA) { proj_particles.addparticle(0, 0, @@ -882,9 +930,9 @@ static void render_powerup(const obj_powerup *prev, const obj_powerup *current) 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; @@ -905,14 +953,14 @@ static void render_flag(const obj_flag *prev, const obj_flag *current) 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(current->local_carry) - pos = local_player_pos; - + 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); @@ -949,7 +997,7 @@ static void anim_seq_eval(sequence *seq, float time, keyframe *frame) blend = (time - frame1->time) / (frame2->time - frame1->time); break; } - } + } if (frame1 && frame2) { @@ -1045,10 +1093,10 @@ static void render_tee(animstate *anim, int skin, int emote, vec2 dir, vec2 pos) { vec2 direction = dir; vec2 position = pos; - + gfx_texture_set(data->images[IMAGE_CHAR_DEFAULT].id); gfx_quads_begin(); - + // draw foots for(int p = 0; p < 2; p++) { @@ -1056,7 +1104,7 @@ static void render_tee(animstate *anim, int skin, int emote, vec2 dir, vec2 pos) // second pass we draw the filling int outline = p==0 ? 1 : 0; int shift = skin; - + for(int f = 0; f < 2; f++) { float basesize = 10.0f; @@ -1066,7 +1114,7 @@ static void render_tee(animstate *anim, int skin, int emote, vec2 dir, vec2 pos) // draw body select_sprite(outline?SPRITE_TEE_BODY_OUTLINE:SPRITE_TEE_BODY, 0, 0, shift*4); gfx_quads_draw(position.x+anim->body.x, position.y+anim->body.y, 4*basesize, 4*basesize); - + // draw eyes if(p == 1) { @@ -1096,18 +1144,18 @@ static void render_tee(animstate *anim, int skin, int emote, vec2 dir, vec2 pos) // draw feet select_sprite(outline?SPRITE_TEE_FOOT_OUTLINE:SPRITE_TEE_FOOT, 0, 0, shift*4); - + keyframe *foot = f ? &anim->front_foot : &anim->back_foot; - + float w = basesize*2.5f; float h = basesize*1.425f; - + gfx_quads_setrotation(foot->angle*pi*2); gfx_quads_draw(position.x+foot->x, position.y+foot->y, w, h); } } - - gfx_quads_end(); + + gfx_quads_end(); } void draw_circle(float x, float y, float r, int segments) @@ -1124,7 +1172,7 @@ void draw_circle(float x, float y, float r, int segments) float sa1 = sinf(a1); float sa2 = sinf(a2); float sa3 = sinf(a3); - + gfx_quads_draw_freeform( x, y, x+ca1*r, y+sa1*r, @@ -1147,7 +1195,7 @@ void draw_round_rect(float x, float y, float w, float h, float r) float sa1 = sinf(a1); float sa2 = sinf(a2); float sa3 = sinf(a3); - + gfx_quads_draw_freeform( x+r, y+r, x+(1-ca1)*r, y+(1-sa1)*r, @@ -1172,7 +1220,7 @@ void draw_round_rect(float x, float y, float w, float h, float 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 @@ -1180,41 +1228,48 @@ void draw_round_rect(float x, float y, float w, float h, float r) gfx_quads_drawTL(x+w-r, y+r, r, h-r*2); // right } -static void render_player(const obj_player *prev_obj, const obj_player *player_obj) +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 prev; - obj_player player; - prev = *prev_obj; - player = *player_obj; - + 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(player.local) + + if(info.local) { // apply predicted results predicted_player.write(&player); predicted_prev_player.write(&prev); intratick = client_intrapredtick(); } - - int skin = charids[player.clientid]; - + + int skin = charids[info.clientid]; + if(gametype != GAMETYPE_DM) - skin = player.team*9; // 0 or 9 + skin = 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; @@ -1237,7 +1292,7 @@ static void render_player(const obj_player *prev_obj, const obj_player *player_o 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) { @@ -1247,16 +1302,16 @@ static void render_player(const obj_player *prev_obj, const obj_player *player_o 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) @@ -1305,7 +1360,7 @@ static void render_player(const obj_player *prev_obj, const obj_player *player_o { p = position; p.y += data->weapons[iw].offsety; - + if(direction.x < 0) { gfx_quads_setrotation(-pi/2-state.attach.angle*pi*2); @@ -1351,7 +1406,7 @@ static void render_player(const obj_player *prev_obj, const obj_player *player_o 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 @@ -1392,16 +1447,16 @@ static void render_player(const obj_player *prev_obj, const obj_player *player_o case WEAPON_SHOTGUN: render_hand(skin, p, direction, -pi/2, vec2(-5, 4)); break; case WEAPON_ROCKET: render_hand(skin, p, direction, -pi/2, vec2(-4, 7)); break; } - + } // render the tee - if(player.local && config.debug) + if(info.local && config.debug) { - vec2 ghost_position = mix(vec2(prev_obj->x, prev_obj->y), vec2(player_obj->x, player_obj->y), client_intratick()); + vec2 ghost_position = mix(vec2(prev_char->x, prev_char->y), vec2(player_char->x, player_char->y), client_intratick()); render_tee(&state, 15, player.emote, direction, ghost_position); // render ghost } - + render_tee(&state, skin, player.emote, direction, position); if(player.state == STATE_CHATTING) @@ -1413,13 +1468,13 @@ static void render_player(const obj_player *prev_obj, const obj_player *player_o gfx_quads_end(); } - if (client_datas[player.clientid].emoticon_start != -1 && client_datas[player.clientid].emoticon_start + 2 * client_tickspeed() > client_tick()) + 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[player.clientid].emoticon_start; - int from_end = client_datas[player.clientid].emoticon_start + 2 * client_tickspeed() - client_tick(); + 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; @@ -1440,7 +1495,7 @@ static void render_player(const obj_player *prev_obj, const obj_player *player_o 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[player.clientid].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(); } @@ -1461,7 +1516,7 @@ void render_sun(float x, float y) 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); @@ -1475,11 +1530,11 @@ void render_sun(float x, float y) } 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(); + gfx_quads_end(); } static bool emoticon_selector_inactive_override = false; @@ -1507,7 +1562,7 @@ int emoticon_selector_render() static bool mouse_down = false; bool return_now = false; - int selected_emoticon; + int selected_emoticon; if (length(emoticon_selector_mouse) < 50) selected_emoticon = -1; @@ -1533,7 +1588,7 @@ int emoticon_selector_render() gfx_mapscreen(0,0,400,300); gfx_blend_normal(); - + gfx_texture_set(-1); gfx_quads_begin(); gfx_setcolor(0,0,0,0.3f); @@ -1570,7 +1625,7 @@ int emoticon_selector_render() return return_now ? selected_emoticon : -1; } -void render_goals(obj_game *gameobj, float x, float y, float w) +void render_goals(float x, float y, float w) { float h = 50.0f; @@ -1580,7 +1635,7 @@ void render_goals(obj_game *gameobj, float x, float y, float w) 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) @@ -1598,7 +1653,7 @@ void render_goals(obj_game *gameobj, float x, float y, float w) } -void render_scoreboard(obj_game *gameobj, float x, float y, float w, int team, const char *title) +void render_scoreboard(float x, float y, float w, int team, const char *title) { //float w = 550.0f; //float x = width/2-w/2; @@ -1608,8 +1663,8 @@ void render_scoreboard(obj_game *gameobj, float x, float y, float w, int team, c animstate idlestate; anim_eval(&data->animations[ANIM_BASE], 0, &idlestate); - anim_eval_add(&idlestate, &data->animations[ANIM_IDLE], 0, 1.0f); - + anim_eval_add(&idlestate, &data->animations[ANIM_IDLE], 0, 1.0f); + //float ystart = y; float h = 600.0f; @@ -1619,7 +1674,7 @@ void render_scoreboard(obj_game *gameobj, float x, float y, float w, int team, c 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) { @@ -1638,15 +1693,15 @@ void render_scoreboard(obj_game *gameobj, float x, float y, float w, int team, c else { gfx_pretty_text(x+10, y, 64, title, -1); - + 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) { @@ -1657,20 +1712,20 @@ void render_scoreboard(obj_game *gameobj, float x, float y, float w, int team, c // find players - const obj_player *players[MAX_CLIENTS] = {0}; + 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) + + if(item.type == OBJTYPE_PLAYER_INFO) { - players[num_players] = (const obj_player *)data; + players[num_players] = (const obj_player_info *)data; num_players++; } } - + // sort players for(int k = 0; k < num_players; k++) // ffs, bubblesort { @@ -1678,7 +1733,7 @@ void render_scoreboard(obj_game *gameobj, float x, float y, float w, int team, c { if(players[i]->score < players[i+1]->score) { - const obj_player *tmp = players[i]; + const obj_player_info *tmp = players[i]; players[i] = players[i+1]; players[i+1] = tmp; } @@ -1694,15 +1749,15 @@ void render_scoreboard(obj_game *gameobj, float x, float y, float w, int team, c // render player scores for(int i = 0; i < num_players; i++) { - const obj_player *player = players[i]; - + const obj_player_info *info = players[i]; + // make sure that we render the correct team - if(team != -1 && player->team != team) + if(team != -1 && info->team != team) continue; - + char buf[128]; float font_size = 46.0f; - if(player->local) + if(info->local) { // background so it's easy to find the local player gfx_texture_set(-1); @@ -1711,17 +1766,17 @@ void render_scoreboard(obj_game *gameobj, float x, float y, float w, int team, c draw_round_rect(x, y, w-20, 48, 20.0f); gfx_quads_end(); } - - sprintf(buf, "%4d", player->score); + + 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[player->clientid].name, -1); - - sprintf(buf, "%4d", player->latency); + 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, player->clientid, EMOTE_NORMAL, vec2(1,0), vec2(x+90, y+28)); + render_tee(&idlestate, info->clientid, EMOTE_NORMAL, vec2(1,0), vec2(x+90, y+28)); y += 50.0f; } } @@ -1737,23 +1792,19 @@ void mapscreen_to_world(float center_x, float center_y, float zoom) // renders the complete game world void render_world(float center_x, float center_y, float zoom) { - const float default_zoom = 3.0f; - float width = 400*default_zoom*zoom; - float height = 300*default_zoom*zoom; - - gfx_mapscreen(center_x-width/2, center_y-height/2, center_x+width/2, center_y+height/2); - - // draw background + 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); // draw the sun if(config.gfx_high_detail) { 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++) @@ -1765,7 +1816,7 @@ void render_world(float center_x, float center_y, float zoom) } gfx_quads_end(); - + // draw backdrop gfx_texture_set(data->images[IMAGE_BACKDROP].id); gfx_quads_begin(); @@ -1774,10 +1825,10 @@ void render_world(float center_x, float center_y, float zoom) 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); @@ -1785,7 +1836,7 @@ void render_world(float center_x, float center_y, float zoom) { 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); @@ -1807,24 +1858,31 @@ void render_world(float center_x, float center_y, float zoom) } } - // render players above all + // 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) + + if(item.type == OBJTYPE_PLAYER_CHARACTER) { const void *prev = snap_find_item(SNAP_PREV, item.type, item.id); - if(prev) + 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 *)data)->clientid].team = ((const obj_player *)data)->team; - render_player((const obj_player *)prev, (const obj_player *)data); + client_datas[((const obj_player_info *)data)->clientid].team = ((const obj_player_info *)data)->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 @@ -1833,9 +1891,9 @@ void render_world(float center_x, float center_y, float zoom) // render foreground tilemaps tilemap_render(32.0f, 1); - + // render damage indications - damageind.render(); + damageind.render(); } static void do_input(int *v, int key) @@ -1847,51 +1905,22 @@ static void do_input(int *v, int key) } void render_game() -{ +{ float width = 400*3.0f; float height = 300*3.0f; - + bool spectate = false; - - // setup world view - obj_game *gameobj = 0; - { - // 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) - { - obj_player *player = (obj_player *)data; - if(player->local) - { - local_player = player; - local_player_pos = vec2(player->x, player->y); - - const void *p = snap_find_item(SNAP_PREV, item.type, item.id); - if(p) - local_player_pos = mix(vec2(((obj_player *)p)->x, ((obj_player *)p)->y), local_player_pos, client_intratick()); - } - } - else if(item.type == OBJTYPE_GAME) - gameobj = (obj_game *)data; - } - } - - local_player_pos = mix(predicted_prev_player.pos, predicted_player.pos, client_intrapredtick()); - if(local_player && local_player->team == -1) + + local_character_pos = mix(predicted_prev_player.pos, predicted_player.pos, client_intrapredtick()); + if(local_info && local_info->team == -1) spectate = true; // set listner pos - snd_set_listener_pos(local_player_pos.x, local_player_pos.y); - + snd_set_listener_pos(local_character_pos.x, local_character_pos.y); + animstate idlestate; anim_eval(&data->animations[ANIM_BASE], 0, &idlestate); - anim_eval_add(&idlestate, &data->animations[ANIM_IDLE], 0, 1.0f); + anim_eval_add(&idlestate, &data->animations[ANIM_IDLE], 0, 1.0f); if (inp_key_down(KEY_ESC)) { @@ -1900,7 +1929,7 @@ void render_game() else menu_active = !menu_active; } - + // handle chat input if (!menu_active) { @@ -1932,13 +1961,13 @@ void render_game() } } } - + 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) @@ -1957,7 +1986,7 @@ void render_game() chat_input_len--; } } - + } else { @@ -1968,7 +1997,7 @@ void render_game() if(inp_key_down(config.key_teamchat)) chat_mode = CHATMODE_TEAM; - + if(chat_mode != CHATMODE_NONE) { mem_zero(chat_input, sizeof(chat_input)); @@ -1977,10 +2006,10 @@ void render_game() } } } - + if (!menu_active) inp_clear(); - + // fetch new input if(!menu_active && (!emoticon_selector_active || emoticon_selector_inactive_override)) { @@ -1994,14 +2023,14 @@ void render_game() mouse_pos = normalize(mouse_pos)*600.0f; } } - + // 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) @@ -2013,14 +2042,14 @@ void render_game() 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 @@ -2033,31 +2062,26 @@ void render_game() if(inp_key_presses(config.key_weapon6)) input.wanted_weapon = 6; } } - + // stress testing if(config.stress) { - //float t = client_localtime(); + float t = client_localtime(); mem_zero(&input, sizeof(input)); - - /* - input.left = 1; - input.jump = ((int)t)&1; - input.fire = ((int)(t*10))&1; - input.hook = ((int)t)&1; - input.activeweapon = ((int)t)%NUM_WEAPONS; + + 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); - */ - - //input.target_x = (int)((rand()/(float)RAND_MAX)*64-32); - //input.target_y = (int)((rand()/(float)RAND_MAX)*64-32); - } snap_input(&input, sizeof(input)); } - + // everything updated, do events if(must_process_events) process_events(SNAP_PREV); @@ -2074,18 +2098,40 @@ void render_game() 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_player_pos.x+offx, local_player_pos.y+offy, 1.0f); + { + 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 = cl_effects.getzoom(client_tick(), client_intratick(), local_player);//orgzoom + ((float)local_player->weaponstage) * 0.1f; + float zoom = 3.0; + if(local_character) + cl_effects.getzoom(client_tick(), client_intratick(), local_character); + // DEBUG TESTING if(inp_key_pressed('M') || zoom > 3.01f) { @@ -2093,12 +2139,12 @@ void render_game() 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; @@ -2106,8 +2152,8 @@ void render_game() 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); @@ -2115,19 +2161,19 @@ void render_game() vec2 cd0 = get_dir(a-(fov*fade)/2.0f); // center direction vec2 cd1 = get_dir(a+(fov*fade)/2.0f); - - vec2 p0n = local_player_pos + d0*32.0f; - vec2 p1n = local_player_pos + d1*32.0f; - vec2 p0f = local_player_pos + d0*1000.0f; - vec2 p1f = local_player_pos + d1*1000.0f; - vec2 cn = local_player_pos + d*32.0f; - vec2 cf = local_player_pos + d*1000.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 cp0n = local_player_pos + cd0*32.0f; - vec2 cp0f = local_player_pos + cd0*1000.0f; - vec2 cp1n = local_player_pos + cd1*32.0f; - vec2 cp1f = local_player_pos + cd1*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, @@ -2135,14 +2181,14 @@ void render_game() p0f.x,p0f.y, p1f.x,p1f.y); gfx_quads_end(); - + gfx_mask_op(MASK_SET, 0); - - render_world(local_player_pos.x+offx, local_player_pos.y+offy, 2.0f); - + + render_world(local_character_pos.x+offx, local_character_pos.y+offy, 2.0f); + gfx_mask_op(MASK_NONE, 0); - - mapscreen_to_world(local_player_pos.x+offx, local_player_pos.y+offy, 1.0f); + + mapscreen_to_world(local_character_pos.x+offx, local_character_pos.y+offy, 1.0f); gfx_texture_set(-1); gfx_blend_normal(); @@ -2150,7 +2196,7 @@ void render_game() 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, @@ -2173,28 +2219,24 @@ void render_game() p1n.x,p1n.y, cp1f.x,cp1f.y, p1f.x,p1f.y); - + gfx_quads_end(); - - + + //gfx_mapscreen(0,0,400*3,300*3); } - - if(local_player && !spectate) + + if(local_character && !spectate) { gfx_texture_set(data->images[IMAGE_GAME].id); gfx_quads_begin(); - + // render cursor if (!menu_active && (!emoticon_selector_active || emoticon_selector_inactive_override)) { - //float width = 400 * cl_effects.getorgzoom(); - //float height = 300 * cl_effects.getorgzoom(); - //gfx_mapscreen(screen_x-width/2, screen_y-height/2, screen_x+width/2, screen_y+height/2); - - select_sprite(data->weapons[local_player->weapon%data->num_weapons].sprite_cursor); + select_sprite(data->weapons[local_character->weapon%data->num_weapons].sprite_cursor); float cursorsize = 64; - draw_sprite(local_player_pos.x+mouse_pos.x, local_player_pos.y+mouse_pos.y, cursorsize); + draw_sprite(local_character_pos.x+mouse_pos.x, local_character_pos.y+mouse_pos.y, cursorsize); } // render ammo count @@ -2204,10 +2246,10 @@ void render_game() 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_player->weaponstage; i++) - gfx_quads_drawTL(local_player->ammocount * 12 -i*12, 32, 11, 11); - select_sprite(data->weapons[local_player->weapon%data->num_weapons].sprite_proj); - for (int i = 0; i < local_player->ammocount; i++) + for (int i = 0; i < local_character->weaponstage; i++) + gfx_quads_drawTL(local_character->ammocount * 12 -i*12, 32, 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(10+i*12,34,10,10); gfx_quads_end(); @@ -2215,12 +2257,12 @@ void render_game() gfx_texture_set(data->images[IMAGE_GAME].id); gfx_quads_begin(); int h = 0; - + // render health select_sprite(SPRITE_HEALTH_FULL); - for(; h < local_player->health; h++) + for(; h < local_character->health; h++) gfx_quads_drawTL(10+h*12,10,10,10); - + select_sprite(SPRITE_HEALTH_EMPTY); for(; h < 10; h++) gfx_quads_drawTL(10+h*12,10,10,10); @@ -2228,38 +2270,38 @@ void render_game() // render armor meter h = 0; select_sprite(SPRITE_ARMOR_FULL); - for(; h < local_player->armor; h++) + for(; h < local_character->armor; h++) gfx_quads_drawTL(10+h*12,22,10,10); - + select_sprite(SPRITE_ARMOR_EMPTY); for(; h < 10; h++) gfx_quads_drawTL(10+h*12,22,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 = 10.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; int skin = gametype == GAMETYPE_TDM ? skinseed + client_datas[killmsgs[r].victim].team : killmsgs[r].victim; @@ -2283,15 +2325,15 @@ void render_game() skin = gametype == GAMETYPE_TDM ? skinseed + client_datas[killmsgs[r].killer].team : killmsgs[r].killer; render_tee(&idlestate, skin, 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); @@ -2311,9 +2353,9 @@ void render_game() gfx_pretty_text(x, y, 10.0f, buf, 380); starty = y; } - + y -= 10; - + int i; for(i = 0; i < chat_max_lines; i++) { @@ -2322,20 +2364,20 @@ void render_game() 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) { @@ -2348,13 +2390,13 @@ void render_game() 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); @@ -2366,7 +2408,7 @@ void render_game() float w = gfx_pretty_text_width(16, text, -1); gfx_pretty_text(200-w/2, 2, 16, text, -1); } - + if(gametype == GAMETYPE_TDM || gametype == GAMETYPE_CTF) { for(int t = 0; t < 2; t++) @@ -2380,21 +2422,21 @@ void render_game() gfx_setcolor(0,0,1,0.5f); draw_round_rect(320+t*35, 300-15, 30, 50, 5.0f); gfx_quads_end(); - + char buf[32]; sprintf(buf, "%d", gameobj->teamscore[t]); float w = gfx_pretty_text_width(14, buf, -1); gfx_pretty_text(320+t*35+30/2-w/2, 300-15, 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); @@ -2409,7 +2451,7 @@ void render_game() { if (modmenu_render(true)) menu_active = false; - + //ingamemenu_render(); return; } @@ -2434,29 +2476,29 @@ void render_game() if (emoticon != -1) send_emoticon(emoticon); } - + // render score board if(inp_key_pressed(KEY_TAB) || // user requested - (!spectate && (local_player && local_player->health == -1)) || // not spectating and is dead + (!spectate && (local_character && local_character->health == -1)) || // 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(gameobj, width/2-w/2, 150.0f, w, -1, 0); + render_scoreboard(width/2-w/2, 150.0f, w, -1, 0); //render_scoreboard(gameobj, 0, 0, -1, 0); } else { - render_scoreboard(gameobj, width/2-w-20, 150.0f, w, 0, "Red Team"); - render_scoreboard(gameobj, width/2 + 20, 150.0f, w, 1, "Blue Team"); + 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(gameobj, width/2-w/2, 150+600+25, w); + + render_goals(width/2-w/2, 150+600+25, w); } } @@ -2471,9 +2513,9 @@ extern "C" void modc_render() snd_stop(music_menu_id); music_menu_id = -1; } - + render_game(); - + // handle team switching if(config.team != -10) { @@ -2489,12 +2531,12 @@ extern "C" void modc_render() { music_menu_id = snd_play(CHN_MUSIC, music_menu, SNDFLAG_LOOP); } - + //netaddr4 server_address; if(modmenu_render(false) == -1) client_quit(); } - + // config.team = -10; } diff --git a/src/game/game.cpp b/src/game/game.cpp index c8c6acb3..136137e8 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -101,6 +101,10 @@ void player_core::tick() { float phys_size = 28.0f; + #define MACRO_CHECK_VELOCITY { dbg_assert(length(vel) < 1000.0f, "velocity error"); } + + MACRO_CHECK_VELOCITY + bool grounded = false; if(col_check_point((int)(pos.x+phys_size/2), (int)(pos.y+phys_size/2+5))) grounded = true; @@ -111,6 +115,8 @@ void player_core::tick() vel.y += gravity; + MACRO_CHECK_VELOCITY + float max_speed = grounded ? ground_control_speed : air_control_speed; float accel = grounded ? ground_control_accel : air_control_accel; float friction = grounded ? ground_friction : air_friction; @@ -121,9 +127,13 @@ void player_core::tick() if(input.right) vel.x = saturated_add(-max_speed, max_speed, vel.x, accel); + MACRO_CHECK_VELOCITY + if(!input.left && !input.right) vel.x *= friction; + MACRO_CHECK_VELOCITY + // handle jumping if(input.jump) { @@ -136,7 +146,9 @@ void player_core::tick() } else jumped = 0; - + + MACRO_CHECK_VELOCITY + // do hook if(input.hook) { @@ -247,9 +259,12 @@ void player_core::tick() // check if we are under the legal limit for the hook if(length(new_vel) < hook_drag_speed || length(new_vel) < length(vel)) vel = new_vel; // no problem. apply + } } + MACRO_CHECK_VELOCITY + if(true) { for(int i = 0; i < MAX_CLIENTS; i++) @@ -265,12 +280,14 @@ void player_core::tick() // handle player <-> player collision float d = distance(pos, p->pos); vec2 dir = normalize(pos - p->pos); - if(d < phys_size*1.25f) + if(d < phys_size*1.25f && d > 1.0f) { float a = phys_size*1.25f - d; vel = vel + dir*a; } + MACRO_CHECK_VELOCITY + // handle hook influence if(hooked_player == i) { @@ -279,6 +296,8 @@ void player_core::tick() float accel = hook_drag_accel * (d/hook_length); vel.x = saturated_add(-hook_drag_speed, hook_drag_speed, vel.x, -accel*dir.x); vel.y = saturated_add(-hook_drag_speed, hook_drag_speed, vel.y, -accel*dir.y); + + MACRO_CHECK_VELOCITY } } } diff --git a/src/game/game_protocol.h b/src/game/game_protocol.h index c6fb28c7..6be89e35 100644 --- a/src/game/game_protocol.h +++ b/src/game/game_protocol.h @@ -22,7 +22,8 @@ enum { OBJTYPE_NULL=0, OBJTYPE_GAME, - OBJTYPE_PLAYER, + OBJTYPE_PLAYER_INFO, + OBJTYPE_PLAYER_CHARACTER, // use this if you are searching for the player entity OBJTYPE_PROJECTILE, OBJTYPE_POWERUP, OBJTYPE_FLAG, @@ -69,7 +70,7 @@ enum STATE_PLAYING, STATE_IN_MENU, STATE_CHATTING, - + //GAMETYPE_DM=0, //GAMETYPE_TDM, //GAMETYPE_CTF, @@ -79,46 +80,45 @@ struct player_input { int left; int right; - + int target_x; int target_y; - + int jump; int fire; int hook; int blink; int state; - + int wanted_weapon; int next_weapon; int prev_weapon; }; - -struct ev_explosion +struct ev_common { int x, y; }; -struct ev_spawn +struct ev_explosion : public ev_common { - int x, y; }; -struct ev_death +struct ev_spawn : public ev_common { - int x, y; }; -struct ev_sound +struct ev_death : public ev_common { - int x, y; - int sound; // if (0x80000000 flag is set -> looping) if (0x40000000 is set -> stop looping }; -struct ev_damageind +struct ev_sound : public ev_common +{ + int sound; +}; + +struct ev_damageind : public ev_common { - int x, y; int angle; }; @@ -128,13 +128,13 @@ struct obj_game int game_over; int sudden_death; int paused; - + int score_limit; int time_limit; int gametype; - + int warmup; - + int teamscore[2]; }; @@ -156,10 +156,10 @@ struct obj_flag { int x, y; int team; - int local_carry; + int local_carry; // is set if the local player has the flag }; - +// core object needed for physics struct obj_player_core { int x, y; @@ -172,25 +172,31 @@ struct obj_player_core int hook_dx, hook_dy; }; -struct obj_player : public obj_player_core +// info about the player that is only needed when it's on screen +struct obj_player_character : public obj_player_core { - int local; - int clientid; int state; int health; int armor; int ammocount; int weaponstage; - + int weapon; // current active weapon + int emote; + int attacktick; // num attack ticks left of current attack - +}; + +// information about the player that is always needed +struct obj_player_info +{ + int local; + int clientid; + + int team; int score; int latency; int latency_flux; - int emote; - - int team; }; diff --git a/src/game/server/game_server.cpp b/src/game/server/game_server.cpp index 13ea42de..57b3b18f 100644 --- a/src/game/server/game_server.cpp +++ b/src/game/server/game_server.cpp @@ -60,8 +60,12 @@ void event_handler::snap(int snapping_client) { if (targets[i] == -1 || targets[i] == snapping_client) { - void *d = snap_new_item(types[i], i, sizes[i]); - mem_copy(d, &data[offsets[i]], sizes[i]); + ev_common *ev = (ev_common *)&data[offsets[i]]; + if(distance(players[snapping_client].pos, vec2(ev->x, ev->y)) < 1500.0f) + { + void *d = snap_new_item(types[i], i, sizes[i]); + mem_copy(d, &data[offsets[i]], sizes[i]); + } } } } @@ -77,9 +81,9 @@ entity::entity(int objtype) pos = vec2(0,0); flags = FLAG_PHYSICS; proximity_radius = 0; - + id = snap_new_id(); - + next_entity = 0; prev_entity = 0; prev_type_entity = 0; @@ -110,7 +114,7 @@ int game_world::find_entities(vec2 pos, float radius, entity **ents, int max) { if(!(ent->flags&entity::FLAG_PHYSICS)) continue; - + if(distance(ent->pos, pos) < radius+ent->proximity_radius) { ents[num] = ent; @@ -119,7 +123,7 @@ int game_world::find_entities(vec2 pos, float radius, entity **ents, int max) break; } } - + return num; } @@ -132,7 +136,7 @@ int game_world::find_entities(vec2 pos, float radius, entity **ents, int max, co { if(!(ent->flags&entity::FLAG_PHYSICS)) continue; - + if(distance(ent->pos, pos) < radius+ent->proximity_radius) { ents[num] = ent; @@ -142,7 +146,7 @@ int game_world::find_entities(vec2 pos, float radius, entity **ents, int max, co } } } - + return num; } @@ -154,7 +158,7 @@ void game_world::insert_entity(entity *ent) dbg_assert(cur != ent, "err"); cur = cur->next_entity; } - + // insert it if(first_entity) first_entity->prev_entity = ent; @@ -180,7 +184,7 @@ void game_world::remove_entity(entity *ent) // not in the list if(!ent->next_entity && !ent->prev_entity && first_entity != ent) return; - + // remove if(ent->prev_entity) ent->prev_entity->next_entity = ent->next_entity; @@ -195,7 +199,7 @@ void game_world::remove_entity(entity *ent) first_entity_types[ent->objtype] = ent->next_type_entity; if(ent->next_type_entity) ent->next_type_entity->prev_type_entity = ent->prev_type_entity; - + ent->next_entity = 0; ent->prev_entity = 0; ent->next_type_entity = 0; @@ -215,11 +219,11 @@ void game_world::reset() for(entity *ent = first_entity; ent; ent = ent->next_entity) ent->reset(); remove_entities(); - + for(entity *ent = first_entity; ent; ent = ent->next_entity) ent->post_reset(); remove_entities(); - + reset_requested = false; } @@ -243,17 +247,17 @@ void game_world::tick() { if(reset_requested) reset(); - + if(!paused) { // update all objects for(entity *ent = first_entity; ent; ent = ent->next_entity) ent->tick(); - + for(entity *ent = first_entity; ent; ent = ent->next_entity) ent->tick_defered(); } - + remove_entities(); } @@ -287,7 +291,7 @@ void projectile::reset() void projectile::tick() { vec2 oldpos = pos; - + int collide = 0; if(bounce) { @@ -302,31 +306,34 @@ void projectile::tick() pos += vel; collide = col_check_point((int)pos.x, (int)pos.y); } - + lifespan--; - + // check player intersection as well vec2 new_pos; entity *targetplayer = (entity*)intersect_player(oldpos, pos, new_pos, powner); - + if(targetplayer || lifespan < 0 || collide || bounce < 0) { if (lifespan >= 0 || weapon == WEAPON_ROCKET) create_sound(pos, sound_impact); - + if (flags & PROJECTILE_FLAGS_EXPLODE) create_explosion(oldpos, owner, weapon, false); else if (targetplayer) { targetplayer->take_damage(normalize(vel) * max(0.001f, force), damage, owner, weapon); } - + world->destroy_entity(this); } } void projectile::snap(int snapping_client) { + if(distance(players[snapping_client].pos, pos) > 1000.0f) + return; + obj_projectile *proj = (obj_projectile *)snap_new_item(OBJTYPE_PROJECTILE, id, sizeof(obj_projectile)); proj->x = (int)pos.x; proj->y = (int)pos.y; @@ -340,7 +347,7 @@ void projectile::snap(int snapping_client) ////////////////////////////////////////////////// // TODO: move to separate file player::player() -: entity(OBJTYPE_PLAYER) +: entity(OBJTYPE_PLAYER_CHARACTER) { init(); } @@ -364,7 +371,7 @@ void player::init() latency_avg = 0; latency_min = 0; latency_max = 0; - + reset(); } @@ -375,16 +382,17 @@ void player::reset() //direction = vec2(0.0f, 1.0f); score = 0; dead = true; + clear_flag(entity::FLAG_PHYSICS); spawning = false; die_tick = 0; damage_taken = 0; state = STATE_UNKNOWN; - + mem_zero(&input, sizeof(input)); mem_zero(&previnput, sizeof(previnput)); - + last_action = -1; - + emote_stop = 0; damage_taken_tick = 0; attack_tick = 0; @@ -398,7 +406,7 @@ void player::set_weapon(int w) active_weapon = w; } - + void player::respawn() { spawning = true; @@ -410,9 +418,9 @@ void player::set_team(int new_team) team = new_team; die(client_id, -1); score--; - + dbg_msg("game", "cid=%d team=%d", client_id, team); - + if(team == -1) clear_flag(FLAG_PHYSICS); else @@ -420,24 +428,26 @@ void player::set_team(int new_team) } -bool try_spawntype(int t, vec2 *pos) +bool try_spawntype(int t, vec2 *outpos) { // get spawn point int start, num; map_get_type(t, &start, &num); if(!num) return false; - - mapres_spawnpoint *sp = (mapres_spawnpoint*)map_get_item(start + (rand()%num), NULL, NULL); - *pos = vec2((float)sp->x, (float)sp->y); + + int id = rand()%num; + dbg_msg("spawn", "%d trying to spawn at %d", server_tick(), id); + + mapres_spawnpoint *sp = (mapres_spawnpoint*)map_get_item(start + id, NULL, NULL); + *outpos = vec2((float)sp->x, (float)sp->y); return true; } - void player::try_respawn() { vec2 spawnpos = vec2(100.0f, -60.0f); - + // get spawn point if(gameobj->gametype == GAMETYPE_CTF) { @@ -453,23 +463,28 @@ void player::try_respawn() if(!try_spawntype(MAPRES_SPAWNPOINT, &spawnpos)) try_spawntype(MAPRES_SPAWNPOINT_RED+(rand()&1), &spawnpos); } - + // check if the position is occupado entity *ents[2] = {0}; - int types[] = {OBJTYPE_PLAYER}; + int types[] = {OBJTYPE_PLAYER_CHARACTER}; int num_ents = world->find_entities(spawnpos, 64, ents, 2, types, 1); for(int i = 0; i < num_ents; i++) { if(ents[i] != this) + { + dbg_msg("spawn", "%d failed", server_tick()); return; + } } - + + dbg_msg("spawn", "%d spawned", server_tick()); spawning = false; pos = spawnpos; - + core.pos = pos; + core.vel = vec2(0,0); core.hooked_player = -1; - + health = 10; armor = 0; @@ -477,12 +492,11 @@ void player::try_respawn() dead = false; set_flag(entity::FLAG_PHYSICS); state = STATE_PLAYING; - + core.hook_state = HOOK_IDLE; - + mem_zero(&input, sizeof(input)); - core.vel = vec2(0.0f, 0.0f); - + // init weapons mem_zero(&weapons, sizeof(weapons)); weapons[WEAPON_HAMMER].got = true; @@ -490,17 +504,19 @@ void player::try_respawn() weapons[WEAPON_GUN].got = true; weapons[WEAPON_GUN].ammo = data->weapons[WEAPON_GUN].maxammo; + weapons[WEAPON_SNIPER].got = true; + weapons[WEAPON_SNIPER].ammo = data->weapons[WEAPON_SNIPER].maxammo; + - active_weapon = WEAPON_GUN; last_weapon = WEAPON_HAMMER; - + reload_timer = 0; // Create sound and spawn effects create_sound(pos, SOUND_PLAYER_SPAWN); create_spawn(pos); - + gameobj->on_player_spawn(this); } @@ -516,14 +532,14 @@ bool player::is_grounded() int player::handle_ninja() { vec2 direction = normalize(vec2(input.target_x, input.target_y)); - + if ((server_tick() - ninjaactivationtick) > (data->weapons[WEAPON_NINJA].duration * server_tickspeed() / 1000)) { // time's up, return active_weapon = last_weapon; return 0; } - + // Check if it should activate if ((input.fire && !(previnput.fire)) && (server_tick() > currentcooldown)) { @@ -536,21 +552,21 @@ int player::handle_ninja() numobjectshit = 0; create_sound(pos, SOUND_NINJA_FIRE); - + // release all hooks when ninja is activated //release_hooked(); //release_hooks(); } currentmovetime--; - + if (currentmovetime == 0) - { + { // reset player velocity core.vel *= 0.2f; //return MODIFIER_RETURNFLAGS_OVERRIDEWEAPON; } - + if (currentmovetime > 0) { // Set player velocity @@ -563,16 +579,16 @@ int player::handle_ninja() { create_smoke(pos); } - + // check if we hit anything along the way { - int type = OBJTYPE_PLAYER; + int type = OBJTYPE_PLAYER_CHARACTER; entity *ents[64]; vec2 dir = pos - oldpos; float radius = phys_size * 2.0f; //length(dir * 0.5f); vec2 center = oldpos + dir * 0.5f; int num = world->find_entities(center, radius, ents, 64, &type, 1); - + for (int i = 0; i < num; i++) { // Check if entity is a player @@ -591,7 +607,7 @@ int player::handle_ninja() // check so we are sufficiently close if (distance(ents[i]->pos, pos) > (phys_size * 2.0f)) continue; - + // hit a player, give him damage and stuffs... create_sound(ents[i]->pos, SOUND_NINJA_HIT); // set his velocity to fast upward (for now) @@ -624,8 +640,8 @@ static input_count count_input(int prev, int cur) else c.releases++; } - - return c; + + return c; } int player::handle_sniper() @@ -693,7 +709,7 @@ int player::handle_sniper() int player::handle_weapons() { vec2 direction = normalize(vec2(input.target_x, input.target_y)); - + if(config.stress) { for(int i = 0; i < NUM_WEAPONS; i++) @@ -701,11 +717,11 @@ int player::handle_weapons() weapons[i].got = true; weapons[i].ammo = 10; } - + if(reload_timer) // twice as fast reload reload_timer--; } - + // check reload timer if(reload_timer) { @@ -737,10 +753,10 @@ int player::handle_weapons() if(weapons[new_weapon].got) prev--; } - + if(input.wanted_weapon) // direct weapon selection new_weapon = input.wanted_weapon-1; - + if(new_weapon != active_weapon && new_weapon >= 0 && new_weapon < NUM_WEAPONS && weapons[new_weapon].got) { if(active_weapon != new_weapon) @@ -756,7 +772,7 @@ int player::handle_weapons() // don't update other weapons while sniper is active return handle_sniper(); } - + if(count_input(previnput.fire, input.fire).presses) //previnput.fire != input.fire && (input.fire&1)) { if(reload_timer == 0) @@ -812,9 +828,9 @@ int player::handle_weapons() } create_sound(pos, SOUND_SHOTGUN_FIRE); break; - } + } } - + weapons[active_weapon].ammo--; attack_tick = server_tick(); reload_timer = data->weapons[active_weapon].firedelay * server_tickspeed() / 1000; @@ -825,7 +841,7 @@ int player::handle_weapons() } } } - + // Update weapons if (active_weapon == WEAPON_HAMMER && reload_timer > 0) { @@ -833,14 +849,14 @@ int player::handle_weapons() // only one that needs update (for now) // do selection for the weapon and bash anything in it // check if we hit anything along the way - int type = OBJTYPE_PLAYER; + int type = OBJTYPE_PLAYER_CHARACTER; entity *ents[64]; vec2 lookdir(direction.x > 0.0f ? 1.0f : -1.0f, 0.0f); vec2 dir = lookdir * data->weapons[active_weapon].meleereach; float radius = length(dir * 0.5f); vec2 center = pos + dir * 0.5f; int num = world->find_entities(center, radius, ents, 64, &type, 1); - + for (int i = 0; i < num; i++) { // Check if entity is a player @@ -859,7 +875,7 @@ int player::handle_weapons() // check so we are sufficiently close if (distance(ents[i]->pos, pos) > (phys_size * 2.0f)) continue; - + // hit a player, give him damage and stuffs... // create sound for bash //create_sound(ents[i]->pos, sound_impact); @@ -913,7 +929,7 @@ void player::tick() latency_accum_max = max(latency_accum_max, info.latency); latency_accum_min = min(latency_accum_min, info.latency); } - + if(server_tick()%server_tickspeed() == 0) { latency_avg = latency_accum/server_tickspeed(); @@ -924,14 +940,14 @@ void player::tick() latency_accum_max = 0; } } - + if(team == -1) { // spectator return; } - - + + if(spawning) try_respawn(); @@ -944,13 +960,13 @@ void player::tick() respawn(); return; } - + //player_core core; //core.pos = pos; //core.jumped = jumped; core.input = input; core.tick(); - + // handle weapons handle_weapons(); /* @@ -959,7 +975,7 @@ void player::tick() // add gravity //if (!(retflags & MODIFIER_RETURNFLAGS_OVERRIDEGRAVITY)) //vel.y += gravity; - + // do the move defered_pos = pos; move_box(&core.pos, &vel, vec2(phys_size, phys_size), 0); @@ -967,9 +983,9 @@ void player::tick() //defered_pos = core.pos; //jumped = core.jumped; - + state = input.state; - + // Previnput previnput = input; return; @@ -979,8 +995,9 @@ void player::tick_defered() { core.move(); core.quantize(); + //dbg_msg("", "%d %.0f,%.0f -> %.0f,%.0f", client_id, pos.x, pos.y, core.pos.x, core.pos.y); pos = core.pos; - + // apply the new position //pos = defered_pos; } @@ -988,9 +1005,9 @@ void player::tick_defered() void player::die(int killer, int weapon) { gameobj->on_player_death(this, get_player(killer), weapon); - + dbg_msg("game", "kill killer='%d:%s' victim='%d:%s' weapon=%d", killer, players[killer].name, client_id, name, weapon); - + // send the kill message msg_pack_start(MSG_KILLMSG, MSGFLAG_VITAL); msg_pack_int(killer); @@ -998,10 +1015,10 @@ void player::die(int killer, int weapon) msg_pack_int(weapon); msg_pack_end(); server_send_msg(-1); - + // a nice sound create_sound(pos, SOUND_PLAYER_DIE); - + // set dead state dead = true; die_tick = server_tick(); @@ -1013,7 +1030,7 @@ bool player::take_damage(vec2 force, int dmg, int from, int weapon) { core.vel += force; - // player only inflicts half damage on self + // player only inflicts half damage on self if(from == client_id) dmg = max(1, dmg/2); @@ -1040,7 +1057,7 @@ bool player::take_damage(vec2 force, int dmg, int from, int weapon) armor -= 1; dmg--; } - + if(dmg > armor) { dmg -= armor; @@ -1049,13 +1066,13 @@ bool player::take_damage(vec2 force, int dmg, int from, int weapon) } else armor -= dmg; - + damage_taken_tick = server_tick(); - + // do damage hit sound if(from >= 0) create_targetted_sound(get_player(from)->pos, SOUND_HIT, from); - + // check for death if(health <= 0) { @@ -1067,9 +1084,9 @@ bool player::take_damage(vec2 force, int dmg, int from, int weapon) player *p = get_player(from); p->emote_type = EMOTE_HAPPY; - p->emote_stop = server_tick() + server_tickspeed(); + p->emote_stop = server_tick() + server_tickspeed(); } - + return false; } @@ -1087,64 +1104,73 @@ bool player::take_damage(vec2 force, int dmg, int from, int weapon) void player::snap(int snaping_client) { - obj_player *player = (obj_player *)snap_new_item(OBJTYPE_PLAYER, client_id, sizeof(obj_player)); - - core.write(player); - - if(snaping_client != client_id) + if(1) { - player->vx = 0; // make sure that we don't send these to clients who don't need them - player->vy = 0; - player->hook_dx = 0; - player->hook_dy = 0; - } + obj_player_info *info = (obj_player_info *)snap_new_item(OBJTYPE_PLAYER_INFO, client_id, sizeof(obj_player_info)); - if (emote_stop < server_tick()) - { - emote_type = EMOTE_NORMAL; - emote_stop = -1; - } + info->latency = latency_avg; + info->latency_flux = latency_max-latency_min; + info->local = 0; + info->clientid = client_id; + info->score = score; + info->team = team; - player->emote = emote_type; - - player->latency = latency_avg; - player->latency_flux = latency_max-latency_min; - - player->ammocount = weapons[active_weapon].ammo; - player->weaponstage = weapons[active_weapon].weaponstage; - player->health = 0; - player->armor = 0; - player->local = 0; - player->clientid = client_id; - player->weapon = active_weapon; - player->attacktick = attack_tick; - - if(client_id == snaping_client) - { - player->local = 1; - player->health = health; - player->armor = armor; + if(client_id == snaping_client) + info->local = 1; } - - if(dead) - player->health = -1; - - //if(length(vel) > 15.0f) - // player->emote = EMOTE_HAPPY; - - //if(damage_taken_tick+50 > server_tick()) - // player->emote = EMOTE_PAIN; - - if (player->emote == EMOTE_NORMAL) + + if(health > 0 && distance(players[snaping_client].pos, pos) < 1000.0f) { - if(250 - ((server_tick() - last_action)%(250)) < 5) - player->emote = EMOTE_BLINK; - } - - player->score = score; - player->team = team; + obj_player_character *character = (obj_player_character *)snap_new_item(OBJTYPE_PLAYER_CHARACTER, client_id, sizeof(obj_player_character)); + + core.write(character); + + if(snaping_client != client_id) + { + character->vx = 0; // make sure that we don't send these to clients who don't need them + character->vy = 0; + character->hook_dx = 0; + character->hook_dy = 0; + } + + if (emote_stop < server_tick()) + { + emote_type = EMOTE_NORMAL; + emote_stop = -1; + } + + character->emote = emote_type; + + character->ammocount = weapons[active_weapon].ammo; + character->health = 0; + character->armor = 0; + character->weapon = active_weapon; + character->weaponstage = weapons[active_weapon].weaponstage; + character->attacktick = attack_tick; + + if(client_id == snaping_client) + { + character->health = health; + character->armor = armor; + } + + if(dead) + character->health = -1; + + //if(length(vel) > 15.0f) + // player->emote = EMOTE_HAPPY; - player->state = state; + //if(damage_taken_tick+50 > server_tick()) + // player->emote = EMOTE_PAIN; + + if (character->emote == EMOTE_NORMAL) + { + if(250 - ((server_tick() - last_action)%(250)) < 5) + character->emote = EMOTE_BLINK; + } + + character->state = state; + } } player *players; @@ -1158,9 +1184,9 @@ powerup::powerup(int _type, int _subtype) type = _type; subtype = _subtype; proximity_radius = phys_size; - + reset(); - + // TODO: should this be done here? world->insert_entity(this); } @@ -1182,7 +1208,7 @@ void powerup::tick() { // respawn spawntick = -1; - + if(type == POWERUP_WEAPON) create_sound(pos, SOUND_WEAPON_SPAWN, 0); } @@ -1214,7 +1240,7 @@ void powerup::tick() respawntime = data->powerupinfo[type].respawntime; } break; - + case POWERUP_WEAPON: if(subtype >= 0 && subtype < NUM_WEAPONS) { @@ -1223,7 +1249,7 @@ void powerup::tick() pplayer->weapons[subtype].got = true; pplayer->weapons[subtype].ammo = min(10, pplayer->weapons[subtype].ammo + data->powerupinfo[type].amount); respawntime = data->powerupinfo[type].respawntime; - + // TODO: data compiler should take care of stuff like this if(subtype == WEAPON_ROCKET) create_sound(pos, SOUND_PICKUP_ROCKET); @@ -1244,7 +1270,7 @@ void powerup::tick() // loop through all players, setting their emotes entity *ents[64]; - const int types[] = {OBJTYPE_PLAYER}; + const int types[] = {OBJTYPE_PLAYER_CHARACTER}; int num = world->find_entities(vec2(0, 0), 1000000, ents, 64, types, 1); for (int i = 0; i < num; i++) { @@ -1264,7 +1290,7 @@ void powerup::tick() default: break; }; - + if(respawntime >= 0) { dbg_msg("game", "pickup player='%d:%s' item=%d/%d", pplayer->client_id, pplayer->name, type, subtype); @@ -1320,7 +1346,7 @@ void create_explosion(vec2 p, int owner, int weapon, bool bnodamage) ev->x = (int)p.x; ev->y = (int)p.y; } - + if (!bnodamage) { // deal damage @@ -1404,7 +1430,7 @@ player* intersect_player(vec2 pos0, vec2 pos1, vec2& new_pos, entity* notthis) vec2 dir = pos1 - pos0; float radius = length(dir * 0.5f); vec2 center = pos0 + dir * 0.5f; - const int types[] = {OBJTYPE_PLAYER}; + const int types[] = {OBJTYPE_PLAYER_CHARACTER}; int num = world->find_entities(center, radius, ents, 64, types, 1); for (int i = 0; i < num; i++) { @@ -1426,7 +1452,7 @@ void send_chat(int cid, int team, const char *msg) dbg_msg("chat", "%d:%d:%s: %s", cid, team, players[cid].name, msg); else dbg_msg("chat", "*** %s", msg); - + if(team == -1) { msg_pack_start(MSG_CHAT, MSGFLAG_VITAL); @@ -1443,7 +1469,7 @@ void send_chat(int cid, int team, const char *msg) msg_pack_int(1); msg_pack_string(msg, 512); msg_pack_end(); - + for(int i = 0; i < MAX_CLIENTS; i++) { if(players[i].client_id != -1 && players[i].team == team) @@ -1459,20 +1485,20 @@ void mods_tick() // clear all events events.clear(); world->tick(); - + if(world->paused) // make sure that the game object always updates gameobj->tick(); - + if(config.restart) { if(config.restart > 1) gameobj->do_warmup(config.restart); else gameobj->startround(); - + config.restart = 0; } - + if(config.sv_msg[0] != 0) { send_chat(-1, 0, config.sv_msg); @@ -1526,7 +1552,7 @@ void mods_client_enter(int client_id) players[client_id].client_id = client_id; world->insert_entity(&players[client_id]); players[client_id].respawn(); - + CLIENT_INFO info; // fetch login name if(server_getclientinfo(client_id, &info)) { @@ -1544,13 +1570,13 @@ void mods_client_enter(int client_id) else players[client_id].team = gameobj->getteam(client_id); - // + // msg_pack_start(MSG_SETNAME, MSGFLAG_VITAL); msg_pack_int(client_id); msg_pack_string(players[client_id].name, 64); msg_pack_end(); server_send_msg(-1); - + for(int i = 0; i < MAX_CLIENTS; i++) { if(players[client_id].client_id != -1) @@ -1575,7 +1601,7 @@ void mods_client_drop(int client_id) send_chat(-1, -1, buf); dbg_msg("game", "leave player='%d:%s'", client_id, players[client_id].name); - + gameobj->on_player_death(&players[client_id], 0, -1); world->remove_entity(&players[client_id]); players[client_id].client_id = -1; @@ -1624,12 +1650,12 @@ void mods_init() { if(!data) /* only load once */ data = load_data_from_memory(internal_data); - + col_init(32); world = new game_world; players = new player[MAX_CLIENTS]; - + // select gametype if(strcmp(config.gametype, "ctf") == 0) gameobj = new gameobject_ctf; @@ -1637,8 +1663,8 @@ void mods_init() gameobj = new gameobject_tdm; else gameobj = new gameobject_dm; - - // setup core world + + // setup core world for(int i = 0; i < MAX_CLIENTS; i++) { players[i].core.world = &world->core; @@ -1648,15 +1674,15 @@ void mods_init() // int start, num; map_get_type(MAPRES_ITEM, &start, &num); - + // TODO: this is way more complicated then it should be for(int i = 0; i < num; i++) { mapres_item *it = (mapres_item *)map_get_item(start+i, 0, 0); - + int type = -1; int subtype = 0; - + switch(it->type) { case ITEM_WEAPON_GUN: @@ -1675,11 +1701,11 @@ void mods_init() type = POWERUP_WEAPON; subtype = WEAPON_HAMMER; break; - + case ITEM_HEALTH: type = POWERUP_HEALTH; break; - + case ITEM_ARMOR: type = POWERUP_ARMOR; break; @@ -1689,7 +1715,7 @@ void mods_init() subtype = WEAPON_NINJA; break; }; - + if(type != -1) { // LOL, the only new in the entire game code @@ -1698,13 +1724,13 @@ void mods_init() ppower->pos = vec2(it->x, it->y); } } - + if(gameobj->gametype == GAMETYPE_CTF) { } - + world->insert_entity(gameobj); - + if(config.dbg_bots) { @@ -1726,7 +1752,7 @@ void mods_init() count = -1; } }*/ - } + } } void mods_shutdown() @@ -1738,7 +1764,7 @@ void mods_shutdown() players = 0; world = 0; } - + void mods_presnap() {} void mods_postsnap() {} diff --git a/src/game/server/srv_ctf.cpp b/src/game/server/srv_ctf.cpp index 1831db31..57d81aef 100644 --- a/src/game/server/srv_ctf.cpp +++ b/src/game/server/srv_ctf.cpp @@ -68,7 +68,7 @@ void gameobject_ctf::tick() else { player *players[MAX_CLIENTS]; - int types[] = {OBJTYPE_PLAYER}; + int types[] = {OBJTYPE_PLAYER_CHARACTER}; int num = world->find_entities(f->pos, 32.0f, (entity**)players, MAX_CLIENTS, types, 1); for(int i = 0; i < num; i++) { @@ -96,9 +96,7 @@ void gameobject_ctf::tick() } } -////////////////////////////////////////////////// -// FLAG -////////////////////////////////////////////////// +// Flag flag::flag(int _team) : entity(OBJTYPE_FLAG) { @@ -135,4 +133,3 @@ void flag::snap(int snapping_client) else flag->local_carry = 0; } -// FLAG END /////////////////////// |