diff --git a/Makefile b/Makefile index 7cd5731..7b235bb 100644 --- a/Makefile +++ b/Makefile @@ -5,19 +5,20 @@ CFLAGS = -I$(LUADIR)/include/ -I$(SDLDIR)/include/SDL -std=gnu99 -Wall # CFLAGS += -O3 -fexpensive-optimizations -finline-functions -fomit-frame-pointer -DNDEBUG CFLAGS += -ggdb -LDFLAGS = -L$(LUADIR)/lib -L$(SDLDIR)/lib -levent -llua -llualib -lm -lSDL -GUI_LDFLAGS = $(LDFLAGS) -lSDL_image -lSGE -lSDL_gfx +LDFLAGS = -L$(LUADIR)/lib -levent -lSDL -llua -llualib -lm +GUI_LDFLAGS = -L$(SDLDIR)/lib -levent -lSDL -lSDL_image -lSGE -lSDL_gfx all: infond infon -infond: infond.o server.o listener.o map.o path.o misc.o packet.o player.o world.o creature.o scroller.o - $(MAKE) -C $(LUADIR) +infond: lua-5.0.2/lib/liblua.a infond.o server.o listener.o map.o path.o misc.o packet.o player.o world.o creature.o scroller.o $(CC) $^ $(LDFLAGS) -o $@ -infon: infon.o client.o packet.o gui_player.o gui_world.o gui_creature.o gui_scroller.o - $(MAKE) -C $(LUADIR) +infon: lua-5.0.2/lib/liblua.a infon.o client.o packet.o misc.o gui_player.o gui_world.o gui_creature.o gui_scroller.o video.o sprite.o $(CC) $^ $(GUI_LDFLAGS) -o $@ +lua-5.0.2/lib/liblua.a: + $(MAKE) -C $(LUADIR) + clean: $(MAKE) -C $(LUADIR) clean -rm -f *.o infond infon tags diff --git a/client.c b/client.c index fa88939..f8d9dbc 100644 --- a/client.c +++ b/client.c @@ -36,12 +36,12 @@ #include "packet.h" #include "global.h" -#include "player.h" #include "server.h" -#include "world.h" #include "misc.h" -#include "scroller.h" -#include "creature.h" +#include "gui_player.h" +#include "gui_world.h" +#include "gui_scroller.h" +#include "gui_creature.h" static int serverfd; static struct event rd_event; @@ -57,14 +57,16 @@ static void server_handle_packet(packet_t *packet) { //printf("ptype=%d\n", packet->type); switch (packet->type) { case PACKET_PLAYER_UPDATE: - player_from_network(packet); + gui_player_from_network(packet); break; case PACKET_WORLD_UPDATE: - world_from_network(packet); + gui_world_from_network(packet); break; - //case PACKET_CREATURE_UPDATE: creature_f + case PACKET_CREATURE_UPDATE: + gui_creature_from_network(packet); + break; case PACKET_SCROLLER_MSG: - scroller_from_network(packet); + gui_scroller_from_network(packet); break; case PACKET_WELCOME_MSG: server_writeto("guiclient\n", 10); @@ -74,6 +76,9 @@ static void server_handle_packet(packet_t *packet) { packet->len, packet->data); server_destroy("done"); break; + case PACKET_KOTH_UPDATE: + gui_player_king_from_network(packet); + break; default: printf("packet->type %d unknown\n", packet->type); break; @@ -95,7 +100,7 @@ static void server_readable(int fd, short event, void *arg) { packet_t packet; memcpy(&packet,EVBUFFER_DATA(in_buf), (int)EVBUFFER_DATA(in_buf)[0] + 2); int len = packet.len + 2; - packet_reset(&packet); + packet_rewind(&packet); server_handle_packet(&packet); if (!client_is_connected()) return; diff --git a/client.rb b/client.rb index 8a01a34..c94eb70 100644 --- a/client.rb +++ b/client.rb @@ -38,7 +38,7 @@ def read32 print "score=%d " % (socket.read16 - 500) if mask & 16 != 0 puts when 1: - puts "%d, %d => %d (%d) " % [socket.read8, socket.read8, socket.read8, socket.read16] + puts "%d, %d => %d (%d) " % [socket.read8, socket.read8, socket.read8, socket.read8] when 2: puts "msg: %s " % socket.read(len).unpack("A*")[0] when 3: @@ -55,11 +55,13 @@ def read32 print "message=%s " % socket.read(socket.read8).unpack("A*")[0] if mask &128 != 0 puts when 4: - puts "quit msg: %s " % socket.read(len).unpack("A*")[0] + puts "quit msg: %s " % socket.read(len).unpack("A*")[0] break + when 5: + puts "king: %d " % socket.read8 when 32: socket.write("guiclient\n") - puts "welcome: %s" % socket.read(len).delete("\n").strip + puts "welcome: %s" % socket.read(len).delete("\n").strip else puts "???: #{type}" end diff --git a/common_creature.h b/common_creature.h new file mode 100644 index 0000000..3740bee --- /dev/null +++ b/common_creature.h @@ -0,0 +1,58 @@ +/* + + Copyright (c) 2006 Florian Wesch . All Rights Reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + +*/ + +#ifndef COMMON_CREATURE_H +#define COMMON_CREATURE_H + +#define MAXCREATURES 256 + +#define CREATURE_COLORS 16 +#define CREATURE_TYPES 4 +#define CREATURE_DIRECTIONS 32 +#define CREATURE_ANIMS 2 + +#define CREATURE_STATES 8 + +#define CREATURE_NETWORK_RESOLUTION 16 + +typedef enum { + CREATURE_IDLE, + CREATURE_WALK, + CREATURE_HEAL, + CREATURE_EAT, + CREATURE_ATTACK, + CREATURE_CONVERT, + CREATURE_SPAWN, + CREATURE_FEED, +} creature_state; + +#define CREATURE_DIRTY_ALIVE (1 << 0) +#define CREATURE_DIRTY_POS (1 << 1) +#define CREATURE_DIRTY_TYPE (1 << 2) +#define CREATURE_DIRTY_FOOD (1 << 3) +#define CREATURE_DIRTY_HEALTH (1 << 4) +#define CREATURE_DIRTY_STATE (1 << 5) +#define CREATURE_DIRTY_TARGET (1 << 6) +#define CREATURE_DIRTY_MESSAGE (1 << 7) + +#define CREATURE_DIRTY_ALL 0xFF +#define CREATURE_DIRTY_NONE 0x00 + +#endif diff --git a/common_player.h b/common_player.h index 43ad482..7dd2bea 100644 --- a/common_player.h +++ b/common_player.h @@ -21,3 +21,15 @@ #ifndef COMMON_PLAYER_H #define COMMON_PLAYER_H +#define MAXPLAYERS 32 + +#define PLAYER_DIRTY_ALIVE (1 << 0) +#define PLAYER_DIRTY_NAME (1 << 1) +#define PLAYER_DIRTY_COLOR (1 << 2) +#define PLAYER_DIRTY_CPU (1 << 3) +#define PLAYER_DIRTY_SCORE (1 << 4) + +#define PLAYER_DIRTY_ALL 0x1F +#define PLAYER_DIRTY_NONE 0x00 + +#endif diff --git a/creature.c b/creature.c index c762fd1..32063ef 100644 --- a/creature.c +++ b/creature.c @@ -122,68 +122,6 @@ creature_t *creature_nearest_enemy(const creature_t *reference, int *distptr) { return nearest; } -#ifdef SERVER_GUI -void creature_draw() { - creature_t *creature = &creatures[0]; - for (int i = 0; i < MAXCREATURES; i++, creature++) { - if (!CREATURE_USED(creature)) - continue; - - const int x = X_TO_SCREENX(creature->x) - 7; - const int y = Y_TO_SCREENY(creature->y) - 7; - const int hw = creature->network_health * 16 / 100; - const int fw = creature->network_food * 16 / 100; - - if (fw != 16) video_rect(x + fw, y - 4, x + 16, y - 2, 0x00, 0x00, 0x00, 0xB0); - if (fw != 0) video_rect(x, y - 4, x + fw, y - 2, 0xFF, 0xFF, 0xFF, 0xB0); - - if (hw != 16) video_rect(x + hw, y - 2, x + 16, y, 0xFF, 0x00, 0x00, 0xB0); - if (hw != 0) video_rect(x, y - 2, x + hw, y, 0x00, 0xFF, 0x00, 0xB0); - - video_draw(x, y, sprite_get(CREATURE_SPRITE(creature->player->color, - creature->type, - creature->dir, - (game_time >> 7) % 2))); - - //if (game_time > creature->last_state_change + 300 && - // game_time < creature->last_state_change + 1000) - video_draw(x + 15, y - 10, sprite_get(SPRITE_THOUGHT + creature->state)); - - if (game_time < creature->last_msg_set + 2000) - video_tiny(x - strlen(creature->message) * 6 / 2 + 9, y + 14, creature->message); - - /* - if (creature->path) { - int lastx = X_TO_SCREENX(creature->x); - int lasty = Y_TO_SCREENY(creature->y); - pathnode_t *node = creature->path; - while (node) { - int curx = node->x * SPRITE_TILE_SIZE / TILE_WIDTH; - int cury = node->y * SPRITE_TILE_SIZE / TILE_HEIGHT; - video_line(lastx, lasty, curx, cury); - lastx = curx, lasty = cury; - node = node->next; - } - } - */ - - if (creature->state == CREATURE_ATTACK && creature->spawn_time != game_time) { - assert(creature->target >= 0 && creature->target < MAXCREATURES); - const creature_t *target = &creatures[creature->target]; - if (target) { // Das Angegriffene Vieh koennte in dieser Runde bereits getoetet sein. - video_line(x + 6, y + 6, X_TO_SCREENX(target->x) - 3, Y_TO_SCREENY(target->y) - 3); - video_line(x + 6, y + 6, X_TO_SCREENX(target->x) - 3, Y_TO_SCREENY(target->y) + 3); - video_line(x + 6, y + 6, X_TO_SCREENX(target->x) + 3, Y_TO_SCREENY(target->y) - 3); - video_line(x + 6, y + 6, X_TO_SCREENX(target->x) + 3, Y_TO_SCREENY(target->y) + 3); - } - } - } -} -#else -void creature_draw() { -} -#endif - // ------------- Bewegung ------------- @@ -294,8 +232,8 @@ void creature_do_heal(creature_t *creature, int delta) { if (max_heal > creature->food) max_heal = creature->food; - creature->health += max_heal; - creature->food -= max_heal; + creature->health += max_heal; + creature->food -= max_heal; if (max_heal == 0) creature_set_state(creature, CREATURE_IDLE); @@ -437,7 +375,9 @@ void creature_do_convert(creature_t *creature, int delta) { creature->health = creature_max_health(creature); if (creature->food > creature_max_food(creature)) creature->food = creature_max_food(creature); - creature->dirtymask |= CREATURE_DIRTY_TYPE; + creature->dirtymask |= CREATURE_DIRTY_TYPE | + CREATURE_DIRTY_HEALTH | + CREATURE_DIRTY_FOOD; creature_set_state(creature, CREATURE_IDLE); } } @@ -727,31 +667,39 @@ next_creature: ; for (int i = 0; i < MAXCREATURES; i++, creature++) { if (!CREATURE_USED(creature)) continue; - + // Leben/Food Prozentangaben aktualisieren - int newhealth = 100 * creature->health / creature_max_health(creature); + int newhealth = 16 * creature->health / creature_max_health(creature); if (newhealth != creature->network_health) { creature->network_health = newhealth; creature->dirtymask |= CREATURE_DIRTY_HEALTH; } - int newfood = 100 * creature->food / creature_max_food(creature); + int newfood = 16 * creature->food / creature_max_food(creature); if (newfood != creature->network_food) { creature->network_food = newfood; creature->dirtymask |= CREATURE_DIRTY_FOOD; } - if (creature->x != creature->network_x || - creature->y != creature->network_y || - creature->dir != creature->network_dir) - { - creature->network_x = creature->x; - creature->network_y = creature->y; - creature->network_dir = creature->dir; - creature->dirtymask |= CREATURE_DIRTY_POS; + int newx = creature->x / CREATURE_NETWORK_RESOLUTION; + if (newx != creature->network_x) { + creature->network_x = newx; + creature->dirtymask |= CREATURE_DIRTY_POS; + } + + int newy = creature->y / CREATURE_NETWORK_RESOLUTION; + if (newy != creature->network_y) { + creature->network_y = newy; + creature->dirtymask |= CREATURE_DIRTY_POS; } - creature_to_network(creature, creature->dirtymask, PACKET_BROADCAST); + int newdir= creature->dir; + if (newdir != creature->network_dir) { + creature->network_dir = newdir; + creature->dirtymask |= CREATURE_DIRTY_POS; + } + + creature_to_network(creature, creature->dirtymask, SEND_BROADCAST); creature->dirtymask = CREATURE_DIRTY_NONE; } @@ -789,9 +737,8 @@ int creature_set_path(creature_t *creature, int x, int y) { } void creature_set_message(creature_t *creature, const char *message) { - if (strcmp(creature->message, message)) { + if (strncmp(creature->message, message, sizeof(creature->message) - 1)) { snprintf(creature->message, sizeof(creature->message), "%s", message); - creature->last_msg_set = game_time; creature->dirtymask |= CREATURE_DIRTY_MESSAGE; } } @@ -818,7 +765,6 @@ creature_t *creature_spawn(player_t *player, int x, int y, int type, int points) creature->convert_type = type; creature->spawn_food = 0; creature->message[0] = '\0'; - creature->last_msg_set = 0; creature->spawn_time = game_time; creature->last_state_change = game_time; @@ -826,15 +772,9 @@ creature_t *creature_spawn(player_t *player, int x, int y, int type, int points) creature->dirtymask = 0; - creature->network_x = x; - creature->network_y = y; - creature->network_dir = 0; - creature->network_health = 100; - creature->network_food = 0; - player_on_creature_spawned(player, creature_num(creature), points); - creature_to_network(creature, CREATURE_DIRTY_ALL, PACKET_BROADCAST); + creature_to_network(creature, CREATURE_DIRTY_ALL, SEND_BROADCAST); return creature; } @@ -854,7 +794,7 @@ void creature_kill(creature_t *creature, creature_t *killer) { path_delete(creature->path); creature->player = NULL; - creature_to_network(creature, CREATURE_DIRTY_ALIVE, PACKET_BROADCAST); + creature_to_network(creature, CREATURE_DIRTY_ALIVE, SEND_BROADCAST); } void creature_kill_all_players_creatures(player_t *player) { @@ -883,13 +823,13 @@ void creature_to_network(creature_t *creature, int dirtymask, client_t *client) return; packet_t packet; - packet_reset(&packet); + packet_init(&packet, PACKET_CREATURE_UPDATE); packet_write16(&packet, creature_num(creature)); packet_write08(&packet, dirtymask); if (dirtymask & CREATURE_DIRTY_ALIVE) { if (CREATURE_USED(creature)) - packet_write08(&packet, player_num(creature->player)); + packet_write08(&packet, creature->player->color); else packet_write08(&packet, 0xFF); } @@ -913,7 +853,7 @@ void creature_to_network(creature_t *creature, int dirtymask, client_t *client) packet_writeXX(&packet, &creature->message, strlen(creature->message)); } - packet_send(PACKET_CREATURE_UPDATE, &packet, client); + client_send_packet(&packet, client); } diff --git a/creature.h b/creature.h index 07cafd9..d3f7f67 100644 --- a/creature.h +++ b/creature.h @@ -24,13 +24,7 @@ #include "path.h" #include "player.h" #include "server.h" - -#define MAXCREATURES 256 - -#define CREATURE_COLORS 16 -#define CREATURE_TYPES 4 -#define CREATURE_DIRECTIONS 32 -#define CREATURE_ANIMS 2 +#include "common_creature.h" typedef struct creature_s { int x; @@ -45,42 +39,20 @@ typedef struct creature_s { int convert_food; int convert_type; int spawn_food; - enum { - CREATURE_IDLE, - CREATURE_WALK, - CREATURE_HEAL, - CREATURE_EAT, - CREATURE_ATTACK, - CREATURE_CONVERT, - CREATURE_SPAWN, - CREATURE_FEED, - } state; + creature_state state; int age_action_deltas; int last_state_change; int spawn_time; - int network_health; - int network_food; - int network_x; - int network_y; - int network_dir; - char message[9]; - int last_msg_set; - unsigned char dirtymask; -#define CREATURE_DIRTY_ALIVE (1 << 0) -#define CREATURE_DIRTY_POS (1 << 1) -#define CREATURE_DIRTY_TYPE (1 << 2) -#define CREATURE_DIRTY_FOOD (1 << 3) -#define CREATURE_DIRTY_HEALTH (1 << 4) -#define CREATURE_DIRTY_STATE (1 << 5) -#define CREATURE_DIRTY_TARGET (1 << 6) -#define CREATURE_DIRTY_MESSAGE (1 << 7) -#define CREATURE_DIRTY_ALL 0xFF -#define CREATURE_DIRTY_NONE 0x00 + int network_food; + int network_health; + int network_x; + int network_y; + int network_dir; } creature_t; int creature_num(const creature_t *creature); @@ -106,7 +78,6 @@ int creature_attack_distance(const creature_t *creature); void creature_kill_all_players_creatures(player_t *player); int creature_king_player(); void creature_moveall(int delta); -void creature_draw(); /* Network */ void creature_send_initial_update(client_t *client); diff --git a/global.h b/global.h index 24ee282..c65dafc 100644 --- a/global.h +++ b/global.h @@ -29,7 +29,7 @@ lua_State *L; Uint32 game_time; int game_round; -#define GAME_NAME "Infon Battle Arena 'GPN-5-Release'" +#define GAME_NAME "Infon Battle Arena 'Network Edition'" // Pfadsuche, bei der mehrere beieinanderliegende // Tiles zu einem Area zusammengefasst werden. Die diff --git a/gui_creature.c b/gui_creature.c new file mode 100644 index 0000000..eaad8cb --- /dev/null +++ b/gui_creature.c @@ -0,0 +1,185 @@ +/* + + Copyright (c) 2006 Florian Wesch . All Rights Reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + +*/ + +#include +#include +#include +#include + +#include "global.h" +#include "gui_creature.h" +#include "gui_world.h" +#include "video.h" + +static gui_creature_t creatures[MAXCREATURES]; + +#define CREATURE_USED(creature) ((creature)->used) + +void gui_creature_draw() { + gui_creature_t *creature = &creatures[0]; + for (int i = 0; i < MAXCREATURES; i++, creature++) { + if (!CREATURE_USED(creature)) + continue; + + const int x = X_TO_SCREENX(creature->x) - 7; + const int y = Y_TO_SCREENY(creature->y) - 7; + const int hw = creature->health; + const int fw = creature->food; + + if (fw != 16) video_rect(x + fw, y - 4, x + 16, y - 2, 0x00, 0x00, 0x00, 0xB0); + if (fw != 0) video_rect(x, y - 4, x + fw, y - 2, 0xFF, 0xFF, 0xFF, 0xB0); + + if (hw != 16) video_rect(x + hw, y - 2, x + 16, y, 0xFF, 0x00, 0x00, 0xB0); + if (hw != 0) video_rect(x, y - 2, x + hw, y, 0x00, 0xFF, 0x00, 0xB0); + + video_draw(x, y, sprite_get(CREATURE_SPRITE(creature->color, + creature->type, + creature->dir, + (game_time >> 7) % 2))); + + //if (game_time > creature->last_state_change + 300 && + // game_time < creature->last_state_change + 1000) + video_draw(x + 15, y - 10, sprite_get(SPRITE_THOUGHT + creature->state)); + + if (game_time < creature->last_msg_set + 2000) + video_tiny(x - strlen(creature->message) * 6 / 2 + 9, y + 14, creature->message); + + /* + if (creature->path) { + int lastx = X_TO_SCREENX(creature->x); + int lasty = Y_TO_SCREENY(creature->y); + pathnode_t *node = creature->path; + while (node) { + int curx = node->x * SPRITE_TILE_SIZE / TILE_WIDTH; + int cury = node->y * SPRITE_TILE_SIZE / TILE_HEIGHT; + video_line(lastx, lasty, curx, cury); + lastx = curx, lasty = cury; + node = node->next; + } + } + */ + + if (creature->state == CREATURE_ATTACK) { + assert(creature->target >= 0 && creature->target < MAXCREATURES); + const gui_creature_t *target = &creatures[creature->target]; + if (CREATURE_USED(target)) { // Das Angegriffene Vieh koennte in dieser Runde bereits getoetet sein. + video_line(x + 6, y + 6, X_TO_SCREENX(target->x) - 3, Y_TO_SCREENY(target->y) - 3); + video_line(x + 6, y + 6, X_TO_SCREENX(target->x) - 3, Y_TO_SCREENY(target->y) + 3); + video_line(x + 6, y + 6, X_TO_SCREENX(target->x) + 3, Y_TO_SCREENY(target->y) - 3); + video_line(x + 6, y + 6, X_TO_SCREENX(target->x) + 3, Y_TO_SCREENY(target->y) + 3); + } + } + } +} + +void gui_creature_from_network(packet_t *packet) { + uint16_t creatureno; + + if (!packet_read16(packet, &creatureno)) goto failed; + if (creatureno >= MAXCREATURES) goto failed; + gui_creature_t *creature = &creatures[creatureno]; + + uint8_t updatemask; + if (!packet_read08(packet, &updatemask)) goto failed; + + if (updatemask & CREATURE_DIRTY_ALIVE) { + uint8_t alive; + if (!packet_read08(packet, &alive)) goto failed; + if (alive == 0xFF) { + creature->used = 0; + return; + } else { + if (alive >= CREATURE_COLORS) goto failed; + memset(creature, 0, sizeof(gui_creature_t)); + creature->used = 1; + creature->color = alive; + } + } + + if (!CREATURE_USED(creature)) goto failed; + + if (updatemask & CREATURE_DIRTY_POS) { + uint16_t x, y; + uint8_t dir; + if (!packet_read16(packet, &x)) goto failed; + if (!packet_read16(packet, &y)) goto failed; + if (!packet_read08(packet, &dir)) goto failed; + if (dir >= CREATURE_DIRECTIONS) goto failed; + // XXX: x, y checken? + creature->x = x * CREATURE_NETWORK_RESOLUTION; + creature->y = y * CREATURE_NETWORK_RESOLUTION; + creature->dir = dir; + } + + if (updatemask & CREATURE_DIRTY_TYPE) { + uint8_t type; + if (!packet_read08(packet, &type)) goto failed; + if (type >= CREATURE_TYPES) goto failed; + creature->type = type; + } + + if (updatemask & CREATURE_DIRTY_FOOD) { + uint8_t food; + if (!packet_read08(packet, &food)) goto failed; + if (food > 16) goto failed; + creature->food = food; + } + + if (updatemask & CREATURE_DIRTY_HEALTH) { + uint8_t health; + if (!packet_read08(packet, &health)) goto failed; + if (health > 16) goto failed; + creature->health = health; + } + + if (updatemask & CREATURE_DIRTY_STATE) { + uint8_t state; + if (!packet_read08(packet, &state)) goto failed; + if (state >= CREATURE_STATES) goto failed; + creature->state = state; + } + + if (updatemask & CREATURE_DIRTY_TARGET) { + uint16_t target; + if (!packet_read16(packet, &target)) goto failed; + if (target >= MAXCREATURES) goto failed; + creature->target = target; + } + + if (updatemask & CREATURE_DIRTY_MESSAGE) { + uint8_t len; char buf[256]; + if (!packet_read08(packet, &len)) goto failed; + if (!packet_readXX(packet, buf, len)) goto failed; + buf[len] = '\0'; + snprintf(creature->message, sizeof(creature->message), "%s", buf); + } + + return; +failed: + printf("parsing creature packet failed\n"); +} + +void gui_creature_init() { + memset(creatures, 0, sizeof(creatures)); +} + +void gui_creature_shutdown() { +} + diff --git a/gui_creature.h b/gui_creature.h new file mode 100644 index 0000000..d92c23c --- /dev/null +++ b/gui_creature.h @@ -0,0 +1,51 @@ +/* + + Copyright (c) 2006 Florian Wesch . All Rights Reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + +*/ + +#ifndef GUI_CREATURE_H +#define GUI_CREATURE_H + +#include "common_creature.h" +#include "packet.h" + +typedef struct gui_creature_s { + int used; + int x; + int y; + int dir; + int type; + int food; + int health; + int target; + int color; + creature_state state; + + char message[9]; + int last_msg_set; // XXX use me! +} gui_creature_t; + +void gui_creature_draw(); + +/* Network */ +void gui_creature_from_network(packet_t *packet); + +void gui_creature_init(); +void gui_creature_shutdown(); + +#endif diff --git a/gui_player.c b/gui_player.c index 0ca886e..0d8d168 100644 --- a/gui_player.c +++ b/gui_player.c @@ -23,720 +23,25 @@ #include #include -#include -#include - #include "global.h" -#include "player.h" -#include "server.h" -#include "creature.h" #include "sprite.h" -#include "world.h" #include "video.h" -#include "misc.h" #include "rules.h" -#include "scroller.h" - -#define PLAYER_USED(player) (!!((player)->L)) - -static player_t *king_player = NULL; - -void player_score(player_t *player, int scoredelta, char *reason) { - static char buf[1024]; - snprintf(buf, sizeof(buf), "%s %s %d point%s: %s", - player->name, - scoredelta > 0 ? "gained" : "lost", - abs(scoredelta), - abs(scoredelta) == 1 ? "" : "s", - reason); - - add_to_scroller(buf); - player->score += scoredelta; - player->dirtymask |= PLAYER_DIRTY_SCORE; - - printf("stat: %10d %3d '%10s' %5d: %s\n", game_time, player_num(player), player->name, player->score, reason); -} - -void player_on_creature_spawned(player_t *player, int idx, int points) { - player->num_creatures++; - - lua_pushliteral(player->L, "_spawned_creatures"); - lua_rawget(player->L, LUA_GLOBALSINDEX); - if (!lua_isnil(player->L, -1)) { - lua_pushnumber(player->L, game_round); - lua_rawseti(player->L, -2, idx); - } else { - static char msg[] = "cannot locate _spawned_creatures table. did you delete it?\n"; - player_writeto(player, msg, sizeof(msg) - 1); - } - lua_pop(player->L, 1); - - if (points > 0) - player_score(player, points, "Creature Spawned"); -} - -void player_on_creature_killed(player_t *player, int victim, int killer) { - lua_pushliteral(player->L, "_killed_creatures"); - lua_rawget(player->L, LUA_GLOBALSINDEX); - if (!lua_isnil(player->L, -1)) { - lua_pushnumber(player->L, killer); - lua_rawseti(player->L, -2, victim); - } else { - static char msg[] = "cannot locate _killed_creatures table. did you delete it?\n"; - player_writeto(player, msg, sizeof(msg) - 1); - } - lua_pop(player->L, 1); - - player->num_creatures--; - - if (player->num_creatures == 0) - player->all_dead_time = game_time; - - if (killer == victim) { - player_score(player, CREATURE_SUICIDE_POINTS, "Creature suicides"); - } else if (killer == -1) { - player_score(player, CREATURE_DIED_POINTS, "Creature died"); - } else { - creature_t *victim_creature = creature_by_num(victim); - if (victim_creature->type == 0) { - player_score(player, CREATURE_VICTIM_POINTS_0, "Creature was killed"); - } else { - player_score(player, CREATURE_VICTIM_POINTS_1, "Creature was killed"); - } - creature_t *killer_creature = creature_by_num(killer); - player_score(killer_creature->player, CREATURE_KILLED_POINTS, "Killed a creature"); - } -} - -void player_on_creature_attacked(player_t *player, int victim, int attacker) { - lua_pushliteral(player->L, "_attacked_creatures"); - lua_rawget(player->L, LUA_GLOBALSINDEX); - if (!lua_isnil(player->L, -1)) { - lua_pushnumber(player->L, victim); - lua_rawseti(player->L, -2, attacker); - } else { - static char msg[] = "cannot locate _attacked_creatures table. did you delete it?\n"; - player_writeto(player, msg, sizeof(msg) - 1); - } - lua_pop(player->L, 1); -} - -static int luaPrint(lua_State *L) { - player_t *player = lua_touserdata(L, lua_upvalueindex(1)); - lua_consumecycles(L, 100); - int n=lua_gettop(L); - int i; - for (i=1; i<=n; i++) { - if (i>1) player_writeto(player, "\t", 1); - if (lua_isstring(L,i)) - player_writeto(player, lua_tostring(L,i), lua_strlen(L, i)); - else if (lua_isnil(L,i)) - player_writeto(player, "nil", 3); - else if (lua_isboolean(L,i)) - lua_toboolean(L,i) ? player_writeto(player, "true", 4): - player_writeto(player, "false", 5); - else { - char buffer[128]; - snprintf(buffer, sizeof(buffer), "%s:%p",lua_typename(L,lua_type(L,i)),lua_topointer(L,i)); - player_writeto(player, buffer, strlen(buffer)); - } - } - player_writeto(player, "\n", 1); - return 0; -} - -#define get_player_and_creature() \ - player_t *player = lua_touserdata(L, lua_upvalueindex(1)); \ - (void)player; /* Unused Warning weg */ \ - const int creature_idx = (int)luaL_checklong(L, 1); \ - creature_t *creature = creature_by_num(creature_idx); \ - if (!creature) return luaL_error(L, "%d isn't a valid creature", creature_idx); - -#define assure_is_players_creature() \ - do { if (creature->player != player) \ - return luaL_error(L, "%d isn't your creature", creature_idx); \ - } while(0) - -static int luaCreatureSuicide(lua_State *L) { - get_player_and_creature(); - assure_is_players_creature(); - lua_consumecycles(L, 100); - creature_kill(creature, creature); - return 0; -} - -static int luaCreatureSetPath(lua_State *L) { - get_player_and_creature(); - assure_is_players_creature(); - lua_consumecycles(L, 500); - lua_pushboolean(L, creature_set_path(creature, - luaL_checklong(L, 2), - luaL_checklong(L, 3))); - return 1; -} +#include "gui_player.h" +#include "common_player.h" -static int luaCreatureSetTarget(lua_State *L) { - get_player_and_creature(); - assure_is_players_creature(); - lua_consumecycles(L, 20); - lua_pushboolean(L, creature_set_target(creature, - luaL_checklong(L, 2))); - return 1; -} - -static int luaCreatureSetConvert(lua_State *L) { - get_player_and_creature(); - assure_is_players_creature(); - lua_consumecycles(L, 20); - lua_pushboolean(L, creature_set_conversion_type(creature, - luaL_checklong(L, 2))); - return 1; -} - -static int luaCreatureSetMessage(lua_State *L) { - get_player_and_creature(); - assure_is_players_creature(); - lua_consumecycles(L, 500); - creature_set_message(creature, luaL_checkstring(L, 2)); - return 0; -} - -static int luaCreatureNearestEnemy(lua_State *L) { - get_player_and_creature(); - if (RESTRICTIVE) assure_is_players_creature(); - lua_consumecycles(L, 500); - int mindist; - const creature_t *nearest = creature_nearest_enemy(creature, &mindist); - if (!nearest) - return 0; - lua_pushnumber(L, creature_num(nearest)); - lua_pushnumber(L, nearest->x); - lua_pushnumber(L, nearest->y); - lua_pushnumber(L, player_num(nearest->player)); - lua_pushnumber(L, mindist); - return 5; -} - -static int luaCreatureGetHealth(lua_State *L) { - get_player_and_creature(); - lua_pushnumber(L, 100 * creature->health / creature_max_health(creature)); - return 1; -} - -static int luaCreatureGetSpeed(lua_State *L) { - get_player_and_creature(); - if (RESTRICTIVE) assure_is_players_creature(); - lua_pushnumber(L, creature_speed(creature)); - return 1; -} - -static int luaCreatureGetType(lua_State *L) { - get_player_and_creature(); - lua_pushnumber(L, creature->type); - return 1; -} - -static int luaCreatureGetFood(lua_State *L) { - get_player_and_creature(); - if (RESTRICTIVE) assure_is_players_creature(); - lua_pushnumber(L, creature->food); - return 1; -} - -static int luaCreatureGetTileFood(lua_State *L) { - get_player_and_creature(); - assure_is_players_creature(); - lua_pushnumber(L, creature_food_on_tile(creature)); - return 1; -} - -static int luaCreatureGetMaxFood(lua_State *L) { - get_player_and_creature(); - assure_is_players_creature(); - lua_pushnumber(L, creature_max_food(creature)); - return 1; -} - -static int luaCreatureGetPos(lua_State *L) { - get_player_and_creature(); - lua_pushnumber(L, creature->x); - lua_pushnumber(L, creature->y); - return 2; -} +#define PLAYER_USED(player) ((player)->used) -static int luaCreatureGetDistance(lua_State *L) { - get_player_and_creature(); - if (RESTRICTIVE) assure_is_players_creature(); - const creature_t *target = creature_by_num(luaL_checklong(L, 2)); - if (!target) - return 0; - lua_consumecycles(L, 100); - lua_pushnumber(L, creature_dist(creature, target)); - return 1; -} - -static int luaCreatureGetState(lua_State *L) { - get_player_and_creature(); - assure_is_players_creature(); - lua_pushnumber(L, creature->state); - return 1; -} - -static int luaCreatureGetHitpoints(lua_State *L) { - get_player_and_creature(); - if (RESTRICTIVE) assure_is_players_creature(); - lua_pushnumber(L, creature_hitpoints(creature)); - return 1; -} - -static int luaCreatureGetAttackDistance(lua_State *L) { - get_player_and_creature(); - if (RESTRICTIVE) assure_is_players_creature(); - lua_pushnumber(L, creature_attack_distance(creature)); - return 1; -} - -static int luaCreatureSetState(lua_State *L) { - get_player_and_creature(); - assure_is_players_creature(); - int state = luaL_checklong(L, 2); - switch (state) { - case CREATURE_IDLE: - case CREATURE_WALK: - case CREATURE_HEAL: - case CREATURE_EAT: - case CREATURE_ATTACK: - case CREATURE_CONVERT: - case CREATURE_SPAWN: - case CREATURE_FEED: - lua_pushboolean(L, creature_set_state(creature, state)); - break; - default: - luaL_error(L, "invalid state %d", luaL_checklong(L, 2)); - break; - } - return 1; -} - -static int luaAreaSize(lua_State *L) { - lua_pushnumber(L, TILE_X1(1)); - lua_pushnumber(L, TILE_Y1(1)); - lua_pushnumber(L, TILE_X2(world_width() - 2)); - lua_pushnumber(L, TILE_Y1(world_height() - 2)); - return 4; -} - -static int luaGameTime(lua_State *L) { - lua_pushnumber(L, game_time); - return 1; -} - -static int luaGetKothPos(lua_State *L) { - lua_pushnumber(L, TILE_XCENTER(world_koth_x())); - lua_pushnumber(L, TILE_YCENTER(world_koth_y())); - return 2; -} - -static int luaCreatureExists(lua_State *L) { - lua_pushboolean(L, !!creature_by_num(luaL_checklong(L, 1))); - return 1; -} - -static int luaPlayerExists(lua_State *L) { - lua_pushboolean(L, !!player_by_num(luaL_checklong(L, 1))); - return 1; -} - -static int luaPlayerScore(lua_State *L) { - lua_pushnumber(L, player_get_checked_lua(L, luaL_checklong(L, 1))->score); - return 1; -} - -static int luaKingPlayer(lua_State *L) { - player_t *king = player_king(); - if (king) { - lua_pushnumber(L, player_num(king)); - } else { - lua_pushnil(L); - } - return 1; -} - -#define lua_register_player(p,n,f) \ - (lua_pushstring((p)->L, n), \ - lua_pushlightuserdata((p)->L, p), \ - lua_pushcclosure((p)->L, f, 1), \ - lua_settable((p)->L, LUA_GLOBALSINDEX)) - -player_t *player_create(const char *pass) { - int playerno; - - for (playerno = 0; playerno < MAXPLAYERS; playerno++) { - if (!PLAYER_USED(&players[playerno])) - break; - } - - if (playerno == MAXPLAYERS) - return NULL; - - player_t *player = &players[playerno]; - memset(player, 0, sizeof(player_t)); - - snprintf(player->name, sizeof(player->name), "player%d", playerno); - snprintf(player->pass, sizeof(player->pass), "%s", pass); - player->L = lua_open(); - - player->color = playerno % CREATURE_COLORS; - player->all_dead_time = game_time - PLAYER_CREATURE_RESPAWN_DELAY; - player->all_disconnected_time = game_time; - - player->max_cycles = LUA_MAX_CPU; - - lua_baselibopen(player->L); - lua_dblibopen(player->L); - lua_tablibopen(player->L); - lua_strlibopen(player->L); - lua_mathlibopen(player->L); - - lua_register_player(player, "print", luaPrint); - lua_register_player(player, "suicide", luaCreatureSuicide); - lua_register_player(player, "set_path", luaCreatureSetPath); - lua_register_player(player, "get_pos", luaCreatureGetPos); - lua_register_player(player, "get_state", luaCreatureGetState); - lua_register_player(player, "set_state", luaCreatureSetState); - lua_register_player(player, "set_target", luaCreatureSetTarget); - lua_register_player(player, "set_convert", luaCreatureSetConvert); - lua_register_player(player, "nearest_enemy",luaCreatureNearestEnemy); - lua_register_player(player, "get_type", luaCreatureGetType); - lua_register_player(player, "get_food", luaCreatureGetFood); - lua_register_player(player, "get_health", luaCreatureGetHealth); - lua_register_player(player, "get_speed", luaCreatureGetSpeed); - lua_register_player(player, "get_tile_food",luaCreatureGetTileFood); - lua_register_player(player, "get_max_food", luaCreatureGetMaxFood); - lua_register_player(player, "get_distance", luaCreatureGetDistance); - lua_register_player(player, "set_message", luaCreatureSetMessage); - lua_register_player(player, "get_hitpoints", luaCreatureGetHitpoints); - lua_register_player(player, "get_attack_distance",luaCreatureGetAttackDistance); - - lua_register(player->L, "world_size", luaAreaSize); - lua_register(player->L, "game_time", luaGameTime); - lua_register(player->L, "get_koth_pos", luaGetKothPos); - lua_register(player->L, "exists", luaCreatureExists); - lua_register(player->L, "creature_exists", luaCreatureExists); - lua_register(player->L, "player_exists", luaPlayerExists); - lua_register(player->L, "king_player", luaKingPlayer); - lua_register(player->L, "player_score", luaPlayerScore); - - lua_pushliteral(player->L, "CREATURE_IDLE"); - lua_pushnumber(player->L, CREATURE_IDLE); - lua_settable(player->L, LUA_GLOBALSINDEX); - - lua_pushliteral(player->L, "CREATURE_WALK"); - lua_pushnumber(player->L, CREATURE_WALK); - lua_settable(player->L, LUA_GLOBALSINDEX); - - lua_pushliteral(player->L, "CREATURE_HEAL"); - lua_pushnumber(player->L, CREATURE_HEAL); - lua_settable(player->L, LUA_GLOBALSINDEX); - - lua_pushliteral(player->L, "CREATURE_EAT"); - lua_pushnumber(player->L, CREATURE_EAT); - lua_settable(player->L, LUA_GLOBALSINDEX); - - lua_pushliteral(player->L, "CREATURE_ATTACK"); - lua_pushnumber(player->L, CREATURE_ATTACK); - lua_settable(player->L, LUA_GLOBALSINDEX); - - lua_pushliteral(player->L, "CREATURE_CONVERT"); - lua_pushnumber(player->L, CREATURE_CONVERT); - lua_settable(player->L, LUA_GLOBALSINDEX); - - lua_pushliteral(player->L, "CREATURE_SPAWN"); - lua_pushnumber(player->L, CREATURE_SPAWN); - lua_settable(player->L, LUA_GLOBALSINDEX); - - lua_pushliteral(player->L, "CREATURE_FEED"); - lua_pushnumber(player->L, CREATURE_FEED); - lua_settable(player->L, LUA_GLOBALSINDEX); - - lua_pushliteral(player->L, "player_number"); - lua_pushnumber(player->L, playerno); - lua_settable(player->L, LUA_GLOBALSINDEX); - - lua_pushliteral(L, "MAXPLAYERS"); - lua_pushnumber(L, MAXPLAYERS); - lua_settable(L, LUA_GLOBALSINDEX); - - lua_setmaxmem(player->L, LUA_MAX_MEM); - lua_dofile(player->L, "player.lua"); - - player_to_network(player, PLAYER_DIRTY_ALL, PACKET_BROADCAST); - return player; -} - -void player_destroy(player_t *player) { - creature_kill_all_players_creatures(player); - - client_t *client; - while ((client = player->clients)) { - player_detach_client(client, player); - }; - - lua_close(player->L); - player->L = NULL; - - player_to_network(player, PLAYER_DIRTY_ALIVE, PACKET_BROADCAST); -} - -void player_set_name(player_t *player, const char *name) { - snprintf(player->name, sizeof(player->name), "%s", name); - player->dirtymask |= PLAYER_DIRTY_NAME; -} +static gui_player_t players[MAXPLAYERS]; +static gui_player_t *king_player = NULL; -void player_mark_for_kill(player_t *player) { - player->kill_me = 1; -} - -int player_num(player_t *player) { - return player - players; -} - -void player_writeto(player_t *player, const void *data, size_t size) { - if (!player->clients) { - assert(player->num_clients == 0); - return; - } - - client_t *client = player->clients; - do { - client_writeto(client, data, size); - client = client->next; - } while (client != player->clients); -} - -player_t *player_by_num(int playerno) { - if (playerno < 0 || playerno >= MAXPLAYERS) - return NULL; - if (!PLAYER_USED(&players[playerno])) - return NULL; - return &players[playerno]; -} - -player_t *player_get_checked_lua(lua_State *L, int playerno) { - if (playerno < 0 || playerno >= MAXPLAYERS) - luaL_error(L, "player number %d out of range", playerno); - - if (!PLAYER_USED(&players[playerno])) - luaL_error(L, "player %d not in use", playerno); - - return &players[playerno]; -} - -int player_attach_client(client_t *client, player_t *player, const char *pass) { - if (!client || !player) - return 0; - - if (!PLAYER_USED(player)) - return 0; - - // Passwort fhslca? - if (strcmp(pass, player->pass)) - return 0; - - if (client->player) { - if (client->player == player) - return 1; - player_detach_client(client, client->player); - } - - client->player = player; - - player->num_clients++; - - if (player->clients) { - client->prev = player->clients; - client->next = player->clients->next; - client->next->prev = client; - client->prev->next = client; - } else { - client->prev = client->next = player->clients = client; - } - assert(client->next->prev == client); - assert(client->prev->next == client); - assert(player->clients->next->prev == player->clients); - assert(player->clients->prev->next == player->clients); - - return 1; -} - -int player_detach_client(client_t *client, player_t *player) { - if (!client || !player) - return 0; - - if (!client->player) - return 0; - - if (client->player != player) - return 0; - - player->num_clients--; - assert(player->num_clients >= 0); - - if (player->num_clients == 0) - player->all_disconnected_time = game_time; - - client->player = NULL; - - if (player->num_clients == 0) { - player->clients = NULL; - } else { - client->next->prev = client->prev; - client->prev->next = client->next; - player->clients = client->next; - assert(client->next->next->prev == client->next); - assert(client->next->prev->next == client->next); - assert(player->clients->next->prev == player->clients); - assert(player->clients->prev->next == player->clients); - } - - client->next = NULL; - client->prev = NULL; - - return 1; -} - -void player_execute_client_lua(player_t *player, const char *source, const char *where) { - int status = luaL_loadbuffer(player->L, source, strlen(source), where); - - if (status == 0) { - int base = lua_gettop(player->L); - lua_pushliteral(player->L, "_TRACEBACK"); - lua_rawget(player->L, LUA_GLOBALSINDEX); - lua_insert(player->L, base); - lua_setcycles(player->L, player->max_cycles); - status = lua_pcall(player->L, 0, 1, base); // Yield() faehig machen? - lua_remove(player->L, base); - } - - const char *msg = lua_tostring(player->L, -1); - - if (status && !msg) - msg = "(error with no message)"; - - if (msg) { - if (strstr(msg, "attempt to yield across C function")) { - player_writeto(player, msg, strlen(msg)); - player_writeto(player, "\n\n", 2); - player_writeto(player, "--------------------------------------------------------------\n", 63); - player_writeto(player, "Long running operations are not allowed from interactive shell\n", 63); - player_writeto(player, "--------------------------------------------------------------\n", 63); - } else { - player_writeto(player, msg, strlen(msg)); - player_writeto(player, "\n", 1); - } - } - lua_pop(player->L, 1); -} - -void player_think() { - static char errorbuf[1000]; - int playerno; - player_t *player = &players[0]; - for (playerno = 0; playerno < MAXPLAYERS; playerno++, player++) { - if (!PLAYER_USED(player)) - continue; - - // Killen? - if (player->kill_me) { - player_writeto(player, "killed\n", 7); - player_destroy(player); - continue; - } - - // Zu wenig Score? - if (player->score <= PLAYER_KICK_SCORE) { - player_writeto(player, "score too low. try harder!\n", 27); - player_destroy(player); - continue; - } - - // Kein Client mehr da? - if (player->num_clients == 0 && - player->all_disconnected_time + NO_PLAYER_DISCONNECT < game_time) - { - player_destroy(player); - continue; - } - - // Alle Viecher tot? neu spawnen. - if (player->num_creatures == 0 && - game_time > player->all_dead_time + PLAYER_CREATURE_RESPAWN_DELAY) - { - int x, y; - world_find_digged(&x, &y); - creature_spawn(player, TILE_XCENTER(x), TILE_YCENTER(y), 0, 0); - world_find_digged(&x, &y); - creature_spawn(player, TILE_XCENTER(x), TILE_YCENTER(y), 0, 0); - //creature_t * first = creature_spawn(player, TILE_XCENTER(world_koth_x()), TILE_YCENTER(world_koth_y()), 1, 0); - // first->food = creature_max_food(first); - } - - // Spiele Luacode aufrufen - lua_pushliteral(player->L, "_TRACEBACK"); - lua_rawget(player->L, LUA_GLOBALSINDEX); - - lua_pushliteral(player->L, "player_think"); - lua_rawget(player->L, LUA_GLOBALSINDEX); - - lua_setcycles(player->L, player->max_cycles); - - switch (lua_pcall(player->L, 0, 0, -2)) { - case LUA_ERRRUN: - snprintf(errorbuf, sizeof(errorbuf), "runtime error: %s", lua_tostring(player->L, -1)); - lua_pop(player->L, 1); - player_writeto(player, errorbuf, strlen(errorbuf)); - break; - case LUA_ERRMEM: - snprintf(errorbuf, sizeof(errorbuf), "mem error: %s", lua_tostring(player->L, -1)); - lua_pop(player->L, 1); - player_writeto(player, errorbuf, strlen(errorbuf)); - break; - case LUA_ERRERR: - snprintf(errorbuf, sizeof(errorbuf), "error calling errorhandler (_TRACEBACK)"); - lua_pop(player->L, 1); - player_writeto(player, errorbuf, strlen(errorbuf)); - break; - default: - break; - } - - int cycles_left = lua_getcycles(player->L); - - if (cycles_left < 0) - cycles_left = 0; - - int newcpu = 100 * (player->max_cycles - cycles_left) / player->max_cycles; - - if (newcpu != player->cpu_usage) { - player->dirtymask |= PLAYER_DIRTY_CPU; - player->cpu_usage = newcpu; - } - - lua_pop(player->L, 1); - - player_to_network(player, player->dirtymask, PACKET_BROADCAST); - player->dirtymask = PLAYER_DIRTY_NONE; - } -} - -#ifdef SERVER_GUI static int player_sort_by_score(const void *a, const void *b) { - const player_t *pa = *(player_t **)a; - const player_t *pb = *(player_t **)b; + const gui_player_t *pa = *(gui_player_t **)a; + const gui_player_t *pb = *(gui_player_t **)b; return -(pa->score > pb->score) + (pa->score < pb->score); } -void player_draw() { +void gui_player_draw() { static int lastturn = 0; static int page = 0; @@ -752,10 +57,10 @@ void player_draw() { int player_displayed = 0; int num_players = 0; - player_t *sorted[MAXPLAYERS]; + gui_player_t *sorted[MAXPLAYERS]; for (n = 0; n < MAXPLAYERS; n++) { - player_t *player = &players[n]; + gui_player_t *player = &players[n]; if (!PLAYER_USED(player)) continue; @@ -763,11 +68,9 @@ void player_draw() { } //printf("%d\n", num_players); - player_t *king = player_king(); - - if (king) king->score += 1000000; // HACKHACK + if (king_player) king_player->score += 1000000; // HACKHACK qsort(sorted, num_players, sizeof(creature_t*), player_sort_by_score); - if (king) king->score -= 1000000; + if (king_player) king_player->score -= 1000000; int offset = per_page * page; if (offset >= num_players) { @@ -782,13 +85,13 @@ void player_draw() { video_rect(0, video_height() - 32, video_width(), video_height() - 16, 0, 0, 0, 0); for (n = offset; n < offset + num; n++) { - player_t *player = sorted[n]; + gui_player_t *player = sorted[n]; assert(PLAYER_USED(player)); // King in dieser Runde? - if (player == king) { + if (player == king_player) { video_draw(player_displayed * 128 + 10, - video_height() - 86 - 20 * abs(sin(M_PI / 750.0 * (SDL_GetTicks() % 750))), + video_height() - 86 - abs(20.0 * sin(M_PI * (SDL_GetTicks() % 550) / 550.0)), sprite_get(SPRITE_CROWN)); } @@ -817,97 +120,13 @@ void player_draw() { player_displayed++; } } -#else -void player_draw() { -} -#endif - -void player_is_king_of_the_hill(player_t *player, int delta) { - //player_t *old_king = king_player; - - king_player = player; - player->last_koth_time = game_time; - player->koth_time += delta; - while (player->koth_time >= 2000) { - player_score(player, CREATURE_KOTH_POINTS, "King of the Hill!"); - player->koth_time -= 2000; - } - - /* - if (king_player != old_king) { - // Network Sync - packet_t packet; int packet_size; - - packet_size = packet_player_update_king(&packet); - client_writeto_all_gui_clients(&packet, packet_size); - } - */ -} - -void player_there_is_no_king() { - //player_t *old_king = king_player; - king_player = NULL; - /* - if (old_king) { - // Network Sync - packet_t packet; int packet_size; - - packet_size = packet_player_update_king(&packet); - client_writeto_all_gui_clients(&packet, packet_size); - } - */ -} - -player_t *player_king() { - if (king_player && PLAYER_USED(king_player)) - return king_player; - else - return NULL; -} - -void player_send_initial_update(client_t *client) { - int playerno; - player_t *player = &players[0]; - for (playerno = 0; playerno < MAXPLAYERS; playerno++, player++) { - if (!PLAYER_USED(player)) - continue; - - player_to_network(player, PLAYER_DIRTY_ALL, client); - } -} - -void player_to_network(player_t *player, int dirtymask, client_t *client) { - if (dirtymask == PLAYER_DIRTY_NONE) - return; - - packet_t packet; - packet_reset(&packet); - - packet_write08(&packet, player_num(player)); - packet_write08(&packet, dirtymask); - if (dirtymask & PLAYER_DIRTY_ALIVE) - packet_write08(&packet, PLAYER_USED(player)); - if (dirtymask & PLAYER_DIRTY_NAME) { - packet_write08(&packet, strlen(player->name)); - packet_writeXX(&packet, &player->name, strlen(player->name)); - } - if (dirtymask & PLAYER_DIRTY_COLOR) - packet_write08(&packet, player->color); - if (dirtymask & PLAYER_DIRTY_CPU) - packet_write08(&packet, player->cpu_usage); - if (dirtymask & PLAYER_DIRTY_SCORE) - packet_write16(&packet, player->score - PLAYER_KICK_SCORE); - - packet_send(PACKET_PLAYER_UPDATE, &packet, client); -} - -void player_from_network(packet_t *packet) { - uint8_t playerno = 0; +void gui_player_from_network(packet_t *packet) { + uint8_t playerno; if (!packet_read08(packet, &playerno)) goto failed; if (playerno >= MAXPLAYERS) goto failed; - player_t *player = &players[playerno]; + gui_player_t *player = &players[playerno]; uint8_t updatemask; if (!packet_read08(packet, &updatemask)) goto failed; @@ -915,9 +134,12 @@ void player_from_network(packet_t *packet) { if (updatemask & PLAYER_DIRTY_ALIVE) { uint8_t alive; if (!packet_read08(packet, &alive)) goto failed; - player->L = alive ? (void*)0x1 : NULL; - if (!alive) + if (!alive) { return; + } else { + memset(player, 0, sizeof(gui_player_t)); + player->used = 1; + } } if (!PLAYER_USED(player)) goto failed; @@ -949,41 +171,26 @@ void player_from_network(packet_t *packet) { return; failed: printf("parsing player update packet failed\n"); - return; } -/* -int packet_player_update_king(packet_t *packet) { - packet->type = PACKET_PLAYER_KING; - if (player_king()) { - packet->player_update_king.king_player = player_num(player_king()); +void gui_player_king_from_network(packet_t *packet) { + uint8_t kingno; + if (!packet_read08(packet, &kingno)) goto failed; + if (kingno == 0xFF) { + king_player = NULL; } else { - packet->player_update_king.king_player = 0xFF; + if (kingno >= MAXPLAYERS) goto failed; + if (!PLAYER_USED(&players[kingno])) goto failed; + king_player = &players[kingno]; } - return sizeof(packet_player_update_king_t); -} - -void packet_handle_player_update_king(packet_t *packet) { - assert(packet->type == PACKET_PLAYER_KING); - if (packet->player_update_king.king_player == 0xFF) { - king_player = NULL; - return; - } - if (packet->player_update_king.king_player >= MAXPLAYERS) - return; - king_player = &players[packet->player_update_king.king_player]; + return; +failed: + printf("parsing king update packet failed\n"); } -*/ -void player_init() { +void gui_player_init() { memset(players, 0, sizeof(players)); } -void player_shutdown() { - int playerno; - for (playerno = 0; playerno < MAXPLAYERS; playerno++) { - if (PLAYER_USED(&players[playerno]) && - players[playerno].L != (void*)0x1) - player_destroy(&players[playerno]); - } +void gui_player_shutdown() { } diff --git a/gui_player.h b/gui_player.h index f9d6597..0f587d1 100644 --- a/gui_player.h +++ b/gui_player.h @@ -23,79 +23,26 @@ #include -#include - #include "packet.h" -#define MAXPLAYERS 32 - -typedef struct player_s { +typedef struct gui_player_s { + int used; char name[16]; - char pass[16]; int color; - lua_State *L; - int num_creatures; - - int num_clients; - client_t *clients; int score; - int koth_time; - int last_koth_time; - - int all_dead_time; - int all_disconnected_time; - - int max_cycles; int cpu_usage; - int kill_me; - unsigned char dirtymask; -#define PLAYER_DIRTY_ALIVE (1 << 0) -#define PLAYER_DIRTY_NAME (1 << 1) -#define PLAYER_DIRTY_COLOR (1 << 2) -#define PLAYER_DIRTY_CPU (1 << 3) -#define PLAYER_DIRTY_SCORE (1 << 4) - -#define PLAYER_DIRTY_ALL 0x1F -#define PLAYER_DIRTY_NONE 0x00 -} player_t; - -player_t players[MAXPLAYERS]; +} gui_player_t; -int player_attach_client(client_t *client, player_t *player, const char *pass); -int player_detach_client(client_t *client, player_t *player); - -void player_on_creature_spawned(player_t *player, int idx, int points); -void player_on_creature_killed(player_t *player, int victim, int killer); -void player_on_creature_attacked(player_t *player, int victim, int attacker); - -void player_execute_client_lua(player_t *player, const char *source, const char *where); - -player_t *player_get_checked_lua(lua_State *L, int playerno); -player_t *player_by_num(int playerno); -int player_num(player_t *player); -void player_writeto(player_t *player, const void *data, size_t size); - -void player_set_name(player_t *player, const char *name); -player_t *player_create(const char *pass); -void player_mark_for_kill(player_t *player); - -void player_think(); -void player_draw(); - -void player_is_king_of_the_hill(player_t *player, int delta); -void player_there_is_no_king(); -player_t *player_king(); +void gui_player_draw(); /* Network */ -void player_send_initial_update(client_t *client); -void player_to_network(player_t *player, int dirtymask, client_t *client); -void player_from_network(packet_t *packet); - +void gui_player_from_network(packet_t *packet); +void gui_player_king_from_network(packet_t *packet); -void player_init(); -void player_shutdown(); +void gui_player_init(); +void gui_player_shutdown(); #endif diff --git a/gui_scroller.c b/gui_scroller.c index d485fb6..598a350 100644 --- a/gui_scroller.c +++ b/gui_scroller.c @@ -75,18 +75,18 @@ void gui_scroller_draw() { video_draw(video_width() - 190, 20, sprite_get(SPRITE_LOGO)); } -void scroller_from_network(packet_t *packet) { +void gui_scroller_from_network(packet_t *packet) { char buf[257]; memcpy(buf, &packet->data, packet->len); buf[packet->len] = '\0'; append(buf); } -void scroller_init() { +void gui_scroller_init() { scrollbuffer = evbuffer_new(); last_time = SDL_GetTicks(); } -void scroller_shutdown() { +void gui_scroller_shutdown() { evbuffer_free(scrollbuffer); } diff --git a/gui_world.c b/gui_world.c index 3271692..973a342 100644 --- a/gui_world.c +++ b/gui_world.c @@ -23,6 +23,7 @@ #include #include "gui_world.h" +#include "video.h" static int world_w; static int world_h; @@ -31,42 +32,21 @@ static int koth_x; static int koth_y; static int *map_sprites; -static int *map_food; +static sprite_t **map_food; static int displaymode; void gui_world_draw() { for (int y = 0; y < world_h; y++) { for (int x = 0; x < world_w; x++) { - int val; - switch (displaymode) { - case 0: - video_draw(x * SPRITE_TILE_SIZE, - y * SPRITE_TILE_SIZE, - sprite_get(map_sprites[y * world_w + x])); - break; - case 1: - val = (int)MAP_TILE(map_pathfind, x, y)->area; - video_rect(x * SPRITE_TILE_SIZE, - y * SPRITE_TILE_SIZE, - (x+1) * SPRITE_TILE_SIZE, - (y+1) * SPRITE_TILE_SIZE, - val % 206, -val / 200, val, 0xFF); - break; - case 2: - val = MAP_TILE(map_pathfind, x, y)->region; - video_rect(x * SPRITE_TILE_SIZE, - y * SPRITE_TILE_SIZE, - (x+1) * SPRITE_TILE_SIZE, - (y+1) * SPRITE_TILE_SIZE, - val * 206, -val * 200, val, 0xFF); - break; - } + video_draw(x * SPRITE_TILE_SIZE, + y * SPRITE_TILE_SIZE, + sprite_get(map_sprites[y * world_w + x])); - int food = map_food[y * world_w + x]; - if (food > 0) { + sprite_t *food_sprite = map_food[y * world_w + x]; + if (food_sprite) { video_draw(x * SPRITE_TILE_SIZE, y * SPRITE_TILE_SIZE, - sprite_get(SPRITE_FOOD + food / 1000)); + food_sprite); } } } @@ -87,10 +67,14 @@ void gui_world_from_network(packet_t *packet) { if (!packet_read08(packet, &spriteno)) goto failed; if (!sprite_exists(spriteno)) goto failed; map_sprites[x + world_w * y] = spriteno; - uint16_t food; - if (!packet_read16(packet, &food)) goto failed; - if (food > MAX_TILE_FOOD) goto failed; - map_food[x + world_w * y] = food; + uint8_t food; + if (!packet_read08(packet, &food)) goto failed; + if (food == 0xFF) { + map_food[x + world_w * y] = NULL; + } else { + if (food >= SPRITE_NUM_FOOD) goto failed; + map_food[x + world_w * y] = sprite_get(SPRITE_FOOD + food); + } return; failed: printf("parsing world update packet failed\n"); @@ -106,7 +90,7 @@ void gui_world_init(int w, int h) { map_sprites = malloc(w * h * sizeof(int)); - map_food = malloc(w * h * sizeof(int)); + map_food = malloc(w * h * sizeof(sprite_t*)); memset(map_food, 0, w * h * sizeof(int)); // Tile Texturen setzen diff --git a/infon.c b/infon.c index 0ecc774..47ff7d7 100644 --- a/infon.c +++ b/infon.c @@ -30,10 +30,10 @@ #include "sprite.h" #include "misc.h" -//#include "gui_creature.h" +#include "gui_creature.h" #include "gui_world.h" #include "gui_scroller.h" -//#include "gui_player.h" +#include "gui_player.h" static int running = 1; @@ -76,13 +76,26 @@ int main(int argc, char *argv[]) { sprite_init(); gui_scroller_init(); gui_world_init(width / SPRITE_TILE_SIZE, height / SPRITE_TILE_SIZE - 2); - //gui_player_init(); - //gui_creature_init(); + gui_player_init(); + gui_creature_init(); game_round = 0; game_time = 0; + Uint32 lastticks = SDL_GetTicks(); while (running && client_is_connected()) { + Uint32 nowticks = SDL_GetTicks(); + + if (nowticks < lastticks || nowticks > lastticks + 1000) { + // Timewarp? + lastticks = nowticks; + SDL_Delay(5); + continue; + } else if (nowticks - lastticks < 10) { + SDL_Delay(5); + continue; + } + SDL_Event event; while (SDL_PollEvent(&event)) { switch (event.type) { @@ -111,15 +124,15 @@ int main(int argc, char *argv[]) { // Anzeigen gui_world_draw(); - creature_draw(); + gui_creature_draw(); gui_scroller_draw(); - player_draw(); + gui_player_draw(); video_flip(); } - //gui_creature_shutdown(); - //gui_player_shutdown(); + gui_creature_shutdown(); + gui_player_shutdown(); gui_world_shutdown(); gui_scroller_shutdown(); diff --git a/packet.c b/packet.c index 781b0e8..1d86ab3 100644 --- a/packet.c +++ b/packet.c @@ -28,17 +28,13 @@ #include "scroller.h" #include "creature.h" -void packet_reset(packet_t *packet) { +void packet_rewind(packet_t *packet) { packet->offset = 0; } -void packet_send(int type, packet_t *packet, client_t *client) { - packet->len = packet->offset; - packet->type = type; - if (!client) - client_writeto_all_gui_clients(packet, 1 + 1 + packet->len); - else - client_writeto(client, packet, 1 + 1 + packet->len); +void packet_init(packet_t *packet, int type) { + packet->type = type; + packet_rewind(packet); } int packet_read08(packet_t *packet, uint8_t *data) { diff --git a/packet.h b/packet.h index 68f11db..f006bd3 100644 --- a/packet.h +++ b/packet.h @@ -21,9 +21,7 @@ #ifndef PACKET_H #define PACKET_H -#include "server.h" - -#define PACKET_BROADCAST NULL +#include typedef struct { // Wire Data @@ -34,14 +32,15 @@ typedef struct { #define PACKET_SCROLLER_MSG 2 #define PACKET_CREATURE_UPDATE 3 #define PACKET_QUIT_MSG 4 +#define PACKET_KOTH_UPDATE 5 #define PACKET_WELCOME_MSG 32 uint8_t data[256]; // Mgmt Data uint8_t offset; } packet_t __attribute__((packed)); -void packet_reset(packet_t *packet); -void packet_send(int type, packet_t *packet, client_t *client); +void packet_rewind(packet_t *packet); +void packet_init (packet_t *packet, int type); int packet_read08(packet_t *packet, uint8_t *data); int packet_read16(packet_t *packet, uint16_t *data); diff --git a/player.c b/player.c index bf1be37..2f2b5d9 100644 --- a/player.c +++ b/player.c @@ -37,6 +37,7 @@ #define PLAYER_USED(player) (!!((player)->L)) +static player_t players[MAXPLAYERS]; static player_t *king_player = NULL; void player_score(player_t *player, int scoredelta, char *reason) { @@ -468,7 +469,7 @@ player_t *player_create(const char *pass) { lua_setmaxmem(player->L, LUA_MAX_MEM); lua_dofile(player->L, "player.lua"); - player_to_network(player, PLAYER_DIRTY_ALL, PACKET_BROADCAST); + player_to_network(player, PLAYER_DIRTY_ALL, SEND_BROADCAST); return player; } @@ -483,7 +484,7 @@ void player_destroy(player_t *player) { lua_close(player->L); player->L = NULL; - player_to_network(player, PLAYER_DIRTY_ALIVE, PACKET_BROADCAST); + player_to_network(player, PLAYER_DIRTY_ALIVE, SEND_BROADCAST); } void player_set_name(player_t *player, const char *name) { @@ -722,13 +723,24 @@ void player_think() { lua_pop(player->L, 1); - player_to_network(player, player->dirtymask, PACKET_BROADCAST); + player_to_network(player, player->dirtymask, SEND_BROADCAST); player->dirtymask = PLAYER_DIRTY_NONE; } } +void player_send_king_update(client_t *client) { + // Network Sync + packet_t packet; + packet_init(&packet, PACKET_KOTH_UPDATE); + if (king_player) + packet_write08(&packet, player_num(king_player)); + else + packet_write08(&packet, 0xFF); + client_send_packet(&packet, client); +} + void player_is_king_of_the_hill(player_t *player, int delta) { - //player_t *old_king = king_player; + player_t *old_king = king_player; king_player = player; player->last_koth_time = game_time; @@ -738,30 +750,16 @@ void player_is_king_of_the_hill(player_t *player, int delta) { player->koth_time -= 2000; } - /* - if (king_player != old_king) { - // Network Sync - packet_t packet; int packet_size; - - packet_size = packet_player_update_king(&packet); - client_writeto_all_gui_clients(&packet, packet_size); - } - */ + if (king_player != old_king) + player_send_king_update(SEND_BROADCAST); } void player_there_is_no_king() { - //player_t *old_king = king_player; + player_t *old_king = king_player; king_player = NULL; - /* - if (old_king) { - // Network Sync - packet_t packet; int packet_size; - - packet_size = packet_player_update_king(&packet); - client_writeto_all_gui_clients(&packet, packet_size); - } - */ + if (old_king) + player_send_king_update(SEND_BROADCAST); } player_t *player_king() { @@ -780,6 +778,8 @@ void player_send_initial_update(client_t *client) { player_to_network(player, PLAYER_DIRTY_ALL, client); } + + player_send_king_update(client); } void player_to_network(player_t *player, int dirtymask, client_t *client) { @@ -787,7 +787,7 @@ void player_to_network(player_t *player, int dirtymask, client_t *client) { return; packet_t packet; - packet_reset(&packet); + packet_init(&packet, PACKET_PLAYER_UPDATE); packet_write08(&packet, player_num(player)); packet_write08(&packet, dirtymask); @@ -804,7 +804,7 @@ void player_to_network(player_t *player, int dirtymask, client_t *client) { if (dirtymask & PLAYER_DIRTY_SCORE) packet_write16(&packet, player->score - PLAYER_KICK_SCORE); - packet_send(PACKET_PLAYER_UPDATE, &packet, client); + client_send_packet(&packet, client); } diff --git a/player.h b/player.h index 2ba55cd..c26e6a4 100644 --- a/player.h +++ b/player.h @@ -27,8 +27,7 @@ #include "server.h" #include "packet.h" - -#define MAXPLAYERS 32 +#include "common_player.h" typedef struct player_s { char name[16]; @@ -53,18 +52,8 @@ typedef struct player_s { int kill_me; unsigned char dirtymask; -#define PLAYER_DIRTY_ALIVE (1 << 0) -#define PLAYER_DIRTY_NAME (1 << 1) -#define PLAYER_DIRTY_COLOR (1 << 2) -#define PLAYER_DIRTY_CPU (1 << 3) -#define PLAYER_DIRTY_SCORE (1 << 4) - -#define PLAYER_DIRTY_ALL 0x1F -#define PLAYER_DIRTY_NONE 0x00 } player_t; -player_t players[MAXPLAYERS]; - int player_attach_client(client_t *client, player_t *player, const char *pass); int player_detach_client(client_t *client, player_t *player); diff --git a/scroller.c b/scroller.c index dfdb35c..de6511e 100644 --- a/scroller.c +++ b/scroller.c @@ -23,11 +23,12 @@ #include "scroller.h" #include "packet.h" +#include "server.h" void add_to_scroller(const char* msg) { // Network Sync packet_t packet; - packet_reset(&packet); + packet_init(&packet, PACKET_SCROLLER_MSG); packet_writeXX(&packet, msg, strlen(msg)); - packet_send(PACKET_SCROLLER_MSG, &packet, PACKET_BROADCAST); + client_send_packet(&packet, SEND_BROADCAST); } diff --git a/server.c b/server.c index 5b8b203..edd9a97 100644 --- a/server.c +++ b/server.c @@ -34,10 +34,10 @@ #include #include +#include "server.h" #include "packet.h" #include "global.h" #include "player.h" -#include "server.h" #include "world.h" #include "listener.h" #include "misc.h" @@ -202,6 +202,14 @@ void client_writeto_all_gui_clients(const void *data, size_t size) { } while (client != guiclients); } +void client_send_packet(packet_t *packet, client_t *client) { + packet->len = packet->offset; + if (!client) + client_writeto_all_gui_clients(packet, 1 + 1 + packet->len); + else + client_writeto(client, packet, 1 + 1 + packet->len); +} + static void client_writable(int fd, short event, void *arg) { struct event *cb_event = arg; client_t *client = &clients[fd]; @@ -230,9 +238,9 @@ void client_destroy(client_t *client, char *reason) { // Versuchen, den Rest rauszuschreiben. if (client->is_gui_client) { packet_t packet; - packet_reset(&packet); + packet_init(&packet, PACKET_QUIT_MSG); packet_writeXX(&packet, reason, strlen(reason)); - packet_send(PACKET_QUIT_MSG, &packet, client); + client_send_packet(&packet, client); } else { evbuffer_add(client->out_buf, "\nconnection terminating: ", 25); evbuffer_add(client->out_buf, reason, strlen(reason)); diff --git a/server.h b/server.h index 7ba6780..42cc66a 100644 --- a/server.h +++ b/server.h @@ -26,8 +26,12 @@ #include +#include "packet.h" + #define MAXCLIENTS 1024 +#define SEND_BROADCAST NULL + typedef struct client_s { struct event rd_event; struct event wr_event; @@ -52,6 +56,9 @@ void client_writeto(client_t *client, const void *data, size_t size); void client_writeto_all_gui_clients(const void *data, size_t size); void client_destroy(client_t *client, char *reason); +void client_send_packet(packet_t *packet, client_t *client); + + void server_tick(); void server_init(); diff --git a/sprite.h b/sprite.h index 769688c..e154445 100644 --- a/sprite.h +++ b/sprite.h @@ -56,7 +56,7 @@ // Thought Konstanten #define SPRITE_THOUGHT (SPRITE_FOOD + SPRITE_NUM_FOOD) -#define SPRITE_NUM_THOUGHT 8 +#define SPRITE_NUM_THOUGHT CREATURE_STATES // Koth Krone #define SPRITE_CROWN (SPRITE_THOUGHT + SPRITE_NUM_THOUGHT) diff --git a/world.c b/world.c index 1cceec8..c89895a 100644 --- a/world.c +++ b/world.c @@ -55,7 +55,7 @@ int world_dig(int x, int y, maptype_e type) { map_dig(map_pathfind, x, y); map_sprites[y * world_w + x] = SPRITE_PLAIN + rand() % SPRITE_NUM_PLAIN; - world_to_network(x, y, PACKET_BROADCAST); + world_to_network(x, y, SEND_BROADCAST); return 1; } @@ -69,6 +69,10 @@ int world_get_food(int x, int y) { return map_food[y * world_w + x]; } +static int food_to_network_food(int food) { + return food == 0 ? 0xFF : food / 1000; +} + int world_add_food(int x, int y, int amount) { if (!world_walkable(x, y)) return 0; @@ -79,8 +83,8 @@ int world_add_food(int x, int y, int amount) { if (new < 0) new = 0; map_food[y * world_w + x] = new; - if (new != old) - world_to_network(x, y, PACKET_BROADCAST); + if (food_to_network_food(new) != food_to_network_food(old)) + world_to_network(x, y, SEND_BROADCAST); return new - old; } @@ -93,10 +97,11 @@ int world_food_eat(int x, int y, int amount) { if (amount > ontile) amount = ontile; - map_food[y * world_w + x] -= amount; + int old = map_food[y * world_w + x]; + int new = map_food[y * world_w + x] -= amount; - if (amount != 0) - world_to_network(x, y, PACKET_BROADCAST); + if (food_to_network_food(new) != food_to_network_food(old)) + world_to_network(x, y, SEND_BROADCAST); return amount; } @@ -140,13 +145,17 @@ void world_send_initial_update(client_t *client) { void world_to_network(int x, int y, client_t *client) { packet_t packet; - packet_reset(&packet); + packet_init(&packet, PACKET_WORLD_UPDATE); packet_write08(&packet, x); packet_write08(&packet, y); packet_write08(&packet, map_sprites[x + world_w * y]); - packet_write16(&packet, map_food[x + world_w * y]); - packet_send(PACKET_WORLD_UPDATE, &packet, client); + if (map_food[x + world_w * y] == 0) { + packet_write08(&packet, 0xFF); + } else { + packet_write08(&packet, map_food[x + world_w * y] / 1000); + } + client_send_packet(&packet, client); } void world_init(int w, int h) {