larger update. reduced the amount of video memory used from ~60 to ~36mb on a typical map
BIN
data/cloud-1.png
Before Width: | Height: | Size: 26 KiB |
BIN
data/cloud-2.png
Before Width: | Height: | Size: 25 KiB |
BIN
data/cloud-3.png
Before Width: | Height: | Size: 9.6 KiB |
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 51 KiB |
BIN
data/demo.map
BIN
data/dm2.map
Before Width: | Height: | Size: 167 KiB |
BIN
data/game.png
Normal file
After Width: | Height: | Size: 79 KiB |
Before Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 239 B |
Before Width: | Height: | Size: 249 B |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 410 B |
Before Width: | Height: | Size: 470 B |
Before Width: | Height: | Size: 410 B |
Before Width: | Height: | Size: 430 B |
Before Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 581 B |
Before Width: | Height: | Size: 7.1 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 722 B |
Before Width: | Height: | Size: 791 B |
Before Width: | Height: | Size: 130 B |
Before Width: | Height: | Size: 190 B |
Before Width: | Height: | Size: 556 B |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 533 B |
BIN
data/gui_bg.png
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 62 KiB |
BIN
data/maps/dm1.map
Normal file
BIN
data/maps/dm2.map
Normal file
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 67 KiB |
Before Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 78 KiB |
|
@ -144,16 +144,8 @@ sounds {
|
|||
|
||||
|
||||
images {
|
||||
weapons {
|
||||
filename "data/tileset_weapons.png"
|
||||
}
|
||||
|
||||
game {
|
||||
filename "data/game_main.png"
|
||||
}
|
||||
|
||||
particles {
|
||||
filename "data/tileset_particles.png"
|
||||
filename "data/game.png"
|
||||
}
|
||||
|
||||
sun {
|
||||
|
@ -169,7 +161,7 @@ images {
|
|||
}
|
||||
|
||||
gui_widgets {
|
||||
filename "data/gui/gui_widgets.png"
|
||||
filename "data/gui_widgets.png"
|
||||
}
|
||||
|
||||
menu_background {
|
||||
|
@ -181,23 +173,15 @@ images {
|
|||
}
|
||||
|
||||
cursor {
|
||||
filename "data/gui/cursor.png"
|
||||
filename "data/gui_cursor.png"
|
||||
}
|
||||
|
||||
banner {
|
||||
filename "data/gui_logo.png"
|
||||
}
|
||||
|
||||
cloud_1 {
|
||||
filename "data/cloud-1.png"
|
||||
}
|
||||
|
||||
cloud_2 {
|
||||
filename "data/cloud-2.png"
|
||||
}
|
||||
|
||||
cloud_3 {
|
||||
filename "data/cloud-3.png"
|
||||
clouds {
|
||||
filename "data/cloudmap.png"
|
||||
}
|
||||
|
||||
chat_bubbles {
|
||||
|
@ -207,55 +191,55 @@ images {
|
|||
|
||||
particles {
|
||||
part1 {
|
||||
sprite sprites.particles.part1
|
||||
sprite sprites.game.part1
|
||||
color 0.7 0.7 0.7 1.0
|
||||
life 50
|
||||
}
|
||||
|
||||
part2 {
|
||||
sprite sprites.particles.part2
|
||||
sprite sprites.game.part2
|
||||
color 1.0 1.0 1.0 1.0
|
||||
life 50
|
||||
}
|
||||
|
||||
part3 {
|
||||
sprite sprites.particles.part3
|
||||
sprite sprites.game.part3
|
||||
color 0.8 0.8 0.8 1.0
|
||||
life 50
|
||||
}
|
||||
|
||||
part4 {
|
||||
sprite sprites.particles.part4
|
||||
sprite sprites.game.part4
|
||||
color 0.98 0.1 0.16 1.0
|
||||
life 70
|
||||
}
|
||||
|
||||
part5 {
|
||||
sprite sprites.particles.part5
|
||||
sprite sprites.game.part5
|
||||
color 1.0 1.0 1.0 1.0
|
||||
life 70
|
||||
}
|
||||
|
||||
part6 {
|
||||
sprite sprites.particles.part6
|
||||
sprite sprites.game.part6
|
||||
color 0.6 0.6 0.6 1.0
|
||||
life 100
|
||||
}
|
||||
|
||||
part7 {
|
||||
sprite sprites.particles.part7
|
||||
sprite sprites.game.part7
|
||||
color 1.0 1.0 1.0 1.0
|
||||
life 100
|
||||
}
|
||||
|
||||
part8 {
|
||||
sprite sprites.particles.part8
|
||||
sprite sprites.game.part8
|
||||
color 0.7 0.7 0.7 1.0
|
||||
life 150
|
||||
}
|
||||
|
||||
part9 {
|
||||
sprite sprites.particles.part9
|
||||
sprite sprites.game.part9
|
||||
color 1.0 1.0 1.0 1.0
|
||||
life 40
|
||||
}
|
||||
|
@ -315,13 +299,13 @@ projectileparticles {
|
|||
|
||||
weapons {
|
||||
gun {
|
||||
sprite_body sprites.weapons.weapon_gun_body
|
||||
sprite_cursor sprites.weapons.weapon_gun_cursor
|
||||
sprite_proj sprites.weapons.weapon_gun_proj
|
||||
sprite_body sprites.game.weapon_gun_body
|
||||
sprite_cursor sprites.game.weapon_gun_cursor
|
||||
sprite_proj sprites.game.weapon_gun_proj
|
||||
sprite_muzzles {
|
||||
sprites.weapons.weapon_gun_muzzle1
|
||||
sprites.weapons.weapon_gun_muzzle2
|
||||
sprites.weapons.weapon_gun_muzzle3
|
||||
sprites.game.weapon_gun_muzzle1
|
||||
sprites.game.weapon_gun_muzzle2
|
||||
sprites.game.weapon_gun_muzzle3
|
||||
}
|
||||
|
||||
nummuzzlesprites 3
|
||||
|
@ -343,9 +327,9 @@ weapons {
|
|||
}
|
||||
|
||||
rocket {
|
||||
sprite_body sprites.weapons.weapon_rocket_body
|
||||
sprite_cursor sprites.weapons.weapon_rocket_cursor
|
||||
sprite_proj sprites.weapons.weapon_rocket_proj
|
||||
sprite_body sprites.game.weapon_rocket_body
|
||||
sprite_cursor sprites.game.weapon_rocket_cursor
|
||||
sprite_proj sprites.game.weapon_rocket_proj
|
||||
sprite_muzzles {
|
||||
}
|
||||
|
||||
|
@ -368,13 +352,13 @@ weapons {
|
|||
}
|
||||
|
||||
shotgun {
|
||||
sprite_body sprites.weapons.weapon_shotgun_body
|
||||
sprite_cursor sprites.weapons.weapon_shotgun_cursor
|
||||
sprite_proj sprites.weapons.weapon_shotgun_proj
|
||||
sprite_body sprites.game.weapon_shotgun_body
|
||||
sprite_cursor sprites.game.weapon_shotgun_cursor
|
||||
sprite_proj sprites.game.weapon_shotgun_proj
|
||||
sprite_muzzles {
|
||||
sprites.weapons.weapon_shotgun_muzzle1
|
||||
sprites.weapons.weapon_shotgun_muzzle2
|
||||
sprites.weapons.weapon_shotgun_muzzle3
|
||||
sprites.game.weapon_shotgun_muzzle1
|
||||
sprites.game.weapon_shotgun_muzzle2
|
||||
sprites.game.weapon_shotgun_muzzle3
|
||||
}
|
||||
|
||||
nummuzzlesprites 3
|
||||
|
@ -396,9 +380,9 @@ weapons {
|
|||
}
|
||||
|
||||
hammer {
|
||||
sprite_body sprites.weapons.weapon_hammer_body
|
||||
sprite_cursor sprites.weapons.weapon_hammer_cursor
|
||||
sprite_proj sprites.weapons.weapon_hammer_proj
|
||||
sprite_body sprites.game.weapon_hammer_body
|
||||
sprite_cursor sprites.game.weapon_hammer_cursor
|
||||
sprite_proj sprites.game.weapon_hammer_proj
|
||||
sprite_muzzles {
|
||||
}
|
||||
|
||||
|
@ -420,9 +404,9 @@ weapons {
|
|||
velocity 0
|
||||
}
|
||||
rocket_backpack {
|
||||
sprite_body sprites.weapons.weapon_hammer_body
|
||||
sprite_cursor sprites.weapons.weapon_hammer_cursor
|
||||
sprite_proj sprites.weapons.weapon_hammer_proj
|
||||
sprite_body sprites.game.weapon_hammer_body
|
||||
sprite_cursor sprites.game.weapon_hammer_cursor
|
||||
sprite_proj sprites.game.weapon_hammer_proj
|
||||
sprite_muzzles {
|
||||
}
|
||||
|
||||
|
@ -444,13 +428,13 @@ weapons {
|
|||
velocity 0
|
||||
}
|
||||
ninja {
|
||||
sprite_body sprites.weapons.weapon_ninja_body
|
||||
sprite_cursor sprites.weapons.weapon_ninja_cursor
|
||||
sprite_proj sprites.weapons.weapon_ninja_proj
|
||||
sprite_body sprites.game.weapon_ninja_body
|
||||
sprite_cursor sprites.game.weapon_ninja_cursor
|
||||
sprite_proj sprites.game.weapon_ninja_proj
|
||||
sprite_muzzles {
|
||||
sprites.weapons.hadoken1
|
||||
sprites.weapons.hadoken2
|
||||
sprites.weapons.hadoken3
|
||||
sprites.game.hadoken1
|
||||
sprites.game.hadoken2
|
||||
sprites.game.hadoken3
|
||||
}
|
||||
|
||||
nummuzzlesprites 3
|
||||
|
@ -473,30 +457,33 @@ weapons {
|
|||
}
|
||||
|
||||
sprites {
|
||||
|
||||
particles images.particles 16 16 {
|
||||
part1 2 0 2 2
|
||||
part2 4 0 2 2
|
||||
part3 6 0 2 2
|
||||
part4 8 0 2 2
|
||||
part5 10 0 2 2
|
||||
part6 2 2 2 2
|
||||
part7 4 2 2 2
|
||||
part8 6 2 2 2
|
||||
part9 8 2 2 2
|
||||
coulds images.clouds 16 16 {
|
||||
cloud1 0 0 16 7
|
||||
cloud2 0 7 11 8
|
||||
cloud3 11 7 5 5
|
||||
}
|
||||
|
||||
hud images.game 32 16 {
|
||||
health_full 0 0 4 4
|
||||
health_empty 5 0 4 4
|
||||
armor_full 0 5 4 4
|
||||
armor_empty 5 5 4 4
|
||||
star1 0 10 3 3
|
||||
star2 3 10 3 3
|
||||
star3 6 10 3 3
|
||||
}
|
||||
game images.game 32 16 {
|
||||
|
||||
health_full 21 0 2 2
|
||||
health_empty 23 0 2 2
|
||||
armor_full 21 2 2 2
|
||||
armor_empty 23 2 2 2
|
||||
|
||||
star1 15 0 2 2
|
||||
star2 17 0 2 2
|
||||
star3 19 0 2 2
|
||||
|
||||
part1 6 0 1 1
|
||||
part2 6 1 1 1
|
||||
part3 7 0 1 1
|
||||
part4 7 1 1 1
|
||||
part5 8 0 1 1
|
||||
part6 8 1 1 1
|
||||
part7 9 0 2 2
|
||||
part8 11 0 2 2
|
||||
part9 13 0 2 2
|
||||
|
||||
weapons images.weapons 32 32 {
|
||||
weapon_gun_body 2 4 4 2
|
||||
weapon_gun_cursor 0 4 2 2
|
||||
weapon_gun_proj 6 4 2 2
|
||||
|
@ -526,12 +513,10 @@ sprites {
|
|||
hook_chain 2 0 1 1
|
||||
hook_head 3 0 2 1
|
||||
|
||||
hadoken1 1 12 7 4
|
||||
hadoken2 8 12 8 4
|
||||
hadoken3 17 12 7 4
|
||||
}
|
||||
|
||||
powerups images.weapons 32 32 {
|
||||
hadoken1 25 0 7 4
|
||||
hadoken2 25 4 7 4
|
||||
hadoken3 25 8 7 4
|
||||
|
||||
powerup_health 10 2 2 2
|
||||
powerup_armor 12 2 2 2
|
||||
powerup_weapon 3 0 6 2
|
||||
|
|
|
@ -278,11 +278,34 @@ static int tilesets_new()
|
|||
}
|
||||
|
||||
|
||||
static void tilesets_delete(int index)
|
||||
{
|
||||
// remove the tileset
|
||||
if(tilesets[index].tex_id >= 0)
|
||||
gfx_unload_texture(tilesets[index].tex_id);
|
||||
|
||||
for(int i = index; i < num_tilesets-1; i++)
|
||||
tilesets[i] = tilesets[i+1];
|
||||
num_tilesets--;
|
||||
|
||||
// adjust
|
||||
for(int i = 0; i < layers_count(); i++)
|
||||
{
|
||||
if(layers_get(i)->tileset_id == index)
|
||||
layers_get(i)->tileset_id = -1;
|
||||
else if(layers_get(i)->tileset_id > index)
|
||||
layers_get(i)->tileset_id--;
|
||||
}
|
||||
}
|
||||
|
||||
static void tilesets_clear()
|
||||
{
|
||||
// TODO: remove texture aswell
|
||||
for(int i = 0; i < num_tilesets; i++)
|
||||
mem_free(tilesets[num_tilesets].img.data);
|
||||
{
|
||||
if(tilesets[i].tex_id >= 0)
|
||||
gfx_unload_texture(tilesets[i].tex_id);
|
||||
mem_free(tilesets[i].img.data);
|
||||
}
|
||||
num_tilesets = 0;
|
||||
|
||||
}
|
||||
|
@ -795,23 +818,31 @@ static void editor_render()
|
|||
{
|
||||
char buf[128];
|
||||
sprintf(buf, "#%d %dx%d", i, tilesets_get(i)->img.width, tilesets_get(i)->img.height);
|
||||
if(ui_do_button(&tilesets_get(i)->img, "L", layers_get(current_layer)->tileset_id == i, tilesetsbox_x, tilesetsbox_y+i*7, 6, 6, draw_editor_button))
|
||||
if(ui_do_button(&tilesets_get(i)->img.width, "L", layers_get(current_layer)->tileset_id == i, tilesetsbox_x, tilesetsbox_y+i*7, 6, 6, draw_editor_button))
|
||||
{
|
||||
// load image
|
||||
editor_loadimage = i;
|
||||
}
|
||||
|
||||
if(ui_do_button(tilesets_get(i), buf, layers_get(current_layer)->tileset_id == i, tilesetsbox_x+8, tilesetsbox_y+i*7, toolbox_width-8, 6, draw_editor_button))
|
||||
|
||||
if(ui_do_button(tilesets_get(i), buf, layers_get(current_layer)->tileset_id == i, tilesetsbox_x+16, tilesetsbox_y+i*7, toolbox_width-16, 6, draw_editor_button))
|
||||
{
|
||||
// select tileset for layer
|
||||
dbg_msg("editor", "settings tileset %d=i", current_layer, i);
|
||||
dbg_msg("editor", "settings tileset %d=%d", current_layer, i);
|
||||
layers_get(current_layer)->tileset_id = i;
|
||||
}
|
||||
|
||||
if(ui_do_button(&tilesets_get(i)->img.height, "D", layers_get(current_layer)->tileset_id == i, tilesetsbox_x+8, tilesetsbox_y+i*7, 6, 6, draw_editor_button)
|
||||
&& (inp_key_pressed(input::lctrl) || inp_key_pressed(input::rctrl)))
|
||||
{
|
||||
dbg_msg("editor", "deleting tileset %d", i);
|
||||
tilesets_delete(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
// (add) button for tilesets
|
||||
static int load_tileset;
|
||||
if(ui_do_button(&load_tileset, "(Add)", 0, tilesetsbox_x, tilesetsbox_y+tilesets_count()*7+3, toolbox_width, 6, draw_editor_button))
|
||||
static int add_tileset;
|
||||
if(ui_do_button(&add_tileset, "(Add)", 0, tilesetsbox_x, tilesetsbox_y+tilesets_count()*7+3, toolbox_width, 6, draw_editor_button))
|
||||
tilesets_new();
|
||||
|
||||
if(brush.tiles != 0)
|
||||
|
|
|
@ -15,16 +15,29 @@
|
|||
#include "ui.h"
|
||||
|
||||
#include <engine/compression.h>
|
||||
|
||||
#include <engine/network.h>
|
||||
#include <engine/versions.h>
|
||||
#include <engine/config.h>
|
||||
//#include <engine/network.h>
|
||||
|
||||
#include <mastersrv/mastersrv.h>
|
||||
#include "client.h"
|
||||
|
||||
using namespace baselib;
|
||||
|
||||
static int info_request_begin;
|
||||
static int info_request_end;
|
||||
static int snapshot_part;
|
||||
static int64 local_start_time;
|
||||
static int64 game_start_time;
|
||||
static int current_tick;
|
||||
static float latency = 0;
|
||||
static int extra_polating = 0;
|
||||
static int debug_font;
|
||||
static float frametime = 0.0001f;
|
||||
static net_client net;
|
||||
static netaddr4 master_server;
|
||||
static netaddr4 server_address;
|
||||
static const char *server_spam_address=0;
|
||||
|
||||
// --- input wrappers ---
|
||||
static int keyboard_state[2][input::last];
|
||||
static int keyboard_current = 0;
|
||||
|
@ -135,15 +148,11 @@ static void client_snapshot_purge_until(int tick)
|
|||
}
|
||||
|
||||
static snapshot_info *snapshots[NUM_SNAPSHOT_TYPES];
|
||||
static int current_tick;
|
||||
static int recived_snapshots;
|
||||
static int64 snapshot_start_time;
|
||||
static int64 local_start_time;
|
||||
static int64 game_start_time;
|
||||
static float latency = 0;
|
||||
static int extra_polating = 0;
|
||||
static char snapshot_incomming_data[MAX_SNAPSHOT_SIZE];
|
||||
|
||||
// ---
|
||||
float client_localtime()
|
||||
{
|
||||
return (time_get()-local_start_time)/(float)(time_freq());
|
||||
|
@ -173,6 +182,7 @@ static void snap_init()
|
|||
|
||||
}
|
||||
|
||||
// ------ time functions ------
|
||||
float client_intratick()
|
||||
{
|
||||
return (time_get() - snapshot_start_time)/(float)(time_freq()/SERVER_TICK_SPEED);
|
||||
|
@ -188,6 +198,11 @@ int client_tickspeed()
|
|||
return SERVER_TICK_SPEED;
|
||||
}
|
||||
|
||||
float client_frametime()
|
||||
{
|
||||
return frametime;
|
||||
}
|
||||
|
||||
void *snap_find_item(int snapid, int type, int id)
|
||||
{
|
||||
// TODO: linear search. should be fixed.
|
||||
|
@ -200,17 +215,9 @@ void *snap_find_item(int snapid, int type, int id)
|
|||
return 0x0;
|
||||
}
|
||||
|
||||
|
||||
int menu_loop(); // TODO: what is this?
|
||||
static float frametime = 0.0001f;
|
||||
|
||||
float client_frametime()
|
||||
{
|
||||
return frametime;
|
||||
}
|
||||
|
||||
static net_client net;
|
||||
|
||||
// ----- send functions -----
|
||||
int client_send_msg()
|
||||
{
|
||||
const msg_info *info = msg_get_info();
|
||||
|
@ -228,6 +235,53 @@ int client_send_msg()
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void client_send_info()
|
||||
{
|
||||
recived_snapshots = 0;
|
||||
game_start_time = -1;
|
||||
|
||||
msg_pack_start_system(NETMSG_INFO, MSGFLAG_VITAL);
|
||||
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);
|
||||
msg_pack_end();
|
||||
client_send_msg();
|
||||
}
|
||||
|
||||
static void client_send_error(const char *error)
|
||||
{
|
||||
/*
|
||||
pack(NETMSG_CLIENT_ERROR, "s", error);
|
||||
*/
|
||||
/*
|
||||
packet p(NETMSG_CLIENT_ERROR);
|
||||
p.write_str(error);
|
||||
send_packet(&p);
|
||||
//send_packet(&p);
|
||||
//send_packet(&p);
|
||||
*/
|
||||
}
|
||||
|
||||
static void client_send_input()
|
||||
{
|
||||
msg_pack_start_system(NETMSG_INPUT, 0);
|
||||
msg_pack_int(input_data_size);
|
||||
for(int i = 0; i < input_data_size/4; i++)
|
||||
msg_pack_int(input_data[i]);
|
||||
msg_pack_end();
|
||||
client_send_msg();
|
||||
}
|
||||
|
||||
|
||||
// ------ server browse ----
|
||||
static struct
|
||||
{
|
||||
server_info infos[MAX_SERVERS];
|
||||
|
@ -237,15 +291,13 @@ static struct
|
|||
} servers;
|
||||
static int serverlist_lan = 1;
|
||||
|
||||
static netaddr4 master_server;
|
||||
|
||||
int client_serverbrowse_getlist(server_info **serverlist)
|
||||
{
|
||||
*serverlist = servers.infos;
|
||||
return servers.num;
|
||||
}
|
||||
|
||||
void client_serverbrowse_init()
|
||||
static void client_serverbrowse_init()
|
||||
{
|
||||
servers.num = 0;
|
||||
}
|
||||
|
@ -288,6 +340,46 @@ void client_serverbrowse_refresh(int lan)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
static void client_serverbrowse_request(int id)
|
||||
{
|
||||
dbg_msg("client", "requesting server info from %d.%d.%d.%d:%d",
|
||||
servers.addresses[id].ip[0], servers.addresses[id].ip[1], servers.addresses[id].ip[2],
|
||||
servers.addresses[id].ip[3], servers.addresses[id].port);
|
||||
NETPACKET packet;
|
||||
packet.client_id = -1;
|
||||
packet.address = servers.addresses[id];
|
||||
packet.flags = PACKETFLAG_CONNLESS;
|
||||
packet.data_size = sizeof(SERVERBROWSE_GETINFO);
|
||||
packet.data = SERVERBROWSE_GETINFO;
|
||||
net.send(&packet);
|
||||
servers.request_times[id] = time_get();
|
||||
}
|
||||
|
||||
static void client_serverbrowse_update()
|
||||
{
|
||||
int64 timeout = time_freq();
|
||||
int64 now = time_get();
|
||||
int max_requests = 10;
|
||||
|
||||
// timeout old requests
|
||||
while(info_request_begin < servers.num && info_request_begin < info_request_end)
|
||||
{
|
||||
if(now > servers.request_times[info_request_begin]+timeout)
|
||||
info_request_begin++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
// send new requests
|
||||
while(info_request_end < servers.num && info_request_end-info_request_begin < max_requests)
|
||||
{
|
||||
client_serverbrowse_request(info_request_end);
|
||||
info_request_end++;
|
||||
}
|
||||
}
|
||||
|
||||
// ------ state handling -----
|
||||
enum
|
||||
{
|
||||
STATE_OFFLINE,
|
||||
|
@ -298,12 +390,9 @@ enum
|
|||
STATE_QUIT,
|
||||
};
|
||||
|
||||
static netaddr4 server_address;
|
||||
static const char *server_spam_address=0;
|
||||
|
||||
static int state;
|
||||
static int get_state() { return state; }
|
||||
static void set_state(int s)
|
||||
static int client_get_state() { return state; }
|
||||
static void client_set_state(int s)
|
||||
{
|
||||
dbg_msg("game", "state change. last=%d current=%d", state, s);
|
||||
state = s;
|
||||
|
@ -335,71 +424,24 @@ void client_connect(const char *server_address_str)
|
|||
dbg_msg("client", "could not find the address of %s, connecting to localhost", buf);
|
||||
|
||||
net.connect(&server_address);
|
||||
set_state(STATE_CONNECTING);
|
||||
client_set_state(STATE_CONNECTING);
|
||||
}
|
||||
|
||||
// --- client ---
|
||||
// TODO: remove this class
|
||||
void client::send_info()
|
||||
void client_disconnect()
|
||||
{
|
||||
recived_snapshots = 0;
|
||||
game_start_time = -1;
|
||||
|
||||
msg_pack_start_system(NETMSG_INFO, MSGFLAG_VITAL);
|
||||
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();
|
||||
}
|
||||
|
||||
void client::send_entergame()
|
||||
{
|
||||
msg_pack_start_system(NETMSG_ENTERGAME, MSGFLAG_VITAL);
|
||||
msg_pack_end();
|
||||
client_send_msg();
|
||||
}
|
||||
|
||||
void client::send_error(const char *error)
|
||||
{
|
||||
/*
|
||||
pack(NETMSG_CLIENT_ERROR, "s", error);
|
||||
*/
|
||||
/*
|
||||
packet p(NETMSG_CLIENT_ERROR);
|
||||
p.write_str(error);
|
||||
send_packet(&p);
|
||||
//send_packet(&p);
|
||||
//send_packet(&p);
|
||||
*/
|
||||
}
|
||||
|
||||
void client::send_input()
|
||||
{
|
||||
msg_pack_start_system(NETMSG_INPUT, 0);
|
||||
msg_pack_int(input_data_size);
|
||||
for(int i = 0; i < input_data_size/4; i++)
|
||||
msg_pack_int(input_data[i]);
|
||||
msg_pack_end();
|
||||
client_send_msg();
|
||||
}
|
||||
|
||||
void client::disconnect()
|
||||
{
|
||||
send_error("disconnected");
|
||||
client_send_error("disconnected");
|
||||
net.disconnect("disconnected");
|
||||
set_state(STATE_OFFLINE);
|
||||
client_set_state(STATE_OFFLINE);
|
||||
map_unload();
|
||||
}
|
||||
|
||||
bool client::load_data()
|
||||
static bool client_load_data()
|
||||
{
|
||||
debug_font = gfx_load_texture("data/debug_font.png");
|
||||
return true;
|
||||
}
|
||||
extern int memory_alloced;
|
||||
void client::debug_render()
|
||||
|
||||
static void client_debug_render()
|
||||
{
|
||||
if(!config.debug)
|
||||
return;
|
||||
|
@ -420,36 +462,38 @@ void client::debug_render()
|
|||
static float frametime_avg = 0;
|
||||
frametime_avg = frametime_avg*0.9f + frametime*0.1f;
|
||||
char buffer[512];
|
||||
sprintf(buffer, "send: %6d recv: %6d latency: %4.0f %c fps: %d",
|
||||
sprintf(buffer, "send: %6d recv: %6d latency: %4.0f %c gfxmem: %6dk fps: %3d",
|
||||
(current.send_bytes-prev.send_bytes)*10,
|
||||
(current.recv_bytes-prev.recv_bytes)*10,
|
||||
latency*1000.0f, extra_polating?'E':' ', (int)(1.0f/frametime_avg));
|
||||
latency*1000.0f, extra_polating?'E':' ',
|
||||
gfx_memory_usage()/1024,
|
||||
(int)(1.0f/frametime_avg));
|
||||
gfx_quads_text(2, 2, 16, buffer);
|
||||
|
||||
}
|
||||
|
||||
void client::render()
|
||||
static void client_render()
|
||||
{
|
||||
gfx_clear(0.0f,0.0f,0.0f);
|
||||
|
||||
// this should be moved around abit
|
||||
// TODO: clean this shit up!
|
||||
if(get_state() == STATE_ONLINE)
|
||||
if(client_get_state() == STATE_ONLINE)
|
||||
{
|
||||
modc_render();
|
||||
|
||||
// debug render stuff
|
||||
debug_render();
|
||||
client_debug_render();
|
||||
|
||||
}
|
||||
else if (get_state() != STATE_CONNECTING && get_state() != STATE_LOADING)
|
||||
else if (client_get_state() != STATE_CONNECTING && client_get_state() != STATE_LOADING)
|
||||
{
|
||||
//netaddr4 server_address;
|
||||
int status = modmenu_render();
|
||||
if (status == -1)
|
||||
set_state(STATE_QUIT);
|
||||
client_set_state(STATE_QUIT);
|
||||
}
|
||||
else if (get_state() == STATE_CONNECTING || get_state() == STATE_LOADING)
|
||||
else if (client_get_state() == STATE_CONNECTING || client_get_state() == STATE_LOADING)
|
||||
{
|
||||
static int64 start = time_get();
|
||||
static int tee_texture;
|
||||
|
@ -459,7 +503,7 @@ void client::render()
|
|||
if (!inited)
|
||||
{
|
||||
tee_texture = gfx_load_texture("data/gui_tee.png");
|
||||
connecting_texture = gfx_load_texture("data/gui/connecting.png");
|
||||
connecting_texture = gfx_load_texture("data/gui_connecting.png");
|
||||
|
||||
inited = true;
|
||||
}
|
||||
|
@ -479,229 +523,18 @@ void client::render()
|
|||
ui_do_image(connecting_texture, 88, 150, 256, 64);
|
||||
|
||||
if(inp_key_down(input::esc))
|
||||
disconnect();
|
||||
client_disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
void client::run(const char *direct_connect_server)
|
||||
{
|
||||
local_start_time = time_get();
|
||||
snapshot_part = 0;
|
||||
info_request_begin = 0;
|
||||
info_request_end = 0;
|
||||
|
||||
client_serverbrowse_init();
|
||||
|
||||
// init graphics and sound
|
||||
if(!gfx_init())
|
||||
return;
|
||||
|
||||
snd_init(); // sound is allowed to fail
|
||||
|
||||
// load data
|
||||
if(!load_data())
|
||||
return;
|
||||
|
||||
// init snapshotting
|
||||
snap_init();
|
||||
|
||||
// init the mod
|
||||
modc_init();
|
||||
|
||||
// init menu
|
||||
modmenu_init();
|
||||
|
||||
// open socket
|
||||
net.open(0, 0);
|
||||
|
||||
//
|
||||
net_host_lookup(config.masterserver, MASTERSERVER_PORT, &master_server);
|
||||
|
||||
// connect to the server if wanted
|
||||
if(direct_connect_server)
|
||||
client_connect(direct_connect_server);
|
||||
|
||||
//int64 inputs_per_second = 50;
|
||||
//int64 time_per_input = time_freq()/inputs_per_second;
|
||||
int64 game_starttime = time_get();
|
||||
int64 last_input = game_starttime;
|
||||
|
||||
int64 reporttime = time_get();
|
||||
int64 reportinterval = time_freq()*1;
|
||||
int frames = 0;
|
||||
|
||||
input::set_mouse_mode(input::mode_relative);
|
||||
|
||||
while (1)
|
||||
{
|
||||
frames++;
|
||||
int64 frame_start_time = time_get();
|
||||
|
||||
// switch snapshot
|
||||
if(recived_snapshots >= 3)
|
||||
{
|
||||
int64 now = time_get();
|
||||
while(1)
|
||||
{
|
||||
snapshot_info *cur = snapshots[SNAP_CURRENT];
|
||||
int64 tickstart = game_start_time + (cur->tick+1)*time_freq()/50;
|
||||
int64 t = tickstart;
|
||||
if(latency > 0)
|
||||
t += (int64)(time_freq()*(latency*1.1f));
|
||||
|
||||
if(t < now)
|
||||
{
|
||||
snapshot_info *next = snapshots[SNAP_CURRENT]->next;
|
||||
if(next)
|
||||
{
|
||||
snapshots[SNAP_PREV] = snapshots[SNAP_CURRENT];
|
||||
snapshots[SNAP_CURRENT] = next;
|
||||
snapshot_start_time = t;
|
||||
}
|
||||
else
|
||||
{
|
||||
extra_polating = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
extra_polating = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// send input
|
||||
if(get_state() == STATE_ONLINE)
|
||||
{
|
||||
if(server_spam_address)
|
||||
disconnect();
|
||||
|
||||
if(input_is_changed || time_get() > last_input+time_freq())
|
||||
{
|
||||
send_input();
|
||||
input_is_changed = 0;
|
||||
last_input = time_get();
|
||||
}
|
||||
}
|
||||
|
||||
if(get_state() == STATE_OFFLINE && server_spam_address)
|
||||
client_connect(server_spam_address);
|
||||
|
||||
// update input
|
||||
inp_update();
|
||||
|
||||
//
|
||||
if(input::pressed(input::f1))
|
||||
input::set_mouse_mode(input::mode_absolute);
|
||||
if(input::pressed(input::f2))
|
||||
input::set_mouse_mode(input::mode_relative);
|
||||
|
||||
// panic button
|
||||
if(input::pressed(input::lctrl) && input::pressed('Q'))
|
||||
break;
|
||||
|
||||
if(input::pressed(input::f5))
|
||||
{
|
||||
// ack snapshot
|
||||
msg_pack_start_system(NETMSG_SNAPACK, 0);
|
||||
msg_pack_int(-1);
|
||||
msg_pack_end();
|
||||
client_send_msg();
|
||||
}
|
||||
|
||||
// pump the network
|
||||
pump_network();
|
||||
|
||||
// update the server browser
|
||||
serverbrowse_update();
|
||||
|
||||
// render
|
||||
render();
|
||||
|
||||
// swap the buffers
|
||||
gfx_swap();
|
||||
|
||||
// check conditions
|
||||
if(get_state() == STATE_BROKEN || get_state() == STATE_QUIT)
|
||||
break;
|
||||
|
||||
// be nice
|
||||
if(config.cpu_throttle)
|
||||
thread_sleep(1);
|
||||
|
||||
if(reporttime < time_get())
|
||||
{
|
||||
dbg_msg("client/report", "fps=%.02f netstate=%d",
|
||||
frames/(float)(reportinterval/time_freq()), net.state());
|
||||
frames = 0;
|
||||
reporttime += reportinterval;
|
||||
}
|
||||
|
||||
/*if (input::pressed(input::esc))
|
||||
if (get_state() == STATE_CONNECTING || get_state() == STATE_ONLINE)
|
||||
disconnect();*/
|
||||
|
||||
// update frametime
|
||||
frametime = (time_get()-frame_start_time)/(float)time_freq();
|
||||
}
|
||||
|
||||
modc_shutdown();
|
||||
disconnect();
|
||||
|
||||
modmenu_shutdown();
|
||||
|
||||
gfx_shutdown();
|
||||
snd_shutdown();
|
||||
}
|
||||
|
||||
void client::error(const char *msg)
|
||||
static void client_error(const char *msg)
|
||||
{
|
||||
dbg_msg("game", "error: %s", msg);
|
||||
send_error(msg);
|
||||
set_state(STATE_BROKEN);
|
||||
client_send_error(msg);
|
||||
client_set_state(STATE_BROKEN);
|
||||
}
|
||||
|
||||
void client::serverbrowse_request(int id)
|
||||
{
|
||||
dbg_msg("client", "requesting server info from %d.%d.%d.%d:%d",
|
||||
servers.addresses[id].ip[0], servers.addresses[id].ip[1], servers.addresses[id].ip[2],
|
||||
servers.addresses[id].ip[3], servers.addresses[id].port);
|
||||
NETPACKET packet;
|
||||
packet.client_id = -1;
|
||||
packet.address = servers.addresses[id];
|
||||
packet.flags = PACKETFLAG_CONNLESS;
|
||||
packet.data_size = sizeof(SERVERBROWSE_GETINFO);
|
||||
packet.data = SERVERBROWSE_GETINFO;
|
||||
net.send(&packet);
|
||||
servers.request_times[id] = time_get();
|
||||
}
|
||||
|
||||
void client::serverbrowse_update()
|
||||
{
|
||||
int64 timeout = time_freq();
|
||||
int64 now = time_get();
|
||||
int max_requests = 10;
|
||||
|
||||
// timeout old requests
|
||||
while(info_request_begin < servers.num && info_request_begin < info_request_end)
|
||||
{
|
||||
if(now > servers.request_times[info_request_begin]+timeout)
|
||||
info_request_begin++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
// send new requests
|
||||
while(info_request_end < servers.num && info_request_end-info_request_begin < max_requests)
|
||||
{
|
||||
serverbrowse_request(info_request_end);
|
||||
info_request_end++;
|
||||
}
|
||||
}
|
||||
|
||||
void client::process_packet(NETPACKET *packet)
|
||||
static void client_process_packet(NETPACKET *packet)
|
||||
{
|
||||
if(packet->client_id == -1)
|
||||
{
|
||||
|
@ -788,19 +621,19 @@ void client::process_packet(NETPACKET *packet)
|
|||
{
|
||||
const char *map = msg_unpack_string();
|
||||
dbg_msg("client/network", "connection accepted, map=%s", map);
|
||||
set_state(STATE_LOADING);
|
||||
client_set_state(STATE_LOADING);
|
||||
|
||||
if(map_load(map))
|
||||
{
|
||||
modc_entergame();
|
||||
send_entergame();
|
||||
client_send_entergame();
|
||||
dbg_msg("client/network", "loading done");
|
||||
// now we will wait for two snapshots
|
||||
// to finish the connection
|
||||
}
|
||||
else
|
||||
{
|
||||
error("failure to load map");
|
||||
client_error("failure to load map");
|
||||
}
|
||||
}
|
||||
else if(msg == NETMSG_SNAP || msg == NETMSG_SNAPEMPTY) //|| msg == NETMSG_SNAPSMALL || msg == NETMSG_SNAPEMPTY)
|
||||
|
@ -892,7 +725,7 @@ void client::process_packet(NETPACKET *packet)
|
|||
|
||||
//int ncrc = snapshot_crc((snapshot*)tmpbuffer3);
|
||||
//if(crc != ncrc)
|
||||
//dbg_msg("client", "client snapshot crc failure %d %d", crc, ncrc);
|
||||
// dbg_msg("client", "client snapshot crc failure %d %d", crc, ncrc);
|
||||
|
||||
// apply snapshot, cycle pointers
|
||||
recived_snapshots++;
|
||||
|
@ -908,7 +741,7 @@ void client::process_packet(NETPACKET *packet)
|
|||
if(recived_snapshots == 2)
|
||||
{
|
||||
local_start_time = time_get();
|
||||
set_state(STATE_ONLINE);
|
||||
client_set_state(STATE_ONLINE);
|
||||
}
|
||||
|
||||
int64 now = time_get();
|
||||
|
@ -953,35 +786,210 @@ void client::process_packet(NETPACKET *packet)
|
|||
}
|
||||
}
|
||||
|
||||
void client::pump_network()
|
||||
|
||||
static void client_pump_network()
|
||||
{
|
||||
net.update();
|
||||
|
||||
// check for errors
|
||||
if(get_state() != STATE_OFFLINE && net.state() == NETSTATE_OFFLINE)
|
||||
if(client_get_state() != STATE_OFFLINE && net.state() == NETSTATE_OFFLINE)
|
||||
{
|
||||
// TODO: add message to the user there
|
||||
set_state(STATE_OFFLINE);
|
||||
client_set_state(STATE_OFFLINE);
|
||||
}
|
||||
|
||||
//
|
||||
if(get_state() == STATE_CONNECTING && net.state() == NETSTATE_ONLINE)
|
||||
if(client_get_state() == STATE_CONNECTING && net.state() == NETSTATE_ONLINE)
|
||||
{
|
||||
// we switched to online
|
||||
dbg_msg("client", "connected, sending info");
|
||||
set_state(STATE_LOADING);
|
||||
send_info();
|
||||
client_set_state(STATE_LOADING);
|
||||
client_send_info();
|
||||
}
|
||||
|
||||
// process packets
|
||||
NETPACKET packet;
|
||||
while(net.recv(&packet))
|
||||
process_packet(&packet);
|
||||
client_process_packet(&packet);
|
||||
}
|
||||
|
||||
static void client_run(const char *direct_connect_server)
|
||||
{
|
||||
local_start_time = time_get();
|
||||
snapshot_part = 0;
|
||||
info_request_begin = 0;
|
||||
info_request_end = 0;
|
||||
|
||||
client_serverbrowse_init();
|
||||
|
||||
// init graphics and sound
|
||||
if(!gfx_init())
|
||||
return;
|
||||
|
||||
snd_init(); // sound is allowed to fail
|
||||
|
||||
// load data
|
||||
if(!client_load_data())
|
||||
return;
|
||||
|
||||
// init snapshotting
|
||||
snap_init();
|
||||
|
||||
// init the mod
|
||||
modc_init();
|
||||
|
||||
// init menu
|
||||
modmenu_init();
|
||||
|
||||
// open socket
|
||||
net.open(0, 0);
|
||||
|
||||
//
|
||||
net_host_lookup(config.masterserver, MASTERSERVER_PORT, &master_server);
|
||||
|
||||
// connect to the server if wanted
|
||||
if(direct_connect_server)
|
||||
client_connect(direct_connect_server);
|
||||
|
||||
//int64 inputs_per_second = 50;
|
||||
//int64 time_per_input = time_freq()/inputs_per_second;
|
||||
int64 game_starttime = time_get();
|
||||
int64 last_input = game_starttime;
|
||||
|
||||
int64 reporttime = time_get();
|
||||
int64 reportinterval = time_freq()*1;
|
||||
int frames = 0;
|
||||
|
||||
input::set_mouse_mode(input::mode_relative);
|
||||
|
||||
while (1)
|
||||
{
|
||||
frames++;
|
||||
int64 frame_start_time = time_get();
|
||||
|
||||
// switch snapshot
|
||||
if(recived_snapshots >= 3)
|
||||
{
|
||||
int64 now = time_get();
|
||||
while(1)
|
||||
{
|
||||
snapshot_info *cur = snapshots[SNAP_CURRENT];
|
||||
int64 tickstart = game_start_time + (cur->tick+1)*time_freq()/50;
|
||||
int64 t = tickstart;
|
||||
if(latency > 0)
|
||||
t += (int64)(time_freq()*(latency*1.1f));
|
||||
|
||||
if(t < now)
|
||||
{
|
||||
snapshot_info *next = snapshots[SNAP_CURRENT]->next;
|
||||
if(next)
|
||||
{
|
||||
snapshots[SNAP_PREV] = snapshots[SNAP_CURRENT];
|
||||
snapshots[SNAP_CURRENT] = next;
|
||||
snapshot_start_time = t;
|
||||
}
|
||||
else
|
||||
{
|
||||
extra_polating = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
extra_polating = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// send input
|
||||
if(client_get_state() == STATE_ONLINE)
|
||||
{
|
||||
if(server_spam_address)
|
||||
client_disconnect();
|
||||
|
||||
if(input_is_changed || time_get() > last_input+time_freq())
|
||||
{
|
||||
client_send_input();
|
||||
input_is_changed = 0;
|
||||
last_input = time_get();
|
||||
}
|
||||
}
|
||||
|
||||
if(client_get_state() == STATE_OFFLINE && server_spam_address)
|
||||
client_connect(server_spam_address);
|
||||
|
||||
// update input
|
||||
inp_update();
|
||||
|
||||
//
|
||||
if(input::pressed(input::f1))
|
||||
input::set_mouse_mode(input::mode_absolute);
|
||||
if(input::pressed(input::f2))
|
||||
input::set_mouse_mode(input::mode_relative);
|
||||
|
||||
// panic button
|
||||
if(input::pressed(input::lctrl) && input::pressed('Q'))
|
||||
break;
|
||||
|
||||
if(input::pressed(input::f5))
|
||||
{
|
||||
// ack snapshot
|
||||
msg_pack_start_system(NETMSG_SNAPACK, 0);
|
||||
msg_pack_int(-1);
|
||||
msg_pack_end();
|
||||
client_send_msg();
|
||||
}
|
||||
|
||||
// pump the network
|
||||
client_pump_network();
|
||||
|
||||
// update the server browser
|
||||
client_serverbrowse_update();
|
||||
|
||||
// render
|
||||
client_render();
|
||||
|
||||
// swap the buffers
|
||||
gfx_swap();
|
||||
|
||||
// check conditions
|
||||
if(client_get_state() == STATE_BROKEN || client_get_state() == STATE_QUIT)
|
||||
break;
|
||||
|
||||
// be nice
|
||||
if(config.cpu_throttle)
|
||||
thread_sleep(1);
|
||||
|
||||
if(reporttime < time_get())
|
||||
{
|
||||
dbg_msg("client/report", "fps=%.02f netstate=%d",
|
||||
frames/(float)(reportinterval/time_freq()), net.state());
|
||||
frames = 0;
|
||||
reporttime += reportinterval;
|
||||
}
|
||||
|
||||
/*if (input::pressed(input::esc))
|
||||
if (get_state() == STATE_CONNECTING || get_state() == STATE_ONLINE)
|
||||
disconnect();*/
|
||||
|
||||
// update frametime
|
||||
frametime = (time_get()-frame_start_time)/(float)time_freq();
|
||||
}
|
||||
|
||||
modc_shutdown();
|
||||
client_disconnect();
|
||||
|
||||
modmenu_shutdown(); // TODO: remove this
|
||||
|
||||
gfx_shutdown();
|
||||
snd_shutdown();
|
||||
}
|
||||
|
||||
|
||||
int editor_main(int argc, char **argv);
|
||||
|
||||
client main_client;
|
||||
//client main_client;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
|
@ -1035,7 +1043,7 @@ int main(int argc, char **argv)
|
|||
else
|
||||
{
|
||||
// start the client
|
||||
main_client.run(direct_connect_server);
|
||||
client_run(direct_connect_server);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
#ifndef __CLIENT_H
|
||||
#define __CLIENT_H
|
||||
|
||||
#include <engine/network.h>
|
||||
// --- client ---
|
||||
// TODO: remove this class
|
||||
class client
|
||||
{
|
||||
public:
|
||||
int info_request_begin;
|
||||
int info_request_end;
|
||||
|
||||
int snapshot_part;
|
||||
|
||||
int debug_font; // TODO: rfemove this line
|
||||
|
||||
// data to hold three snapshots
|
||||
// previous,
|
||||
|
||||
void send_info();
|
||||
|
||||
void send_entergame();
|
||||
|
||||
void send_error(const char *error);
|
||||
|
||||
void send_input();
|
||||
|
||||
void disconnect();
|
||||
|
||||
bool load_data();
|
||||
|
||||
void debug_render();
|
||||
|
||||
void render();
|
||||
|
||||
void run(const char *direct_connect_server);
|
||||
|
||||
void error(const char *msg);
|
||||
|
||||
void serverbrowse_request(int id);
|
||||
|
||||
void serverbrowse_update();
|
||||
void process_packet(NETPACKET *packet);
|
||||
|
||||
void pump_network();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -43,6 +43,7 @@ static float screen_y1 = 0;
|
|||
struct texture_holder
|
||||
{
|
||||
opengl::texture tex;
|
||||
int memsize;
|
||||
int flags;
|
||||
int next;
|
||||
};
|
||||
|
@ -51,6 +52,7 @@ static const int MAX_TEXTURES = 128;
|
|||
|
||||
static texture_holder textures[MAX_TEXTURES];
|
||||
static int first_free_texture;
|
||||
static int memory_usage = 0;
|
||||
|
||||
static const unsigned char null_texture_data[] = {
|
||||
0xff,0x00,0x00,0xff, 0xff,0x00,0x00,0xff, 0x00,0xff,0x00,0xff, 0x00,0xff,0x00,0xff,
|
||||
|
@ -70,6 +72,11 @@ static void draw_quad(bool _bflush = false)
|
|||
{
|
||||
if (!_bflush)
|
||||
num_vertices += 4;
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
if(GLEW_ARB_vertex_buffer_object)
|
||||
{
|
||||
// set the data
|
||||
|
@ -177,6 +184,7 @@ bool gfx_init()
|
|||
|
||||
//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
// create null texture, will get id=0
|
||||
gfx_load_texture_raw(4,4,IMG_RGBA,null_texture_data);
|
||||
|
@ -230,6 +238,7 @@ int gfx_unload_texture(int index)
|
|||
{
|
||||
textures[index].tex.clear();
|
||||
textures[index].next = first_free_texture;
|
||||
memory_usage -= textures[index].memsize;
|
||||
first_free_texture = index;
|
||||
return 0;
|
||||
}
|
||||
|
@ -246,6 +255,8 @@ void gfx_blend_additive()
|
|||
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
||||
}
|
||||
|
||||
int gfx_memory_usage() { return memory_usage; }
|
||||
|
||||
static unsigned char sample(int w, int h, const unsigned char *data, int u, int v, int offset)
|
||||
{
|
||||
return (data[(v*w+u)*4+offset]+
|
||||
|
@ -256,6 +267,8 @@ static unsigned char sample(int w, int h, const unsigned char *data, int u, int
|
|||
|
||||
int gfx_load_texture_raw(int w, int h, int format, const void *data)
|
||||
{
|
||||
bool mipmap = true;
|
||||
|
||||
// grab texture
|
||||
int tex = first_free_texture;
|
||||
first_free_texture = textures[tex].next;
|
||||
|
@ -302,6 +315,19 @@ int gfx_load_texture_raw(int w, int h, int format, const void *data)
|
|||
textures[tex].tex.data2d(w, h, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, texdata);
|
||||
}
|
||||
|
||||
textures[tex].memsize = w*h*4;
|
||||
if(mipmap)
|
||||
{
|
||||
while(w > 2 && h > 2)
|
||||
{
|
||||
w>>=1;
|
||||
h>>=1;
|
||||
textures[tex].memsize += w*h*4;
|
||||
}
|
||||
}
|
||||
|
||||
memory_usage += textures[tex].memsize;
|
||||
|
||||
mem_free(tmpdata);
|
||||
|
||||
return tex;
|
||||
|
|
|
@ -1,228 +1,6 @@
|
|||
#include <baselib/system.h>
|
||||
#include <string.h>
|
||||
|
||||
// LZW Compressor
|
||||
struct SYM
|
||||
{
|
||||
unsigned char *data;
|
||||
int size;
|
||||
int next;
|
||||
};
|
||||
|
||||
struct SYMBOLS
|
||||
{
|
||||
SYM syms[512];
|
||||
int jumptable[256];
|
||||
int currentsym;
|
||||
};
|
||||
|
||||
static SYMBOLS symbols;
|
||||
|
||||
// symbol info
|
||||
inline int sym_size(int i) { return symbols.syms[i].size; }
|
||||
inline unsigned char *sym_data(int i) { return symbols.syms[i].data; }
|
||||
|
||||
static void sym_index(int sym)
|
||||
{
|
||||
int table = symbols.syms[sym].data[0];
|
||||
symbols.syms[sym].next = symbols.jumptable[table];
|
||||
symbols.jumptable[table] = sym;
|
||||
}
|
||||
|
||||
static void sym_unindex(int sym)
|
||||
{
|
||||
int table = symbols.syms[sym].data[0];
|
||||
int prev = -1;
|
||||
int current = symbols.jumptable[table];
|
||||
|
||||
while(current != -1)
|
||||
{
|
||||
if(current == sym)
|
||||
{
|
||||
if(prev != -1)
|
||||
symbols.syms[prev].next = symbols.syms[current].next;
|
||||
else
|
||||
symbols.jumptable[table] = symbols.syms[current].next;
|
||||
break;
|
||||
}
|
||||
|
||||
prev = current;
|
||||
current = symbols.syms[current].next;
|
||||
}
|
||||
}
|
||||
|
||||
static int sym_add(unsigned char *sym, long len)
|
||||
{
|
||||
int i = 256+symbols.currentsym;
|
||||
symbols.syms[i].data = sym;
|
||||
symbols.syms[i].size = len;
|
||||
symbols.currentsym = (symbols.currentsym+1)%255;
|
||||
return i;
|
||||
}
|
||||
|
||||
static int sym_add_and_index(unsigned char *sym, long len)
|
||||
{
|
||||
if(symbols.syms[256+symbols.currentsym].size)
|
||||
sym_unindex(256+symbols.currentsym);
|
||||
int s = sym_add(sym, len);
|
||||
sym_index( s);
|
||||
return s;
|
||||
}
|
||||
|
||||
static void sym_init()
|
||||
{
|
||||
static unsigned char table[256];
|
||||
for(int i = 0; i < 256; i++)
|
||||
{
|
||||
table[i] = i;
|
||||
symbols.syms[i].data = &table[i];
|
||||
symbols.syms[i].size = 1;
|
||||
symbols.jumptable[i] = -1;
|
||||
}
|
||||
|
||||
for(int i = 0; i < 512; i++)
|
||||
symbols.syms[i].next = -1;
|
||||
|
||||
/*
|
||||
// insert some symbols to start with
|
||||
static unsigned char zeros[8] = {0,0,0,0,0,0,0,0};
|
||||
//static unsigned char one1[4] = {0,0,0,1};
|
||||
//static unsigned char one2[4] = {1,0,0,0};
|
||||
sym_add_and_index(zeros, 2);
|
||||
sym_add_and_index(zeros, 3);
|
||||
sym_add_and_index(zeros, 4);
|
||||
sym_add_and_index(zeros, 5);
|
||||
sym_add_and_index(zeros, 6);
|
||||
sym_add_and_index(zeros, 7);
|
||||
sym_add_and_index(zeros, 8);
|
||||
|
||||
//sym_add_and_index(one1, 4);
|
||||
//sym_add_and_index(one2, 4);*/
|
||||
|
||||
symbols.currentsym = 0;
|
||||
}
|
||||
|
||||
static int sym_find(unsigned char *data, int size, int avoid)
|
||||
{
|
||||
int best = data[0];
|
||||
int bestlen = 1;
|
||||
int current = symbols.jumptable[data[0]];
|
||||
|
||||
while(current != -1)
|
||||
{
|
||||
if(current != avoid && symbols.syms[current].size <= size && memcmp(data, symbols.syms[current].data, symbols.syms[current].size) == 0)
|
||||
{
|
||||
if(bestlen < symbols.syms[current].size)
|
||||
{
|
||||
bestlen = symbols.syms[current].size;
|
||||
best = current;
|
||||
}
|
||||
}
|
||||
|
||||
current = symbols.syms[current].next;
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
//
|
||||
// compress
|
||||
//
|
||||
long lzw_compress(const void *src_, int size, void *dst_)
|
||||
{
|
||||
unsigned char *src = (unsigned char *)src_;
|
||||
unsigned char *end = (unsigned char *)src_+size;
|
||||
unsigned char *dst = (unsigned char *)dst_;
|
||||
long left = (end-src);
|
||||
int lastsym = -1;
|
||||
|
||||
// init symboltable
|
||||
sym_init();
|
||||
|
||||
bool done = false;
|
||||
while(!done)
|
||||
{
|
||||
unsigned char *flagptr = dst;
|
||||
unsigned char flagbits = 0;
|
||||
int b = 0;
|
||||
|
||||
dst++; // skip a byte where the flags are
|
||||
|
||||
for(; b < 8; b++)
|
||||
{
|
||||
if(left <= 0) // check for EOF
|
||||
{
|
||||
// write EOF symbol
|
||||
flagbits |= 1<<b;
|
||||
*dst++ = 255;
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
|
||||
int sym = sym_find(src, left, lastsym);
|
||||
int symsize = sym_size( sym);
|
||||
|
||||
if(sym&0x100)
|
||||
flagbits |= 1<<b; // add bit that says that its a symbol
|
||||
|
||||
*dst++ = sym&0xff; // set symbol
|
||||
|
||||
if(left > symsize+1) // create new symbol
|
||||
lastsym = sym_add_and_index(src, symsize+1);
|
||||
|
||||
src += symsize; // advance src
|
||||
left -= symsize;
|
||||
}
|
||||
|
||||
// write the flags
|
||||
*flagptr = flagbits;
|
||||
}
|
||||
|
||||
return (long)(dst-(unsigned char*)dst_);
|
||||
}
|
||||
|
||||
//
|
||||
// decompress
|
||||
//
|
||||
long lzw_decompress(const void *src_, void *dst_)
|
||||
{
|
||||
unsigned char *src = (unsigned char *)src_;
|
||||
unsigned char *dst = (unsigned char *)dst_;
|
||||
unsigned char *prevdst = 0;
|
||||
int prevsize = -1;
|
||||
int item;
|
||||
|
||||
sym_init();
|
||||
|
||||
while(1)
|
||||
{
|
||||
unsigned char flagbits = 0;
|
||||
flagbits = *src++; // read flags
|
||||
|
||||
int b = 0;
|
||||
for(; b < 8; b++)
|
||||
{
|
||||
item = *src++;
|
||||
if(flagbits&(1<<b))
|
||||
item |= 256;
|
||||
|
||||
if(item == 0x1ff) // EOF symbol
|
||||
return (dst-(unsigned char *)dst_);
|
||||
|
||||
if(prevdst) // this one could be removed
|
||||
sym_add(prevdst, prevsize+1);
|
||||
|
||||
memcpy(dst, sym_data(item), sym_size(item));
|
||||
prevdst = dst;
|
||||
prevsize = sym_size(item);
|
||||
dst += sym_size(item);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Format: ESDDDDDD EDDDDDDD EDD... Extended, Data, Sign
|
||||
unsigned char *vint_pack(unsigned char *dst, int i)
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// lzw is no longer in use
|
||||
long lzw_compress(const void *src, int size, void *dst);
|
||||
long lzw_decompress(const void *src, void *dst);
|
||||
//long lzw_compress(const void *src, int size, void *dst);
|
||||
//long lzw_decompress(const void *src, void *dst);
|
||||
|
||||
unsigned char *vint_pack(unsigned char *dst, int i);
|
||||
const unsigned char *vint_unpack(const unsigned char *src, int *inout);
|
||||
|
|
|
@ -753,6 +753,7 @@ void gfx_pretty_text(float x, float y, float size, const char *text);
|
|||
float gfx_pretty_text_width(float size, const char *text, int length = -1);
|
||||
|
||||
void gfx_getscreen(float *tl_x, float *tl_y, float *br_x, float *br_y);
|
||||
int gfx_memory_usage();
|
||||
|
||||
void mods_message(int msg, int client_id);
|
||||
void modc_message(int msg);
|
||||
|
@ -768,6 +769,7 @@ struct server_info
|
|||
};
|
||||
|
||||
void client_connect(const char *address);
|
||||
void client_disconnect();
|
||||
|
||||
void client_serverbrowse_refresh(int lan);
|
||||
int client_serverbrowse_getlist(server_info **servers);
|
||||
|
|
|
@ -45,7 +45,7 @@ int map_is_loaded()
|
|||
int map_load(const char *mapname)
|
||||
{
|
||||
char buf[512];
|
||||
sprintf(buf, "data/%s.map", mapname);
|
||||
sprintf(buf, "data/maps/%s.map", mapname);
|
||||
map = datafile_load(buf);
|
||||
return map != 0;
|
||||
}
|
||||
|
|
|
@ -565,7 +565,7 @@ int main(int argc, char **argv)
|
|||
config_reset();
|
||||
config_load("default.cfg");
|
||||
|
||||
const char *mapname = "demo";
|
||||
const char *mapname = "dm1";
|
||||
|
||||
// parse arguments
|
||||
for(int i = 1; i < argc; i++)
|
||||
|
|
|
@ -5,19 +5,17 @@
|
|||
#include <string.h>
|
||||
#include <engine/config.h>
|
||||
#include <engine/client/ui.h>
|
||||
#include <engine/client/client.h>
|
||||
#include "../game.h"
|
||||
#include "mapres_image.h"
|
||||
#include "mapres_tilemap.h"
|
||||
#include "data.h"
|
||||
#include "menu.h"
|
||||
|
||||
extern client main_client;
|
||||
using namespace baselib;
|
||||
|
||||
data_container *data = 0x0;
|
||||
|
||||
int charids[16] = {2,10,0,4,12,6,14,1,9,15,13,11,7,5,8,3};
|
||||
static int charids[16] = {2,10,0,4,12,6,14,1,9,15,13,11,7,5,8,3};
|
||||
|
||||
static int gametype = GAMETYPE_DM;
|
||||
static int skinseed = 0;
|
||||
|
@ -122,7 +120,7 @@ static void select_sprite(sprite *spr, int flags=0, int sx=0, int sy=0)
|
|||
gfx_quads_setsubset(x/(float)cx,y/(float)cy,(x+w)/(float)cx,(y+h)/(float)cy);
|
||||
}
|
||||
|
||||
static void select_sprite(int id, int flags=0, int sx=0, int sy=0)
|
||||
void select_sprite(int id, int flags=0, int sx=0, int sy=0)
|
||||
{
|
||||
if(id < 0 || id > data->num_sprites)
|
||||
return;
|
||||
|
@ -324,7 +322,7 @@ public:
|
|||
void render()
|
||||
{
|
||||
gfx_blend_additive();
|
||||
gfx_texture_set(data->images[IMAGE_PARTICLES].id);
|
||||
gfx_texture_set(data->images[IMAGE_GAME].id);
|
||||
gfx_quads_begin();
|
||||
|
||||
for(int i = 0; i < num_particles; i++)
|
||||
|
@ -606,7 +604,7 @@ void modc_newsnapshot()
|
|||
|
||||
static void render_projectile(obj_projectile *prev, obj_projectile *current, int itemid)
|
||||
{
|
||||
gfx_texture_set(data->images[IMAGE_WEAPONS].id);
|
||||
gfx_texture_set(data->images[IMAGE_GAME].id);
|
||||
gfx_quads_begin();
|
||||
|
||||
select_sprite(data->weapons[current->type%data->num_weapons].sprite_proj);
|
||||
|
@ -631,7 +629,7 @@ static void render_projectile(obj_projectile *prev, obj_projectile *current, int
|
|||
|
||||
static void render_powerup(obj_powerup *prev, obj_powerup *current)
|
||||
{
|
||||
gfx_texture_set(data->images[IMAGE_WEAPONS].id);
|
||||
gfx_texture_set(data->images[IMAGE_GAME].id);
|
||||
gfx_quads_begin();
|
||||
vec2 pos = mix(vec2(prev->x, prev->y), vec2(current->x, current->y), client_intratick());
|
||||
float angle = 0.0f;
|
||||
|
@ -925,7 +923,7 @@ static void render_player(obj_player *prev, obj_player *player)
|
|||
// draw hook
|
||||
if(player->hook_active)
|
||||
{
|
||||
gfx_texture_set(data->images[IMAGE_WEAPONS].id);
|
||||
gfx_texture_set(data->images[IMAGE_GAME].id);
|
||||
gfx_quads_begin();
|
||||
//gfx_quads_begin();
|
||||
|
||||
|
@ -955,7 +953,7 @@ static void render_player(obj_player *prev, obj_player *player)
|
|||
|
||||
// draw gun
|
||||
{
|
||||
gfx_texture_set(data->images[IMAGE_WEAPONS].id);
|
||||
gfx_texture_set(data->images[IMAGE_GAME].id);
|
||||
gfx_quads_begin();
|
||||
gfx_quads_setrotation(state.attach.angle*pi*2+angle);
|
||||
|
||||
|
@ -1189,7 +1187,7 @@ void ingamemenu_render()
|
|||
if (ui_do_button(&menu_quit, "Disconnect", 0, column1_x, row3_y, 250, 48, draw_teewars_button))
|
||||
{
|
||||
menu_active = 0;
|
||||
main_client.disconnect();
|
||||
client_disconnect();
|
||||
}
|
||||
|
||||
gfx_texture_set(data->images[IMAGE_CURSOR].id);
|
||||
|
@ -1389,17 +1387,18 @@ void modc_render()
|
|||
|
||||
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_images[6] = {IMAGE_CLOUD_1, IMAGE_CLOUD_2, IMAGE_CLOUD_3};
|
||||
static int cloud_sprites[6] = {SPRITE_CLOUD1, SPRITE_CLOUD2, SPRITE_CLOUD3};
|
||||
|
||||
gfx_texture_set(data->images[IMAGE_CLOUDS].id);
|
||||
gfx_quads_begin();
|
||||
for(int i = 0; i < 3; i++)
|
||||
{
|
||||
float parallax_amount = 0.55f;
|
||||
gfx_texture_set(data->images[cloud_images[i]].id);
|
||||
gfx_quads_begin();
|
||||
select_sprite(cloud_sprites[i]);
|
||||
gfx_quads_drawTL((cloud_pos[i].x+fmod(client_localtime()*cloud_speed[i]+i*100.0f, 1700.0f))+screen_x*parallax_amount,
|
||||
cloud_pos[i].y+screen_y*parallax_amount, 300, 300);
|
||||
gfx_quads_end();
|
||||
}
|
||||
gfx_quads_end();
|
||||
|
||||
|
||||
// draw backdrop
|
||||
|
@ -1407,7 +1406,7 @@ void modc_render()
|
|||
gfx_quads_begin();
|
||||
float parallax_amount = 0.25f;
|
||||
for(int x = -1; x < 3; x++)
|
||||
gfx_quads_drawTL(1024*x+screen_x*parallax_amount, (screen_y)*parallax_amount+150, 1024, 1024);
|
||||
gfx_quads_drawTL(1024*x+screen_x*parallax_amount, (screen_y)*parallax_amount+150+512, 1024, 512);
|
||||
gfx_quads_end();
|
||||
}
|
||||
|
||||
|
@ -1461,7 +1460,7 @@ void modc_render()
|
|||
|
||||
if(local_player)
|
||||
{
|
||||
gfx_texture_set(data->images[IMAGE_WEAPONS].id);
|
||||
gfx_texture_set(data->images[IMAGE_GAME].id);
|
||||
gfx_quads_begin();
|
||||
|
||||
// render cursor
|
||||
|
@ -1540,7 +1539,7 @@ void modc_render()
|
|||
x -= 44.0f;
|
||||
if (killmsgs[r].weapon >= 0)
|
||||
{
|
||||
gfx_texture_set(data->images[IMAGE_WEAPONS].id);
|
||||
gfx_texture_set(data->images[IMAGE_GAME].id);
|
||||
gfx_quads_begin();
|
||||
select_sprite(data->weapons[killmsgs[r].weapon].sprite_body);
|
||||
draw_sprite(x, y+28, 96);
|
||||
|
|
|
@ -141,7 +141,8 @@ struct pretty_font
|
|||
|
||||
extern pretty_font *current_font;
|
||||
|
||||
void render_sun(float x, float y);
|
||||
extern void render_sun(float x, float y);
|
||||
extern void select_sprite(int id, int flags=0, int sx=0, int sy=0);
|
||||
|
||||
void draw_background(float t)
|
||||
{
|
||||
|
@ -152,48 +153,19 @@ void draw_background(float t)
|
|||
|
||||
render_sun(170, 170);
|
||||
|
||||
gfx_texture_set(data->images[IMAGE_CLOUD_1].id);
|
||||
gfx_texture_set(data->images[IMAGE_CLOUDS].id);
|
||||
gfx_quads_begin();
|
||||
gfx_quads_setcolor(1,1,1,1);
|
||||
gfx_quads_setsubset(
|
||||
0.0f, // startx
|
||||
0.0f, // starty
|
||||
1.0f, // endx
|
||||
1.0f); // endy
|
||||
gfx_quads_drawTL(3500 - fmod(t * 20 + 2000, 4524), 0, 512, 512);
|
||||
gfx_quads_end();
|
||||
|
||||
gfx_texture_set(data->images[IMAGE_CLOUD_2].id);
|
||||
gfx_quads_begin();
|
||||
gfx_quads_setcolor(1,1,1,1);
|
||||
gfx_quads_setsubset(
|
||||
0.0f, // startx
|
||||
0.0f, // starty
|
||||
1.0f, // endx
|
||||
1.0f); // endy
|
||||
gfx_quads_drawTL(3000 - fmod(t * 50 + 2000, 4024), 150, 512, 512);
|
||||
gfx_quads_end();
|
||||
|
||||
gfx_texture_set(data->images[IMAGE_CLOUD_3].id);
|
||||
gfx_quads_begin();
|
||||
gfx_quads_setcolor(1,1,1,1);
|
||||
gfx_quads_setsubset(
|
||||
0.0f, // startx
|
||||
0.0f, // starty
|
||||
1.0f, // endx
|
||||
1.0f); // endy
|
||||
gfx_quads_drawTL(4000 - fmod(t * 60 + 500, 4512), 300, 256, 256);
|
||||
select_sprite(SPRITE_CLOUD1);
|
||||
gfx_quads_drawTL(3500 - fmod(t * 20 + 2000, 4524), 0, 512, 512);
|
||||
select_sprite(SPRITE_CLOUD2);
|
||||
gfx_quads_drawTL(3000 - fmod(t * 50 + 2000, 4024), 150, 512, 512);
|
||||
select_sprite(SPRITE_CLOUD3);
|
||||
gfx_quads_drawTL(4000 - fmod(t * 60 + 500, 4512), 300, 256, 256);
|
||||
gfx_quads_end();
|
||||
|
||||
gfx_texture_set(data->images[IMAGE_MENU_BACKGROUND].id);
|
||||
gfx_quads_begin();
|
||||
gfx_quads_setcolor(1,1,1,1);
|
||||
gfx_quads_setsubset(
|
||||
0.0f, // startx
|
||||
0.0f, // starty
|
||||
1.0f, // endx
|
||||
1.0f); // endy
|
||||
gfx_quads_drawTL(0, -400, 1600, 1600);
|
||||
gfx_quads_drawTL(0, 400, 1600, 1600/2);
|
||||
gfx_quads_end();
|
||||
|
||||
int frame = int(t * 10) % 3;
|
||||
|
|
BIN
tilesets/grassland_doodads.png
Normal file
After Width: | Height: | Size: 76 KiB |
BIN
tilesets/grassland_main.png
Normal file
After Width: | Height: | Size: 67 KiB |
Before Width: | Height: | Size: 6.9 KiB |
Before Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 146 KiB |
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 76 KiB |
BIN
tilesets/unprocessed/grassland_main.png
Normal file
After Width: | Height: | Size: 72 KiB |