Crossfire Client, Trunk  R18666
/home/leaf/crossfire/client/trunk/common/player.c
Go to the documentation of this file.
00001 const char * const rcsid_common_player_c =
00002     "$Id: player.c 12149 2009-08-20 02:11:28Z kbulgrien $";
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 
00040 #include <client.h>
00041 #include <external.h>
00042 #include <script.h>
00043 
00044 /* This translates the numeric direction id's into the actual direction
00045  * commands.  This lets us send the actual command (ie, 'north'), which
00046  * makes handling on the server side easier.
00047  */
00048 
00049 const char *const directions[9] = {"stay", "north", "northeast", "east", "southeast",
00050                 "south","southwest", "west", "northwest"};
00051 
00052 
00053 /*
00054  *  Initialiazes player item, information is received from server
00055  */
00056 void new_player (long tag, char *name, long weight, long face)
00057 {
00058     Spell *spell, *spnext;
00059 
00060     cpl.ob->tag    = tag;
00061     cpl.ob->nrof   = 1;
00062     copy_name (cpl.ob->d_name, name);
00063     cpl.ob->weight = (float) weight / 1000;
00064     cpl.ob->face   = face;
00065 
00066     if (cpl.spelldata) {
00067         for (spell = cpl.spelldata; spell; spell = spnext) {
00068             spnext = spell->next;
00069             free(spell);
00070         }
00071         cpl.spelldata = NULL;
00072     }
00073 
00074 }
00075 
00076 void look_at(int x, int y)
00077 {
00078     cs_print_string(csocket.fd, "lookat %d %d", x, y);
00079 }
00080 
00081 void client_send_apply (int tag)
00082 {
00083     cs_print_string(csocket.fd, "apply %d", tag);
00084 }
00085 
00086 void client_send_examine (int tag)
00087 {
00088     cs_print_string(csocket.fd, "examine %d", tag);
00089 
00090 }
00091 
00092 /* Requests nrof objects of tag get moved to loc. */
00093 void client_send_move (int loc, int tag, int nrof)
00094 {
00095     cs_print_string(csocket.fd, "move %d %d %d", loc, tag, nrof);
00096 }
00097 
00098 
00099 
00100 void move_player(int dir) {
00101     /* Should we perhaps use the real repeat count here? */
00102     send_command(directions[dir], -1, SC_NORMAL);
00103 }
00104 
00105 
00106 /* Fire & Run code.  The server handles repeating of these actions, so
00107  * we only need to send a run or fire command for a particular direction
00108  * once - we use the drun and dfire to keep track if we need to send
00109  * the full command.
00110  */
00111 static int drun=-1, dfire=-1;
00112 
00113 /* Fires in a specified direction.  Note that direction 0 is a valid
00114  * case - the fire is centered on the player.
00115  */
00116 
00117 void stop_fire(void)
00118 {
00119     if (cpl.input_state != Playing) return;
00120     dfire |= 0x100;
00121 }
00122 
00123 void clear_fire_run(void)
00124 {
00125     if ((dfire!=-1) && (dfire & 0x100)) {
00126         send_command("fire_stop", -1, SC_FIRERUN);
00127         dfire=-1;
00128     }
00129     if ((drun!=-1) && (drun & 0x100)) {
00130         send_command("run_stop", -1, SC_FIRERUN);
00131         drun=-1;
00132     }
00133 }
00134 
00135 void clear_fire(void)
00136 {
00137     if (dfire!=-1) {
00138         send_command("fire_stop", -1, SC_FIRERUN);
00139         dfire=-1;
00140     }
00141 }
00142 
00143 void clear_run(void)
00144 {
00145     if (drun!=-1) {
00146         send_command("run_stop", -1, SC_FIRERUN);
00147         drun=-1;
00148     }
00149 }
00150 
00151 
00152 void fire_dir(int dir) {
00153     char buf[MAX_BUF];
00154 
00155     if (cpl.input_state != Playing) return;
00156     if (dir!= dfire) {
00157         snprintf(buf, sizeof(buf), "fire %d", dir);
00158         if (send_command(buf, cpl.count, SC_NORMAL)) {
00159             dfire=dir;
00160             cpl.count=0;
00161         }
00162     } else {
00163         dfire &= 0xff;  /* Mark it so that we need a stop_fire */
00164     }
00165 }
00166 
00167 void stop_run(void)
00168 {
00169     send_command("run_stop", -1, SC_FIRERUN);
00170     drun |= 0x100;
00171 }
00172 
00173 void run_dir(int dir) {
00174     char buf[MAX_BUF];
00175 
00176     if (dir!=drun) {
00177         snprintf(buf, sizeof(buf), "run %d", dir);
00178         if (send_command(buf, -1, SC_NORMAL))
00179             drun=dir;
00180     } else {
00181         drun &= 0xff;
00182     }
00183 }
00184 
00185 
00186 /* This should be used for all 'command' processing.  Other functions should
00187  * call this so that proper windowing will be done.
00188  * command is the text command, repeat is a count value, or -1 if none
00189  * is desired and we don't want to reset the current count.
00190  * must_send means we must send this command no matter what (ie, it is
00191  * an administrative type of command like fire_stop, and failure to send
00192  * it will cause definate problems
00193  * return 1 if command was sent, 0 if not sent.
00194  */
00195 
00196 int send_command(const char *command, int repeat, int must_send) {
00197     static char last_command[MAX_BUF]="";
00198 
00199     script_monitor(command,repeat,must_send);
00200     if (cpl.input_state==Reply_One) {
00201         LOG(LOG_ERROR,"common::send_command","Wont send command '%s' - since in reply mode!",
00202                 command);
00203         cpl.count=0;
00204         return 0;
00205     }
00206 
00207     /* Does the server understand 'ncom'? If so, special code */
00208     if (csocket.cs_version >= 1021) {
00209         int commdiff=csocket.command_sent - csocket.command_received;
00210 
00211         if (commdiff<0) commdiff +=256;
00212 
00213         /* if too many unanswered commands, not a must send, and command is
00214          * the same, drop it
00215          */
00216         if (commdiff>use_config[CONFIG_CWINDOW] && !must_send && !strcmp(command, last_command)) {
00217             if (repeat!=-1) cpl.count=0;
00218             return 0;
00219 #if 0 /* Obnoxious warning message we don't need */
00220             fprintf(stderr,"Wont send command %s - window oversized %d %d\n",
00221                     command, csocket.command_sent, csocket.command_received);
00222 #endif
00223         }
00224         else {
00225             SockList sl;
00226             uint8 buf[MAX_BUF];
00227 
00228             /* Don't want to copy in administrative commands */
00229             if (!must_send) strcpy(last_command, command);
00230             csocket.command_sent++;
00231             csocket.command_sent &= 0xff;   /* max out at 255 */
00232 
00233             SockList_Init(&sl, buf);
00234             SockList_AddString(&sl, "ncom ");
00235             SockList_AddShort(&sl, csocket.command_sent);
00236             SockList_AddInt(&sl, repeat);
00237             SockList_AddString(&sl, command);
00238             SockList_Send(&sl, csocket.fd);
00239         }
00240     } else {
00241         cs_print_string(csocket.fd, "command %d %s", repeat,command);
00242     }
00243     if (repeat!=-1) cpl.count=0;
00244     return 1;
00245 }
00246 
00247 void CompleteCmd(unsigned char *data, int len)
00248 {
00249     if (len !=6) {
00250         LOG(LOG_ERROR,"common::CompleteCmd","Invalid length %d - ignoring", len);
00251         return;
00252     }
00253     csocket.command_received = GetShort_String(data);
00254     csocket.command_time = GetInt_String(data+2);
00255     script_sync(csocket.command_sent - csocket.command_received);
00256 }
00257 
00258 
00259 
00260 /* This does special processing on the 'take' command.  If the
00261  * player has a container open, we want to specifiy what object
00262  * to move from that since we've sorted it.  command is
00263  * the command as tped, cpnext is any optional params.
00264  */
00265 void command_take (const char *command, const char *cpnext)
00266 {
00267     /* If the player has specified optional data, or the player
00268      * does not have a container open, just issue the command
00269      * as normal
00270      */
00271     if (cpnext || cpl.container == NULL)
00272         send_command(command, cpl.count, 0);
00273     else {
00274         if (cpl.container->inv == NULL)
00275             draw_ext_info(NDI_BLACK, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_NOTICE,
00276                 "There is nothing in the container to move");
00277         else
00278             cs_print_string(csocket.fd,"move %d %d %d", cpl.ob->tag,
00279                 cpl.container->inv->tag, cpl.count);
00280     }
00281 }