Skip to content

Commit

Permalink
Multiplayer works. Version 1.1.0.
Browse files Browse the repository at this point in the history
  • Loading branch information
a-nikolaev committed Jul 9, 2013
1 parent 09c3642 commit 979759a
Show file tree
Hide file tree
Showing 18 changed files with 1,176 additions and 115 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ clean:
$(CC) $(CFLAGS) -c $(patsubst %.o,%.c,$@)

$(EXEC): $(OBJS)
$(CC) $(CFLAGS) -o $(EXEC) grid.o state.o king.o output.o main.o $(LDFLAGS)
$(CC) $(CFLAGS) -o $(EXEC) grid.o state.o king.o network.o output.o client.o server.o main.o $(LDFLAGS)


install:
Expand Down
55 changes: 53 additions & 2 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ Command line arguments
Map height (default is 21)

-S [rhombus|rect|hex]
Map shape. It also sets N=4 for rhombus and rectangle, and N=6 for the hexagon.
Map shape (rectangle is default). Max number of countries N=4 for rhombus and rectangle, and N=6 for the hexagon.

-l [2|3| ... N]
Sets L, the number of countries (default is N).
Expand All @@ -52,7 +52,7 @@ Command line arguments
Inequality between the countries (0 is the lowest, 4 in the highest).

-q [1|2| ... L]
Choose player's location by its quality (1 = the best available on the map, L = the worst).
Choose player's location by its quality (1 = the best available on the map, L = the worst). Only in the singleplayer mode.

-r
Absolutely random initial conditions, overrides options -l, -i, and -q.
Expand All @@ -66,6 +66,18 @@ Command line arguments
-R seed
Specify a random seed (unsigned integer) for map generation.

-E [1|2| ... L]
Start a server for not more than L clients.

-e port
Server's port (19140 is default).

-C IP
Start a client and connect to the provided server's IP-address.

-c port
Clients's port (19150 is default).

-h
Display help information

Expand Down Expand Up @@ -169,6 +181,45 @@ Controls

Q quit

Multiplayer
===========

To start a server for two players:
$ ./curseofwar -E 2

To start a client and connect to the server:
$ ./curseofwar -C <server's IP>

To specify ports, use -e option for server's port, and -c option for client's port.
By default, servers are using port 19140, and clients are using port 19150.

Examples:
Start a server for a single client using port 11111
$ ./curseofwar -E 1 -e 11111

To connect to it:
$ ./curseofwar -C <server's IP> -e 11111

Alternatively, to connect to it using port 12345 on the client's side:
$ ./curseofwar -C <server's IP> -c 12345 -e 11111

Note that all needed map options must be setup when you start a server,
the map and other data are transmitted to clients, once they are connected.

Example:
Server for 3 clients, no computer opponents, hexagonal map, and equal conditions for all:
$ ./curseofwar -E3 -l3 -S hex -i0

Game speed cannot be changed by a client, so it must be set initially by the server.
Not all data is sent to clients (e.g. some info about population).

Multiplayer mode is at relatively early development stage. Changes may occure at any moment.
When you play with other people, make sure that you are using the same version of the game.
Hopefully, game's client-server communication protocol will be improved in future.
All communication is made via UDP.

Please, report you problems with multiplayer.

License
=======
Curse of War -- Real Time Strategy Game for Linux.
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.0.4
1.1.0
177 changes: 177 additions & 0 deletions client.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
/******************************************************************************
Curse of War -- Real Time Strategy Game for Linux.
Copyright (C) 2013 Alexey Nikolaev.
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 3 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, see <http://www.gnu.org/licenses/>.
******************************************************************************/
#include "client.h"
#include "state.h"

int client_init ();

int client_connect ();

