static void wid_intro_create (void) { if (wid_intro) { return; } music_play_intro(); wid_intro = wid_new_window("intro"); wid_set_no_shape(wid_intro); fpoint tl = {0.0f, 0.0f}; fpoint br = {1.0f, 1.0f}; wid_set_tl_br_pct(wid_intro, tl, br); color col = BLACK; col.a = 0; glcolor(col); wid_set_mode(wid_intro, WID_MODE_NORMAL); wid_set_color(wid_intro, WID_COLOR_TL, col); wid_set_color(wid_intro, WID_COLOR_BR, col); wid_set_color(wid_intro, WID_COLOR_BG, col); wid_intro_bg_create(); wid_update(wid_intro); wid_move_to_pct_centered(wid_intro, 0.5f, 0.5f); wid_fade_in(wid_intro_title, intro_effect_delay*2); wid_intro_menu_create(); }
static void wid_intro_bg_create (void) { if (!wid_intro_title) { widp wid = wid_intro_title = wid_new_window("bg"); fpoint tl = { 0.0, 0.0 }; fpoint br = { 0.75, 0.15 }; wid_set_tl_br_pct(wid, tl, br); wid_set_tex(wid, 0, "main_title"); wid_lower(wid); color c; c = WHITE; wid_set_mode(wid, WID_MODE_NORMAL); wid_set_color(wid, WID_COLOR_TL, c); wid_set_color(wid, WID_COLOR_BR, c); wid_set_color(wid, WID_COLOR_BG, c); wid_update(wid); wid_move_to_pct_centered(wid_intro_title, 0.5f, -2.1f); wid_set_on_tick(wid, wid_intro_tick); wid_intro_tick_reset(); wid_set_do_not_lower(wid, true); } }
/* * Replace or place a tile. */ widp wid_game_map_client_replace_tile (widp w, double x, double y, thingp t, tpp tp) { tree_rootp thing_tiles; const char *tilename; tilep tile; widp child; verify(w); /* * Grow tl and br to fit the template thing. Use the first tile. */ if (!tp) { tp = thing_tp(t); if (!tp) { ERR("no thing template to replace on client"); return (0); } } if ((x < 0) || (y < 0) || (x >= MAP_WIDTH) || (y >= MAP_WIDTH)) { LOG("client: thing template [%s] cannot be placed at %f %f", tp_short_name(tp), x, y); return (0); } thing_tiles = tp_get_tiles(tp); if (!thing_tiles) { ERR("thing template [%s] has no tiles", tp_short_name(tp)); return (0); } thing_tilep thing_tile; /* * Get a random tile to start with. */ thing_tile = (typeof(thing_tile)) thing_tile_random(thing_tiles); /* * Find the real tile that corresponds to this name. */ tilename = thing_tile_name(thing_tile); tile = tile_find(tilename); if (!tile) { ERR("tile name %s from thing %s not found on client", tilename, tp_short_name(tp)); return (0); } /* * Make a new thing. */ child = wid_new_square_button(wid_game_map_client_grid_container, "client map tile"); wid_set_mode(child, WID_MODE_NORMAL); wid_set_no_shape(child); /* * "paint" the thing. */ wid_game_map_client_set_thing_template(child, tp); if (!t) { t = thing_client_local_new(tp); } wid_set_thing(child, t); wid_set_tile(child, tile); double dx = 0; double dy = 0; /* * Does it appear as a different size on screen? */ double scale = tp_get_scale(tp); /* * So we have baby and bigger slimes. But alas this is visual only and has * no effect on hp on the server yet. */ if (thing_is_variable_size(t)) { scale += gaussrand(0.0, 0.05); } if (scale != 1.0) { wid_scaling_blit_to_pct_in(child, scale, scale, 500, 9999999); } if (thing_is_cloud_effect(t)) { /* * The epicenter needs to be where it was on the server as we do a * flood fill to see where the rest of the explosion goes. */ if (!t->is_epicenter) { dx = gaussrand(0.0, 0.5); dy = gaussrand(0.0, 0.5); } wid_fade_out(child, 1000); } thing_client_wid_update(t, x + dx, y + dy, false /* smooth */, true /* is new */); /* * Offset tall things */ if (scale != 1.0) { if (thing_is_blit_y_offset(t)) { wid_set_blit_y_offset(child, wid_get_height(child) * scale * -((scale - 1.0) / 2.0)); } } /* * If this is a pre-existing thing perhaps being recreated ona new level * then it will have a direction already. Update it. */ if (thing_is_animated(t)) { thing_animate(t); } /* * This adds it to the grid wid. */ #ifdef DEBUG_CLIENT_THING wid_update(child); char name[20]; sprintf(name, "%d",t->thing_id); wid_set_text(child,name); #endif /* * We've been told about the epicenter of an explsion, now emulate the * blast. */ if (t->is_epicenter && thing_is_cloud_effect(t) ) { if ((tp->id == THING_EXPLOSION1) || (tp->id == THING_EXPLOSION2) || (tp->id == THING_EXPLOSION3) || (tp->id == THING_EXPLOSION4) || (tp->id == THING_SMALL_EXPLOSION1) || (tp->id == THING_SMALL_EXPLOSION2) || (tp->id == THING_SMALL_EXPLOSION3) || (tp->id == THING_SMALL_EXPLOSION4) || (tp->id == THING_MED_EXPLOSION1) || (tp->id == THING_MED_EXPLOSION2) || (tp->id == THING_MED_EXPLOSION3) || (tp->id == THING_MED_EXPLOSION4) || (tp->id == THING_FIREBURST1) || (tp->id == THING_FIREBURST2) || (tp->id == THING_FIREBURST3) || (tp->id == THING_FIREBURST4) || (tp->id == THING_BOMB) || (tp->id == THING_POISON1) || (tp->id == THING_POISON2) || (tp->id == THING_CLOUDKILL1) || (tp->id == THING_CLOUDKILL2)) { level_place_explosion(client_level, 0, /* owner */ tp, t->x, t->y, t->x, t->y); } else { ERR("unknown explosion %s", thing_logname(t)); } } const char *sound = tp_sound_on_creation(tp); if (sound) { if (thing_is_cloud_effect(t)) { if (t->is_epicenter) { sound_play_at(sound, t->x, t->y); } } else { sound_play_at(sound, t->x, t->y); } } return (child); }
/* * Create the wid_game_map_client */ void wid_game_map_client_wid_create (void) { if (sdl_is_exiting()) { return; } if (wid_game_map_client_window) { return; } wid_notify_flush(); LOG("Client: Create map"); { fpoint tl = {0.0f, 0.0f}; fpoint br = {1.0f, 1.0f}; wid_game_map_client_window = wid_new_square_window("wid_game_map_client"); wid_set_movable(wid_game_map_client_window, false); wid_set_do_not_raise(wid_game_map_client_window, true); wid_set_no_shape(wid_game_map_client_window); wid_set_mode(wid_game_map_client_window, WID_MODE_NORMAL); wid_set_text_advance(wid_game_map_client_window, 0.9f); wid_set_text_scaling(wid_game_map_client_window, 2.0f); wid_set_text_pos(wid_game_map_client_window, true, 0.5f, 0.10f); wid_set_text_bot(wid_game_map_client_window, true); wid_set_text_lhs(wid_game_map_client_window, true); wid_set_tl_br_pct(wid_game_map_client_window, tl, br); fsize sz = {0.0f, 0.0f}; wid_set_tex_tl(wid_game_map_client_window, sz); fsize sz2 = {1.0f, 1.0f}; wid_set_tex_br(wid_game_map_client_window, sz2); wid_set_on_key_down(wid_game_map_client_window, wid_game_map_key_event); wid_set_on_joy_down(wid_game_map_client_window, wid_game_map_joy_event); } { fpoint tl = {0.00f, 0.00f}; fpoint br = {1.00f, 1.00f}; wid_game_map_client_grid_container = wid_new_container(wid_game_map_client_window, "wid game client grid container"); wid_set_no_shape(wid_game_map_client_grid_container); wid_set_color(wid_game_map_client_grid_container, WID_COLOR_TL, BLACK); wid_set_color(wid_game_map_client_grid_container, WID_COLOR_BG, BLACK); wid_set_color(wid_game_map_client_grid_container, WID_COLOR_BR, BLACK); wid_set_on_mouse_motion(wid_game_map_client_grid_container, wid_game_map_client_receive_mouse_motion); wid_set_tl_br_pct(wid_game_map_client_grid_container, tl, br); wid_set_tex(wid_game_map_client_grid_container, 0, 0); wid_set_on_key_down(wid_game_map_client_grid_container, wid_game_map_key_event); wid_set_on_joy_down(wid_game_map_client_grid_container, wid_game_map_joy_event); LOG("Client: Created map container window"); } { double base_tile_width = ((1.0f / ((double)TILES_SCREEN_WIDTH)) * (double)global_config.video_gl_width); double base_tile_height = ((1.0f / ((double)TILES_SCREEN_HEIGHT)) * (double)global_config.video_gl_height); fpoint tl = { 0, 0 }; fpoint br = { 0, 0 }; br.x += base_tile_width; br.y += base_tile_height; client_tile_width = br.x - tl.x; client_tile_height = br.y - tl.y; client_tile_width = br.x - tl.x; client_tile_height = br.y - tl.y; if (!client_tile_width) { client_tile_width = TILE_WIDTH; } if (!client_tile_height) { client_tile_height = TILE_HEIGHT; } wid_new_grid(wid_game_map_client_grid_container, MAP_WIDTH, MAP_HEIGHT, client_tile_width, client_tile_height); LOG("Client: Created map container window grid"); } /* * Mark that we want to learn the starting stats so we can use those * when starting again with this player type. */ global_config.starting_stats_inited = false; level_pos_t level_pos = global_config.stats.level_pos; if (!level_pos.x && !level_pos.y) { level_pos.x = (myrand() % LEVEL_INITIAL_RANDOM) + 1; level_pos.y = 1; } client_level = level_new(wid_game_map_client_grid_container, level_pos, false /* is_editor */, false /* is_map_editor */, false /* on_server */); LOG("Client: Created level %d.%d", level_pos.y, level_pos.x); if (!client_level) { WARN("failed to load level %u.%u", level_pos.y, level_pos.x); } wid_game_map_client_vert_scroll = wid_new_vert_scroll_bar(wid_game_map_client_window, wid_game_map_client_grid_container); wid_game_map_client_horiz_scroll = wid_new_horiz_scroll_bar(wid_game_map_client_window, wid_game_map_client_grid_container); wid_visible(wid_get_parent(wid_game_map_client_vert_scroll), 0); wid_visible(wid_get_parent(wid_game_map_client_horiz_scroll), 0); wid_visible(wid_game_map_client_vert_scroll, 0); wid_visible(wid_game_map_client_horiz_scroll, 0); wid_update(wid_game_map_client_vert_scroll); wid_update(wid_game_map_client_horiz_scroll); wid_game_map_client_score_update(client_level, true /* redo */); wid_hide(wid_game_map_client_window, 0); if (global_config.server_current_players > 1) { wid_visible(wid_chat_window, 0); } }
void thing_dead (levelp level, thingp t, thingp killer, const char *reason, ...) { /* * If in a shop, this might be the shopkeeper. */ thingp owner = thing_owner(level, t); /* * If an arrow, this might be an elf. */ thingp real_killer = 0; if (killer) { real_killer = thing_owner(level, killer); if (!real_killer) { real_killer = killer; } } va_list args; verify(t); tpp tp = thing_tp(t); /* * If the reason of death was collection, some things we do not want * to do. */ if (!t->is_collected) { /* * When it dies, doth it polymorph and thus avoid the reaper? * e.g. a mob spawner dying and creating a smaller one. */ const char *polymorph = tp_polymorph_on_death(tp); if (thing_is_sawblade(t) && killer) { /* * Skip polymorph if there is a killer. We want the blades to * just vanish and not get more bloody. That only happens if * there is no killer and we force a polymorph. */ } else if (polymorph) { tpp what = tp_find(polymorph); if (!what) { ERR("could now find %s to polymorph into on %s death", polymorph, thing_logname(t)); } /* * It doth polymorph. */ t->tp_id = tp_to_id(what); t->hp = what->max_hp; return; } /* * Or perhaps it does die, but spawns something else, like the * player dying and creating a mob spawner. */ const char *spawn = tp_spawn_on_death(tp); if (spawn) { thingp newt = thing_mob_spawn_on_death(level, t); /* * If this is the player death then give the gravestone a lot of * health or it can be immediately killed by a lingering explosion * that killed the player too. */ if (newt && thing_is_player(t)) { newt->hp = 200; } } } /* * If a wall is gone, remove the decorations. */ if (thing_is_wall(t)) { if (!level->is_being_destroyed) { /* * Keep walls on edge of level to stop things falling off. */ if ((int)t->x <= 0) { return; } if ((int)t->x >= MAP_WIDTH-1) { return; } if ((int)t->y <= 0) { return; } if ((int)t->y >= MAP_HEIGHT-1) { return; } int dx, dy; for (dx = -1; dx <= 1; dx++) { for (dy = -1; dy <= 1; dy++) { widp w; while (map_find_wall_deco_at(level, t->x + dx, t->y + dy, &w)) { thing_destroy(level, wid_get_thing(w), __FUNCTION__); } } } } } /* * You only die once. */ if (thing_is_dead(t)) { return; } thing_set_is_dead(t, true); /* * Bounty for the killer? */ uint32_t xp = tp_get_bonus_score_on_death(tp); if (xp && real_killer) { /* * Did someone throw this weapon and gets the xp? */ int32_t val = tp_get_bonus_score_on_death(tp); if (val) { real_killer->score += val; if (thing_is_player(real_killer)) { #if 0 if (thing_is_cloud_effect(killer)) { /* * Too many packets if we kill a lot of things in one * go. * * But it looks nice... 8) */ } else { #endif MSG_SHOUT_AT(OVER_THING, t, 0, 0, "%%%%font=%s$%%%%fg=%s$+%d XP", "large", "gold", val); #if 0 } #endif } } } /* * Flash briefly red on death. */ if (thing_is_monst(t) || thing_is_mob_spawner(t) || thing_is_rock(t) || thing_is_wall(t) || thing_is_door(t)) { widp w = t->wid; if (w) { wid_set_mode(w, WID_MODE_ACTIVE); if (!wid_is_hidden(w)) { wid_set_color(w, WID_COLOR_BLIT, RED); } } } /* * Boom! If this bomb is not being collected then make it blow up. */ { #if 0 if (thing_is_treasure(t)) { CON("%s destroyed",thing_logname(t)); if (owner) { CON(" %s owner is keeper",thing_logname(owner)); } if (killer) { CON(" %s killer ",thing_logname(killer)); } if (real_killer) { CON(" %s real_killer ",thing_logname(real_killer)); } } #endif if (!t->is_collected) { if (thing_is_bomb(t) || thing_is_fireball(t) || thing_is_bullet(t)) { level_place_explosion(level, 0, /* owner */ thing_tp(t), t->x, t->y, t->x, t->y); } /* * Breaking stuff in a shop? bad idea. */ if (thing_is_treasure(t)) { if (owner && thing_is_shopkeeper(owner)) { if (thing_is_player(real_killer)) { shop_break_message(level, real_killer, owner); } else { shop_whodunnit_break_message(level, real_killer, owner); } } } } else { /* * Collecting a thing? */ if (thing_is_treasure(t)) { if (owner && thing_is_shopkeeper(owner)) { if (thing_is_player(real_killer)) { shop_collect_message(level, real_killer, t); } } } } } /* * Stop bouncing or swaying. */ if (t->wid) { if (tp_is_effect_pulse(tp)) { wid_scaling_to_pct_in(t->wid, 1.0, 1.0, 0, 0); } if (tp_is_effect_sway(tp)) { wid_rotate_to_pct_in(t->wid, 0, 0, 0, 0); } } /* * Log the means of death! */ if (reason) { va_start(args, reason); thing_dead_(level, t, dynvprintf(reason, args)); va_end(args); } else { thing_dead_(level, t, 0); } }
/* * Key down etc... */ static uint8_t wid_text_input_receive_input (widp w, const SDL_KEYSYM *key) { widp button; switch (key->sym) { case SDLK_RETURN: button = wid_find(wid_get_top_parent(w), "ok"); if (button) { wid_text_input_button_selected(button); return (true); } button = wid_find(wid_get_top_parent(w), "yes"); if (button) { wid_text_input_button_selected(button); return (true); } if (wid_text_input_button_selected(w)) { return (true); } break; case SDLK_ESCAPE: { button = wid_find(wid_get_top_parent(w), "cancel"); if (button) { wid_text_input_button_selected(button); return (true); } button = wid_find(wid_get_top_parent(w), "no"); if (button) { wid_text_input_button_selected(button); return (true); } button = wid_find(wid_get_top_parent(w), "close"); if (button) { wid_text_input_button_selected(button); return (true); } if (wid_text_input_button_selected(w)) { return (true); } break; } default: break; } /* * Feed to the general input handler */ int32_t ret = wid_receive_input(w, key); /* * Update the text_input to show only matching files. */ widp container = wid_find(wid_get_top_parent(w), wid_text_input_filelist_container_str); if (!container) { return (ret); } tree_root *r = wid_get_children(container); if (!r) { return (ret); } tree_node *n = tree_root_first(r); while (n) { fpoint container_tl; fpoint container_br; fpoint trough_tl; fpoint trough_br; double child_height; widp child; fpoint tl; fpoint br; child = (typeof(child)) n; /* * If a partial match, highlight the widget. */ if (strncmp(wid_get_text(child), wid_get_text(w), strlen(wid_get_text(w)))) { n = tree_get_next(r, r->node, n); continue; } wid_set_mode(child, WID_MODE_ACTIVE); /* * Find where the child is with respect to the parent. */ wid_get_tl_br(child, &tl, &br); wid_get_tl_br(container, &container_tl, &container_br); /* * Compare within the overall height of all children. */ wid_get_children_size(container, 0, &child_height); /* * What percentage of the way down. */ double pct = (double)(tl.y - container_tl.y) / (double)child_height; /* * Now adjust the scrollbar. */ widp scrollbar = wid_get_scrollbar_vert(container); /* * But we need the trough height. */ wid_get_tl_br(wid_get_parent(scrollbar), &trough_tl, &trough_br); double trough_height = wid_get_height(wid_get_parent(scrollbar)); /* * Now apply the same percentage as a wid move. */ wid_move_to_abs_in(scrollbar, trough_tl.x, trough_tl.y + pct * trough_height, 100); return (ret); } return (ret); }
/* * Create the wid_text_input */ widp wid_large_text_input (const char *title, double x, double y, int32_t args, ...) { widp wid_text_input_container; widp wid_text_input_title; widp wid_text_input_window; widp wid_text_input_textbox; double title_h; uint32_t toth = 0; uint32_t maxbuttonw = 0; uint32_t maxbuttonh = 0; uint32_t button_y; va_list ap; const char *button_names[args]; double maxw; double maxh; wid_text_input_callback button_callback[args]; memset(button_callback, 0, sizeof(button_callback)); { double w; fontp font = large_font; ttf_text_size(&font, "TITLE", &w, &title_h, 0, 1.0f, 1.0f, false /* fixed width */); toth += title_h; } { fontp font = large_font; ttf_text_size(&font, "xxxxxxxxxxxxxxxx", &maxw, &maxh, 0, 1.0f, 1.0f, false /* fixed width */); } maxw = min(maxw, (uint32_t) ((game.video_gl_width * 3) / 4)); { int32_t n = args; while (n--) { button_names[n] = 0; } } { va_start(ap, args); int32_t n = args; while (n--) { button_names[args - n - 1] = va_arg(ap, const char*); button_callback[args - n - 1] = va_arg(ap, wid_text_input_callback); } va_end(ap); } { int32_t n = args; while (n--) { double w; double h; const char *button_name = button_names[n]; if (!button_name){ button_name = "<bug>"; } fontp font = med_font; ttf_text_size(&font, button_name, &w, &h, 0, 1.0f, 1.0f, false /* fixed width */); w += BUTTON_PAD_X; maxbuttonw = max(w, maxbuttonw); maxbuttonh = max(h, maxbuttonh); } } { wid_text_input_window = wid_new_rounded_window("wid_text_input"); wid_set_color(wid_text_input_window, WID_COLOR_TEXT, WHITE); color c = STEELBLUE2; c.a = 200; wid_set_color(wid_text_input_window, WID_COLOR_BG, c); c = STEELBLUE; c.a = 150; wid_set_color(wid_text_input_window, WID_COLOR_TL, c); wid_set_color(wid_text_input_window, WID_COLOR_BR, c); wid_set_bevel(wid_text_input_window, 4); fpoint tl = {0, 0}; fpoint br = {0, 0}; br.x += maxw; br.y += toth; br.y += toth; br.y += toth; br.x += PAD_X; /* * Space for input box. */ br.y += maxbuttonh; button_y = br.y; br.y += maxbuttonh; wid_set_tl_br(wid_text_input_window, tl, br); } if (title) { fpoint tl = {0, 0}; fpoint br = {0, 0}; br.x += maxw + PAD_X; br.y += title_h; tl.y += title_h/2; br.y += title_h/2; wid_text_input_title = wid_new_container(wid_text_input_window, "wid text_input container1"); wid_set_tl_br(wid_text_input_title, tl, br); wid_set_font(wid_text_input_title, large_font); wid_set_text(wid_text_input_title, title); } { fpoint tl = {0, 0}; fpoint br = {0, 0}; br.x = maxw; br.y += toth; tl.x += PAD_X/2; br.x += PAD_X/2; if (title) { /* * Add space for title. */ tl.y += title_h; br.y += title_h; } wid_text_input_container = wid_new_container(wid_text_input_window, wid_text_input_filelist_container_str); wid_set_tl_br(wid_text_input_container, tl, br); } { widp child; fpoint tl = {0.0f, 0.0f}; fpoint br = {0.0f, 0.0f}; tl.x = PAD_X / 2; tl.y = button_y - maxbuttonh - PAD_Y * 4; br.x = maxw + PAD_X / 2; br.y = tl.y + maxbuttonh * 4 - PAD_Y * 2; child = wid_new_square_button(wid_text_input_window, wid_text_input_filename_input_str); wid_set_color(child, WID_COLOR_BG, BLACK); wid_set_color(child, WID_COLOR_TL, STEELBLUE); wid_set_color(child, WID_COLOR_BR, STEELBLUE); color c; c = STEELBLUE2; wid_set_mode(child, WID_MODE_NORMAL); c.a = 100; wid_set_color(child, WID_COLOR_BG, c); wid_set_mode(child, WID_MODE_OVER); c.a = 50; wid_set_color(child, WID_COLOR_BG, c); wid_set_mode(child, WID_MODE_ACTIVE); c.a = 60; wid_set_color(child, WID_COLOR_BG, c); wid_set_mode(child, WID_MODE_NORMAL); wid_set_color(child, WID_COLOR_TEXT, GREEN); wid_set_tl_br(child, tl, br); wid_set_font(child, large_font); wid_set_text_outline(child, true); wid_set_on_key_down(child, wid_text_input_receive_input); wid_set_show_cursor(child, true); wid_set_focusable(child, args + 2); wid_text_input_textbox = child; } { int32_t x = 0; int32_t n = args; int32_t focus_order = args + 1; x += maxw; x += PAD_X/2; while (n--) { double w; double h; const char *button_name = button_names[n]; fontp font = med_font; ttf_text_size(&font, button_name, &w, &h, 0, 1.0f, 1.0f, false /* fixed width */); widp child; child = wid_new_rounded_small_button(wid_text_input_window, button_name); fpoint tl; fpoint br; tl.y = button_y; br.y = tl.y + maxbuttonh; br.x = x; tl.x = br.x - maxbuttonw; x = tl.x; x -= BUTTON_PAD_X; wid_set_tl_br(child, tl, br); wid_set_text(child, button_name); wid_set_font(child, med_font); color c; if (focus_order == 1) { c = GREEN; } else if (focus_order == 2) { c = STEELBLUE2; } else if (focus_order == 3) { c = CYAN; } else { c = GRAY; } wid_set_mode(child, WID_MODE_NORMAL); c.a = 100; wid_set_color(child, WID_COLOR_BG, c); wid_set_mode(child, WID_MODE_OVER); c.a = 250; wid_set_color(child, WID_COLOR_BG, c); wid_set_mode(child, WID_MODE_NORMAL); wid_set_focusable(child, focus_order--); wid_set_on_mouse_down(child, wid_text_input_button_event); wid_set_context(child, (void*)button_callback[n]); } } wid_move_to_pct_centered(wid_text_input_window, -2.5, y); wid_fade_in(wid_text_input_window, wid_fade_delay); wid_move_to_pct_centered_in(wid_text_input_window, x, y, wid_swipe_delay); wid_raise(wid_text_input_window); wid_focus_lock(wid_text_input_window); wid_update(wid_text_input_window); return (wid_text_input_textbox); }