|
Atrinik Client 2.5
|
00001 /************************************************************************ 00002 * Atrinik, a Multiplayer Online Role Playing Game * 00003 * * 00004 * Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team * 00005 * * 00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game) * 00007 * and Crossfire (Multiplayer game for X-windows). * 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 at admin@atrinik.org * 00024 ************************************************************************/ 00025 00030 #include <global.h> 00031 00032 #ifndef WIN32 00033 # include <sys/wait.h> 00034 #endif 00035 00036 static void script_dead(int i); 00037 static void script_process_cmd(int i); 00038 static int script_by_name(const char *name); 00039 static void script_send_item(int i, const char *head, const object *it); 00040 00042 static struct script *scripts = NULL; 00043 00045 static int num_scripts = 0; 00046 00047 #ifdef WIN32 00048 00049 #define write(x, y, z) emulate_write(x, y, z) 00050 #define read(x, y, z) emulate_read(x, y, z) 00051 00052 static int emulate_read(HANDLE fd, char *buf, size_t len) 00053 { 00054 DWORD dwBytesRead; 00055 BOOL rc; 00056 00057 FlushFileBuffers(fd); 00058 rc = ReadFile(fd, buf, (DWORD) len, &dwBytesRead, NULL); 00059 00060 if (rc == 0) 00061 { 00062 return -1; 00063 } 00064 00065 buf[dwBytesRead] = '\0'; 00066 00067 return dwBytesRead; 00068 } 00069 00070 static int emulate_write(HANDLE fd, const char *buf, size_t len) 00071 { 00072 DWORD dwBytesWritten; 00073 BOOL rc; 00074 00075 rc = WriteFile(fd, buf, (DWORD) len, &dwBytesWritten, NULL); 00076 FlushFileBuffers(fd); 00077 00078 if (rc == 0) 00079 { 00080 return -1; 00081 } 00082 00083 return dwBytesWritten; 00084 } 00085 00086 #endif 00087 00092 void script_load(const char *cparams) 00093 { 00094 #ifndef WIN32 00095 pid_t pid; 00096 int fds[2], i = 1; 00097 char *argv[256]; 00098 struct stat statbuf; 00099 #else 00100 SECURITY_ATTRIBUTES saAttr; 00101 PROCESS_INFORMATION piProcInfo; 00102 STARTUPINFO siStartupInfo; 00103 HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup, hChildStdoutRd; 00104 HANDLE hChildStdoutWr, hChildStdoutRdDup, hSaveStdin, hSaveStdout; 00105 #endif 00106 char *name, *args, params[MAX_BUF]; 00107 00108 if (!cparams) 00109 { 00110 draw_info(COLOR_RED, "Please specify a script to execute."); 00111 return; 00112 } 00113 00114 /* cparams as passed in is a const value, so need to copy it 00115 * to data we can write over. */ 00116 strncpy(params, cparams, MAX_BUF - 1); 00117 params[MAX_BUF - 1] = '\0'; 00118 00119 /* Get name and args */ 00120 name = params; 00121 args = name; 00122 00123 while (*args && *args != ' ') 00124 { 00125 args++; 00126 } 00127 00128 while (*args && *args == ' ') 00129 { 00130 *args++ = '\0'; 00131 } 00132 00133 if (*args == '\0') 00134 { 00135 args = NULL; 00136 } 00137 00138 #ifndef WIN32 00139 /* Fill in argv[] */ 00140 argv[0] = name; 00141 00142 while (args && *args && i < (int) (sizeof(argv) / sizeof(*argv)) - 1) 00143 { 00144 argv[i++] = args; 00145 00146 while (*args && *args != ' ') 00147 { 00148 args++; 00149 } 00150 00151 while (*args && *args == ' ') 00152 { 00153 *args++ = '\0'; 00154 } 00155 } 00156 00157 argv[i] = NULL; 00158 00159 if (stat(argv[0], &statbuf) || !S_ISREG(statbuf.st_mode) || !(statbuf.st_mode & S_IXUSR)) 00160 { 00161 draw_info(COLOR_RED, "The script does not exist, is not a regular file or is not executable."); 00162 return; 00163 } 00164 00165 /* Create a pair of sockets */ 00166 if (socketpair(PF_LOCAL, SOCK_STREAM, AF_LOCAL, fds)) 00167 { 00168 draw_info(COLOR_RED, "Unable to start script: socketpair failed."); 00169 return; 00170 } 00171 00172 pid = fork(); 00173 00174 if (pid == -1) 00175 { 00176 close(fds[0]); 00177 close(fds[1]); 00178 00179 draw_info(COLOR_RED, "Unable to start script: fork failed."); 00180 return; 00181 } 00182 00183 if (pid == 0) 00184 { 00185 int r; 00186 00187 /* Clean up file descriptor space */ 00188 r = dup2(fds[0], 0); 00189 00190 if (r != 0) 00191 { 00192 fprintf(stderr, "Script Child: Failed to set pipe as stdin\n"); 00193 } 00194 00195 r = dup2(fds[0], 1); 00196 00197 if (r != 1) 00198 { 00199 fprintf(stderr, "Script Child: Failed to set pipe as stdout\n"); 00200 } 00201 00202 /* Execute */ 00203 r = execvp(argv[0], argv); 00204 00205 if (r != -1) 00206 { 00207 printf("draw %s Script child: no error, but no execvp().\n", COLOR_RED); 00208 } 00209 else 00210 { 00211 printf("draw %s Script child failed to start: %s\n", COLOR_RED, strerror(errno)); 00212 } 00213 00214 exit(1); 00215 } 00216 00217 close(fds[0]); 00218 00219 if (fcntl(fds[1], F_SETFL, O_NDELAY) == -1) 00220 { 00221 LOG(llevDebug, "Error on fcntl.\n"); 00222 } 00223 #else 00224 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 00225 saAttr.bInheritHandle = 1; 00226 saAttr.lpSecurityDescriptor = NULL; 00227 00228 hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE); 00229 00230 if (!CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0)) 00231 { 00232 draw_info(COLOR_RED, "script_load(): stdout CreatePipe() failed."); 00233 return; 00234 } 00235 00236 if (!SetStdHandle(STD_OUTPUT_HANDLE, hChildStdoutWr)) 00237 { 00238 draw_info(COLOR_RED, "script_load(): Failed to redirect stdout using SetStdHandle()."); 00239 return; 00240 } 00241 00242 if (!DuplicateHandle(GetCurrentProcess(), hChildStdoutRd, GetCurrentProcess(), &hChildStdoutRdDup, 0, 0, DUPLICATE_SAME_ACCESS)) 00243 { 00244 draw_info(COLOR_RED, "script_load(): Failed to duplicate stdout using DuplicateHandle()."); 00245 return; 00246 } 00247 00248 CloseHandle(hChildStdoutRd); 00249 00250 hSaveStdin = GetStdHandle(STD_INPUT_HANDLE); 00251 00252 if (!CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) 00253 { 00254 draw_info(COLOR_RED, "script_load(): stdin CreatePipe() failed."); 00255 return; 00256 } 00257 00258 if (!SetStdHandle(STD_INPUT_HANDLE, hChildStdinRd)) 00259 { 00260 draw_info(COLOR_RED, "script_load(): Failed to redirect stdin using SetStdHandle()."); 00261 return; 00262 } 00263 00264 if (!DuplicateHandle(GetCurrentProcess(), hChildStdinWr, GetCurrentProcess(), &hChildStdinWrDup, 0, 0, DUPLICATE_SAME_ACCESS)) 00265 { 00266 draw_info(COLOR_RED, "script_load(): failed to duplicate stdin using DuplicateHandle()"); 00267 return; 00268 } 00269 00270 CloseHandle(hChildStdinWr); 00271 00272 ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION)); 00273 ZeroMemory(&siStartupInfo, sizeof(STARTUPINFO)); 00274 siStartupInfo.cb = sizeof(STARTUPINFO); 00275 00276 if (args) 00277 { 00278 args[-1] = ' '; 00279 } 00280 00281 if (!CreateProcess(NULL, name, NULL, NULL, 1, CREATE_NEW_PROCESS_GROUP, NULL, NULL, &siStartupInfo, &piProcInfo)) 00282 { 00283 draw_info(COLOR_RED, "script_load(): CreateProcess() failed."); 00284 return; 00285 } 00286 00287 CloseHandle(piProcInfo.hThread); 00288 00289 if (args) 00290 { 00291 args[-1] = '\0'; 00292 } 00293 00294 if (!SetStdHandle(STD_INPUT_HANDLE, hSaveStdin)) 00295 { 00296 draw_info(COLOR_RED, "script_load(): Restoring original stdin failed."); 00297 return; 00298 } 00299 00300 if (!SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout)) 00301 { 00302 draw_info(COLOR_RED, "script_load(): Restoring original stdout failed."); 00303 return; 00304 } 00305 #endif 00306 00307 /* realloc script array to add new entry; fill in the data */ 00308 scripts = realloc(scripts, sizeof(scripts[0]) * (num_scripts + 1)); 00309 scripts[num_scripts].name = strdup(cparams); 00310 scripts[num_scripts].params = args ? strdup(args) : NULL; 00311 00312 #ifndef WIN32 00313 scripts[num_scripts].out_fd = fds[1]; 00314 scripts[num_scripts].in_fd = fds[1]; 00315 scripts[num_scripts].pid = pid; 00316 #else 00317 scripts[num_scripts].out_fd = hChildStdinWrDup; 00318 scripts[num_scripts].in_fd = hChildStdoutRdDup; 00319 scripts[num_scripts].pid = piProcInfo.dwProcessId; 00320 scripts[num_scripts].process = piProcInfo.hProcess; 00321 #endif 00322 scripts[num_scripts].cmd_count = 0; 00323 scripts[num_scripts].events = NULL; 00324 scripts[num_scripts].events_count = 0; 00325 00326 num_scripts++; 00327 } 00328 00330 void script_list() 00331 { 00332 if (num_scripts == 0) 00333 { 00334 draw_info(COLOR_WHITE, "No scripts are currently running."); 00335 } 00336 else 00337 { 00338 int i; 00339 00340 draw_info_format(COLOR_WHITE, "%d scripts are currently running:", num_scripts); 00341 00342 for (i = 0; i < num_scripts; i++) 00343 { 00344 if (scripts[i].params) 00345 { 00346 draw_info_format(COLOR_WHITE, "%d %s %s", i + 1, scripts[i].name, scripts[i].params); 00347 } 00348 else 00349 { 00350 draw_info_format(COLOR_WHITE, "%d %s", i + 1, scripts[i].name); 00351 } 00352 } 00353 } 00354 } 00355 00358 void script_process() 00359 { 00360 int i, r; 00361 #ifdef WIN32 00362 DWORD nAvailBytes = 0, dwStatus; 00363 char cTmp; 00364 BOOL bRC, bStatus; 00365 #else 00366 fd_set tmp_read; 00367 int pollret; 00368 struct timeval timeout; 00369 #endif 00370 00371 /* Determine which script's fd is set */ 00372 for (i = 0; i < num_scripts; i++) 00373 { 00374 #ifndef WIN32 00375 FD_ZERO(&tmp_read); 00376 FD_SET(scripts[i].in_fd, &tmp_read); 00377 00378 timeout.tv_sec = 0; 00379 timeout.tv_usec = 0; 00380 00381 if ((pollret = select(scripts[i].in_fd + 1, &tmp_read, NULL, NULL, &timeout)) == -1) 00382 { 00383 LOG(llevDebug, "Got errno %d on select call: %s.\n", errno, strerror(errno)); 00384 } 00385 00386 if (FD_ISSET(scripts[i].in_fd, &tmp_read)) 00387 #else 00388 bStatus = GetExitCodeProcess(scripts[i].process, &dwStatus); 00389 bRC = PeekNamedPipe(scripts[i].in_fd, &cTmp, 1, NULL, &nAvailBytes, NULL); 00390 00391 if (nAvailBytes) 00392 #endif 00393 { 00394 /* Read in script[i].cmd */ 00395 r = read(scripts[i].in_fd, scripts[i].cmd + scripts[i].cmd_count, sizeof(scripts[i].cmd) - scripts[i].cmd_count - 1); 00396 00397 if (r > 0) 00398 { 00399 scripts[i].cmd_count += r; 00400 } 00401 #ifndef WIN32 00402 else if (r == 0 || errno == EBADF) 00403 #else 00404 else if (r == 0 || GetLastError() == ERROR_BROKEN_PIPE) 00405 #endif 00406 { 00407 /* Script has exited; delete it */ 00408 script_dead(i); 00409 return; 00410 } 00411 00412 scripts[i].cmd[scripts[i].cmd_count] = '\0'; 00413 00414 /* If a newline or full buffer has been reached, process it */ 00415 while (scripts[i].cmd_count == sizeof(scripts[i].cmd) - 1 || strchr(scripts[i].cmd, '\n')) 00416 { 00417 script_process_cmd(i); 00418 scripts[i].cmd[scripts[i].cmd_count] = '\0'; 00419 } 00420 00421 /* Only process one script at a time */ 00422 return; 00423 } 00424 #ifdef WIN32 00425 /* Error: assume dead */ 00426 else if (!bRC || (bStatus && (dwStatus != STILL_ACTIVE))) 00427 { 00428 script_dead(i); 00429 } 00430 #endif 00431 } 00432 } 00433 00437 static void script_process_cmd(int i) 00438 { 00439 char cmd[HUGE_BUF], *c; 00440 int l; 00441 00442 /* Strip out just this one command */ 00443 for (l = 0; l < scripts[i].cmd_count; l++) 00444 { 00445 if (scripts[i].cmd[l] == '\n') 00446 { 00447 break; 00448 } 00449 } 00450 00451 l++; 00452 memcpy(cmd, scripts[i].cmd, l); 00453 00454 #ifndef WIN32 00455 cmd[l - 1] = '\0'; 00456 #else 00457 cmd[l - 2] = '\0'; 00458 #endif 00459 00460 if (l < scripts[i].cmd_count) 00461 { 00462 memmove(scripts[i].cmd, scripts[i].cmd + l, scripts[i].cmd_count - l); 00463 scripts[i].cmd_count -= l; 00464 } 00465 else 00466 { 00467 scripts[i].cmd_count = 0; 00468 } 00469 00470 /* Now the data in scripts[i] is ready for the next read. 00471 * We have a complete command in cmd[]. 00472 * Process it. */ 00473 if (!strncmp(cmd, "draw ", 5)) 00474 { 00475 char color[COLOR_BUF]; 00476 const char *cp = cmd; 00477 00478 cp += 5; 00479 00480 snprintf(color, sizeof(color), "%s", cp); 00481 color[sizeof(color) - 1] = '\0'; 00482 cp += 7; 00483 00484 draw_info(color, cp); 00485 } 00486 else if (!strncmp(cmd, "log ", 4)) 00487 { 00488 int log_level; 00489 00490 c = cmd + 4; 00491 00492 while (*c && !isdigit(*c)) 00493 { 00494 c++; 00495 } 00496 00497 /* No log level specified */ 00498 if (!*c) 00499 { 00500 LOG(llevBug, "script_process_cmd(): Log command did not have log level set.\n"); 00501 return; 00502 } 00503 00504 log_level = atoi(c); 00505 00506 while (*c && *c != ' ') 00507 { 00508 c++; 00509 } 00510 00511 /* No log message specified */ 00512 if (!*c) 00513 { 00514 LOG(llevBug, "script_process_cmd(): Log command did not have log message set.\n"); 00515 return; 00516 } 00517 00518 while (*c == ' ') 00519 { 00520 c++; 00521 } 00522 00523 LOG(log_level, "%s\n", c); 00524 } 00525 else if (!strncmp(cmd, "request ", 8)) 00526 { 00527 char buf[MAX_BUF]; 00528 int w = 0; 00529 00530 c = cmd + 8; 00531 00532 if (!strncmp(c, "player", 6)) 00533 { 00534 snprintf(buf, sizeof(buf), "request player %d %s:%s\n", cpl.ob->tag, cpl.name, cpl.ext_title); 00535 w = write(scripts[i].out_fd, buf, strlen(buf)); 00536 } 00537 else if (!strncmp(c, "weight", 5)) 00538 { 00539 snprintf(buf, sizeof(buf), "request weight %d %d %d\n", cpl.weight_limit, (int) (cpl.ob->weight * 1000), (int) (cpl.real_weight * 1000)); 00540 w = write(scripts[i].out_fd, buf, strlen(buf)); 00541 } 00542 else if (!strncmp(c, "stat ", 5)) 00543 { 00544 c += 5; 00545 00546 if (!strncmp(c, "stats", 5)) 00547 { 00548 snprintf(buf, sizeof(buf), "request stat stats %d %d %d %d %d %d %d\n", cpl.stats.Str, cpl.stats.Dex, cpl.stats.Con, cpl.stats.Int, cpl.stats.Wis, cpl.stats.Pow, cpl.stats.Cha); 00549 w = write(scripts[i].out_fd, buf, strlen(buf)); 00550 } 00551 else if (!strncmp(c, "combat", 6)) 00552 { 00553 snprintf(buf, sizeof(buf), "request stat combat %d %d %d %d %d\n", cpl.stats.wc, cpl.stats.ac, cpl.stats.dam, cpl.stats.speed, cpl.stats.weapon_sp); 00554 w = write(scripts[i].out_fd, buf, strlen(buf)); 00555 } 00556 else if (!strncmp(c, "hp", 2)) 00557 { 00558 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); 00559 w = write(scripts[i].out_fd,buf,strlen(buf)); 00560 } 00561 else if (!strncmp(c, "exp", 3)) 00562 { 00563 int s; 00564 00565 snprintf(buf, sizeof(buf), "request stat exp %d %"FMT64, cpl.stats.level, cpl.stats.exp); 00566 w = write(scripts[i].out_fd, buf, strlen(buf)); 00567 00568 for (s = 0; s < MAX_SKILL; s++) 00569 { 00570 snprintf(buf, sizeof(buf), " %d %"FMT64, cpl.stats.skill_level[s], cpl.stats.skill_exp[s]); 00571 w = write(scripts[i].out_fd, buf, strlen(buf)); 00572 } 00573 00574 w = write(scripts[i].out_fd, "\n", 1); 00575 } 00576 else if (!strncmp(c, "protections", 11)) 00577 { 00578 int s; 00579 00580 snprintf(buf, sizeof(buf), "request stat protections"); 00581 w = write(scripts[i].out_fd, buf, strlen(buf)); 00582 00583 for (s = CS_STAT_PROT_START; s <= CS_STAT_PROT_END; s++) 00584 { 00585 snprintf(buf, sizeof(buf), " %d", cpl.stats.protection[s - CS_STAT_PROT_START]); 00586 w = write(scripts[i].out_fd, buf, strlen(buf)); 00587 } 00588 00589 w = write(scripts[i].out_fd, "\n", 1); 00590 } 00591 } 00592 else if (!strncmp(c, "items ", 6)) 00593 { 00594 c += 6; 00595 00596 if (!strncmp(c, "inv", 3)) 00597 { 00598 object *it = cpl.ob->inv; 00599 00600 while (it) 00601 { 00602 script_send_item(i, "request items inv ", it); 00603 it = it->next; 00604 } 00605 00606 strcpy(buf, "request items inv end\n"); 00607 w = write(scripts[i].out_fd, buf, strlen(buf)); 00608 } 00609 else if (!strncmp(c, "applied", 7)) 00610 { 00611 object *it = cpl.ob->inv; 00612 00613 while (it) 00614 { 00615 if (it->flags & F_APPLIED) 00616 { 00617 script_send_item(i, "request items applied ", it); 00618 } 00619 00620 it = it->next; 00621 } 00622 00623 strcpy(buf, "request items applied end\n"); 00624 w = write(scripts[i].out_fd, buf, strlen(buf)); 00625 } 00626 else if (!strncmp(c, "below", 5)) 00627 { 00628 object *it = cpl.below->inv; 00629 00630 while (it) 00631 { 00632 script_send_item(i, "request items below ", it); 00633 it = it->next; 00634 } 00635 00636 strcpy(buf, "request items below end\n"); 00637 w = write(scripts[i].out_fd, buf, strlen(buf)); 00638 } 00639 } 00640 else 00641 { 00642 draw_info_format(COLOR_RED, "Script %d %s malfunction; unimplemented request: %s", i + 1, scripts[i].name, cmd); 00643 } 00644 00645 if (w < 0) 00646 { 00647 LOG(llevBug, "script_process_cmd(): Write system call failed.\n"); 00648 } 00649 } 00650 else if (!strncmp(cmd, "issue ", 6)) 00651 { 00652 c = cmd + 6; 00653 00654 if (!strncmp(c, "command ", 8)) 00655 { 00656 c += 8; 00657 00658 if (!client_command_check(c)) 00659 { 00660 send_command(c); 00661 } 00662 } 00663 else if (!strncmp(c, "string ", 7)) 00664 { 00665 c += 7; 00666 00667 cs_write_string(c, strlen(c)); 00668 } 00669 } 00670 else if (!strncmp(cmd, "event ", 6)) 00671 { 00672 c = cmd + 6; 00673 00674 if (!strncmp(c, "register ", 9)) 00675 { 00676 c += 9; 00677 00678 c = strdup(c); 00679 scripts[i].events = realloc(scripts[i].events, (scripts[i].events_count + 1) * sizeof(scripts[i].events[1])); 00680 scripts[i].events[scripts[i].events_count] = c; 00681 scripts[i].events_count++; 00682 } 00683 else if (!strncmp(c, "unregister ", 11)) 00684 { 00685 int j; 00686 00687 c += 11; 00688 00689 for (j = 0; j < scripts[i].events_count; j++) 00690 { 00691 if (strcmp(c, scripts[i].events[j]) == 0 ) 00692 { 00693 free(scripts[i].events[j]); 00694 00695 while (j + 1 < scripts[i].events_count) 00696 { 00697 scripts[i].events[j] = scripts[i].events[j + 1]; 00698 j++; 00699 } 00700 00701 scripts[i].events_count--; 00702 00703 break; 00704 } 00705 } 00706 } 00707 } 00708 else 00709 { 00710 draw_info_format(COLOR_RED, "Script %d %s malfunction; invalid command: %s", i + 1, scripts[i].name, cmd); 00711 } 00712 } 00713 00719 static void script_send_item(int i, const char *head, const object *it) 00720 { 00721 char buf[HUGE_BUF]; 00722 int w; 00723 00724 snprintf(buf, sizeof(buf), "%s%d %d %f %d %d %s\n", head, it->tag, it->nrof, it->weight, it->flags, it->itype, it->s_name); 00725 w = write(scripts[i].out_fd, buf, strlen(buf)); 00726 00727 if (w < 0) 00728 { 00729 LOG(llevBug, "script_send_item(): Write system call failed.\n"); 00730 } 00731 } 00732 00739 int script_trigger_event(const char *cmd, const uint8 *data, const int data_len, const enum CmdFormat format) 00740 { 00741 int i, e, w, len; 00742 00743 /* For each script... */ 00744 for (i = 0; i < num_scripts; ++i) 00745 { 00746 /* For each registered event */ 00747 for (e = 0; e < scripts[i].events_count; e++) 00748 { 00749 char buf[10240]; 00750 00751 if (strcmp(cmd, scripts[i].events[e])) 00752 { 00753 continue; 00754 } 00755 00756 len = data_len; 00757 00758 switch (format) 00759 { 00760 case ASCII: 00761 snprintf(buf, sizeof(buf), "event %s %s\n", cmd, data); 00762 break; 00763 00764 case SHORT_INT: 00765 snprintf(buf, sizeof(buf), "event %s %d %d\n", cmd, GetShort_String(data), GetInt_String(data + 2)); 00766 break; 00767 00768 case SHORT_ARRAY: 00769 { 00770 int be, p; 00771 00772 be = snprintf(buf, sizeof(buf), "event %s", cmd); 00773 00774 for (p = 0; p * 2 < len && p < 100; ++p) 00775 { 00776 be += snprintf(buf + be, sizeof(buf) - be, " %d", GetShort_String(data + p * 2)); 00777 } 00778 00779 be += snprintf(buf + be, sizeof(buf) - be, "\n"); 00780 break; 00781 } 00782 00783 case INT_ARRAY: 00784 { 00785 int be, p; 00786 00787 be = snprintf(buf, sizeof(buf), "event %s", cmd); 00788 00789 for (p = 0; p * 4 < len; ++p) 00790 { 00791 be += snprintf(buf + be, sizeof(buf) - be, " %d", GetInt_String(data + p * 4)); 00792 } 00793 00794 be += snprintf(buf + be, sizeof(buf) - be, "\n"); 00795 break; 00796 } 00797 00798 case STATS: 00799 { 00800 int j = 0, c, be = 0; 00801 00802 while (j < len) 00803 { 00804 c = data[j++]; 00805 00806 be += snprintf(buf + be, sizeof(buf) - be, "event %s", cmd); 00807 00808 if (c >= CS_STAT_PROT_START && c <= CS_STAT_PROT_END) 00809 { 00810 be += snprintf(buf + be, sizeof(buf) - be, " protects %d %d\n", c - CS_STAT_PROT_START, (sint16) *(data + j++)); 00811 } 00812 else 00813 { 00814 switch (c) 00815 { 00816 case CS_STAT_TARGET_HP: 00817 be += snprintf(buf + be, sizeof(buf) - be, " target_hp %d\n", (int)*(data + j++)); 00818 cpl.target_hp = (int)*(data + j++); 00819 break; 00820 00821 case CS_STAT_REG_HP: 00822 be += snprintf(buf + be, sizeof(buf) - be, " regen_hp %f\n", GetShort_String(data + j) / 10.0f); 00823 j += 2; 00824 break; 00825 00826 case CS_STAT_REG_MANA: 00827 be += snprintf(buf + be, sizeof(buf) - be, " regen_mana %f\n", GetShort_String(data + j) / 10.0f); 00828 j += 2; 00829 break; 00830 00831 case CS_STAT_REG_GRACE: 00832 be += snprintf(buf + be, sizeof(buf) - be, " regen_grace %f\n", GetShort_String(data + j) / 10.0f); 00833 j += 2; 00834 break; 00835 00836 case CS_STAT_HP: 00837 be += snprintf(buf + be, sizeof(buf) - be, " hp %d\n", GetInt_String(data + j)); 00838 j += 4; 00839 break; 00840 00841 case CS_STAT_MAXHP: 00842 be += snprintf(buf + be, sizeof(buf) - be, " maxhp %d\n", GetInt_String(data + j)); 00843 j += 4; 00844 break; 00845 00846 case CS_STAT_SP: 00847 be += snprintf(buf + be, sizeof(buf) - be, " sp %d\n", GetShort_String(data + j)); 00848 j += 2; 00849 break; 00850 00851 case CS_STAT_MAXSP: 00852 be += snprintf(buf + be, sizeof(buf) - be, " maxsp %d\n", GetShort_String(data + j)); 00853 j += 2; 00854 break; 00855 00856 case CS_STAT_GRACE: 00857 be += snprintf(buf + be, sizeof(buf) - be, " grace %d\n", GetShort_String(data + j)); 00858 j += 2; 00859 break; 00860 00861 case CS_STAT_MAXGRACE: 00862 be += snprintf(buf + be, sizeof(buf) - be, " maxgrace %d\n", GetShort_String(data + j)); 00863 j += 2; 00864 break; 00865 00866 case CS_STAT_STR: 00867 be += snprintf(buf + be, sizeof(buf) - be, " str %d\n", (int) *(data + j++)); 00868 break; 00869 00870 case CS_STAT_INT: 00871 be += snprintf(buf + be, sizeof(buf) - be, " int %d\n", (int) *(data + j++)); 00872 break; 00873 00874 case CS_STAT_POW: 00875 be += snprintf(buf + be, sizeof(buf) - be, " pow %d\n", (int) *(data + j++)); 00876 break; 00877 00878 case CS_STAT_WIS: 00879 be += snprintf(buf + be, sizeof(buf) - be, " wis %d\n", (int) *(data + j++)); 00880 break; 00881 00882 case CS_STAT_DEX: 00883 be += snprintf(buf + be, sizeof(buf) - be, " dex %d\n", (int) *(data + j++)); 00884 break; 00885 00886 case CS_STAT_CON: 00887 be += snprintf(buf + be, sizeof(buf) - be, " con %d\n", (int) *(data + j++)); 00888 break; 00889 00890 case CS_STAT_CHA: 00891 be += snprintf(buf + be, sizeof(buf) - be, " cha %d\n", (int) *(data + j++)); 00892 break; 00893 00894 case CS_STAT_EXP: 00895 be += snprintf(buf + be, sizeof(buf) - be, " exp %d\n", GetInt_String(data + j)); 00896 j += 4; 00897 break; 00898 00899 case CS_STAT_LEVEL: 00900 be += snprintf(buf + be, sizeof(buf) - be, " level %d\n", (char) *(data + j++)); 00901 break; 00902 00903 case CS_STAT_WC: 00904 be += snprintf(buf + be, sizeof(buf) - be, " wc %d\n", (char) GetShort_String(data + j)); 00905 j += 2; 00906 break; 00907 00908 case CS_STAT_AC: 00909 be += snprintf(buf + be, sizeof(buf) - be, " ac %d\n", (char) GetShort_String(data + j)); 00910 j += 2; 00911 break; 00912 00913 case CS_STAT_DAM: 00914 be += snprintf(buf + be, sizeof(buf) - be, " dam %d\n", GetShort_String(data + j)); 00915 j += 2; 00916 break; 00917 00918 case CS_STAT_SPEED: 00919 be += snprintf(buf + be, sizeof(buf) - be, " speed %d\n", GetInt_String(data + j)); 00920 j += 4; 00921 break; 00922 00923 case CS_STAT_FOOD: 00924 be += snprintf(buf + be, sizeof(buf) - be, " food %d\n", GetShort_String(data + j)); 00925 j += 2; 00926 break; 00927 00928 case CS_STAT_WEAP_SP: 00929 be += snprintf(buf + be, sizeof(buf) - be, " weapon_speed %d\n", (int)*(data + j++)); 00930 break; 00931 00932 case CS_STAT_FLAGS: 00933 be += snprintf(buf + be, sizeof(buf) - be, " flags %d\n", GetShort_String(data + j)); 00934 j += 2; 00935 break; 00936 00937 case CS_STAT_WEIGHT_LIM: 00938 be += snprintf(buf + be, sizeof(buf) - be, " weight_limit %d\n", GetInt_String(data + j)); 00939 j += 4; 00940 break; 00941 00942 case CS_STAT_ACTION_TIME: 00943 be += snprintf(buf + be, sizeof(buf) - be, " action_time %f\n", abs(GetInt_String(data + j)) / 1000.0f); 00944 j += 4; 00945 break; 00946 00947 case CS_STAT_SKILLEXP_AGILITY: 00948 case CS_STAT_SKILLEXP_PERSONAL: 00949 case CS_STAT_SKILLEXP_MENTAL: 00950 case CS_STAT_SKILLEXP_PHYSIQUE: 00951 case CS_STAT_SKILLEXP_MAGIC: 00952 case CS_STAT_SKILLEXP_WISDOM: 00953 be += snprintf(buf + be, sizeof(buf) - be, " skill_exp %d %"FMT64"\n", (c - CS_STAT_SKILLEXP_START) / 2, GetInt64_String(data + j)); 00954 j += 8; 00955 break; 00956 00957 case CS_STAT_SKILLEXP_AGLEVEL: 00958 case CS_STAT_SKILLEXP_PELEVEL: 00959 case CS_STAT_SKILLEXP_MELEVEL: 00960 case CS_STAT_SKILLEXP_PHLEVEL: 00961 case CS_STAT_SKILLEXP_MALEVEL: 00962 case CS_STAT_SKILLEXP_WILEVEL: 00963 be += snprintf(buf + be, sizeof(buf) - be, " skill_level %d %d\n", (c - CS_STAT_SKILLEXP_START - 1) / 2, (sint16)*(data + j++)); 00964 break; 00965 00966 case CS_STAT_RANGE: 00967 { 00968 int rlen = data[j++]; 00969 00970 be += snprintf(buf + be, sizeof(buf) - be, " range %s\n", cpl.range); 00971 j += rlen; 00972 break; 00973 } 00974 00975 case CS_STAT_EXT_TITLE: 00976 { 00977 int rlen = data[j++]; 00978 00979 be += snprintf(buf + be, sizeof(buf) - be, " ext_title %s\n", cpl.ext_title); 00980 j += rlen; 00981 break; 00982 } 00983 00984 default: 00985 j = len; 00986 break; 00987 } 00988 } 00989 } 00990 00991 break; 00992 } 00993 00994 case MIXED: 00995 case NODATA: 00996 default: 00997 { 00998 int be, p; 00999 01000 /* We may receive null data, in which case len has no meaning */ 01001 if (!data) 01002 { 01003 len = 0; 01004 } 01005 01006 be = snprintf(buf, sizeof(buf), "event %s %d bytes unparsed:", cmd, len); 01007 01008 for (p = 0; p < len && p < 100; ++p) 01009 { 01010 be += snprintf(buf + be, sizeof(buf) - be, " %02x", data[p]); 01011 } 01012 01013 be += snprintf(buf + be, sizeof(buf) - be, "\n"); 01014 break; 01015 } 01016 } 01017 01018 w = write(scripts[i].out_fd, buf, strlen(buf)); 01019 01020 if (w < 0) 01021 { 01022 LOG(llevBug, "script_trigger_event(): Write system call failed.\n"); 01023 } 01024 } 01025 } 01026 01027 return 0; 01028 } 01029 01033 void script_send(const char *params) 01034 { 01035 int i = 0, w; 01036 char *p; 01037 01038 if (!params) 01039 { 01040 return; 01041 } 01042 01043 p = strchr(params, ' '); 01044 01045 if (!p) 01046 { 01047 draw_info(COLOR_RED, "No message to send specified."); 01048 return; 01049 } 01050 01051 while (*p == ' ') 01052 { 01053 *p++ = '\0'; 01054 } 01055 01056 i = script_by_name(params); 01057 01058 if (i < 0) 01059 { 01060 draw_info(COLOR_RED, "No such running script."); 01061 return; 01062 } 01063 01064 /* Send the message */ 01065 w = write(scripts[i].out_fd, "scriptsend ", 11); 01066 w = write(scripts[i].out_fd, p, strlen(p)); 01067 w = write(scripts[i].out_fd, "\n", 1); 01068 01069 if (w < 0) 01070 { 01071 LOG(llevBug, "script_send(): Write system call failed.\n"); 01072 } 01073 } 01074 01078 void script_killall() 01079 { 01080 #ifdef WIN32 01081 while (num_scripts > 0) 01082 { 01083 GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, scripts[0].pid); 01084 script_dead(0); 01085 } 01086 #endif 01087 } 01088 01093 static void script_dead(int i) 01094 { 01095 /* Release resources */ 01096 #ifndef WIN32 01097 close(scripts[i].in_fd); 01098 close(scripts[i].out_fd); 01099 #else 01100 CloseHandle(scripts[i].in_fd); 01101 CloseHandle(scripts[i].out_fd); 01102 CloseHandle(scripts[i].process); 01103 #endif 01104 01105 free(scripts[i].name); 01106 free(scripts[i].params); 01107 01108 #ifndef WIN32 01109 waitpid(-1, NULL, WNOHANG); 01110 #endif 01111 01112 /* Move scripts with higher index numbers down one slot */ 01113 if (i < (num_scripts - 1)) 01114 { 01115 memmove(&scripts[i], &scripts[i + 1], sizeof(scripts[i]) * (num_scripts - i - 1)); 01116 } 01117 01118 /* Update our count */ 01119 num_scripts--; 01120 } 01121 01127 static int script_by_name(const char *name) 01128 { 01129 int i, l = 0; 01130 01131 if (!name) 01132 { 01133 return (num_scripts == 1 ? 0 : -1); 01134 } 01135 01136 /* Parse script number */ 01137 if (isdigit(*name)) 01138 { 01139 i = atoi(name); 01140 i--; 01141 01142 if (i >= 0 && i < num_scripts) 01143 { 01144 return i; 01145 } 01146 } 01147 01148 while (name[l] && name[l] != ' ') 01149 { 01150 l++; 01151 } 01152 01153 for (i = 0; i < num_scripts; i++) 01154 { 01155 if (strncmp(name, scripts[i].name, l) == 0) 01156 { 01157 return i; 01158 } 01159 } 01160 01161 return -1; 01162 } 01163 01167 void script_autoload() 01168 { 01169 FILE *fp; 01170 char line[MAX_BUF]; 01171 01172 if (!(fp = fopen_wrapper(SCRIPTS_AUTOLOAD, "r+"))) 01173 { 01174 LOG(llevInfo, "Can't find file %s. Will not load any scripts.\n", SCRIPTS_AUTOLOAD); 01175 return; 01176 } 01177 01178 while (fgets(line, sizeof(line) - 1, fp)) 01179 { 01180 if (line[0] == '#' || line[0] == '\n') 01181 { 01182 continue; 01183 } 01184 01185 #ifndef WIN32 01186 line[strlen(line) - 1] = '\0'; 01187 #else 01188 line[strlen(line) - 2] = '\0'; 01189 #endif 01190 01191 script_load(line); 01192 } 01193 } 01194 01199 void script_unload(const char *params) 01200 { 01201 int i = script_by_name(params); 01202 01203 if (i < 0 || i >= num_scripts) 01204 { 01205 draw_info(COLOR_RED, "No such running script."); 01206 return; 01207 } 01208 01209 #ifndef WIN32 01210 kill(scripts[i].pid, SIGHUP); 01211 #else 01212 GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, scripts[i].pid); 01213 #endif 01214 01215 draw_info_format(COLOR_GREEN, "Unloaded script #%d.", i + 1); 01216 script_dead(i); 01217 }
1.7.4