-
Notifications
You must be signed in to change notification settings - Fork 0
/
battlefunc.c
269 lines (239 loc) · 8.25 KB
/
battlefunc.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "battle.h"
/* Helper battle functions */
/**
* Write battle command options to attacking client p and
* write to opponent the waiting status.
*/
void menu(struct client *p) {
//p is attacking, opponent is waiting
char outbuf[512];
sprintf(outbuf, "Waiting for %s to strike...\r\n", p->name);
write((p->partner)->fd, outbuf, strlen(outbuf));
/* Remove power move option from menu if necessary */
if (p->power > 0) {
sprintf(outbuf, "(a)ttack\n(p)owermove\n(s)peak something\r\n");
}
else {
sprintf(outbuf, "(a)ttack\n(s)peak something\r\n");
}
write(p->fd, outbuf, strlen(outbuf));
}
/**
* Write hitpoints, powermoves and opponent hp to client p
*/
void stats(struct client *p) {
char outbuf[512];
sprintf(outbuf, "Your hitpoints: %d\r\n", p->hp);
write(p->fd, outbuf, strlen(outbuf));
sprintf(outbuf, "Your powermoves: %d\r\n\n", p->power);
write(p->fd, outbuf, strlen(outbuf));
/* Display opponent hitpoints */
sprintf(outbuf, "%s\'s hitpoints: %d\r\n\n", (p->partner)->name, (p->partner)->hp);
write(p->fd, outbuf, strlen(outbuf));
}
/**
* Process 'a' battle command where client p is attacking.
*/
int regatk(struct client *p){
char outbuf[512];
srand((unsigned) time(NULL)); //Initialize random number generator
//randomize regular attack between 2-6
int atk = (rand() % (6+1-2))+2;
(p->partner)->hp -= atk;
/* Check for game winning condition, opponent hp < 0 */
if (((p->partner)->hp) <= 0) {
return victory(p); //-1 to indicate a victory for battlecmd function
}
else {
sprintf(outbuf, "\nYou hit %s for %d damage!\r\n", (p->partner)->name, atk);
write(p->fd, outbuf, strlen(outbuf));
//write to opponent how much they lost
sprintf(outbuf, "%s hits you for %d damage!\r\n", p->name, atk);
write((p->partner)->fd, outbuf, strlen(outbuf));
}
return 0;
}
/**
* Process 'p' battle command where client p is attacking.
*/
int poweratk(struct client *p){
char outbuf[512];
srand((unsigned) time(NULL));
p->power -= 1;
int atk = (rand() % (6+1-2))+2;
int chance = rand() % 2; //50% chance of hitting, rand value 0 to 1
if (chance == 1) {
(p->partner)->hp -= 3*atk;
}
else {
//attack misses nothing happens to hp
atk = 0;
}
if (((p->partner)->hp ) <= 0) {
return victory(p); //-1 to indicate a victory for battlecmd function
}
else {
if (atk == 0) { //powermove missed
sprintf(outbuf, "\nYou missed!\r\n");
write(p->fd, outbuf, strlen(outbuf));
sprintf(outbuf, "%s missed you!\r\n", p->name);
write((p->partner)->fd, outbuf, strlen(outbuf));
}
else {
sprintf(outbuf, "\nYou hit %s for %d damage!\r\n", (p->partner)->name, 3*atk);
write(p->fd, outbuf, strlen(outbuf));
//write to opponent how much they lost
sprintf(outbuf, "%s powermoves you for %d damage!\r\n", p->name, 3*atk);
write((p->partner)->fd, outbuf, strlen(outbuf));
}
}
return 0;
}
/**
* Process 's' battle command where client p is attacking and wants to speak.
*/
int speak(struct client *p) {
char buf[256]; //buffer for client data (reading from client)
char outbuf[512]; //buffer for output to client
int nbytes;
int inbuf = 0; // buffer is empty; has no bytes
int room = sizeof(buf); // room == capacity of the whole buffer
char *after = buf; // start writing at beginning of buf
while (((nbytes = read(p->fd, after, room)) > 0)) {
inbuf += nbytes;
/* Check for buffer overflow */
if (inbuf >= sizeof(buf)) {
sprintf(outbuf, "\nServer cant handle this lengthy message..\r\n");
write(p->fd, outbuf, strlen(outbuf));
return -1;
}
int where = find_network_newline(buf, inbuf);
if (where >= 0) { // OK. we have a full line
buf[where] = '\0';
buf[where+1] = '\0';
printf("Next message: %s", buf);
sprintf(outbuf, "You speak:%s\r\n\n", buf);
write(p->fd, outbuf, strlen(outbuf));
/* Write the message to opponent */
sprintf(outbuf, "%s takes a break to tell you:\n%s\r\n\n", (p->partner)->name, buf);
write((p->partner)->fd, outbuf, strlen(outbuf));
inbuf -= (where+2);
int i;
for (i=0; i< where; i++) {
buf[i] = '\0';
}
memmove(buf,buf+where+2,inbuf);
break;
}
after = &buf[inbuf];
room = sizeof(buf) - inbuf;
}
if (nbytes == 0) { //Socket closed during speak
return -1; //To be removed by removeclient
}
return 0;
}
/**
* Display game over messages, prepare clients for next battle.
*/
int victory(struct client *p){
char outbuf[512];
/* Display game over messages to battling clients */
sprintf(outbuf, "You are no match for %s. You scurry away...\r\n", p->name);
write((p->partner)->fd, outbuf, strlen(outbuf));
sprintf(outbuf, "%s gives up. You win!\r\n", (p->partner)->name);
write(p->fd, outbuf, strlen(outbuf));
/* Prepare clients for next battles */
sprintf(outbuf, "Awaiting opponent...\r\n");
write(p->fd, outbuf, strlen(outbuf));
write((p->partner)->fd, outbuf, strlen(outbuf));
return -1;
}
/**
* Process battle commands and check for client drop.
* Returns 0 on normal process, 1 for victory, -1 on error
*/
int battlecmd(struct client *p) { //process p battle command
char buf[256]; //buffer for client data (reading from client
char outbuf[512]; //buffer for output to client
int atkresult;
int len = read(p->fd, buf, sizeof(buf) - 1);
if (len > 0) {
if (len > 1) { //discard old lengthy buffers.
int i;
for (i=0; i<len; i++)
buf[i] = '\0';
}
buf[len] = '\0';
/* Check for valid attacking commands 'a' or 'p' */
if (buf[len-1] == 'a' || ((buf[len-1] == 'p') && (p->power != 0))) {
if (buf[len-1] == 'a') {
atkresult = regatk(p);
}
else {
atkresult = poweratk(p);
}
if (atkresult == -1)
return 1; //1 to indicate victory
/* Change client turns */
p->turn = 0;
(p->partner)->turn = 1;
/* Display data for next turn*/
stats(p);
stats(p->partner);
menu(p->partner);
}
else if (buf[len - 1] == 's'){
sprintf(outbuf, "\nSpeak: ");
write(p->fd, outbuf, strlen(outbuf));
/* Call function to buffer for data */
int check = speak(p);
if (check == -1) { //We had a buffer overflow, drop client
sprintf(outbuf, "--%s dropped. You win!\r\n", p->name);
write((p->partner)->fd, outbuf, strlen(outbuf));
printf("Disconnect from %s\n", inet_ntoa(p->ipaddr));
return -1; //Client will be removed by removeclient
}
else { /* Speak successful, continue the active client's turn */
stats(p);
stats(p->partner);
menu(p); //Still p turn and partner still waiting
}
}
else {} //do nothing on invalid cmd, including when powermove = 0
return 0;
}
else if (len == 0) {
//socket is closed
sprintf(outbuf, "--%s dropped. You win!\r\n", p->name);
write((p->partner)->fd, outbuf, strlen(outbuf));
printf("Disconnect from %s\n", inet_ntoa(p->ipaddr));
return -1; //Client will be removed by removeclient
}
else { // shouldn't happen
perror("read");
return -1;
}
}
/**
* Find network newline '\r' in string.
*/
int find_network_newline(char *buf, int inbuf) {
int i = 0;
while (i <= inbuf) {
if (buf[i] == '\r') {
return i;
}
i++;
}
return -1; // '\r' not found
}