|
Crossfire Client, Trunk
R18666
|
00001 const char * const rcsid_common_script_c = 00002 "$Id: script.c 17543 2012-03-16 21:24:20Z ryo_saeba $"; 00003 /* 00004 Crossfire client, a client program for the crossfire program. 00005 00006 Copyright (C) 2003 Mark Wedel & Crossfire Development Team 00007 This source file also Copyright (C) 2003 Preston Crow 00008 00009 This program is free software; you can redistribute it and/or modify 00010 it under the terms of the GNU General Public License as published by 00011 the Free Software Foundation; either version 2 of the License, or 00012 (at your option) any later version. 00013 00014 This program is distributed in the hope that it will be useful, 00015 but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 GNU General Public License for more details. 00018 00019 You should have received a copy of the GNU General Public License 00020 along with this program; if not, write to the Free Software 00021 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00022 00023 The author can be reached via e-mail to crossfire-devel@real-time.com 00024 */ 00025 00026 /* 00027 * This file has its own script.h for prototypes, so don't want to include 00028 * this when doing a 'make proto'. 00029 */ 00030 #ifndef CPROTO 00031 00109 /* 00110 * Include files 00111 */ 00112 00113 /* 00114 * This does not work under Windows for now. Someday this will be fixed :) 00115 */ 00116 00117 #ifndef WIN32 00118 #include <errno.h> 00119 #include <sys/types.h> 00120 #include <sys/socket.h> 00121 #include <sys/wait.h> 00122 /* for SIGHUP */ 00123 #include <signal.h> 00124 #endif 00125 #include <ctype.h> 00126 00127 #include <client.h> 00128 #include <external.h> 00129 #include <script.h> 00130 #include <p_cmd.h> 00131 #include "mapdata.h" 00132 00133 /* 00134 * Data structures 00135 */ 00136 struct script { 00137 char *name; /* the script name */ 00138 char *params; /* the script parameters, if any */ 00139 #ifndef WIN32 00140 int out_fd; /* the file descriptor to which the client writes to the script */ 00141 int in_fd; /* the file descriptor from which we read commands from the script */ 00142 #else 00143 HANDLE out_fd; /* the file descriptor to which the client writes to the script */ 00144 HANDLE in_fd; /* the file descriptor from which we read commands from the script */ 00145 #endif /* WIN32 */ 00146 int monitor; /* true if this script is monitoring commands sent to the server */ 00147 int num_watch; /* number of commands we're watching */ 00148 char **watch; /* array of commands that we're watching */ 00149 int cmd_count; /* bytes already read in */ 00150 char cmd[1024]; /* command from the script */ 00151 #ifndef WIN32 00152 int pid; 00153 #else 00154 DWORD pid; /* Handle to Win32 process ID */ 00155 HANDLE process; /* Handle of Win32 process */ 00156 #endif 00157 int sync_watch; 00158 }; 00159 00160 /* 00161 * Global variables 00162 */ 00163 static struct script *scripts = NULL; 00164 00165 static int num_scripts = 0; 00166 00167 /* 00168 * Prototypes 00169 */ 00170 static int script_by_name(const char *name); 00171 00172 static void script_dead(int i); 00173 00174 static void script_process_cmd(int i); 00175 00176 static void send_map(int i, int x, int y); 00177 00178 static void script_send_item(int i, const char *head, const item *it); 00179 00180 00181 /* 00182 * Functions 00183 */ 00184 00185 #ifdef WIN32 00186 00187 #define write(x, y, z) emulate_write(x, y, z) 00188 #define read(x, y, z) emulate_read(x, y, z) 00189 00190 static int emulate_read(HANDLE fd, char *buf, int len) { 00191 DWORD dwBytesRead; 00192 BOOL rc; 00193 00194 FlushFileBuffers(fd); 00195 rc = ReadFile(fd, buf, len, &dwBytesRead, NULL); 00196 if (rc == FALSE) 00197 return(-1); 00198 buf[dwBytesRead] = '\0'; 00199 00200 return(dwBytesRead); 00201 } 00202 00203 static int emulate_write(HANDLE fd, const char *buf, int len) { 00204 DWORD dwBytesWritten; 00205 BOOL rc; 00206 00207 rc = WriteFile(fd, buf, len, &dwBytesWritten, NULL); 00208 FlushFileBuffers(fd); 00209 if (rc == FALSE) 00210 return(-1); 00211 00212 return(dwBytesWritten); 00213 } 00214 00215 #endif /* WIN32 */ 00216 00217 void script_init(const char *cparams) { 00218 #ifndef WIN32 00219 int pipe1[2]; 00220 #ifdef USE_PIPE 00221 int pipe2[2]; 00222 #endif 00223 int pid; 00224 char *name, *args, params[MAX_BUF]; 00225 00226 if (!cparams) { 00227 draw_ext_info(NDI_RED, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT, 00228 "Please specify a script to launch!"); 00229 return; 00230 } 00231 00232 /* cparams as passed in is a const value, so need to copy it 00233 * to data we can write over. 00234 */ 00235 strncpy(params, cparams, MAX_BUF-1); 00236 params[MAX_BUF-1] = 0; 00237 00238 00239 /* Get name and args */ 00240 name = params; 00241 args = name; 00242 while (*args && *args != ' ') 00243 ++args; 00244 while (*args && *args == ' ') 00245 *args++ = '\0'; 00246 if (*args == 0) { 00247 args = NULL; 00248 } 00249 00250 #ifdef USE_PIPE 00251 /* Create two pipes */ 00252 if (pipe(pipe1)) { 00253 draw_ext_info(NDI_RED, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT, 00254 "Unable to start script--pipe failed"); 00255 return; 00256 } 00257 if (pipe(pipe2)) { 00258 close(pipe1[0]); 00259 close(pipe1[1]); 00260 draw_ext_info(NDI_RED, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT, 00261 "Unable to start script--pipe failed"); 00262 return; 00263 } 00264 #else 00265 /* Create a pair of sockets */ 00266 if (socketpair(PF_LOCAL, SOCK_STREAM, AF_LOCAL, pipe1)) { 00267 draw_ext_info(NDI_RED, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT, 00268 "Unable to start script--socketpair failed"); 00269 return; 00270 } 00271 #endif 00272 00273 /* Fork */ 00274 pid = fork(); 00275 if (pid == -1) { 00276 close(pipe1[0]); 00277 close(pipe1[1]); 00278 #ifdef USE_PIPE 00279 close(pipe2[0]); 00280 close(pipe2[1]); 00281 #endif 00282 draw_ext_info(NDI_RED, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT, 00283 "Unable to start script--fork failed"); 00284 return; 00285 } 00286 00287 /* Child--set stdin/stdout to the pipes, then exec */ 00288 if (pid == 0) { 00289 int i; 00290 int r; 00291 char *argv[256]; 00292 00293 /* Fill in argv[] */ 00294 argv[0] = name; 00295 i = 1; 00296 while (args && *args && i < sizeof(argv)/sizeof(*argv)-1) { 00297 argv[i++] = args; 00298 while (*args && *args != ' ') 00299 ++args; 00300 while (*args && *args == ' ') 00301 *args++ = '\0'; 00302 } 00303 argv[i] = NULL; 00304 00305 /* Clean up file descriptor space */ 00306 r = dup2(pipe1[0], 0); 00307 if (r != 0) { 00308 fprintf(stderr, "Script Child: Failed to set pipe1 as stdin\n"); 00309 } 00310 #ifdef USE_PIPE 00311 r = dup2(pipe2[1], 1); 00312 #else 00313 r = dup2(pipe1[0], 1); 00314 #endif 00315 if (r != 1) { 00316 fprintf(stderr, "Script Child: Failed to set pipe2 as stdout\n"); 00317 } 00318 for (i = 3; i < 100; ++i) 00319 close(i); 00320 00321 /* EXEC */ 00322 r = execvp(argv[0], argv); 00323 00324 /* If we get here, then there's been an failure of some sort. 00325 * In my case, it's often that I don't know what script name to 00326 * give to /script, so exec() can't find the script. 00327 * 00328 * Forward the error back to the client, using the script pipes. 00329 */ 00330 00331 if (r != -1) { 00332 printf("draw %d Script child: no error, but no execvp().\n", NDI_RED); 00333 } else { 00334 printf("draw %d Script child failed to start: %s\n", NDI_RED, strerror(errno)); 00335 } 00336 00337 exit(1); 00338 } 00339 00340 /* Close the child's pipe ends */ 00341 close(pipe1[0]); 00342 #ifdef USE_PIPE 00343 close(pipe2[1]); 00344 #endif 00345 00346 if (fcntl(pipe1[1], F_SETFL, O_NDELAY) == -1) { 00347 LOG(LOG_WARNING, "common::script_init", "Error on fcntl."); 00348 } 00349 00350 /* realloc script array to add new entry; fill in the data */ 00351 scripts = realloc(scripts, sizeof(scripts[0])*(num_scripts+1)); 00352 scripts[num_scripts].name = strdup(name); 00353 scripts[num_scripts].params = args ? strdup(args) : NULL; 00354 scripts[num_scripts].out_fd = pipe1[1]; 00355 #ifdef USE_PIPE 00356 scripts[num_scripts].in_fd = pipe2[0]; 00357 #else 00358 scripts[num_scripts].in_fd = pipe1[1]; 00359 #endif 00360 scripts[num_scripts].monitor = 0; 00361 scripts[num_scripts].num_watch = 0; 00362 scripts[num_scripts].watch = NULL; 00363 scripts[num_scripts].cmd_count = 0; 00364 scripts[num_scripts].pid = pid; 00365 scripts[num_scripts].sync_watch = -1; 00366 ++num_scripts; 00367 #else /* WIN32 */ 00368 00369 char *name, *args; 00370 char params[ MAX_BUF ]; 00371 SECURITY_ATTRIBUTES saAttr; 00372 PROCESS_INFORMATION piProcInfo; 00373 STARTUPINFO siStartupInfo; 00374 HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup, hChildStdoutRd; 00375 HANDLE hChildStdoutWr, hChildStdoutRdDup, hSaveStdin, hSaveStdout; 00376 00377 if (!cparams) { 00378 draw_ext_info(NDI_RED, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT, 00379 "Please specifiy a script to launch!"); 00380 return; 00381 } 00382 00383 strncpy(params, cparams, MAX_BUF-1); 00384 params[MAX_BUF-1] = '\0'; 00385 00386 /* Get name and args */ 00387 name = params; 00388 args = name; 00389 while (*args && *args != ' ') 00390 ++args; 00391 while (*args && *args == ' ') 00392 *args++ = '\0'; 00393 if (*args == 0) { 00394 args = NULL; 00395 } 00396 00397 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 00398 saAttr.bInheritHandle = TRUE; 00399 saAttr.lpSecurityDescriptor = NULL; 00400 00401 hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE); 00402 if (!CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) { 00403 draw_ext_info(NDI_RED, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT, 00404 "Script support: stdout CreatePipe() failed"); 00405 return; 00406 } 00407 00408 if (!SetStdHandle(STD_OUTPUT_HANDLE, hChildStdoutWr)) { 00409 draw_ext_info(NDI_RED, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT, 00410 "Script support: failed to redirect stdout using SetStdHandle()"); 00411 return; 00412 } 00413 00414 if (!DuplicateHandle(GetCurrentProcess(), hChildStdoutRd, GetCurrentProcess(), &hChildStdoutRdDup, 0, FALSE, DUPLICATE_SAME_ACCESS)) { 00415 draw_ext_info(NDI_RED, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT, 00416 "Script support: failed to duplicate stdout using DuplicateHandle()"); 00417 return; 00418 } 00419 00420 CloseHandle(hChildStdoutRd); 00421 00422 hSaveStdin = GetStdHandle(STD_INPUT_HANDLE); 00423 if (!CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) { 00424 draw_ext_info(NDI_RED, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT, 00425 "Script support: stdin CreatePipe() failed"); 00426 return; 00427 } 00428 00429 if (!SetStdHandle(STD_INPUT_HANDLE, hChildStdinRd)) { 00430 draw_ext_info(NDI_RED, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT, 00431 "Script support: failed to redirect stdin using SetStdHandle()"); 00432 return; 00433 } 00434 00435 if (!DuplicateHandle(GetCurrentProcess(), hChildStdinWr, GetCurrentProcess(), &hChildStdinWrDup, 0, FALSE, DUPLICATE_SAME_ACCESS)) { 00436 draw_ext_info(NDI_RED, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT, 00437 "Script support: failed to duplicate stdin using DuplicateHandle()"); 00438 return; 00439 } 00440 00441 CloseHandle(hChildStdinWr); 00442 00443 ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION)); 00444 ZeroMemory(&siStartupInfo, sizeof(STARTUPINFO)); 00445 siStartupInfo.cb = sizeof(STARTUPINFO); 00446 00447 if (args) 00448 args[-1] = ' '; 00449 00450 if (!CreateProcess(NULL, name, NULL, NULL, TRUE, CREATE_NEW_PROCESS_GROUP, NULL, NULL, &siStartupInfo, &piProcInfo)) { 00451 draw_ext_info(NDI_RED, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT, 00452 "Script support: CreateProcess() failed"); 00453 return; 00454 } 00455 00456 CloseHandle(piProcInfo.hThread); 00457 00458 if (args) 00459 args[-1] = '\0'; 00460 00461 if (!SetStdHandle(STD_INPUT_HANDLE, hSaveStdin)) { 00462 draw_ext_info(NDI_RED, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT, 00463 "Script support: restoring original stdin failed"); 00464 return; 00465 } 00466 00467 if (!SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout)) { 00468 draw_ext_info(NDI_RED, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT, 00469 "Script support: restoring original stdout failed"); 00470 return; 00471 } 00472 00473 /* realloc script array to add new entry; fill in the data */ 00474 scripts = realloc(scripts, sizeof(scripts[0])*(num_scripts+1)); 00475 scripts[num_scripts].name = strdup(name); 00476 scripts[num_scripts].params = args ? strdup(args) : NULL; 00477 scripts[num_scripts].out_fd = hChildStdinWrDup; 00478 scripts[num_scripts].in_fd = hChildStdoutRdDup; 00479 scripts[num_scripts].monitor = 0; 00480 scripts[num_scripts].num_watch = 0; 00481 scripts[num_scripts].watch = NULL; 00482 scripts[num_scripts].cmd_count = 0; 00483 scripts[num_scripts].pid = piProcInfo.dwProcessId; 00484 scripts[num_scripts].process = piProcInfo.hProcess; 00485 scripts[num_scripts].sync_watch = -1; 00486 ++num_scripts; 00487 #endif /* WIN32 */ 00488 } 00489 00490 void script_sync(int commdiff) { 00491 int i; 00492 00493 if (commdiff < 0) 00494 commdiff +=256; 00495 for (i = 0; i < num_scripts; ++i) { 00496 if (commdiff <= scripts[i].sync_watch && scripts[i].sync_watch >= 0) { 00497 char buf[1024]; 00498 00499 snprintf(buf, sizeof(buf), "sync %d\n", commdiff); 00500 write(scripts[i].out_fd, buf, strlen(buf)); 00501 scripts[i].sync_watch = -1; 00502 } 00503 } 00504 } 00505 00506 void script_list(void) { 00507 if (num_scripts == 0) { 00508 draw_ext_info(NDI_BLACK, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT, 00509 "No scripts are currently running"); 00510 } else { 00511 int i; 00512 char buf[1024]; 00513 00514 snprintf(buf, sizeof(buf), "%d scripts currently running:", num_scripts); 00515 draw_ext_info(NDI_BLACK, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT, buf); 00516 for (i = 0; i < num_scripts; ++i) { 00517 if (scripts[i].params) 00518 snprintf(buf, sizeof(buf), "%d %s %s", i+1, scripts[i].name, scripts[i].params); 00519 else 00520 snprintf(buf, sizeof(buf), "%d %s", i+1, scripts[i].name); 00521 draw_ext_info(NDI_BLACK, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT, buf); 00522 } 00523 } 00524 } 00525 00526 void script_kill(const char *params) { 00527 int i; 00528 00529 /* Verify that the number is a valid array entry */ 00530 i = script_by_name(params); 00531 if (i < 0 || i >= num_scripts) { 00532 draw_ext_info(NDI_BLACK, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT, 00533 "No such running script"); 00534 return; 00535 } 00536 #ifndef WIN32 00537 kill(scripts[i].pid, SIGHUP); 00538 #else 00539 GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, scripts[i].pid); 00540 #endif /* WIN32 */ 00541 draw_ext_info(NDI_RED, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT, 00542 "Killed script."); 00543 script_dead(i); 00544 } 00545 00546 #ifdef WIN32 00547 void script_killall(void) { 00548 while (num_scripts > 0) { 00549 GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, scripts[0].pid); 00550 script_dead(0); 00551 } 00552 } 00553 #endif /* WIN32 */ 00554 00555 void script_fdset(int *maxfd, fd_set *set) { 00556 #ifndef WIN32 00557 int i; 00558 00559 for (i = 0; i < num_scripts; ++i) { 00560 FD_SET(scripts[i].in_fd, set); 00561 if (scripts[i].in_fd >= *maxfd) 00562 *maxfd = scripts[i].in_fd+1; 00563 } 00564 #endif /* WIN32 */ 00565 } 00566 00567 void script_process(fd_set *set) { 00568 int i; 00569 int r; 00570 #ifdef WIN32 00571 DWORD nAvailBytes = 0; 00572 char cTmp; 00573 BOOL bRC; 00574 DWORD dwStatus; 00575 BOOL bStatus; 00576 #endif 00577 00578 /* Determine which script's fd is set */ 00579 for (i = 0; i < num_scripts; ++i) { 00580 #ifndef WIN32 00581 if (FD_ISSET(scripts[i].in_fd, set)) 00582 #else 00583 bStatus = GetExitCodeProcess(scripts[i].process, &dwStatus); 00584 bRC = PeekNamedPipe(scripts[i].in_fd, &cTmp, 1, NULL, &nAvailBytes, NULL); 00585 if (nAvailBytes) 00586 #endif /* WIN32 */ 00587 { 00588 /* Read in script[i].cmd */ 00589 r = read(scripts[i].in_fd, scripts[i].cmd+scripts[i].cmd_count, sizeof(scripts[i].cmd)-scripts[i].cmd_count-1); 00590 if (r > 0) { 00591 scripts[i].cmd_count += r; 00592 } 00593 #ifndef WIN32 00594 else if (r == 0 || errno == EBADF) 00595 #else 00596 else if (r == 0 || GetLastError() == ERROR_BROKEN_PIPE) 00597 #endif 00598 { 00599 /* Script has exited; delete it */ 00600 script_dead(i); 00601 return; 00602 } 00603 /* If a newline or full buffer has been reached, process it */ 00604 scripts[i].cmd[scripts[i].cmd_count] = 0; /* terminate string */ 00605 while (scripts[i].cmd_count == sizeof(scripts[i].cmd)-1 00606 #ifndef WIN32 00607 || strchr(scripts[i].cmd, '\n')) 00608 #else 00609 || strchr(scripts[i].cmd, '\r\n')) 00610 #endif /* WIN32 */ 00611 { 00612 script_process_cmd(i); 00613 scripts[i].cmd[scripts[i].cmd_count] = 0; /* terminate string */ 00614 } 00615 return; /* Only process one script at a time */ 00616 } 00617 #ifdef WIN32 00618 else if (!bRC || (bStatus && (dwStatus != STILL_ACTIVE))) /* Error: assume dead */ 00619 script_dead(i); 00620 #endif /* WIN32 */ 00621 } 00622 } 00623 00624 void script_watch(const char *cmd, const uint8 *data_initial, const int data_len, const enum CmdFormat format) { 00625 int i; 00626 int w; 00627 int l, len; 00628 const uint8 *data; 00629 00630 /* For each script... */ 00631 for (i = 0; i < num_scripts; ++i) { 00632 /* For each watch... */ 00633 for (w = 0; w < scripts[i].num_watch; ++w) 00634 { 00635 len = data_len; 00636 /* Does this command match our watch? */ 00637 l = strlen(scripts[i].watch[w]); 00638 if (!l || strncmp(cmd, scripts[i].watch[w], l) == 0) 00639 { 00640 char buf[10240]; 00641 00642 data = data_initial; 00643 if (!len) 00644 snprintf(buf, sizeof(buf), "watch %s\n", cmd); 00645 else 00646 switch (format) { 00647 case ASCII: 00648 snprintf(buf, sizeof(buf), "watch %s %s\n", cmd, data); 00649 break; 00650 00651 case SHORT_INT: 00652 snprintf(buf, sizeof(buf), "watch %s %d %d\n", cmd, GetShort_String(data), GetInt_String(data+2)); 00653 break; 00654 00655 case SHORT_ARRAY: 00656 { 00657 int be; 00658 int p; 00659 00660 be = snprintf(buf, sizeof(buf), "watch %s", cmd); 00661 for (p = 0; p*2 < len && p < 100; ++p) { 00662 be += snprintf(buf+be, sizeof(buf)-be, " %d", GetShort_String(data+p*2)); 00663 } 00664 be += snprintf(buf+be, sizeof(buf)-be, "\n"); 00665 } 00666 break; 00667 00668 case INT_ARRAY: 00669 { 00670 int be; 00671 int p; 00672 00673 be = snprintf(buf, sizeof(buf), "watch %s", cmd); 00674 for (p = 0; p*4 < len; ++p) { 00675 be += snprintf(buf+be, sizeof(buf)-be, " %d", GetInt_String(data+p*4)); 00676 } 00677 be += snprintf(buf+be, sizeof(buf)-be, "\n"); 00678 } 00679 break; 00680 00681 case STATS: 00682 { 00683 /* 00684 * We cheat here and log each stat as a separate command, even 00685 * if the server sent a bunch of updates as a single message; 00686 * most scripts will be easier to write if they only parse a fixed 00687 * format. 00688 */ 00689 int be = 0; 00690 while (len) { 00691 int c; /* which stat */ 00692 00693 be += snprintf(buf+be, sizeof(buf)-be, "watch %s", cmd); 00694 c = *data; 00695 ++data; 00696 --len; 00697 if (c >= CS_STAT_RESIST_START && c <= CS_STAT_RESIST_END) { 00698 be += snprintf(buf+be, sizeof(buf)-be, " resists %d %d\n", c, GetShort_String(data)); 00699 data += 2; 00700 len -= 2; 00701 } else if (c >= CS_STAT_SKILLINFO && c < (CS_STAT_SKILLINFO+CS_NUM_SKILLS)) { 00702 be += snprintf(buf+be, sizeof(buf)-be, " skill %d %d %" FMT64 "\n", c, *data, GetInt64_String(data+1)); 00703 data += 9; 00704 len -= 9; 00705 } else 00706 switch (c) { 00707 case CS_STAT_HP: 00708 be += snprintf(buf+be, sizeof(buf)-be, " hp %d\n", GetShort_String(data)); 00709 data += 2; 00710 len -= 2; 00711 break; 00712 00713 case CS_STAT_MAXHP: 00714 be += snprintf(buf+be, sizeof(buf)-be, " maxhp %d\n", GetShort_String(data)); 00715 data += 2; 00716 len -= 2; 00717 break; 00718 00719 case CS_STAT_SP: 00720 be += snprintf(buf+be, sizeof(buf)-be, " sp %d\n", GetShort_String(data)); 00721 data += 2; 00722 len -= 2; 00723 break; 00724 00725 case CS_STAT_MAXSP: 00726 be += snprintf(buf+be, sizeof(buf)-be, " maxsp %d\n", GetShort_String(data)); 00727 data += 2; 00728 len -= 2; 00729 break; 00730 00731 case CS_STAT_GRACE: 00732 be += snprintf(buf+be, sizeof(buf)-be, " grace %d\n", GetShort_String(data)); 00733 data += 2; 00734 len -= 2; 00735 break; 00736 00737 case CS_STAT_MAXGRACE: 00738 be += snprintf(buf+be, sizeof(buf)-be, " maxgrace %d\n", GetShort_String(data)); 00739 data += 2; 00740 len -= 2; 00741 break; 00742 00743 case CS_STAT_STR: 00744 be += snprintf(buf+be, sizeof(buf)-be, " str %d\n", GetShort_String(data)); 00745 data += 2; 00746 len -= 2; 00747 break; 00748 00749 case CS_STAT_INT: 00750 be += snprintf(buf+be, sizeof(buf)-be, " int %d\n", GetShort_String(data)); 00751 data += 2; 00752 len -= 2; 00753 break; 00754 00755 case CS_STAT_POW: 00756 be += snprintf(buf+be, sizeof(buf)-be, " pow %d\n", GetShort_String(data)); 00757 data += 2; 00758 len -= 2; 00759 break; 00760 00761 case CS_STAT_WIS: 00762 be += snprintf(buf+be, sizeof(buf)-be, " wis %d\n", GetShort_String(data)); 00763 data += 2; 00764 len -= 2; 00765 break; 00766 00767 case CS_STAT_DEX: 00768 be += snprintf(buf+be, sizeof(buf)-be, " dex %d\n", GetShort_String(data)); 00769 data += 2; 00770 len -= 2; 00771 break; 00772 00773 case CS_STAT_CON: 00774 be += snprintf(buf+be, sizeof(buf)-be, " con %d\n", GetShort_String(data)); 00775 data += 2; 00776 len -= 2; 00777 break; 00778 00779 case CS_STAT_CHA: 00780 be += snprintf(buf+be, sizeof(buf)-be, " cha %d\n", GetShort_String(data)); 00781 data += 2; 00782 len -= 2; 00783 break; 00784 00785 case CS_STAT_EXP: 00786 be += snprintf(buf+be, sizeof(buf)-be, " exp %d\n", GetInt_String(data)); 00787 data += 4; 00788 len -= 4; 00789 break; 00790 00791 case CS_STAT_EXP64: 00792 be += snprintf(buf+be, sizeof(buf)-be, " exp %" FMT64 "\n", GetInt64_String(data)); 00793 data += 8; 00794 len -= 8; 00795 break; 00796 00797 case CS_STAT_LEVEL: 00798 be += snprintf(buf+be, sizeof(buf)-be, " level %d\n", GetShort_String(data)); 00799 data += 2; 00800 len -= 2; 00801 break; 00802 00803 case CS_STAT_WC: 00804 be += snprintf(buf+be, sizeof(buf)-be, " wc %d\n", GetShort_String(data)); 00805 data += 2; 00806 len -= 2; 00807 break; 00808 00809 case CS_STAT_AC: 00810 be += snprintf(buf+be, sizeof(buf)-be, " ac %d\n", GetShort_String(data)); 00811 data += 2; 00812 len -= 2; 00813 break; 00814 00815 case CS_STAT_DAM: 00816 be += snprintf(buf+be, sizeof(buf)-be, " dam %d\n", GetShort_String(data)); 00817 data += 2; 00818 len -= 2; 00819 break; 00820 00821 case CS_STAT_ARMOUR: 00822 be += snprintf(buf+be, sizeof(buf)-be, " armour %d\n", GetShort_String(data)); 00823 data += 2; 00824 len -= 2; 00825 break; 00826 00827 case CS_STAT_SPEED: 00828 be += snprintf(buf+be, sizeof(buf)-be, " speed %d\n", GetInt_String(data)); 00829 data += 4; 00830 len -= 4; 00831 break; 00832 00833 case CS_STAT_FOOD: 00834 be += snprintf(buf+be, sizeof(buf)-be, " food %d\n", GetShort_String(data)); 00835 data += 2; 00836 len -= 2; 00837 break; 00838 00839 case CS_STAT_WEAP_SP: 00840 be += snprintf(buf+be, sizeof(buf)-be, " weap_sp %d\n", GetInt_String(data)); 00841 data += 4; 00842 len -= 4; 00843 break; 00844 00845 case CS_STAT_FLAGS: 00846 be += snprintf(buf+be, sizeof(buf)-be, " flags %d\n", GetShort_String(data)); 00847 data += 2; 00848 len -= 2; 00849 break; 00850 00851 case CS_STAT_WEIGHT_LIM: 00852 be += snprintf(buf+be, sizeof(buf)-be, " weight_lim %d\n", GetInt_String(data)); 00853 data += 4; 00854 len -= 4; 00855 break; 00856 00857 case CS_STAT_RANGE: 00858 { 00859 int rlen = *data; 00860 ++data; --len; 00861 be += snprintf(buf+be, sizeof(buf)-be, " range %*.*s\n", rlen, rlen, data); 00862 data += rlen; 00863 len -= rlen; 00864 break; 00865 } 00866 00867 case CS_STAT_TITLE: 00868 { 00869 int rlen = *data; 00870 ++data; 00871 --len; 00872 be += snprintf(buf+be, sizeof(buf)-be, " title %*.*s\n", rlen, rlen, data); 00873 data += rlen; 00874 len -= rlen; 00875 break; 00876 } 00877 00878 default: 00879 be += snprintf(buf+be, sizeof(buf)-be, " unknown %d %d bytes left\n", c, len); 00880 len = 0; 00881 } 00882 } 00883 } 00884 break; 00885 00886 case MIXED: 00887 /* magicmap */ 00888 /* mapextended */ 00889 /* item1 item2 */ 00890 /* upditem */ 00891 /* image image2 */ 00892 /* face face1 face2 */ 00893 /* sound */ 00894 /* player */ 00895 /* 00896 * If we find that scripts need data from any of the above, we can 00897 * write special-case code as with stats. In the meantime, fall 00898 * through and just give a hex dump. Script writers should not 00899 * depend on that data format. 00900 */ 00901 case NODATA: 00902 default: { 00903 int be; 00904 int p; 00905 00906 /*we may receive an null data, in which case len has no meaning*/ 00907 if (!data) 00908 len = 0; 00909 be = snprintf(buf, sizeof(buf), "watch %s %d bytes unparsed:", cmd, len); 00910 for (p = 0; p < len && p < 100; ++p) { 00911 be += snprintf(buf+be, sizeof(buf)-be, " %02x", data[p]); 00912 } 00913 be += snprintf(buf+be, sizeof(buf)-be, "\n"); 00914 } 00915 break; 00916 } 00917 write(scripts[i].out_fd, buf, strlen(buf)); 00918 } 00919 } 00920 } 00921 } 00922 00923 void script_monitor(const char *command, int repeat, int must_send) { 00924 int i; 00925 00926 /* For each script... */ 00927 for (i = 0; i < num_scripts; ++i) { 00928 /* Do we send the command? */ 00929 if (scripts[i].monitor) { 00930 char buf[1024]; 00931 00932 snprintf(buf, sizeof(buf), "monitor %d %d %s\n", repeat, must_send, command); 00933 write(scripts[i].out_fd, buf, strlen(buf)); 00934 } 00935 } 00936 } 00937 00938 void script_monitor_str(const char *command) { 00939 int i; 00940 00941 /* For each script... */ 00942 for (i = 0; i < num_scripts; ++i) { 00943 /* Do we send the command? */ 00944 if (scripts[i].monitor) { 00945 char buf[1024]; 00946 00947 snprintf(buf, sizeof(buf), "monitor %s\n", command); 00948 write(scripts[i].out_fd, buf, strlen(buf)); 00949 } 00950 } 00951 } 00952 00953 void script_tell(const char *params) { 00954 int i; 00955 char *p; 00956 00957 if (params == NULL) { 00958 draw_ext_info(NDI_RED, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT, 00959 "Which script do you want to talk to?"); 00960 return; 00961 } 00962 p = strchr(params, ' '); 00963 if (p == NULL) { 00964 draw_ext_info(NDI_RED, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT, 00965 "What do you want to tell the script?"); 00966 return; 00967 } 00968 while (*p == ' ') { 00969 *p++ = '\0'; 00970 } 00971 00972 /* Find the script */ 00973 i = script_by_name(params); 00974 if (i < 0) { 00975 draw_ext_info(NDI_BLACK, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT, 00976 "No such running script"); 00977 return; 00978 } 00979 00980 /* Send the message */ 00981 write(scripts[i].out_fd, "scripttell ", 11); 00982 write(scripts[i].out_fd, p, strlen(p)); 00983 write(scripts[i].out_fd, "\n", 1); 00984 } 00985 00986 static int script_by_name(const char *name) { 00987 int i; 00988 int l; 00989 00990 if (name == NULL) { 00991 return(num_scripts == 1 ? 0 : -1); 00992 } 00993 00994 /* Parse script number */ 00995 if (isdigit(*name)) { 00996 i = atoi(name); 00997 --i; 00998 if (i >= 0 && i < num_scripts) 00999 return(i); 01000 } 01001 01002 /* Parse script name */ 01003 l = 0; 01004 while (name[l] && name[l] != ' ') 01005 ++l; 01006 for (i = 0; i < num_scripts; ++i) { 01007 if (strncmp(name, scripts[i].name, l) == 0) 01008 return(i); 01009 } 01010 return(-1); 01011 } 01012 01013 static void script_dead(int i) { 01014 int w; 01015 01016 /* Release resources */ 01017 #ifndef WIN32 01018 close(scripts[i].in_fd); 01019 close(scripts[i].out_fd); 01020 #else 01021 CloseHandle(scripts[i].in_fd); 01022 CloseHandle(scripts[i].out_fd); 01023 CloseHandle(scripts[i].process); 01024 #endif 01025 free(scripts[i].name); 01026 free(scripts[i].params); 01027 for (w = 0; w < scripts[i].num_watch; ++w) 01028 free(scripts[i].watch[w]); 01029 free(scripts[i].watch); 01030 01031 #ifndef WIN32 01032 waitpid(-1, NULL, WNOHANG); 01033 #endif 01034 01035 /* Move scripts with higher index numbers down one slot */ 01036 if (i < (num_scripts-1)) { 01037 memmove(&scripts[i], &scripts[i+1], sizeof(scripts[i])*(num_scripts-i-1)); 01038 } 01039 01040 /* Update our count */ 01041 --num_scripts; 01042 } 01043 01044 static void send_map(int i, int x, int y) { 01045 char buf[1024]; 01046 01047 if (x < 0 || y < 0 || the_map.x <= x || the_map.y <= y) { 01048 snprintf(buf, sizeof(buf), "request map %d %d unknown\n", x, y); 01049 write(scripts[i].out_fd, buf, strlen(buf)); 01050 } 01051 /*** FIXME *** send more relevant data ***/ 01052 snprintf(buf, sizeof(buf), "request map %d %d %d %c %c %c %c" 01053 " smooth %d %d %d heads %d %d %d tails %d %d %d\n", 01054 x, y, the_map.cells[x][y].darkness, 01055 the_map.cells[x][y].need_update ? 'y' : 'n', 01056 the_map.cells[x][y].have_darkness ? 'y' : 'n', 01057 the_map.cells[x][y].need_resmooth ? 'y' : 'n', 01058 the_map.cells[x][y].cleared ? 'y' : 'n', 01059 the_map.cells[x][y].smooth[0], the_map.cells[x][y].smooth[1], the_map.cells[x][y].smooth[2], 01060 the_map.cells[x][y].heads[0].face, the_map.cells[x][y].heads[1].face, the_map.cells[x][y].heads[2].face, 01061 the_map.cells[x][y].tails[0].face, the_map.cells[x][y].tails[1].face, the_map.cells[x][y].tails[2].face 01062 ); 01063 write(scripts[i].out_fd, buf, strlen(buf)); 01064 } 01065 01066 static void script_process_cmd(int i) { 01067 char cmd[1024]; 01068 char *c; 01069 int l; 01070 01071 /* 01072 * Strip out just this one command 01073 */ 01074 for (l = 0; l < scripts[i].cmd_count; ++l) { 01075 if (scripts[i].cmd[l] == '\n') 01076 break; 01077 } 01078 ++l; 01079 memcpy(cmd, scripts[i].cmd, l); 01080 #ifndef WIN32 01081 cmd[l-1] = 0; 01082 #else 01083 cmd[l-2] = 0; 01084 #endif 01085 if (l < scripts[i].cmd_count) { 01086 memmove(scripts[i].cmd, scripts[i].cmd+l, scripts[i].cmd_count-l); 01087 scripts[i].cmd_count -= l; 01088 } else { 01089 scripts[i].cmd_count = 0; 01090 } 01091 01092 /* 01093 * Now the data in scripts[i] is ready for the next read. 01094 * We have a complete command in cmd[]. 01095 * Process it. 01096 */ 01097 /* 01098 * Script commands 01099 * 01100 * watch <command type> 01101 * unwatch <command type> 01102 * request <data type> 01103 * issue <repeat> <must_send> <command> 01104 * localcmd <command> [<params>] 01105 * draw <color> <text> 01106 * monitor 01107 * unmonitor 01108 */ 01109 if (strncmp(cmd, "sync", 4) == 0) { 01110 c = cmd+4; 01111 while (*c && *c != ' ') 01112 ++c; 01113 while (*c == ' ') 01114 ++c; 01115 scripts[i].sync_watch = -1; 01116 if (isdigit(*c)) { 01117 scripts[i].sync_watch = atoi(c); 01118 } 01119 script_sync(csocket.command_sent - csocket.command_received); /* in case we are already there */ 01120 } else if (strncmp(cmd, "watch", 5) == 0) { 01121 c = cmd+5; 01122 while (*c && *c != ' ') 01123 ++c; 01124 while (*c == ' ') 01125 ++c; 01126 c = strdup(c); 01127 scripts[i].watch = realloc(scripts[i].watch, (scripts[i].num_watch+1)*sizeof(scripts[i].watch[1])); 01128 scripts[i].watch[scripts[i].num_watch] = c; 01129 ++scripts[i].num_watch; 01130 } else if (strncmp(cmd, "unwatch", 7) == 0) { 01131 int w; 01132 01133 c = cmd+7; 01134 while (*c && *c != ' ') 01135 ++c; 01136 while (*c == ' ') 01137 ++c; 01138 for (w = 0; w < scripts[i].num_watch; ++w) { 01139 if (strcmp(c, scripts[i].watch[w]) == 0) { 01140 free(scripts[i].watch[w]); 01141 while (w+1 < scripts[i].num_watch) { 01142 scripts[i].watch[w] = scripts[i].watch[w+1]; 01143 ++w; 01144 } 01145 --scripts[i].num_watch; 01146 break; 01147 } 01148 } 01149 } else if (strncmp(cmd, "request", 7) == 0) { 01150 c = cmd+7; 01151 while (*c && *c != ' ') 01152 ++c; 01153 while (*c == ' ') 01154 ++c; 01155 if (!*c) 01156 return; /* bad request */ 01157 /* 01158 * Request information from the client's view of the world 01159 * (mostly defined in client.h) 01160 * 01161 * Valid requests: 01162 * 01163 * player Return the player's tag and title 01164 * range Return the type and name of the currently selected range attack 01165 * stat <type> Return the specified stats 01166 * stat stats Return Str,Con,Dex,Int,Wis,Pow,Cha 01167 * stat cmbt Return wc,ac,dam,speed,weapon_sp 01168 * stat hp Return hp,maxhp,sp,maxsp,grace,maxgrace,food 01169 * stat xp Return level,xp,skill-1 level,skill-1 xp,... 01170 * stat resists Return resistances 01171 * stat paths Return spell paths: attuned, repelled, denied. 01172 * weight Return maxweight, weight 01173 * flags Return flags (fire, run) 01174 * items inv Return a list of items in the inventory, one per line 01175 * items actv Return a list of inventory items that are active, one per line 01176 * items on Return a list of items under the player, one per line 01177 * items cont Return a list of items in the open container, one per line 01178 * map pos Return the players x,y within the current map 01179 * map near Return the 3x3 grid of the map centered on the player 01180 * map all Return all the known map information 01181 * map <x> <y> Return the information about square x,y in the current map 01182 * skills Return a list of all skill names, one per line (see also stat xp) 01183 * spells Return a list of known spells, one per line 01184 */ 01185 if (strncmp(c, "player", 6) == 0) { 01186 char buf[1024]; 01187 01188 snprintf(buf, sizeof(buf), "request player %d %s\n", cpl.ob->tag, cpl.title); 01189 write(scripts[i].out_fd, buf, strlen(buf)); 01190 } else if (strncmp(c, "range", 5) == 0) { 01191 char buf[1024]; 01192 01193 snprintf(buf, sizeof(buf), "request range %s\n", cpl.range); 01194 write(scripts[i].out_fd, buf, strlen(buf)); 01195 } else if (strncmp(c, "weight", 5) == 0) { 01196 char buf[1024]; 01197 01198 snprintf(buf, sizeof(buf), "request weight %d %d\n", cpl.stats.weight_limit, (int)(cpl.ob->weight*1000)); 01199 write(scripts[i].out_fd, buf, strlen(buf)); 01200 } else if (strncmp(c, "stat ", 5) == 0) { 01201 c += 4; 01202 while (*c && *c != ' ') 01203 ++c; 01204 while (*c == ' ') 01205 ++c; 01206 if (!*c) 01207 return; /* bad request */ 01208 /* 01209 * stat stats Return Str,Con,Dex,Int,Wis,Pow,Cha 01210 * stat cmbt Return wc,ac,dam,speed,weapon_sp 01211 * stat hp Return hp,maxhp,sp,maxsp,grace,maxgrace,food 01212 * stat xp Return level,xp,skill-1 level,skill-1 xp,... 01213 * stat resists Return resistances 01214 */ 01215 if (strncmp(c, "stats", 5) == 0) { 01216 char buf[1024]; 01217 01218 snprintf(buf, sizeof(buf), "request stat stats %d %d %d %d %d %d %d\n", cpl.stats.Str, cpl.stats.Con, cpl.stats.Dex, cpl.stats.Int, cpl.stats.Wis, cpl.stats.Pow, cpl.stats.Cha); 01219 write(scripts[i].out_fd, buf, strlen(buf)); 01220 } else if (strncmp(c, "cmbt", 4) == 0) { 01221 char buf[1024]; 01222 01223 snprintf(buf, sizeof(buf), "request stat cmbt %d %d %d %d %d\n", cpl.stats.wc, cpl.stats.ac, cpl.stats.dam, cpl.stats.speed, cpl.stats.weapon_sp); 01224 write(scripts[i].out_fd, buf, strlen(buf)); 01225 } else if (strncmp(c, "hp", 2) == 0) { 01226 char buf[1024]; 01227 01228 snprintf(buf, sizeof(buf), "request stat hp %d %d %d %d %d %d %d\n", cpl.stats.hp, cpl.stats.maxhp, cpl.stats.sp, cpl.stats.maxsp, cpl.stats.grace, cpl.stats.maxgrace, cpl.stats.food); 01229 write(scripts[i].out_fd, buf, strlen(buf)); 01230 } else if (strncmp(c, "xp", 2) == 0) { 01231 char buf[1024]; 01232 int s; 01233 01234 snprintf(buf, sizeof(buf), "request stat xp %d %" FMT64, cpl.stats.level, cpl.stats.exp); 01235 write(scripts[i].out_fd, buf, strlen(buf)); 01236 for (s = 0; s < MAX_SKILL; ++s) { 01237 snprintf(buf, sizeof(buf), " %d %" FMT64, cpl.stats.skill_level[s], cpl.stats.skill_exp[s]); 01238 write(scripts[i].out_fd, buf, strlen(buf)); 01239 } 01240 write(scripts[i].out_fd, "\n", 1); 01241 } else if (strncmp(c, "resists", 7) == 0) { 01242 char buf[1024]; 01243 int s; 01244 01245 snprintf(buf, sizeof(buf), "request stat resists"); 01246 write(scripts[i].out_fd, buf, strlen(buf)); 01247 for (s = 0; s < 30; ++s) { 01248 snprintf(buf, sizeof(buf), " %d", cpl.stats.resists[s]); 01249 write(scripts[i].out_fd, buf, strlen(buf)); 01250 } 01251 write(scripts[i].out_fd, "\n", 1); 01252 } else if (strncmp(c, "paths", 2) == 0) { 01253 char buf[1024]; 01254 01255 snprintf(buf, sizeof(buf), "request stat paths %d %d %d\n", cpl.stats.attuned, cpl.stats.repelled, cpl.stats.denied); 01256 write(scripts[i].out_fd, buf, strlen(buf)); 01257 } 01258 } else if (strncmp(c, "flags", 5) == 0) { 01259 char buf[1024]; 01260 01261 snprintf(buf, sizeof(buf), "request flags %d %d %d %d\n", cpl.stats.flags, cpl.fire_on, cpl.run_on, cpl.no_echo); 01262 write(scripts[i].out_fd, buf, strlen(buf)); 01263 } else if (strncmp(c, "items ", 6) == 0) { 01264 c += 5; 01265 while (*c && *c != ' ') 01266 ++c; 01267 while (*c == ' ') 01268 ++c; 01269 if (!*c) 01270 return; /* bad request */ 01271 /* 01272 * items inv Return a list of items in the inventory, one per line 01273 * items actv Return a list of inventory items that are active, one per line 01274 * items on Return a list of items under the player, one per line 01275 * items cont Return a list of items in the open container, one per line 01276 */ 01277 if (strncmp(c, "inv", 3) == 0) { 01278 char *buf; 01279 item *it; 01280 01281 for (it = cpl.ob->inv; it; it = it->next) { 01282 script_send_item(i, "request items inv ", it); 01283 } 01284 buf = "request items inv end\n"; 01285 write(scripts[i].out_fd, buf, strlen(buf)); 01286 } 01287 if (strncmp(c, "actv", 4) == 0) { 01288 char *buf; 01289 item *it; 01290 01291 for (it = cpl.ob->inv; it; it = it->next) { 01292 if (it->applied) 01293 script_send_item(i, "request items actv ", it); 01294 } 01295 buf = "request items actv end\n"; 01296 write(scripts[i].out_fd, buf, strlen(buf)); 01297 } 01298 if (strncmp(c, "on", 2) == 0) { 01299 char *buf; 01300 item *it; 01301 01302 for (it = cpl.below->inv; it; it = it->next) { 01303 script_send_item(i, "request items on ", it); 01304 } 01305 buf = "request items on end\n"; 01306 write(scripts[i].out_fd, buf, strlen(buf)); 01307 } 01308 if (strncmp(c, "cont", 4) == 0) { 01309 char *buf; 01310 item *it; 01311 01312 if (cpl.container) { 01313 for (it = cpl.container->inv; it; it = it->next) { 01314 script_send_item(i, "request items cont ", it); 01315 } 01316 } 01317 buf = "request items cont end\n"; 01318 write(scripts[i].out_fd, buf, strlen(buf)); 01319 } 01320 } else if (strncmp(c, "map ", 4) == 0) { 01321 int x, y; 01322 01323 c += 3; 01324 while (*c && *c != ' ') 01325 ++c; 01326 while (*c == ' ') 01327 ++c; 01328 if (!*c) 01329 return; /* bad request */ 01330 /* 01331 * map pos Return the players x,y within the current map 01332 * map near Return the 3x3 grid of the map centered on the player 01333 * map all Return all the known map information 01334 * map <x> <y> Return the information about square x,y in the current map 01335 */ 01336 if (strncmp(c, "pos", 3) == 0) { 01337 char buf[1024]; 01338 01339 snprintf(buf, sizeof(buf), "request map pos %d %d\n", pl_pos.x+use_config[CONFIG_MAPWIDTH]/2, pl_pos.y+use_config[CONFIG_MAPHEIGHT]/2); 01340 write(scripts[i].out_fd, buf, strlen(buf)); 01341 } else if (strncmp(c, "near", 4) == 0) { 01342 for (y = 0; y < 3; ++y) 01343 for (x = 0; x < 3; ++x) 01344 send_map(i, 01345 x+pl_pos.x+use_config[CONFIG_MAPWIDTH]/2-1, 01346 y+pl_pos.y+use_config[CONFIG_MAPHEIGHT]/2-1 01347 ); 01348 } else if (strncmp(c, "all", 3) == 0) { 01349 char buf[1024]; 01350 01351 for (y = 0; y < the_map.y; ++y) 01352 for (x = 0; x < the_map.x; ++x) 01353 send_map(i, x, y); 01354 snprintf(buf, sizeof(buf), "request map end\n"); 01355 write(scripts[i].out_fd, buf, strlen(buf)); 01356 } else { 01357 while (*c && !isdigit(*c)) 01358 ++c; 01359 if (!*c) 01360 return; /* No x specified */ 01361 x = atoi(c); 01362 while (*c && *c != ' ') 01363 ++c; 01364 while (*c && !isdigit(*c)) 01365 ++c; 01366 if (!*c) 01367 return; /* No y specified */ 01368 y = atoi(c); 01369 send_map(i, x, y); 01370 } 01371 } else if (strncmp(c, "skills", 6) == 0) { 01372 char buf[1024]; 01373 int s; 01374 01375 for (s = 0; s < CS_NUM_SKILLS; s++) { 01376 if (skill_names[s]) { 01377 sprintf(buf, "request skills %d %s\n", CS_STAT_SKILLINFO + s, skill_names[s]); 01378 write(scripts[i].out_fd, buf, strlen(buf)); 01379 } 01380 } 01381 sprintf(buf, "request skills end\n"); 01382 write(scripts[i].out_fd, buf, strlen(buf)); 01383 } else if (strncmp(c, "spells", 6) == 0) { 01384 char buf[1024]; 01385 Spell *spell; 01386 01387 for (spell = cpl.spelldata; spell; spell = spell->next) { 01388 sprintf(buf, "request spells %d %d %d %d %d %d %d %d %s\n", 01389 spell->tag, spell->level, spell->sp, spell->grace, 01390 spell->skill_number, spell->path, spell->time, 01391 spell->dam, spell->name); 01392 write(scripts[i].out_fd, buf, strlen(buf)); 01393 } 01394 sprintf(buf, "request spells end\n"); 01395 write(scripts[i].out_fd, buf, strlen(buf)); 01396 } else { 01397 char buf[1024]; 01398 01399 snprintf(buf, sizeof(buf), "Script %d %s malfunction; unimplemented request:", i+1, scripts[i].name); 01400 draw_ext_info(NDI_RED, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT, buf); 01401 draw_ext_info(NDI_RED, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT, cmd); 01402 } 01403 } else if (strncmp(cmd, "issue", 5) == 0) { 01404 int repeat; 01405 int must_send; 01406 01407 c = cmd+5; 01408 while (*c && *c == ' ') 01409 ++c; 01410 if (*c && (isdigit(*c) || *c == '-')) { /* repeat specified; use send_command() */ 01411 repeat = atoi(c); 01412 while (*c && *c != ' ') 01413 ++c; 01414 while (*c && !isdigit(*c) && *c != '-') 01415 ++c; 01416 if (!*c) 01417 return; /* No must_send specified */ 01418 must_send = atoi(c); 01419 while (*c && *c != ' ') 01420 ++c; 01421 if (!*c) 01422 return; /* No command specified */ 01423 while (*c == ' ') 01424 ++c; 01425 if (repeat != -1) { 01426 int r; 01427 01428 r = send_command(c, repeat, must_send); 01429 if (r != 1) { 01430 char buf[1024]; 01431 01432 snprintf(buf, sizeof(buf), "Script %d %s malfunction; command not sent", i+1, scripts[i].name); 01433 draw_ext_info( 01434 NDI_RED, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT, buf); 01435 draw_ext_info( 01436 NDI_RED, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT, cmd); 01437 } 01438 } 01439 } else { 01440 c = cmd+5; 01441 while (*c && *c != ' ') 01442 ++c; 01443 while (*c == ' ') 01444 ++c; 01445 01446 /* 01447 * Check special cases: "mark <tag>" or "lock <new state> <tag>" 01448 */ 01449 if (strncmp(c, "mark", 4) == 0) { 01450 int tag; 01451 SockList sl; 01452 uint8 buf[MAX_BUF]; 01453 01454 c += 4; 01455 01456 while (*c && !isdigit(*c)) 01457 ++c; 01458 if (!*c) 01459 return; /* No tag specified */ 01460 tag = atoi(c); 01461 01462 SockList_Init(&sl, buf); 01463 SockList_AddString(&sl, "mark "); 01464 SockList_AddInt(&sl, tag); 01465 SockList_Send(&sl, csocket.fd); 01466 } else if (strncmp(c, "lock", 4) == 0) { 01467 int tag, locked; 01468 SockList sl; 01469 uint8 buf[MAX_BUF]; 01470 01471 c += 4; 01472 01473 while (*c && !isdigit(*c)) 01474 ++c; 01475 if (!*c) 01476 return; /* No state specified */ 01477 locked = atoi(c); 01478 while (*c && *c != ' ') 01479 ++c; 01480 while (*c && !isdigit(*c)) 01481 ++c; 01482 if (!*c) 01483 return; /* No tag specified */ 01484 tag = atoi(c); 01485 01486 SockList_Init(&sl, buf); 01487 SockList_AddString(&sl, "lock "); 01488 SockList_AddChar(&sl, locked); 01489 SockList_AddInt(&sl, tag); 01490 SockList_Send(&sl, csocket.fd); 01491 } else { 01492 cs_print_string(csocket.fd, "%s", c); 01493 } 01494 } 01495 } else if (strncmp(cmd, "localcmd", 8) == 0){ 01496 char *param; 01497 01498 c = cmd+8; 01499 while (*c == ' ') 01500 c++; 01501 param = c; 01502 while ((*param != '\0') && (*param != ' ')) 01503 param++; 01504 if (*param == ' '){ 01505 *param = '\0'; 01506 param++; 01507 } else 01508 param = NULL; 01509 01510 if (!handle_local_command(c, param)){ 01511 char buf[1024]; 01512 01513 snprintf(buf, sizeof(buf), "Script %s malfunction; localcmd not understood", scripts[i].name); 01514 draw_ext_info(NDI_RED, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT, buf); 01515 snprintf(buf, sizeof(buf), "Script <<localcmd %s %s>>", c, (param == NULL) ? "" : param); 01516 draw_ext_info(NDI_RED, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT, buf); 01517 } 01518 } else if (strncmp(cmd, "draw", 4) == 0) { 01519 int color; 01520 01521 c = cmd+4; 01522 while (*c && !isdigit(*c)) 01523 ++c; 01524 if (!*c) 01525 return; /* No color specified */ 01526 color = atoi(c); 01527 while (*c && *c != ' ') 01528 ++c; 01529 if (!*c) 01530 return; /* No message specified */ 01531 while (*c == ' ') 01532 ++c; 01533 draw_ext_info(color, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT, c); 01534 } else if (strncmp(cmd, "monitor", 7) == 0) 01535 scripts[i].monitor = 1; 01536 else if (strncmp(cmd, "unmonitor", 9) == 0) 01537 scripts[i].monitor = 0; 01538 else { 01539 char buf[1024]; 01540 01541 snprintf(buf, sizeof(buf), "Script %d %s malfunction; invalid command:", i+1, scripts[i].name); 01542 draw_ext_info(NDI_RED, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT, buf); 01543 draw_ext_info(NDI_RED, MSG_TYPE_CLIENT, MSG_TYPE_CLIENT_SCRIPT, cmd); 01544 } 01545 } 01546 01547 /* 01548 * script_send_item() 01549 * 01550 * Send one line to the script with item information. 01551 * 01552 * A header string is passed in. The format is: 01553 * 01554 * <header> tag num weight flags type name 01555 * 01556 * flags are a bitmask: 01557 * magic, cursed, damned, unpaid, locked, applied, open, was_open, inv_updated 01558 * 256 128 64 32 16 8 4 2 1 01559 */ 01560 static void script_send_item(int i, const char *head, const item *it) { 01561 char buf[4096]; 01562 int flags; 01563 01564 flags = it->magical; 01565 flags = (flags<<1)|it->cursed; 01566 flags = (flags<<1)|it->damned; 01567 flags = (flags<<1)|it->unpaid; 01568 flags = (flags<<1)|it->locked; 01569 flags = (flags<<1)|it->applied; 01570 flags = (flags<<1)|it->open; 01571 flags = (flags<<1)|it->was_open; 01572 flags = (flags<<1)|it->inv_updated; 01573 snprintf(buf, sizeof(buf), "%s%d %d %d %d %d %s\n", head, it->tag, it->nrof, (int)(it->weight*1000+0.5), flags, it->type, it->d_name); 01574 write(scripts[i].out_fd, buf, strlen(buf)); 01575 } 01576 01577 #endif /* CPROTO */
1.7.6.1