Crossfire Client, Trunk  R19307
player.c
Go to the documentation of this file.
00001 /*
00002  * Crossfire -- cooperative multi-player graphical RPG and adventure game
00003  *
00004  * Copyright (c) 1999-2013 Mark Wedel and the Crossfire Development Team
00005  * Copyright (c) 1992 Frank Tore Johansen
00006  *
00007  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
00008  * welcome to redistribute it under certain conditions. For details, please
00009  * see COPYING and LICENSE.
00010  *
00011  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
00012  */
00013 
00029 #include <client.h>
00030 #include <external.h>
00031 #include <script.h>
00032 
00033 /* This translates the numeric direction id's into the actual direction
00034  * commands.  This lets us send the actual command (ie, 'north'), which
00035  * makes handling on the server side easier.
00036  */
00037 
00038 const char *const directions[9] = {"stay", "north", "northeast", "east", "southeast",
00039                                    "south","southwest", "west", "northwest"
00040                                   };
00041 
00042 
00043 /*
00044  *  Initialiazes player item, information is received from server
00045  */
00046 void new_player (long tag, char *name, long weight, long face)
00047 {
00048     Spell *spell, *spnext;
00049 
00050     cpl.ob->tag    = tag;
00051     cpl.ob->nrof   = 1;
00052     copy_name (cpl.ob->d_name, name);
00053 
00054     /* Right after player exit server will send this with empty name. */
00055     if (strlen(name) != 0) {
00056         keybindings_init(name);
00057     }
00058 
00059     cpl.ob->weight = (float) weight / 1000;
00060     cpl.ob->face   = face;
00061 
00062     if (cpl.spelldata) {
00063         for (spell = cpl.spelldata; spell; spell = spnext) {
00064             spnext = spell->next;
00065             free(spell);
00066         }
00067         cpl.spelldata = NULL;
00068     }
00069 
00070 }
00071 
00072 void look_at(int x, int y)
00073 {
00074     cs_print_string(csocket.fd, "lookat %d %d", x, y);
00075 }
00076 
00077 void client_send_apply (int tag)
00078 {
00079     cs_print_string(csocket.fd, "apply %d", tag);
00080 }
00081 
00082 void client_send_examine (int tag)
00083 {
00084     cs_print_string(csocket.fd, "examine %d", tag);
00085 
00086 }
00087 
00088 /* Requests nrof objects of tag get moved to loc. */
00089 void client_send_move (int loc, int tag, int nrof)
00090 {
00091     cs_print_string(csocket.fd, "move %d %d %d", loc, tag, nrof);
00092 }
00093 
00094 
00095 
00096 void move_player(int dir)
00097 {
00098     /* Should we perhaps use the real repeat count here? */
00099     send_command(directions[dir], -1, SC_NORMAL);
00100 }
00101 
00102 
00103 /* Fire & Run code.  The server handles repeating of these actions, so
00104  * we only need to send a run or fire command for a particular direction
00105  * once - we use the drun and dfire to keep track if we need to send
00106  * the full command.
00107  */
00108 static int drun=-1, dfire=-1;
00109 
00110 /* Fires in a specified direction.  Note that direction 0 is a valid
00111  * case - the fire is centered on the player.
00112  */
00113 
00114 void stop_fire(void)
00115 {
00116     if (cpl.input_state != Playing) {
00117         return;
00118     }
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 {
00153     char buf[MAX_BUF];
00154 
00155     if (cpl.input_state != Playing) {
00156         return;
00157     }
00158     if (dir!= dfire) {
00159         snprintf(buf, sizeof(buf), "fire %d", dir);
00160         if (send_command(buf, cpl.count, SC_NORMAL)) {
00161             dfire=dir;
00162             cpl.count=0;
00163         }
00164     } else {
00165         dfire &= 0xff;  /* Mark it so that we need a stop_fire */
00166     }
00167 }
00168 
00169 void stop_run(void)
00170 {
00171     send_command("run_stop", -1, SC_FIRERUN);
00172     drun |= 0x100;
00173 }
00174 
00175 void run_dir(int dir)
00176 {
00177     char buf[MAX_BUF];
00178 
00179     if (dir!=drun) {
00180         snprintf(buf, sizeof(buf), "run %d", dir);
00181         if (send_command(buf, -1, SC_NORMAL)) {
00182             drun=dir;
00183         }
00184     } else {
00185         drun &= 0xff;
00186     }
00187 }
00188 
00189 
00190 /* This should be used for all 'command' processing.  Other functions should
00191  * call this so that proper windowing will be done.
00192  * command is the text command, repeat is a count value, or -1 if none
00193  * is desired and we don't want to reset the current count.
00194  * must_send means we must send this command no matter what (ie, it is
00195  * an administrative type of command like fire_stop, and failure to send
00196  * it will cause definate problems
00197  * return 1 if command was sent, 0 if not sent.
00198  */
00199 
00200 int send_command(const char *command, int repeat, int must_send)
00201 {
00202     static char last_command[MAX_BUF]="";
00203 
00204     script_monitor(command,repeat,must_send);
00205     if (cpl.input_state==Reply_One) {
00206         LOG(LOG_ERROR,"common::send_command","Wont send command '%s' - since in reply mode!",
00207             command);
00208         cpl.count=0;
00209         return 0;
00210     }
00211 
00212     /* Does the server understand 'ncom'? If so, special code */
00213     if (csocket.cs_version >= 1021) {
00214         int commdiff=csocket.command_sent - csocket.command_received;
00215 
00216         if (commdiff<0) {
00217             commdiff +=256;
00218         }
00219 
00220         /* if too many unanswered commands, not a must send, and command is
00221          * the same, drop it
00222          */
00223         if (commdiff>use_config[CONFIG_CWINDOW] && !must_send && !strcmp(command, last_command)) {
00224             if (repeat!=-1) {
00225                 cpl.count=0;
00226             }
00227             return 0;
00228 #if 0 /* Obnoxious warning message we don't need */
00229             fprintf(stderr,"Wont send command %s - window oversized %d %d\n",
00230                     command, csocket.command_sent, csocket.command_received);
00231 #endif
00232         } else {
00233             SockList sl;
00234             uint8 buf[MAX_BUF];
00235 
00236             /* Don't want to copy in administrative commands */
00237             if (!must_send) {
00238                 strcpy(last_command, command);
00239             }
00240             csocket.command_sent++;
00241             csocket.command_sent &= 0xff;   /* max out at 255 */
00242 
00243             SockList_Init(&sl, buf);
00244             SockList_AddString(&sl, "ncom ");
00245             SockList_AddShort(&sl, csocket.command_sent);
00246             SockList_AddInt(&sl, repeat);
00247             SockList_AddString(&sl, command);
00248             SockList_Send(&sl, csocket.fd);
00249         }
00250     } else {
00251         cs_print_string(csocket.fd, "command %d %s", repeat,command);
00252     }
00253     if (repeat!=-1) {
00254         cpl.count=0;
00255     }
00256     return 1;
00257 }
00258 
00259 void CompleteCmd(unsigned char *data, int len)
00260 {
00261     if (len !=6) {
00262         LOG(LOG_ERROR,"common::CompleteCmd","Invalid length %d - ignoring", len);
00263         return;
00264     }
00265     csocket.command_received = GetShort_String(data);
00266     csocket.command_time = GetInt_String(data+2);
00267     script_sync(csocket.command_sent - csocket.command_received);
00268 }
00269 
00270 
00271 
00272 /* This does special processing on the 'take' command.  If the
00273  * player has a container open, we want to specifiy what object
00274  * to move from that since we've sorted it.  command is
00275  * the command as tped, cpnext is any optional params.
00276  */
00277 void command_take (const char *command, const char *cpnext)
00278 {
00279     /* If the player has specified optional data, or the player
00280      * does not have a container open, just issue the command
00281      * as normal
00282      */
00283     if (cpnext || cpl.container == NULL) {
00284         send_command(command, cpl.count, 0);
00285     } else {
00286         if (cpl.container->inv == NULL)
00287             draw_ext_info(NDI_BLACK, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_NOTICE,
00288                           "There is nothing in the container to move");
00289         else
00290             cs_print_string(csocket.fd,"move %d %d %d", cpl.ob->tag,
00291                             cpl.container->inv->tag, cpl.count);
00292     }
00293 }