Crossfire Client, Branch
R11627
|
00001 const char * const rcsid_common_player_c = 00002 "$Id: player.c 9201 2008-06-01 17:32:45Z anmaster $"; 00003 /* 00004 Crossfire client, a client program for the crossfire program. 00005 00006 Copyright (C) 2001 Mark Wedel & Crossfire Development Team 00007 00008 This program is free software; you can redistribute it and/or modify 00009 it under the terms of the GNU General Public License as published by 00010 the Free Software Foundation; either version 2 of the License, or 00011 (at your option) any later version. 00012 00013 This program is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 GNU General Public License for more details. 00017 00018 You should have received a copy of the GNU General Public License 00019 along with this program; if not, write to the Free Software 00020 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00021 00022 The author can be reached via e-mail to crossfire-devel@real-time.com 00023 */ 00024 00025 00026 #include <client.h> 00027 #include <external.h> 00028 #include <script.h> 00029 00030 /* This file handles various player related functions. This includes 00031 * both things that operate on the player item, cpl structure, or 00032 * various commands that the player issues. 00033 * 00034 * This file does most of the handling of commands from the client to 00035 * server (see commands.c for server->client) 00036 * 00037 * does most of the work for sending messages to the server 00038 * Again, most of these appear self explanatory. Most send a bunch of 00039 * commands like apply, examine, fire, run, etc. This looks like it 00040 * was done by Mark to remove the old keypress stupidity I used. 00041 */ 00042 00043 /* This translates the numeric direction id's into the actual direction 00044 * commands. This lets us send the actual command (ie, 'north'), which 00045 * makes handling on the server side easier. 00046 */ 00047 00048 const char *const directions[9] = {"stay", "north", "northeast", "east", "southeast", 00049 "south","southwest", "west", "northwest"}; 00050 00051 00052 /* 00053 * Initialiazes player item, information is received from server 00054 */ 00055 void new_player (long tag, char *name, long weight, long face) 00056 { 00057 Spell *spell, *spnext; 00058 00059 cpl.ob->tag = tag; 00060 cpl.ob->nrof = 1; 00061 copy_name (cpl.ob->d_name, name); 00062 cpl.ob->weight = (float) weight / 1000; 00063 cpl.ob->face = face; 00064 00065 if (cpl.spelldata) { 00066 for (spell = cpl.spelldata; spell; spell = spnext) { 00067 spnext = spell->next; 00068 free(spell); 00069 } 00070 cpl.spelldata = NULL; 00071 } 00072 00073 } 00074 00075 void look_at(int x, int y) 00076 { 00077 cs_print_string(csocket.fd, "lookat %d %d", x, y); 00078 } 00079 00080 void client_send_apply (int tag) 00081 { 00082 cs_print_string(csocket.fd, "apply %d", tag); 00083 } 00084 00085 void client_send_examine (int tag) 00086 { 00087 cs_print_string(csocket.fd, "examine %d", tag); 00088 00089 } 00090 00091 /* Requests nrof objects of tag get moved to loc. */ 00092 void client_send_move (int loc, int tag, int nrof) 00093 { 00094 cs_print_string(csocket.fd, "move %d %d %d", loc, tag, nrof); 00095 } 00096 00097 00098 00099 void move_player(int dir) { 00100 /* Should we perhaps use the real repeat count here? */ 00101 send_command(directions[dir], -1, SC_NORMAL); 00102 } 00103 00104 00105 /* Fire & Run code. The server handles repeating of these actions, so 00106 * we only need to send a run or fire command for a particular direction 00107 * once - we use the drun and dfire to keep track if we need to send 00108 * the full command. 00109 */ 00110 static int drun=-1, dfire=-1; 00111 00112 /* Fires in a specified direction. Note that direction 0 is a valid 00113 * case - the fire is centered on the player. 00114 */ 00115 00116 void stop_fire(void) 00117 { 00118 if (cpl.input_state != Playing) return; 00119 dfire |= 0x100; 00120 } 00121 00122 void clear_fire_run(void) 00123 { 00124 if ((dfire!=-1) && (dfire & 0x100)) { 00125 send_command("fire_stop", -1, SC_FIRERUN); 00126 dfire=-1; 00127 } 00128 if ((drun!=-1) && (drun & 0x100)) { 00129 send_command("run_stop", -1, SC_FIRERUN); 00130 drun=-1; 00131 } 00132 } 00133 00134 void clear_fire(void) 00135 { 00136 if (dfire!=-1) { 00137 send_command("fire_stop", -1, SC_FIRERUN); 00138 dfire=-1; 00139 } 00140 } 00141 00142 void clear_run(void) 00143 { 00144 if (drun!=-1) { 00145 send_command("run_stop", -1, SC_FIRERUN); 00146 drun=-1; 00147 } 00148 } 00149 00150 00151 void fire_dir(int dir) { 00152 char buf[MAX_BUF]; 00153 00154 if (cpl.input_state != Playing) return; 00155 if (dir!= dfire) { 00156 snprintf(buf, sizeof(buf), "fire %d", dir); 00157 if (send_command(buf, cpl.count, SC_NORMAL)) { 00158 dfire=dir; 00159 cpl.count=0; 00160 } 00161 } else { 00162 dfire &= 0xff; /* Mark it so that we need a stop_fire */ 00163 } 00164 } 00165 00166 void stop_run(void) 00167 { 00168 send_command("run_stop", -1, SC_FIRERUN); 00169 drun |= 0x100; 00170 } 00171 00172 void run_dir(int dir) { 00173 char buf[MAX_BUF]; 00174 00175 if (dir!=drun) { 00176 snprintf(buf, sizeof(buf), "run %d", dir); 00177 if (send_command(buf, -1, SC_NORMAL)) 00178 drun=dir; 00179 } else { 00180 drun &= 0xff; 00181 } 00182 } 00183 00184 00185 /* This should be used for all 'command' processing. Other functions should 00186 * call this so that proper windowing will be done. 00187 * command is the text command, repeat is a count value, or -1 if none 00188 * is desired and we don't want to reset the current count. 00189 * must_send means we must send this command no matter what (ie, it is 00190 * an administrative type of command like fire_stop, and failure to send 00191 * it will cause definate problems 00192 * return 1 if command was sent, 0 if not sent. 00193 */ 00194 00195 int send_command(const char *command, int repeat, int must_send) { 00196 static char last_command[MAX_BUF]=""; 00197 00198 script_monitor(command,repeat,must_send); 00199 if (cpl.input_state==Reply_One) { 00200 LOG(LOG_ERROR,"common::send_command","Wont send command '%s' - since in reply mode!", 00201 command); 00202 cpl.count=0; 00203 return 0; 00204 } 00205 00206 /* Does the server understand 'ncom'? If so, special code */ 00207 if (csocket.cs_version >= 1021) { 00208 int commdiff=csocket.command_sent - csocket.command_received; 00209 00210 if (commdiff<0) commdiff +=256; 00211 00212 /* if too many unanswered commands, not a must send, and command is 00213 * the same, drop it 00214 */ 00215 if (commdiff>use_config[CONFIG_CWINDOW] && !must_send && !strcmp(command, last_command)) { 00216 if (repeat!=-1) cpl.count=0; 00217 return 0; 00218 #if 0 /* Obnoxious warning message we don't need */ 00219 fprintf(stderr,"Wont send command %s - window oversized %d %d\n", 00220 command, csocket.command_sent, csocket.command_received); 00221 #endif 00222 } 00223 else { 00224 SockList sl; 00225 uint8 buf[MAX_BUF]; 00226 00227 /* Don't want to copy in administrative commands */ 00228 if (!must_send) strcpy(last_command, command); 00229 csocket.command_sent++; 00230 csocket.command_sent &= 0xff; /* max out at 255 */ 00231 00232 SockList_Init(&sl, buf); 00233 SockList_AddString(&sl, "ncom "); 00234 SockList_AddShort(&sl, csocket.command_sent); 00235 SockList_AddInt(&sl, repeat); 00236 SockList_AddString(&sl, command); 00237 SockList_Send(&sl, csocket.fd); 00238 } 00239 } else { 00240 cs_print_string(csocket.fd, "command %d %s", repeat,command); 00241 } 00242 if (repeat!=-1) cpl.count=0; 00243 return 1; 00244 } 00245 00246 void CompleteCmd(unsigned char *data, int len) 00247 { 00248 if (len !=6) { 00249 LOG(LOG_ERROR,"common::CompleteCmd","Invalid length %d - ignoring", len); 00250 return; 00251 } 00252 csocket.command_received = GetShort_String(data); 00253 csocket.command_time = GetInt_String(data+2); 00254 script_sync(csocket.command_sent - csocket.command_received); 00255 } 00256 00257 00258 00259 /* This does special processing on the 'take' command. If the 00260 * player has a container open, we want to specifiy what object 00261 * to move from that since we've sorted it. command is 00262 * the command as tped, cpnext is any optional params. 00263 */ 00264 void command_take (const char *command, const char *cpnext) 00265 { 00266 /* If the player has specified optional data, or the player 00267 * does not have a container open, just issue the command 00268 * as normal 00269 */ 00270 if (cpnext || cpl.container == NULL) 00271 send_command(command, cpl.count, 0); 00272 else { 00273 if (cpl.container->inv == NULL) 00274 draw_info("There is nothing in the container to move", NDI_BLACK); 00275 else 00276 cs_print_string(csocket.fd,"move %d %d %d", cpl.ob->tag, 00277 cpl.container->inv->tag, cpl.count); 00278 } 00279 }