Crossfire Client, Trunk  R20922
player.c
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2013 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
29 #include "client.h"
30 #include "external.h"
31 #include "script.h"
32 
33 bool profile_latency = false;
34 
36 const char *const directions[] = {"stay", "north", "northeast",
37  "east", "southeast", "south",
38  "southwest", "west", "northwest"};
39 
43 void new_player(long tag, char *name, long weight, long face) {
44  Spell *spell, *spnext;
45 
46  cpl.ob->tag = tag;
47  cpl.ob->nrof = 1;
48  copy_name(cpl.ob->d_name, name);
49 
50  /* Right after player exit server will send this with empty name. */
51  if (strlen(name) != 0) {
52  keybindings_init(name);
53  }
54 
55  cpl.ob->weight = (float)weight / 1000;
56  cpl.ob->face = face;
57 
58  if (cpl.spelldata) {
59  for (spell = cpl.spelldata; spell; spell = spnext) {
60  spnext = spell->next;
61  free(spell);
62  }
63  cpl.spelldata = NULL;
64  }
65 }
66 
67 void look_at(int x, int y) {
68  cs_print_string(csocket.fd, "lookat %d %d", x, y);
69 }
70 
71 void client_send_apply(int tag) {
72  cs_print_string(csocket.fd, "apply %d", tag);
73 }
74 
75 void client_send_examine(int tag) {
76  cs_print_string(csocket.fd, "examine %d", tag);
77 }
78 
82 void client_send_move(int loc, int tag, int nrof) {
83  cs_print_string(csocket.fd, "move %d %d %d", loc, tag, nrof);
84 }
85 
86 /* Fire & Run code. The server handles repeating of these actions, so
87  * we only need to send a run or fire command for a particular direction
88  * once - we use the drun and dfire to keep track if we need to send
89  * the full command.
90  */
91 static int drun=-1, dfire=-1;
92 
93 void stop_fire() {
94  if (cpl.input_state != Playing) {
95  return;
96  }
97  dfire |= 0x100;
98 }
99 
100 void clear_fire() {
101  if (dfire != -1) {
102  send_command("fire_stop", -1, SC_FIRERUN);
103  dfire = -1;
104  }
105 }
106 
107 void clear_run() {
108  if (drun != -1) {
109  send_command("run_stop", -1, SC_FIRERUN);
110  drun = -1;
111  }
112 }
113 
114 void fire_dir(int dir) {
115  if (cpl.input_state != Playing) {
116  return;
117  }
118  if (dir != dfire) {
119  char buf[MAX_BUF];
120  snprintf(buf, sizeof(buf), "fire %d", dir);
121  if (send_command(buf, cpl.count, SC_NORMAL)) {
122  dfire = dir;
123  cpl.count = 0;
124  }
125  } else {
126  dfire &= 0xff; /* Mark it so that we need a stop_fire */
127  }
128 }
129 
130 void stop_run() {
131  send_command("run_stop", -1, SC_FIRERUN);
132  drun |= 0x100;
133 }
134 
135 void run_dir(int dir) {
136  if (dir != drun) {
137  char buf[MAX_BUF];
138  snprintf(buf, sizeof(buf), "run %d", dir);
139  if (send_command(buf, -1, SC_NORMAL)) {
140  drun = dir;
141  }
142  } else {
143  drun &= 0xff;
144  }
145 }
146 
147 /* This should be used for all 'command' processing. Other functions should
148  * call this so that proper windowing will be done.
149  * command is the text command, repeat is a count value, or -1 if none
150  * is desired and we don't want to reset the current count.
151  * must_send means we must send this command no matter what (ie, it is
152  * an administrative type of command like fire_stop, and failure to send
153  * it will cause definate problems
154  * return 1 if command was sent, 0 if not sent.
155  */
156 int send_command(const char *command, int repeat, int must_send) {
157  static char last_command[MAX_BUF]="";
158 
159  script_monitor(command,repeat,must_send);
160  if (cpl.input_state==Reply_One) {
161  LOG(LOG_ERROR,"common::send_command","Wont send command '%s' - since in reply mode!",
162  command);
163  cpl.count=0;
164  return 0;
165  }
166 
167  /* Does the server understand 'ncom'? If so, special code */
168  if (csocket.cs_version >= 1021) {
170 
171  if (commdiff<0) {
172  commdiff +=256;
173  }
174 
175  /* if too many unanswered commands, not a must send, and command is
176  * the same, drop it
177  */
178  if (commdiff>use_config[CONFIG_CWINDOW] && !must_send && !strcmp(command, last_command)) {
179  if (repeat!=-1) {
180  cpl.count=0;
181  }
182  return 0;
183 #if 0 /* Obnoxious warning message we don't need */
184  fprintf(stderr,"Wont send command %s - window oversized %d %d\n",
186 #endif
187  } else {
188  SockList sl;
189  guint8 buf[MAX_BUF];
190 
191  /* Don't want to copy in administrative commands */
192  if (!must_send) {
193  strcpy(last_command, command);
194  }
196  csocket.command_sent &= 0xff; /* max out at 255 */
197 
198  SockList_Init(&sl, buf);
199  SockList_AddString(&sl, "ncom ");
201  SockList_AddInt(&sl, repeat);
202  SockList_AddString(&sl, command);
203  SockList_Send(&sl, csocket.fd);
204  if (profile_latency) {
205  printf("[profile/com] %d,%" G_GINT64_FORMAT ",%s\n",
206  csocket.command_sent, g_get_monotonic_time(), command);
207  }
208  }
209  } else {
210  cs_print_string(csocket.fd, "command %d %s", repeat,command);
211  }
212  if (repeat!=-1) {
213  cpl.count=0;
214  }
215  return 1;
216 }
217 
218 void CompleteCmd(unsigned char *data, int len) {
219  if (len !=6) {
220  LOG(LOG_ERROR,"common::CompleteCmd","Invalid length %d - ignoring", len);
221  return;
222  }
225  const int in_flight = csocket.command_sent - csocket.command_received;
226  if (profile_latency) {
227  gint64 t = g_get_monotonic_time();
228  printf("[profile/comc] %d,%" G_GINT64_FORMAT ",%d,%d\n",
230  }
231  script_sync(in_flight);
232 }
233 
234 /* This does special processing on the 'take' command. If the
235  * player has a container open, we want to specifiy what object
236  * to move from that since we've sorted it. command is
237  * the command as tped, cpnext is any optional params.
238  */
239 void command_take(const char *command, const char *cpnext) {
240  /* If the player has specified optional data, or the player
241  * does not have a container open, just issue the command
242  * as normal
243  */
244  if (cpnext || cpl.container == NULL) {
245  send_command(command, cpl.count, 0);
246  } else {
247  if (cpl.container->inv == NULL)
249  "There is nothing in the container to move");
250  else
251  cs_print_string(csocket.fd,"move %d %d %d", cpl.ob->tag,
253  }
254 }
float weight
Definition: item.h:61
#define copy_name(t, f)
Definition: item.h:43
int command_time
Definition: client.h:128
void SockList_AddShort(SockList *sl, guint16 data)
Definition: newsocket.c:64
GSocketConnection * fd
Definition: client.h:120
void command_take(const char *command, const char *cpnext)
Definition: player.c:239
gint16 use_config[CONFIG_NUMS]
Definition: init.c:40
void run_dir(int dir)
Definition: player.c:135
short GetShort_String(const unsigned char *data)
Definition: newsocket.c:172
item * ob
Definition: client.h:336
ClientSocket csocket
Definition: client.c:67
#define MSG_TYPE_CLIENT
Definition: newclient.h:395
#define NDI_BLACK
Definition: newclient.h:221
gint32 tag
Definition: item.h:59
guint32 nrof
Definition: item.h:60
void script_sync(int commdiff)
Definition: script.c:480
void LOG(LogLevel level, const char *origin, const char *format,...)
Definition: misc.c:109
void client_send_apply(int tag)
Definition: player.c:71
void look_at(int x, int y)
Definition: player.c:67
#define MSG_TYPE_CLIENT_NOTICE
Definition: newclient.h:664
void SockList_AddInt(SockList *sl, guint32 data)
Definition: newsocket.c:80
int send_command(const char *command, int repeat, int must_send)
Definition: player.c:156
void clear_fire()
Definition: player.c:100
char d_name[NAME_LEN]
Definition: item.h:55
int SockList_Send(SockList *sl, GSocketConnection *c)
Definition: newsocket.c:112
Client_Player cpl
Definition: client.c:66
item * container
Definition: client.h:339
void client_send_move(int loc, int tag, int nrof)
Definition: player.c:82
#define CONFIG_CWINDOW
Definition: client.h:188
void SockList_AddString(SockList *sl, const char *str)
Definition: newsocket.c:98
#define MAX_BUF
Definition: client.h:40
void new_player(long tag, char *name, long weight, long face)
Definition: player.c:43
bool profile_latency
Definition: player.c:33
guint32 count
Definition: client.h:359
struct Spell_struct * next
Definition: client.h:295
Warning that something definitely didn&#39;t work.
Definition: client.h:444
void stop_fire()
Definition: player.c:93
static int drun
Definition: player.c:91
Spell * spelldata
Definition: client.h:350
#define SC_NORMAL
Definition: client.h:93
static int dfire
Definition: player.c:91
#define SC_FIRERUN
Definition: client.h:94
void draw_ext_info(int orig_color, int type, int subtype, const char *message)
Definition: info.c:932
void SockList_Init(SockList *sl, guint8 *buf)
Definition: newsocket.c:32
int command_sent
Definition: client.h:123
void client_send_examine(int tag)
Definition: player.c:75
Input_State input_state
Definition: client.h:341
int command_received
Definition: client.h:123
void CompleteCmd(unsigned char *data, int len)
Definition: player.c:218
int cs_print_string(GSocketConnection *fd, const char *str,...)
Definition: newsocket.c:245
gint16 face
Definition: item.h:62
struct item_struct * inv
Definition: item.h:54
void clear_run()
Definition: player.c:107
void stop_run()
Definition: player.c:130
int GetInt_String(const unsigned char *data)
Definition: newsocket.c:142
const char *const directions[]
Definition: player.c:36
void fire_dir(int dir)
Definition: player.c:114
void script_monitor(const char *command, int repeat, int must_send)
Definition: script.c:919
int cs_version
Definition: client.h:121
void keybindings_init(const char *character_name)
Definition: keys.c:541