added skins, tweaked prediction like hell

This commit is contained in:
Magnus Auvinen 2007-11-04 00:19:41 +00:00
parent f724ab006c
commit daf89a01ff
34 changed files with 419 additions and 163 deletions

BIN
data/skins/bluekitty.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

BIN
data/skins/bluestripe.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

BIN
data/skins/brownbear.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

BIN
data/skins/cammo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

BIN
data/skins/cammostripes.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

BIN
data/skins/coala.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

BIN
data/skins/limekitty.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

BIN
data/skins/ninja.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
data/skins/pinky.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

BIN
data/skins/redbopp.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

BIN
data/skins/redstripe.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

BIN
data/skins/saddo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

BIN
data/skins/toptri.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5 KiB

BIN
data/skins/twinbop.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

BIN
data/skins/twintri.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

BIN
data/skins/warpaint.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

View file

@ -618,19 +618,20 @@ sprites {
}
tees images.char_default 16 64 {
tee_body 0 0 4 4
tee_body_outline 4 0 4 4
tee_foot 8 3 2 1
tee_foot_outline 13 2 2 1
tee_hand 8 0 2 2
tee_hand_outline 13 0 2 2
tees images.char_default 8 4 {
tee_body 0 0 3 3
tee_body_outline 3 0 3 3
tee_foot 6 1 2 1
tee_foot_outline 6 2 2 1
tee_hand 6 0 1 1
tee_hand_outline 7 0 1 1
tee_eye_normal 10 2 1 1
tee_eye_pain 11 3 1 1
tee_eye_happy 11 2 1 1
tee_eye_surprise 12 0 1 1
tee_eye_angry 10 3 1 1
tee_eye_normal 2 3 1 1
tee_eye_angry 3 3 1 1
tee_eye_pain 4 3 1 1
tee_eye_happy 5 3 1 1
tee_eye_dead 6 3 1 1
tee_eye_surprise 7 3 1 1
}
chatbubbles images.chat_bubbles 4 4 {

View file

@ -19,7 +19,7 @@
#include <mastersrv/mastersrv.h>
const int prediction_margin = 5; /* magic network prediction value */
const int prediction_margin = 10; /* magic network prediction value */
/*
Server Time
@ -182,6 +182,7 @@ SMOOTHTIME game_time;
SMOOTHTIME predicted_time;
GRAPH intra_graph;
GRAPH predict_graph;
/* --- input snapping --- */
static int input_data[MAX_INPUT_SIZE] = {0};
@ -272,11 +273,11 @@ static void client_send_info()
msg_pack_string(config.player_name, 128);
msg_pack_string(config.clan_name, 128);
msg_pack_string(config.password, 128);
msg_pack_string("myskin", 128);
msg_pack_end();
client_send_msg();
}
static void client_send_entergame()
{
msg_pack_start_system(NETMSG_ENTERGAME, MSGFLAG_VITAL);
@ -284,6 +285,13 @@ static void client_send_entergame()
client_send_msg();
}
static void client_send_ready()
{
msg_pack_start_system(NETMSG_READY, MSGFLAG_VITAL);
msg_pack_end();
client_send_msg();
}
static void client_send_error(const char *error)
{
/*
@ -380,6 +388,14 @@ static void client_on_enter_game()
current_recv_tick = 0;
}
void client_entergame()
{
/* now we will wait for two snapshots */
/* to finish the connection */
client_send_entergame();
client_on_enter_game();
}
void client_connect(const char *server_address_str)
{
char buf[512];
@ -412,6 +428,8 @@ void client_connect(const char *server_address_str)
graph_init(&intra_graph, 0.0f, 1.0f);
graph_init(&input_late_graph, 0.0f, 1.0f);
graph_init(&predict_graph, 0.0f, 200.0f);
}
void client_disconnect()
@ -463,8 +481,9 @@ static void client_debug_render()
/* render graphs */
gfx_mapscreen(0,0,400.0f,300.0f);
graph_render(&game_time.graph, 300, 10, 90, 50);
graph_render(&predict_graph, 300, 10, 90, 50);
graph_render(&predicted_time.graph, 300, 10+50+10, 90, 50);
graph_render(&intra_graph, 300, 10+50+10+50+10, 90, 50);
graph_render(&input_late_graph, 300, 10+50+10+50+10+50+10, 90, 50);
@ -574,13 +593,15 @@ static void client_process_packet(NETPACKET *packet)
if(map_load(map))
{
dbg_msg("client/network", "loading done");
client_send_ready();
modc_connected();
/*
modc_entergame();
client_send_entergame();
dbg_msg("client/network", "loading done");
/* now we will wait for two snapshots */
/* to finish the connection */
client_on_enter_game();
*/
/*client_on_enter_game();*/
}
else
{
@ -736,7 +757,7 @@ static void client_process_packet(NETPACKET *packet)
if(recived_snapshots == 2)
{
/* start at 200ms and work from there */
st_init(&predicted_time, (game_tick+10)*time_freq()/50);
st_init(&predicted_time, game_tick*time_freq()/50);
st_init(&game_time, (game_tick-1)*time_freq()/50);
snapshots[SNAP_PREV] = snapshot_storage.first;
snapshots[SNAP_CURRENT] = snapshot_storage.last;
@ -744,6 +765,11 @@ static void client_process_packet(NETPACKET *packet)
client_set_state(CLIENTSTATE_ONLINE);
}
{
int64 now = time_get();
graph_add(&predict_graph, (st_get(&predicted_time, now)-st_get(&game_time, now))/(float)time_freq());
}
st_update(&game_time, (game_tick-1)*time_freq()/50);
/* ack snapshot */
@ -950,15 +976,16 @@ static void client_run(const char *direct_connect_server)
if(inp_key_pressed(KEY_F2))
inp_mouse_mode_relative();
if(inp_key_pressed(KEY_LCTRL) && inp_key_pressed('Q'))
break;
if(inp_key_pressed(KEY_F5))
{
ack_game_tick = -1;
client_send_input();
}
}
/* panic quit button */
if(inp_key_pressed(KEY_LCTRL) && inp_key_pressed(KEY_LSHIFT) && inp_key_pressed('Q'))
break;
/* pump the network */
client_pump_network();

View file

@ -536,8 +536,10 @@ void gfx_swap()
for(; index < 1000; index++)
{
IOHANDLE io = io_open(filename, IOFLAG_READ);
IOHANDLE io;
sprintf(filename, "screenshot%04d.png", index);
io = io_open(filename, IOFLAG_READ);
if(io)
io_close(io);
else

View file

@ -2,7 +2,9 @@
MACRO_CONFIG_INT(volume, 200, 0, 255)
MACRO_CONFIG_INT(cpu_throttle, 0, 0, 1)
MACRO_CONFIG_STR(player_name, 32, "nameless tee")
MACRO_CONFIG_STR(clan_name, 32, "")
MACRO_CONFIG_STR(password, 32, "")

View file

@ -743,9 +743,12 @@ int modmenu_render(int ingame);
/* undocumented callbacks */
void modc_connected();
void modc_message(int msg);
void modc_predict();
void mods_message(int msg, int client_id);
void mods_connected(int client_id);
const char *modc_net_version();
@ -753,6 +756,9 @@ const char *mods_net_version();
/* server */
int server_getclientinfo(int client_id, CLIENT_INFO *info);
const char *server_clientname(int client_id);
void server_setclientname(int client_id, const char *name);
int server_tick();
int server_tickspeed();
@ -823,6 +829,7 @@ int *client_get_input(int tick);
void client_connect(const char *address);
void client_disconnect();
void client_quit();
void client_entergame();
void client_rcon(const char *cmd);

View file

@ -1,5 +1,28 @@
#include "system.h"
/*
Connection diagram - How the initilization works.
Client -> INFO -> Server
Contains version info, name, and some other info.
Client <- MAP <- Server
Contains current map.
Client -> READY -> Server
The client has loaded the map and is ready to go,
but the mod needs to send it's information aswell.
modc_connected is called on the client and
mods_connected is called on the server.
The client should call client_entergame when the
mod has done it's initilization.
Client -> ENTERGAME -> Server
Tells the server to start sending snapshots.
client_entergame and server_client_enter is called.
*/
enum
{
NETMSG_NULL=0,
@ -15,6 +38,7 @@ enum
NETMSG_SNAPSMALL,
/* sent by client */
NETMSG_READY,
NETMSG_ENTERGAME,
NETMSG_INPUT,
NETMSG_CMD,

View file

@ -57,8 +57,9 @@ static int snap_id_inited = 0;
enum
{
SRVCLIENT_STATE_EMPTY = 0,
SRVCLIENT_STATE_CONNECTING = 1,
SRVCLIENT_STATE_INGAME = 2
SRVCLIENT_STATE_CONNECTING,
SRVCLIENT_STATE_READY,
SRVCLIENT_STATE_INGAME
};
typedef struct
@ -161,6 +162,20 @@ void snap_free_id(int id)
}
}
const char *server_clientname(int client_id)
{
if(client_id < 0 || client_id > MAX_CLIENTS || clients[client_id].state < SRVCLIENT_STATE_READY)
return "(invalid client)";
return clients[client_id].name;
}
void server_setclientname(int client_id, const char *name)
{
if(client_id < 0 || client_id > MAX_CLIENTS || clients[client_id].state < SRVCLIENT_STATE_READY)
return;
strncpy(clients[client_id].name, name, MAX_NAME_LENGTH);
}
int server_tick()
{
return current_tick;
@ -404,7 +419,6 @@ static void server_process_client_packet(NETPACKET *packet)
{
char version[64];
const char *password;
const char *skin;
strncpy(version, msg_unpack_string(), 64);
if(strcmp(version, mods_net_version()) != 0)
{
@ -418,9 +432,6 @@ static void server_process_client_packet(NETPACKET *packet)
strncpy(clients[cid].name, msg_unpack_string(), MAX_NAME_LENGTH);
strncpy(clients[cid].clan, msg_unpack_string(), MAX_CLANNAME_LENGTH);
password = msg_unpack_string();
skin = msg_unpack_string();
(void)password; /* ignore these variables */
(void)skin;
if(config.password[0] != 0 && strcmp(config.password, password) != 0)
{
@ -431,6 +442,15 @@ static void server_process_client_packet(NETPACKET *packet)
server_send_map(cid);
}
else if(msg == NETMSG_READY)
{
if(clients[cid].state == SRVCLIENT_STATE_CONNECTING)
{
dbg_msg("server", "player is ready. cid=%x", cid);
clients[cid].state = SRVCLIENT_STATE_READY;
mods_connected(cid);
}
}
else if(msg == NETMSG_ENTERGAME)
{
if(clients[cid].state != SRVCLIENT_STATE_INGAME)

View file

@ -26,10 +26,8 @@ enum
data_container *data = 0x0;
static int charids[16] = {2,10,0,4,12,6,9,1,3,15,13,11,7,5,8,14};
int gametype = GAMETYPE_DM;
static int skinseed = 0;
//static int skinseed = 0;
static int music_menu = -1;
static int music_menu_id = -1;
@ -53,13 +51,42 @@ static const obj_player_character *local_prev_character = 0;
static const obj_player_info *local_info = 0;
static const obj_game *gameobj = 0;
struct client_data
// do this better and nicer
struct skin
{
int org_texture;
int color_texture;
char name[31];
const char term[1];
};
enum
{
MAX_SKINS=256,
};
struct tee_render_info
{
int texture;
vec4 color;
};
static skin skins[MAX_SKINS] = {{-1, -1, {0}, {0}}};
static int num_skins = 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
@ -514,6 +541,46 @@ static void render_loading(float percent)
gfx_swap();
}
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;
}
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++;
}
extern "C" void modc_init()
{
// setup sound channels
@ -556,27 +623,13 @@ extern "C" void modc_init()
data->images[i].id = gfx_load_texture(data->images[i].filename);
current++;
}
// load skins
fs_listdir("data/skins", skinscan, 0);
}
extern "C" void modc_entergame()
{
col_init(32);
img_init();
tilemap_init();
chat_reset();
proj_particles.reset();
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;
}
extern "C" void modc_shutdown()
@ -755,6 +808,10 @@ extern "C" void modc_predict()
// 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++)
{
@ -781,16 +838,10 @@ extern "C" void modc_predict()
world.players[c]->move();
world.players[c]->quantize();
// get the data from the local player
if(local_cid == c && world.players[local_cid])
{
if(tick == client_predtick())
predicted_player = *world.players[local_cid];
else if(tick == client_predtick()-1)
predicted_prev_player = *world.players[local_cid];
}
}
if(tick == client_predtick() && world.players[local_cid])
predicted_player = *world.players[local_cid];
}
}
@ -850,10 +901,15 @@ extern "C" void modc_newsnapshot()
}
}
void send_changename_request(const char *name)
void send_info(bool start)
{
msg_pack_start(MSG_CHANGENAME, MSGFLAG_VITAL);
msg_pack_string(name, 64);
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_color);
msg_pack_end();
client_send_msg();
}
@ -1043,10 +1099,11 @@ static void anim_eval_add(animstate *state, animation *anim, float time, float a
anim_add(state, &add, amount);
}
static void render_hand(int skin, vec2 center_pos, vec2 dir, float angle_offset, vec2 post_rot_offset)
static void render_hand(int skin_id, vec2 center_pos, vec2 dir, float angle_offset, vec2 post_rot_offset)
{
// for drawing hand
int shift = charids[skin%16];
skin_id = skin_id%num_skins;
float basesize = 10.0f;
//dir = normalize(hook_pos-pos);
@ -1066,7 +1123,8 @@ static void render_hand(int skin, vec2 center_pos, vec2 dir, float angle_offset,
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(data->images[IMAGE_CHAR_DEFAULT].id);
gfx_texture_set(skins[skin_id].color_texture);
gfx_quads_begin();
// two passes
@ -1074,7 +1132,7 @@ static void render_hand(int skin, vec2 center_pos, vec2 dir, float angle_offset,
{
bool outline = i == 0;
select_sprite(outline?SPRITE_TEE_HAND_OUTLINE:SPRITE_TEE_HAND, 0, 0, shift*4);
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);
}
@ -1083,30 +1141,33 @@ static void render_hand(int skin, vec2 center_pos, vec2 dir, float angle_offset,
gfx_quads_end();
}
static void render_tee(animstate *anim, int skin, int emote, vec2 dir, vec2 pos)
static void render_tee(animstate *anim, tee_render_info *info, int emote, vec2 dir, vec2 pos)
{
vec2 direction = dir;
vec2 direction = dir;
vec2 position = pos;
gfx_texture_set(data->images[IMAGE_CHAR_DEFAULT].id);
//gfx_texture_set(data->images[IMAGE_CHAR_DEFAULT].id);
gfx_texture_set(info->texture);
gfx_quads_begin();
gfx_setcolor(info->color.r, info->color.g, info->color.b, info->color.a);
//gfx_quads_draw(pos.x, pos.y-128, 128, 128);
// draw foots
// first pass we draw the outline
// second pass we draw the filling
for(int p = 0; p < 2; p++)
{
// first pass we draw the outline
// second pass we draw the filling
int outline = p==0 ? 1 : 0;
int shift = skin;
//int shift = skin;
for(int f = 0; f < 2; f++)
{
float basesize = 10.0f;
float basesize = 16.0f;
if(f == 1)
{
gfx_quads_setrotation(anim->body.angle*pi*2);
// draw body
select_sprite(outline?SPRITE_TEE_BODY_OUTLINE:SPRITE_TEE_BODY, 0, 0, shift*4);
select_sprite(outline?SPRITE_TEE_BODY_OUTLINE:SPRITE_TEE_BODY, 0, 0, 0);
gfx_quads_draw(position.x+anim->body.x, position.y+anim->body.y, 4*basesize, 4*basesize);
// draw eyes
@ -1115,34 +1176,34 @@ static void render_tee(animstate *anim, int skin, int emote, vec2 dir, vec2 pos)
switch (emote)
{
case EMOTE_PAIN:
select_sprite(SPRITE_TEE_EYE_PAIN, 0, 0, shift*4);
select_sprite(SPRITE_TEE_EYE_PAIN, 0, 0, 0);
break;
case EMOTE_HAPPY:
select_sprite(SPRITE_TEE_EYE_HAPPY, 0, 0, shift*4);
select_sprite(SPRITE_TEE_EYE_HAPPY, 0, 0, 0);
break;
case EMOTE_SURPRISE:
select_sprite(SPRITE_TEE_EYE_SURPRISE, 0, 0, shift*4);
select_sprite(SPRITE_TEE_EYE_SURPRISE, 0, 0, 0);
break;
case EMOTE_ANGRY:
select_sprite(SPRITE_TEE_EYE_ANGRY, 0, 0, shift*4);
select_sprite(SPRITE_TEE_EYE_ANGRY, 0, 0, 0);
break;
default:
select_sprite(SPRITE_TEE_EYE_NORMAL, 0, 0, shift*4);
select_sprite(SPRITE_TEE_EYE_NORMAL, 0, 0, 0);
break;
}
int h = emote == EMOTE_BLINK ? (int)(basesize/3) : (int)(basesize);
gfx_quads_draw(position.x-4+direction.x*4, position.y-8+direction.y*3, basesize, h);
gfx_quads_draw(position.x+4+direction.x*4, position.y-8+direction.y*3, -basesize, h);
gfx_quads_draw(position.x-4+direction.x*4, position.y-8+direction.y*3, basesize*1.5f, h*1.5f);
gfx_quads_draw(position.x+4+direction.x*4, position.y-8+direction.y*3, -basesize*1.5f, h*1.5f);
}
}
// draw feet
select_sprite(outline?SPRITE_TEE_FOOT_OUTLINE:SPRITE_TEE_FOOT, 0, 0, shift*4);
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*2.5f;
float h = basesize*1.425f;
float w = basesize*2.5f*1.5f;
float h = basesize*1.425f*1.5f;
gfx_quads_setrotation(foot->angle*pi*2);
gfx_quads_draw(position.x+foot->x, position.y+foot->y, w, h);
@ -1249,10 +1310,10 @@ static void render_player(
intratick = client_intrapredtick();
}
int skin = charids[info.clientid];
if(gametype != GAMETYPE_DM)
skin = info.team*9; // 0 or 9
// 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;
@ -1317,7 +1378,7 @@ static void render_player(
gfx_quads_setrotation(0);
gfx_quads_end();
render_hand(skin, position, normalize(hook_pos-pos), -pi/2, vec2(20, 0));
render_hand(skin_id, position, normalize(hook_pos-pos), -pi/2, vec2(20, 0));
}
// draw gun
@ -1437,9 +1498,9 @@ static void render_player(
switch (player.weapon)
{
case WEAPON_GUN: render_hand(skin, p, direction, -3*pi/4, vec2(-15, 4)); break;
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;
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;
}
}
@ -1448,11 +1509,13 @@ static void render_player(
if(info.local && config.debug)
{
vec2 ghost_position = mix(vec2(prev_char->x, prev_char->y), vec2(player_char->x, player_char->y), client_intratick());
render_tee(&state, 15, player.emote, direction, ghost_position); // render ghost
tee_render_info ghost = client_datas[info.clientid].skin_info;
ghost.color.a = 0.5f;
render_tee(&state, &ghost, player.emote, direction, ghost_position); // render ghost
}
// render the tee
render_tee(&state, skin, player.emote, direction, position);
render_tee(&state, &client_datas[info.clientid].skin_info, player.emote, direction, position);
if(player.state == STATE_CHATTING)
{
@ -1785,7 +1848,7 @@ void render_scoreboard(float x, float y, float w, int team, const char *title)
gfx_pretty_text(x+w-tw-35, y, font_size, buf, -1);
// render avatar
render_tee(&idlestate, info->clientid, EMOTE_NORMAL, vec2(1,0), vec2(x+90, y+28));
render_tee(&idlestate, &client_datas[info->clientid].skin_info, EMOTE_NORMAL, vec2(1,0), vec2(x+90, y+28));
y += 50.0f;
}
}
@ -1882,7 +1945,7 @@ void render_world(float center_x, float center_y, float zoom)
const void *info = snap_find_item(SNAP_CURRENT, OBJTYPE_PLAYER_INFO, item.id);
if(prev && prev_info && info)
{
client_datas[((const obj_player_info *)data)->clientid].team = ((const obj_player_info *)data)->team;
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,
@ -1905,6 +1968,22 @@ void render_world(float center_x, float center_y, float zoom)
damageind.render();
}
static void next_skin()
{
int skin_id = 0;
for(int i = 0; i < num_skins; i++)
{
if(strcmp(config.player_skin, skins[i].name) == 0)
{
skin_id = (i+1)%num_skins;
break;
}
}
config_set_player_skin(&config, skins[skin_id].name);
send_info(false);
}
static void do_input(int *v, int key)
{
*v += inp_key_presses(key) + inp_key_releases(key);
@ -1915,6 +1994,9 @@ static void do_input(int *v, int key)
void render_game()
{
if(inp_key_down('L'))
next_skin();
float width = 400*3.0f;
float height = 300*3.0f;
@ -2319,8 +2401,8 @@ void render_game()
// render victim tee
x -= 24.0f;
int skin = gametype == GAMETYPE_TDM ? skinseed + client_datas[killmsgs[r].victim].team : killmsgs[r].victim;
render_tee(&idlestate, skin, EMOTE_PAIN, vec2(-1,0), vec2(x, y+28));
//int skin = gametype == GAMETYPE_TDM ? skinseed + client_datas[killmsgs[r].victim].team : killmsgs[r].victim;
render_tee(&idlestate, &client_datas[killmsgs[r].victim].skin_info, EMOTE_PAIN, vec2(-1,0), vec2(x, y+28));
x -= 32.0f;
// render weapon
@ -2337,8 +2419,8 @@ void render_game()
// render killer tee
x -= 24.0f;
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));
//skin = gametype == GAMETYPE_TDM ? skinseed + client_datas[killmsgs[r].killer].team : killmsgs[r].killer;
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
@ -2532,6 +2614,7 @@ extern "C" void modc_render()
render_game();
// handle team switching
// TODO: FUGLY!!!
if(config.team != -10)
{
msg_pack_start(MSG_SETTEAM, MSGFLAG_VITAL);
@ -2586,11 +2669,33 @@ extern "C" void modc_message(int msg)
else
snd_play(CHN_GUI, data->sounds[SOUND_CHAT_SERVER].sounds[0].id, 0);
}
else if(msg == MSG_SETNAME)
else if(msg == MSG_SETINFO)
{
int cid = msg_unpack_int();
const char *name = msg_unpack_string();
const char *skinname = msg_unpack_string();
int color = msg_unpack_int();
(void)color;
strncpy(client_datas[cid].name, name, 64);
strncpy(client_datas[cid].skin_name, skinname, 64);
client_datas[cid].skin_info.color = vec4(1,1,1,1); //color;
// find new skin
client_datas[cid].skin_id = 0;
for(int i = 0; i < num_skins; i++)
{
if(strcmp(skins[i].name, client_datas[cid].skin_name) == 0)
{
client_datas[cid].skin_id = i;
break;
}
}
client_datas[cid].skin_info.texture = skins[client_datas[cid].skin_id].org_texture;
}
else if(msg == MSG_READY_TO_ENTER)
{
client_entergame();
}
else if(msg == MSG_KILLMSG)
{
@ -2609,5 +2714,28 @@ extern "C" void modc_message(int msg)
}
}
extern "C" void modc_connected()
{
// init some stuff
col_init(32);
img_init();
tilemap_init();
chat_reset();
proj_particles.reset();
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; }

View file

@ -1303,7 +1303,7 @@ static int settings_sound_render()
}
extern void draw_round_rect(float x, float y, float w, float h, float r);
void send_changename_request(const char *name);
extern void send_info(bool);
static int settings_render(bool ingame)
{
@ -1344,10 +1344,13 @@ static int settings_render(bool ingame)
if (ui_do_button(&save_button, "Save", 0, 482, 490, 128, 48, draw_teewars_button, 0))
{
// did we change our name?
if (ingame && strcmp(config.player_name, config_copy.player_name) != 0)
send_changename_request(config_copy.player_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

View file

@ -38,15 +38,17 @@ enum
enum
{
MSG_NULL=0,
MSG_SAY,
MSG_CHAT,
MSG_SETNAME,
MSG_KILLMSG,
MSG_SAY, // client -> server
MSG_CHAT, // server -> client
MSG_SETINFO, // server -> client - contains name, skin and color info
MSG_KILLMSG, // server -> client
MSG_SETTEAM,
MSG_JOIN,
MSG_QUIT,
MSG_EMOTICON,
MSG_CHANGENAME,
MSG_STARTINFO, // client -> server
MSG_CHANGEINFO, // client -> server
MSG_READY_TO_ENTER // server -> client
};
enum

View file

@ -39,6 +39,9 @@ MACRO_CONFIG_INT(dynamic_camera, 1, 0, 1)
MACRO_CONFIG_INT(warmup, 0, 0, 0)
MACRO_CONFIG_INT(team, -10, -1, 0)
MACRO_CONFIG_INT(player_color, -1, -1, 256)
MACRO_CONFIG_STR(player_skin, 64, "default")
MACRO_CONFIG_INT(dbg_new_gui, 0, 0, 1)

View file

@ -355,11 +355,6 @@ player::player()
void player::init()
{
proximity_radius = phys_size;
name[0] = 'n';
name[1] = 'o';
name[2] = 'o';
name[3] = 'b';
name[4] = 0;
client_id = -1;
team = -1; // -1 == spectator
extrapowerflags = 0;
@ -406,7 +401,6 @@ void player::set_weapon(int w)
active_weapon = w;
}
void player::respawn()
{
spawning = true;
@ -504,9 +498,8 @@ void player::try_respawn()
weapons[WEAPON_GUN].got = true;
weapons[WEAPON_GUN].ammo = data->weapons[WEAPON_GUN].maxammo;
weapons[WEAPON_SNIPER].got = true;
weapons[WEAPON_SNIPER].ammo = data->weapons[WEAPON_SNIPER].maxammo;
//weapons[WEAPON_SNIPER].got = true;
//weapons[WEAPON_SNIPER].ammo = data->weapons[WEAPON_SNIPER].maxammo;
active_weapon = WEAPON_GUN;
last_weapon = WEAPON_HAMMER;
@ -1006,7 +999,9 @@ 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);
dbg_msg("game", "kill killer='%d:%s' victim='%d:%s' weapon=%d",
killer, server_clientname(killer),
client_id, server_clientname(client_id), weapon);
// send the kill message
msg_pack_start(MSG_KILLMSG, MSGFLAG_VITAL);
@ -1292,7 +1287,8 @@ void powerup::tick()
if(respawntime >= 0)
{
dbg_msg("game", "pickup player='%d:%s' item=%d/%d", pplayer->client_id, pplayer->name, type, subtype);
dbg_msg("game", "pickup player='%d:%s' item=%d/%d",
pplayer->client_id, server_clientname(pplayer->client_id), type, subtype);
spawntick = server_tick() + server_tickspeed() * respawntime;
}
}
@ -1448,7 +1444,7 @@ player* intersect_player(vec2 pos0, vec2 pos1, vec2& new_pos, entity* notthis)
void send_chat(int cid, int team, const char *msg)
{
if(cid >= 0 && cid < MAX_CLIENTS)
dbg_msg("chat", "%d:%d:%s: %s", cid, team, players[cid].name, msg);
dbg_msg("chat", "%d:%d:%s: %s", cid, team, server_clientname(cid), msg);
else
dbg_msg("chat", "*** %s", msg);
@ -1523,17 +1519,15 @@ void mods_client_input(int client_id, void *input)
}
}
void send_set_name(int cid, const char *old_name, const char *new_name)
void send_info(int who, int to_who)
{
msg_pack_start(MSG_SETNAME, MSGFLAG_VITAL);
msg_pack_int(cid);
msg_pack_string(new_name, 64);
msg_pack_start(MSG_SETINFO, MSGFLAG_VITAL);
msg_pack_int(who);
msg_pack_string(server_clientname(who), 64);
msg_pack_string(players[who].skin_name, 64);
msg_pack_int(players[who].skin_color);
msg_pack_end();
server_send_msg(-1);
char msg[256];
sprintf(msg, "*** %s changed name to %s", old_name, new_name);
send_chat(-1, -1, msg);
server_send_msg(to_who);
}
void send_emoticon(int cid, int emoticon)
@ -1547,21 +1541,21 @@ void send_emoticon(int cid, int emoticon)
void mods_client_enter(int client_id)
{
players[client_id].init();
players[client_id].client_id = client_id;
world->insert_entity(&players[client_id]);
players[client_id].respawn();
dbg_msg("game", "join player='%d:%s'", client_id, server_clientname(client_id));
char buf[512];
sprintf(buf, "%s has joined the game", server_clientname(client_id));
send_chat(-1, -1, buf);
}
CLIENT_INFO info; // fetch login name
if(server_getclientinfo(client_id, &info))
{
strcpy(players[client_id].name, info.name);
}
else
strcpy(players[client_id].name, "(bot)");
void mods_connected(int client_id)
{
players[client_id].init();
players[client_id].client_id = client_id;
dbg_msg("game", "join player='%d:%s'", client_id, players[client_id].name);
//dbg_msg("game", "join player='%d:%s'", client_id, server_clientname(client_id));
// Check which team the player should be on
if(gameobj->gametype == GAMETYPE_DM)
@ -1570,9 +1564,10 @@ void mods_client_enter(int client_id)
players[client_id].team = gameobj->getteam(client_id);
//
msg_pack_start(MSG_SETNAME, MSGFLAG_VITAL);
/*
msg_pack_start(MSG_SETINFO, MSGFLAG_VITAL);
msg_pack_int(client_id);
msg_pack_string(players[client_id].name, 64);
msg_pack_string(server_clientname(client_id), 64);
msg_pack_end();
server_send_msg(-1);
@ -1580,26 +1575,23 @@ void mods_client_enter(int client_id)
{
if(players[client_id].client_id != -1)
{
msg_pack_start(MSG_SETNAME, MSGFLAG_VITAL);
msg_pack_start(MSG_SETINFO, MSGFLAG_VITAL);
msg_pack_int(i);
msg_pack_string(players[i].name, 64);
msg_pack_string(server_clientname(i), 64);
msg_pack_end();
server_send_msg(client_id);
}
}
}*/
char buf[512];
sprintf(buf, "%s has joined the game", players[client_id].name);
send_chat(-1, -1, buf);
}
void mods_client_drop(int client_id)
{
char buf[512];
sprintf(buf, "%s has left the game", players[client_id].name);
sprintf(buf, "%s has left the game", server_clientname(client_id));
send_chat(-1, -1, buf);
dbg_msg("game", "leave player='%d:%s'", client_id, players[client_id].name);
dbg_msg("game", "leave player='%d:%s'", client_id, server_clientname(client_id));
gameobj->on_player_death(&players[client_id], 0, -1);
world->remove_entity(&players[client_id]);
@ -1623,18 +1615,50 @@ void mods_message(int msg, int client_id)
// Switch team on given client and kill/respawn him
players[client_id].set_team(msg_unpack_int());
}
else if (msg == MSG_CHANGENAME)
else if (msg == MSG_CHANGEINFO || msg == MSG_STARTINFO)
{
const char *name = msg_unpack_string();
const char *skin_name = msg_unpack_string();
int skin_color = msg_unpack_int();
// check for invalid chars
const char *p = name;
while (*p)
if (*p++ < 32)
{
if(*p < 32)
return;
p++;
}
send_set_name(client_id, players[client_id].name, name);
strcpy(players[client_id].name, name);
//
if(msg == MSG_CHANGEINFO && strcmp(name, server_clientname(client_id)) != 0)
{
char msg[256];
sprintf(msg, "*** %s changed name to %s", server_clientname(client_id), name);
send_chat(-1, -1, msg);
}
//send_set_name(client_id, players[client_id].name, name);
strncpy(players[client_id].skin_name, skin_name, 64);
server_setclientname(client_id, name);
players[client_id].skin_color = skin_color;
if(msg == MSG_STARTINFO)
{
// send all info to this client
for(int i = 0; i < MAX_CLIENTS; i++)
{
if(players[i].client_id != -1)
send_info(i, client_id);
}
msg_pack_start(MSG_READY_TO_ENTER, MSGFLAG_VITAL);
msg_pack_end();
server_send_msg(client_id);
}
send_info(client_id, -1);
}
else if (msg == MSG_EMOTICON)
{
@ -1742,8 +1766,9 @@ void mods_init()
{*/
for(int i = 0; i < config.dbg_bots ; i++)
{
mods_connected(MAX_CLIENTS-i-1);
mods_client_enter(MAX_CLIENTS-i-1);
strcpy(players[MAX_CLIENTS-i-1].name, "(bot)");
//strcpy(players[MAX_CLIENTS-i-1].name, "(bot)");
if(gameobj->gametype != GAMETYPE_DM)
players[MAX_CLIENTS-i-1].team = i&1;
}

View file

@ -28,6 +28,7 @@ gameobject::gameobject()
sudden_death = 0;
round_start_tick = server_tick();
round_count = 0;
is_teamplay = false;
}
void gameobject::endround()

View file

@ -121,6 +121,8 @@ protected:
int warmup;
int round_count;
bool is_teamplay;
public:
int gametype;
gameobject();
@ -237,7 +239,8 @@ public:
//
int client_id;
char name[64];
char skin_name[64];
int skin_color;
// input
player_input previnput;
@ -287,7 +290,7 @@ public:
void respawn();
void set_team(int team);
bool is_grounded();
void set_weapon(int w);

View file

@ -21,6 +21,8 @@ gameobject_ctf::gameobject_ctf()
// report massive failure
}
}
is_teamplay = true;
}
void gameobject_ctf::on_player_spawn(class player *p)

View file

@ -2,6 +2,11 @@
#include "srv_common.h"
#include "srv_tdm.h"
gameobject_tdm::gameobject_tdm()
{
is_teamplay = true;
}
void gameobject_tdm::tick()
{
if(game_over_tick == -1)

View file

@ -2,5 +2,6 @@
class gameobject_tdm : public gameobject
{
public:
gameobject_tdm();
virtual void tick();
};

View file

@ -97,12 +97,12 @@ int run(int port, NETADDR4 dest)
// send and remove packet
//if((rand()%20) != 0) // heavy packetloss
// net_udp4_send(socket, &p->send_to, p->data, p->data_size);
net_udp4_send(socket, &p->send_to, p->data, p->data_size);
// update lag
double flux = rand()/(double)RAND_MAX;
int ms_spike = 0;
int ms_flux = 50;
int ms_flux = 20;
int ms_ping = 50;
current_latency = ((time_freq()*ms_ping)/1000) + (int64)(((time_freq()*ms_flux)/1000)*flux); // 50ms