int client_process_msg_s_state (struct state *st, struct msg_s_data *msg) {

if (ntohl( msg->time ) <= st->time) return -1;

int p, i, j;
for (p=0; p<MAX_PLAYER; ++p) {
st->country[p].gold = ntohl( msg->gold[p] );

st->fg[p].width = msg->width;
st->fg[p].height = msg->height;
}

st->time = ntohl( msg->time );

st->controlled = msg->control;

st->grid.width = msg->width;
st->grid.height = msg->height;

for (i=0; i<MAX_WIDTH; ++i) {
for (j=0; j<MAX_HEIGHT; ++j) {
st->grid.tiles[i][j].cl = msg->tile[i][j];

for (p=0; p<MAX_PLAYER; ++p)
st->grid.tiles[i][j].units[p][citizen] = 0;

st->grid.tiles[i][j].pl = msg->owner[i][j];
st->grid.tiles[i][j].units[msg->owner[i][j]][citizen] = ntohs( msg->pop[i][j] );

for (p=0; p<MAX_PLAYER; ++p){
st->fg[p].call[i][j] = 0;
if ( (msg->flag[i][j] & (1<<p)) == 0)
st->fg[p].flag[i][j] = 0;
else
st->fg[p].flag[i][j] = 1;
}
}
}
return 0;
}

int client_receive_msg_s (int sfd, struct state *st) {
static uint8_t buf[MSG_BUF_SIZE];
static struct msg_s_data msg_data;

struct sockaddr_storage peer_addr; /* address you receive a message from */
socklen_t peer_addr_len = sizeof(peer_addr);

int nread = recvfrom(sfd, buf, MSG_BUF_SIZE-1, 0,
(struct sockaddr *) &peer_addr, &peer_addr_len);
if (nread == -1) return -1; /* Ignore failed request */

uint8_t msg;
if (nread >= 1) {
msg = buf[0];
switch (msg) {
case MSG_S_STATE:
if (nread-1 >= sizeof(struct msg_s_data)) {
memcpy(&msg_data, buf+1, sizeof(struct msg_s_data));
client_process_msg_s_state (st, &msg_data);
}
else {return -1;}
break;
}
}

return msg;
}

int client_process_input (struct state *st, struct ui *ui, char c, int sfd, struct addrinfo *srv_addr) {
int cursi = ui->cursor.i;
int cursj = ui->cursor.j;

switch (c) {
case 'Q':
case 'q':
return 1; /* quit program */
/*
case 'f':
st->prev_speed = st->speed;
st->speed = faster(st->speed);
break;
case 's':
st->prev_speed = st->speed;
st->speed = slower(st->speed);
break;
*/
case 'p':
if (st->speed == sp_pause)
send_msg_c (sfd, srv_addr, MSG_C_PAUSE, 0, 0, 0);
else {
send_msg_c (sfd, srv_addr, MSG_C_UNPAUSE, 0, 0, 0);
}
break;
case 'h': case K_LEFT:
cursi--;
break;
case 'l': case K_RIGHT:
cursi++;
break;
case 'k': case K_UP:
cursj--;
if (cursj % 2 == 1)
cursi++;
break;
case 'j': case K_DOWN:
cursj++;
if (cursj % 2 == 0)
cursi--;
break;
case ' ':
if (st->fg[st->controlled].flag[ui->cursor.i][ui->cursor.j] == 0)
send_msg_c (sfd, srv_addr, MSG_C_FLAG_ON, ui->cursor.i, ui->cursor.j, 0);
else
send_msg_c (sfd, srv_addr, MSG_C_FLAG_OFF, ui->cursor.i, ui->cursor.j, 0);
break;
case 'x':
send_msg_c (sfd, srv_addr, MSG_C_FLAG_OFF_ALL, 0, 0, 0);
break;
case 'c':
send_msg_c (sfd, srv_addr, MSG_C_FLAG_OFF_HALF, 0, 0, 0);
break;
case 'r':
case 'v':
send_msg_c (sfd, srv_addr, MSG_C_BUILD, ui->cursor.i, ui->cursor.j, 0);
break;

case ESCAPE:
case 91:
break;
}

cursi = IN_SEGMENT(cursi, 0, st->grid.width-1);
cursj = IN_SEGMENT(cursj, 0, st->grid.height-1);
if ( is_visible(st->grid.tiles[cursi][cursj].cl) ) {
ui->cursor.i = cursi;
ui->cursor.j = cursj;
}
return 0; /* not finished */
}

