diff --git a/datasrc/teewars.ds b/datasrc/teewars.ds index 72b1cfcf9..94c23083e 100644 --- a/datasrc/teewars.ds +++ b/datasrc/teewars.ds @@ -220,6 +220,10 @@ images { chat_bubbles { filename "data/chatbubbles.png" } + + emoticons { + filename "data/emoticons.png" + } } particles { @@ -581,6 +585,25 @@ sprites { chatbubbles images.chat_bubbles 4 4 { chat_dotdot 0 1 1 1 } + + emoticons images.emoticons 4 4 { + oop 0 0 1 1 + exclamation 1 0 1 1 + hearts 2 0 1 1 + drop 3 0 1 1 + dotdot 0 1 1 1 + music1 1 1 1 1 + music2 2 1 1 1 + ghost 3 1 1 1 + sushi 0 2 1 1 + splattee 1 2 1 1 + deviltee 2 2 1 1 + zomg 3 2 1 1 + zzz 0 3 1 1 + blank1 1 3 1 1 + deadtee 2 3 1 1 + blank2 3 3 1 1 + } } animations { diff --git a/src/game/client/game_client.cpp b/src/game/client/game_client.cpp index 52a58ad54..8838cfec6 100644 --- a/src/game/client/game_client.cpp +++ b/src/game/client/game_client.cpp @@ -25,6 +25,7 @@ static int music_menu_id = -1; static bool chat_active = false; static bool menu_active = false; +static bool emoticon_selector_active = false; static vec2 mouse_pos; static vec2 local_player_pos; @@ -34,6 +35,8 @@ struct client_data { char name[64]; int team; + int emoticon; + int emoticon_start; } client_datas[MAX_CLIENTS]; inline float frandom() { return rand()/(float)(RAND_MAX); } @@ -523,6 +526,8 @@ void modc_entergame() { 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++) @@ -692,6 +697,22 @@ void modc_newsnapshot() } } +void send_changename_request(const char *name) +{ + msg_pack_start(MSG_CHANGENAME, MSGFLAG_VITAL); + msg_pack_string(name, 64); + msg_pack_end(); + client_send_msg(); +} + +void send_emoticon(int emoticon) +{ + msg_pack_start(MSG_EMOTICON, MSGFLAG_VITAL); + msg_pack_int(emoticon); + msg_pack_end(); + client_send_msg(); +} + static void render_projectile(const obj_projectile *prev, const obj_projectile *current, int itemid) { gfx_texture_set(data->images[IMAGE_GAME].id); @@ -1227,16 +1248,23 @@ static void render_player(const obj_player *prev, const obj_player *player) if(player->state == STATE_CHATTING) { - gfx_texture_set(data->images[IMAGE_CHAT_BUBBLES].id); gfx_quads_begin(); select_sprite(SPRITE_CHAT_DOTDOT); gfx_quads_draw(position.x + 24, position.y - 40, 64,64); gfx_quads_end(); } - -} + if (client_datas[player->clientid].emoticon_start + 2 * client_tickspeed() > client_tick()) + { + gfx_texture_set(data->images[IMAGE_EMOTICONS].id); + gfx_quads_begin(); + // client_datas::emoticon is an offset from the first emoticon + select_sprite(SPRITE_OOP + client_datas[player->clientid].emoticon); + gfx_quads_draw(position.x, position.y - 55, 64, 64); + gfx_quads_end(); + } +} void render_sun(float x, float y) { @@ -1274,6 +1302,89 @@ void render_sun(float x, float y) gfx_quads_end(); } +static bool emoticon_selector_inactive_override = false; +static int emoticon_selector_input_count = 0; +static int emoticon_selector_input_iter = 0; +static vec2 emoticon_selector_inputs[10]; + +void emoticon_selector_reset() +{ + emoticon_selector_input_count = 0; + emoticon_selector_input_iter = 0; +} + +int emoticon_selector_render() +{ + int x, y; + inp_mouse_relative(&x, &y); + + if (x || y) + { + emoticon_selector_inputs[emoticon_selector_input_iter++ % 10] = vec2(x, y); + + emoticon_selector_input_count++; + if (emoticon_selector_input_count > 10) + emoticon_selector_input_count = 10; + } + + float selected_angle = 0; + + if (emoticon_selector_input_count > 5) + { + vec2 sum; + + for (int i = 0; i < emoticon_selector_input_count; i++) + sum += emoticon_selector_inputs[i]; + + selected_angle = get_angle(normalize(sum)); + if (selected_angle < 0) + selected_angle += 2*pi; + } + + static bool mouse_down = false; + int emoticon_selected = -1; + bool return_now = false; + + if (inp_key_pressed(baselib::input::mouse_1)) + { + mouse_down = true; + } + else if (mouse_down) + { + return_now = true; + mouse_down = false; + emoticon_selector_active = false; + emoticon_selector_inactive_override = true; + } + + gfx_mapscreen(0,0,400,300); + + gfx_texture_set(data->images[IMAGE_EMOTICONS].id); + gfx_quads_begin(); + + for (int i = 0; i < 16; i++) + { + float angle = 2*pi*i/16.0; + float diff = fabs(selected_angle-angle); + + bool selected = diff < pi/16; + + if (return_now && selected) + emoticon_selected = i; + + float size = selected ? 48 : 32; + + float nudge_x = 60 * cos(angle); + float nudge_y = 60 * sin(angle); + select_sprite(SPRITE_OOP + i); + gfx_quads_draw(200 + nudge_x, 150 + nudge_y, size, size); + } + + gfx_quads_end(); + + return emoticon_selected; +} + void render_game() { animstate idlestate; @@ -1350,7 +1461,7 @@ void render_game() } // fetch new input - if(!menu_active) + if(!menu_active && (!emoticon_selector_active || emoticon_selector_inactive_override)) { int x, y; inp_mouse_relative(&x, &y); @@ -1379,7 +1490,8 @@ void render_game() input.left = inp_key_pressed(config.key_move_left); input.right = inp_key_pressed(config.key_move_right); input.jump = inp_key_pressed(config.key_jump); - input.fire = inp_key_pressed(config.key_fire); + // TODO: this is not very well done. it should check this some other way + input.fire = emoticon_selector_active ? 0 : inp_key_pressed(config.key_fire); input.hook = inp_key_pressed(config.key_hook); //input.blink = inp_key_pressed('S'); @@ -1728,6 +1840,27 @@ void render_game() //ingamemenu_render(); return; } + + if (inp_key_pressed('E')) + { + if (!emoticon_selector_active) + { + emoticon_selector_active = true; + emoticon_selector_reset(); + } + } + else + { + emoticon_selector_active = false; + emoticon_selector_inactive_override = false; + } + + if (emoticon_selector_active && !emoticon_selector_inactive_override) + { + int emoticon = emoticon_selector_render(); + if (emoticon != -1) + send_emoticon(emoticon); + } // render score board if(inp_key_pressed(baselib::input::tab) || // user requested @@ -1990,7 +2123,7 @@ void modc_message(int msg) const char *message = msg_unpack_string(); dbg_msg("message", "chat cid=%d msg='%s'", cid, message); chat_add_line(cid, message); - + if(cid >= 0) snd_play(data->sounds[SOUND_CHAT_CLIENT].sounds[0].id, SND_PLAY_ONCE, 1.0f, 0.0f); else @@ -2010,4 +2143,11 @@ void modc_message(int msg) killmsgs[killmsg_current].weapon = msg_unpack_int(); killmsgs[killmsg_current].tick = client_tick(); } + else if (msg == MSG_EMOTICON) + { + int cid = msg_unpack_int(); + int emoticon = msg_unpack_int(); + client_datas[cid].emoticon = emoticon; + client_datas[cid].emoticon_start = client_tick(); + } } diff --git a/src/game/client/menu.cpp b/src/game/client/menu.cpp index b5cbc1b63..b2a4fbb84 100644 --- a/src/game/client/menu.cpp +++ b/src/game/client/menu.cpp @@ -974,6 +974,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); static int settings_render(bool ingame) { @@ -1013,6 +1014,10 @@ static int settings_render(bool ingame) static int save_button; if (ui_do_button(&save_button, "Save", 0, 482, 490, 128, 48, draw_teewars_button)) { + // did we change our name? + if (ingame && strcmp(config.player_name, config_copy.player_name) != 0) + send_changename_request(config_copy.player_name); + config = config_copy; #ifdef CONF_PLATFORM_MACOSX config_save("~/.teewars"); diff --git a/src/game/game.h b/src/game/game.h index ef2007a9a..855e964b5 100644 --- a/src/game/game.h +++ b/src/game/game.h @@ -53,6 +53,8 @@ enum MSG_SWITCHTEAM, MSG_JOIN, MSG_QUIT, + MSG_EMOTICON, + MSG_CHANGENAME, }; enum diff --git a/src/game/server/game_server.cpp b/src/game/server/game_server.cpp index 54e6f32f8..82141d63d 100644 --- a/src/game/server/game_server.cpp +++ b/src/game/server/game_server.cpp @@ -1987,6 +1987,28 @@ void send_chat_all(int cid, const char *msg) server_send_msg(-1); } +void send_set_name(int cid, const char *old_name, const char *new_name) +{ + msg_pack_start(MSG_SETNAME, MSGFLAG_VITAL); + msg_pack_int(cid); + msg_pack_string(new_name, 64); + msg_pack_end(); + server_send_msg(-1); + + char msg[256]; + sprintf(msg, "*** %s changed name to %s", old_name, new_name); + send_chat_all(-1, msg); +} + +void send_emoticon(int cid, int emoticon) +{ + msg_pack_start(MSG_EMOTICON, MSGFLAG_VITAL); + msg_pack_int(cid); + msg_pack_int(emoticon % 16); + msg_pack_end(); + server_send_msg(-1); +} + void mods_client_enter(int client_id) { players[client_id].init(); @@ -1994,7 +2016,6 @@ void mods_client_enter(int client_id) world.insert_entity(&players[client_id]); players[client_id].respawn(); - client_info info; // fetch login name if(server_getclientinfo(client_id, &info)) { @@ -2060,6 +2081,24 @@ void mods_message(int msg, int client_id) players[client_id].die(client_id, -1); players[client_id].score--; } + else if (msg == MSG_CHANGENAME) + { + const char *name = msg_unpack_string(); + + // check for invalid chars + const char *p = name; + while (*p) + if (*p++ < 32) + return; + + send_set_name(client_id, players[client_id].name, name); + strcpy(players[client_id].name, name); + } + else if (msg == MSG_EMOTICON) + { + int emoteicon = msg_unpack_int(); + send_emoticon(client_id, emoteicon % 16); + } } extern unsigned char internal_data[]; @@ -2119,7 +2158,7 @@ void mods_init() if(type != -1) { // LOL, the only new in the entire game code - // perhaps we can get rid of it. seams like a stupid thing to have + // perhaps we can get rid of it. seems like a stupid thing to have powerup *ppower = new powerup(type, subtype); ppower->pos = vec2(it->x, it->y); }