Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial NPCs & NPC traits (AI) #57

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ LIBDIR='lib'
WORKDIR='bin'
SRC='itmmorgue.c client.c config.c splash.c locale.c menu.c stuff.c'
SRC="$SRC windows.c area.c chat.c keyboard.c server.c protocol.c sysmsg.c"
SRC="$SRC connection.c levels.c tiles.c player.c event.c"
SRC="$SRC connection.c levels.c tiles.c player.c event.c npc.c npc_traits.c"
HDR='itmmorgue.h client.h config.h default_config.h stuff.h windows.h'
HDR="$HDR area.h chat.h keyboard.h server.h protocol.h sysmsg.h"
HDR="$HDR connection.h levels.h tiles.h player.h event.h"
HDR="$HDR connection.h levels.h tiles.h player.h event.h npc.h npc_traits.h"
LIB='trie/trie.o'
DEBUG=1
####################################################################
Expand Down
7 changes: 7 additions & 0 deletions src/area.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "client.h"
#include "windows.h"
#include "stuff.h"
#include "npc.h"

tile_t *c_curr;
level_t *c_levels = NULL;
Expand Down Expand Up @@ -178,6 +179,12 @@ void draw_area() {
S[S_PLAYER] | color2attr(players[i].color));
}

/* Draw the NPCs */
for (size_t i = 0; i < npcs_len; ++i) {
mvwaddch(W(W_AREA), npcs[i].y - top_y, npcs[i].x - top_x,
S[npcs[i].tile] | color2attr(npcs[i].color));
}

return;
}

28 changes: 9 additions & 19 deletions src/client.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// vim: sw=4 ts=4 et :
#include "itmmorgue.h"
#include "npc.h"