void send_msg_c (int sfd, struct addrinfo *srv_addr, uint8_t msg, uint8_t i, uint8_t j, uint8_t info) {
struct msg_c_data mcd = {i, j, info};
static uint8_t buf[MSG_BUF_SIZE];
buf[0] = msg;
memcpy(buf+1, &mcd, sizeof(mcd));
int nsent = sendto(sfd, buf, 1+sizeof(mcd), 0, srv_addr->ai_addr, srv_addr->ai_addrlen);
if (nsent == -1) {
perror("client: sendto");
}
}
34 changes: 34 additions & 0 deletions client.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/******************************************************************************
Curse of War -- Real Time Strategy Game for Linux.
Copyright (C) 2013 Alexey Nikolaev.
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 3 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, see <http://www.gnu.org/licenses/>.
******************************************************************************/
#ifndef _CLIENT_H
#define _CLIENT_H

#include "network.h"
#include "messaging.h"
#include "state.h"

int client_process_input (struct state *st, struct ui *ui, char c, int sfd, struct addrinfo *srv_addr);
int client_process_msg_s_state (struct state *st, struct msg_s_data *msg);

int client_receive_msg_s (int sfd, struct state *st);

void send_msg_c (int sfd, struct addrinfo *srv_addr, uint8_t msg, uint8_t i, uint8_t j, uint8_t info);

#endif
6 changes: 6 additions & 0 deletions common.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@
#define MAX(x,y) (x<y)?(y):(x)
#define IN_SEGMENT(x,l,r) (((x)<(l))?(l) : ( ((x)>(r))?(r):(x) ))

#define ESCAPE '\033'
#define K_UP 65
#define K_DOWN 66
#define K_RIGHT 67
#define K_LEFT 68

/* game speed */
enum config_speed {sp_pause, sp_slowest, sp_slower, sp_slow, sp_normal, sp_fast, sp_faster, sp_fastest};

Expand Down
34 changes: 27 additions & 7 deletions grid.c
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,8 @@ void sort (int val[], int item[], int len) {
}

int conflict (struct grid *g, struct loc loc_arr[], int available_loc_num,
int players[], int players_num, int locations_num, int human_player, int conditions, int ineq)
int players[], int players_num, int locations_num, int ui_players[], int ui_players_num,
int conditions, int ineq)
{
int i, j, p, c;
/* first, remove all cities */
Expand All @@ -329,7 +330,7 @@ int conflict (struct grid *g, struct loc loc_arr[], int available_loc_num,

locations_num = IN_SEGMENT(locations_num, 2, available_loc_num);

int num = MIN(locations_num, players_num);
int num = MIN(locations_num, players_num + ui_players_num);

/* shift in the positions arrays */
int di = rand() % available_loc_num;
Expand Down Expand Up @@ -398,11 +399,20 @@ int conflict (struct grid *g, struct loc loc_arr[], int available_loc_num,
}
}

/* a shuffled copy of the players array */
int *sh_players = malloc(sizeof(int)*players_num);
/* suffled computer players */
int *sh_players_comp = malloc(sizeof(int)*players_num);
for(i=0; i<players_num; ++i)
sh_players[i] = players[i];
shuffle(sh_players, players_num);
sh_players_comp[i] = players[i];
shuffle(sh_players_comp, players_num);

/* a shuffled copy of the players array */
int *sh_players = malloc(sizeof(int)*num);
for(i=0; i<ui_players_num; ++i)
sh_players[i] = ui_players[i];
int dplayer = rand() % players_num;
for(; i<num; ++i)
sh_players[i] = sh_players_comp[(i-ui_players_num + dplayer) % players_num];
shuffle(sh_players, num);

/* human player index */
int ihuman = rand() % num;
Expand All @@ -417,11 +427,21 @@ int conflict (struct grid *g, struct loc loc_arr[], int available_loc_num,
int ii = loc_index[i];
int x = chosen_loc[ ii ].i;
int y = chosen_loc[ ii ].j;
/*
if (human_player != NEUTRAL && ihuman == ii)
g->tiles[x][y].pl = human_player;
else
g->tiles[x][y].pl = sh_players[i];

*/
if (ui_players_num > 1) {
g->tiles[x][y].pl = sh_players[i];
}
else {
if (ii == ihuman)
g->tiles[x][y].pl = ui_players[0];
else
g->tiles[x][y].pl = sh_players_comp[i];
}
g->tiles[x][y].units[ g->tiles[x][y].pl ][citizen] = 10;

i++;
Expand Down
Loading

0 comments on commit 979759a

Please sign in to comment.