void at_exit(void) {
if (! isendwin()) {
Expand Down Expand Up @@ -112,13 +113,16 @@ void* worker() {
case MSG_PUT_LEVEL:
logger("[C] [PUT_LEVEL]");
break;
case MSG_PUT_NPC:
logger("[C] [PUT_NPC]");
break;
default:
warnf("Unknown type: %d", mbuf.msg.type);
logger("[C] [UNKNOWN]");
continue;
}

char *payload;
char *payload = NULL;

if (mbuf.msg.size > 0) {
payload = malloc(mbuf.msg.size);
Expand All @@ -138,45 +142,31 @@ void* worker() {
switch (mbuf.msg.type) {
case MSG_PUT_CHAT:
c_chat_add(payload);

free(payload);

break;
case MSG_PUT_SYSMSG:
c_sysmsg_add(payload);

free(payload);

break;
case MSG_PUT_AREA:
c_area_update(1, (tileblock_t *)payload);

free(payload);

break;
case MSG_PUT_PLAYERS_FULL:
c_receive_players_full((players_full_mbuf_t *)payload);

free(payload);

break;
case MSG_PUT_PLAYERS:
c_receive_players((players_mbuf_t *)payload);

free(payload);

break;
case MSG_PUT_LEVEL:
c_level_add((level_t *)payload);

free(payload);

break;
case MSG_PUT_NPC:
c_receive_npc((npc_mbuf_t *) payload);
break;
default:
warnf("Unknown type: %d", mbuf.msg.type);
logger("[C] [UNKNOWN]");
continue;
}
free(payload);
} while (server_connected == 1 && ! end);

return NULL;
Expand Down
15 changes: 15 additions & 0 deletions src/event.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// vim: sw=4 ts=4 et :
#include "itmmorgue.h"
#include "npc.h"

// Thread object for event_loop
pthread_t ev_thread;
Expand Down Expand Up @@ -116,9 +117,23 @@ static inline void event_loop() {
P_EV_UNLOCK;
}

// 5. Calculate new NPC actions and apply them
for (size_t id = 0; id < npcs_len; ++id) {
if (npcs[id].trait) {
// Well, context is not defined yet
npcs[id].trait(&npcs[id], NULL);
}
}

// 7. Send new state to the players
for (size_t id = 0; id < players_len; id++) {
s_send_players_full(players + id);
// 7b. Send new NPC states to the players
/* TODO: send updates only for visible NPCs
(maybe even only for ones that changed their state) */
for (size_t npc_id = 0; npc_id < npcs_len; ++npc_id) {
s_send_npc(players[id].connection, &npcs[npc_id]);
}
}
}

Expand Down
49 changes: 49 additions & 0 deletions src/npc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#include "npc.h"

npc_t npcs[2048];
size_t npcs_len = 0;

void s_send_npc(connection_t * connection, npc_t * npc) {
npc_mbuf_t * npc_mbuf;

if (!connection) {
return;
}

if (!(npc_mbuf = (npc_mbuf_t *) malloc(sizeof(npc_mbuf_t)))) {
panic("Error creating npc_mbuf to send!");
}

npc_mbuf->id = npc->id;

npc_mbuf->tile = npc->tile;
npc_mbuf->color = npc->color;

npc_mbuf->x = npc->x;
npc_mbuf->y = npc->y;

mbuf_t s2c_mbuf;
s2c_mbuf.payload = (void *) npc_mbuf;
s2c_mbuf.msg.type = MSG_PUT_NPC;
s2c_mbuf.msg.size = sizeof(npc_mbuf_t);

loggerf("[S] Sending NPC id: %u", npc->id);
mqueue_put(connection->mqueueptr, s2c_mbuf);
}

void c_receive_npc(npc_mbuf_t * mbuf) {
if (!mbuf) {
return;
}

if (npcs_len < mbuf->id + 1) {
npcs_len = mbuf->id + 1;
}

npcs[mbuf->id].tile = mbuf->tile;
npcs[mbuf->id].color = mbuf->color;

npcs[mbuf->id].x = mbuf->x;
npcs[mbuf->id].y = mbuf->y;
}

45 changes: 45 additions & 0 deletions src/npc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#ifndef NPC_H
#define NPC_H

#include "itmmorgue.h"

struct npc;

typedef void (*npc_trait_t)(struct npc * npc, void * ctx);

typedef struct npc {
uint32_t id;

enum stuff tile;
enum colors color;

uint16_t x;
uint16_t y;

/* npc stats (hp, mp, atk, def, (de)buffs, speed...) */

void * trait_ctx;
npc_trait_t trait;
} npc_t;

/* currently, the only difference between partial and full
NPC update is tile and color, so there are no partials */
typedef struct npc_mbuf {
uint32_t id;

enum stuff tile;
enum colors color;

uint16_t x;
uint16_t y;
} npc_mbuf_t;

void s_send_npc(connection_t * connection, npc_t * npc);
void c_receive_npc(npc_mbuf_t * mbuf);

/* should use some data structure with ability to query
by coords (x, y) */
extern npc_t npcs[];
extern size_t npcs_len;

#endif // #ifndef NPC_H
43 changes: 43 additions & 0 deletions src/npc_traits.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#include "npc_traits.h"

void npc_trait_square_movement(npc_t * npc, void * ctx)
{
// ctx is for external context, not bound to current NPC
(void) ctx;

if (!npc) {
return;
}

trait_square_movement_ctx_t * trait_ctx = (trait_square_movement_ctx_t *) npc->trait_ctx;
switch (trait_ctx->direction) {
case TOP:
if (trait_ctx->distance == (trait_ctx->progress)++) {
trait_ctx->direction = RIGHT;
trait_ctx->progress = 0;
}
--(npc->y);
break;
case RIGHT:
if (trait_ctx->distance == (trait_ctx->progress)++) {
trait_ctx->direction = DOWN;
trait_ctx->progress = 0;
}
++(npc->x);
break;
case DOWN:
if (trait_ctx->distance == (trait_ctx->progress)++) {
trait_ctx->direction = LEFT;
trait_ctx->progress = 0;
}
++(npc->y);
break;
case LEFT:
if (trait_ctx->distance == (trait_ctx->progress)++) {
trait_ctx->direction = TOP;
trait_ctx->progress = 0;
}
--(npc->x);
break;
}
}
18 changes: 18 additions & 0 deletions src/npc_traits.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#ifndef NPC_TRAITS_H
#define NPC_TRAITS_H

#include "npc.h"

typedef struct trait_square_movement_ctx {
enum {
TOP = 0,
RIGHT,
DOWN,
LEFT
} direction;
size_t distance, progress;
} trait_square_movement_ctx_t;

void npc_trait_square_movement(npc_t * npc, void * ctx);

#endif // #ifndef NPC_TRAITS_H
2 changes: 2 additions & 0 deletions src/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ typedef struct msg {
MSG_MOVE_PLAYER, // c2s send player's move

MSG_PUT_STATUS, // s2c player status update

MSG_PUT_NPC, // s2c npc transmission
} type;
int version; // Protocol version, generated during compilation
size_t size; // Size of payload or zero if there is no payload
Expand Down
60 changes: 59 additions & 1 deletion src/server.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// vim: sw=4 ts=4 et :
#include "server.h"

#include "npc.h"
#include "npc_traits.h"

connection_t *first_connection;
connection_t *last_connection;

Expand Down Expand Up @@ -333,8 +336,62 @@ void* process_client(connection_t *connection) {
for (size_t i = 0; i < players_len; i++) {
s_send_players_full(players + i);
}
break;

goto chat_out;
}

char * scan = NULL;
if ( (scan = strstr(payload, "!spawn")) ) {
char * x_arg = NULL,
* y_arg = NULL,
* distance_arg = NULL;

while (*scan++) {
if (*scan == ' ' && scan[1] != ' ') {
if (!x_arg) {
x_arg = ++scan;
} else if (!y_arg) {
y_arg = ++scan;
} else if (!distance_arg) {
distance_arg = ++scan;
} else {
break;
}
}
}

int x = 15, y = 15, distance = 5;
if (x_arg) {
x = atoi(x_arg);
}
if (y_arg) {
y = atoi(y_arg);
}
if (distance_arg) {
distance = atoi(distance_arg);
}

trait_square_movement_ctx_t * spawned_ctx =
(trait_square_movement_ctx_t *) calloc(sizeof(trait_square_movement_ctx_t), 1);
spawned_ctx->distance = distance;

npc_t spawned = {
.id = npcs_len,

.tile = S_TRAP,
.color = D_WHITE,

.x = x,
.y = y,

.trait_ctx = spawned_ctx,
.trait = npc_trait_square_movement
};
npcs[npcs_len++] = spawned;

goto chat_out;
}

s_chat_add(&schat, payload);
size = strlen(payload) + 1;

Expand All @@ -355,6 +412,7 @@ void* process_client(connection_t *connection) {
"New message in your chat!\n");
}

chat_out:
free(payload);

break;
Expand Down