PageRenderTime 64ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/prvm_cmds.c

https://gitlab.com/xonotic/darkplaces
C | 7366 lines | 4891 code | 858 blank | 1617 comment | 1009 complexity | ac48622bb0bee129912c328ab7c76e96 MD5 | raw file
Possible License(s): GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. // AK
  2. // Basically every vm builtin cmd should be in here.
  3. // All 3 builtin and extension lists can be found here
  4. // cause large (I think they will) parts are from pr_cmds the same copyright like in pr_cmds
  5. // also applies here
  6. #include "quakedef.h"
  7. #include "prvm_cmds.h"
  8. #include "libcurl.h"
  9. #include <time.h>
  10. #include "cl_collision.h"
  11. #include "clvm_cmds.h"
  12. #include "csprogs.h"
  13. #include "ft2.h"
  14. #include "mdfour.h"
  15. extern cvar_t prvm_backtraceforwarnings;
  16. #ifdef USEODE
  17. extern dllhandle_t ode_dll;
  18. #endif
  19. // LordHavoc: changed this to NOT use a return statement, so that it can be used in functions that must return a value
  20. void VM_Warning(prvm_prog_t *prog, const char *fmt, ...)
  21. {
  22. va_list argptr;
  23. char msg[MAX_INPUTLINE];
  24. static double recursive = -1;
  25. va_start(argptr,fmt);
  26. dpvsnprintf(msg,sizeof(msg),fmt,argptr);
  27. va_end(argptr);
  28. Con_Print(msg);
  29. // TODO: either add a cvar/cmd to control the state dumping or replace some of the calls with Con_Printf [9/13/2006 Black]
  30. if(prvm_backtraceforwarnings.integer && recursive != realtime) // NOTE: this compares to the time, just in case if PRVM_PrintState causes a Host_Error and keeps recursive set
  31. {
  32. recursive = realtime;
  33. PRVM_PrintState(prog, 0);
  34. recursive = -1;
  35. }
  36. }
  37. //============================================================================
  38. // Common
  39. // TODO DONE: move vm_files and vm_fssearchlist to prvm_prog_t struct
  40. // TODO: move vm_files and vm_fssearchlist back [9/13/2006 Black]
  41. // TODO: (move vm_files and vm_fssearchlist to prvm_prog_t struct again) [2007-01-23 LordHavoc]
  42. // TODO: will this war ever end? [2007-01-23 LordHavoc]
  43. void VM_CheckEmptyString(prvm_prog_t *prog, const char *s)
  44. {
  45. if (ISWHITESPACE(s[0]))
  46. prog->error_cmd("%s: Bad string", prog->name);
  47. }
  48. void VM_GenerateFrameGroupBlend(prvm_prog_t *prog, framegroupblend_t *framegroupblend, const prvm_edict_t *ed)
  49. {
  50. // self.frame is the interpolation target (new frame)
  51. // self.frame1time is the animation base time for the interpolation target
  52. // self.frame2 is the interpolation start (previous frame)
  53. // self.frame2time is the animation base time for the interpolation start
  54. // self.lerpfrac is the interpolation strength for self.frame2
  55. // self.lerpfrac3 is the interpolation strength for self.frame3
  56. // self.lerpfrac4 is the interpolation strength for self.frame4
  57. // pitch angle on a player model where the animator set up 5 sets of
  58. // animations and the csqc simply lerps between sets)
  59. framegroupblend[0].frame = (int) PRVM_gameedictfloat(ed, frame );
  60. framegroupblend[1].frame = (int) PRVM_gameedictfloat(ed, frame2 );
  61. framegroupblend[2].frame = (int) PRVM_gameedictfloat(ed, frame3 );
  62. framegroupblend[3].frame = (int) PRVM_gameedictfloat(ed, frame4 );
  63. framegroupblend[0].start = PRVM_gameedictfloat(ed, frame1time);
  64. framegroupblend[1].start = PRVM_gameedictfloat(ed, frame2time);
  65. framegroupblend[2].start = PRVM_gameedictfloat(ed, frame3time);
  66. framegroupblend[3].start = PRVM_gameedictfloat(ed, frame4time);
  67. framegroupblend[1].lerp = PRVM_gameedictfloat(ed, lerpfrac );
  68. framegroupblend[2].lerp = PRVM_gameedictfloat(ed, lerpfrac3 );
  69. framegroupblend[3].lerp = PRVM_gameedictfloat(ed, lerpfrac4 );
  70. // assume that the (missing) lerpfrac1 is whatever remains after lerpfrac2+lerpfrac3+lerpfrac4 are summed
  71. framegroupblend[0].lerp = 1 - framegroupblend[1].lerp - framegroupblend[2].lerp - framegroupblend[3].lerp;
  72. }
  73. // LordHavoc: quite tempting to break apart this function to reuse the
  74. // duplicated code, but I suspect it is better for performance
  75. // this way
  76. void VM_FrameBlendFromFrameGroupBlend(frameblend_t *frameblend, const framegroupblend_t *framegroupblend, const dp_model_t *model, double curtime)
  77. {
  78. int sub2, numframes, f, i, k;
  79. int isfirstframegroup = true;
  80. int nolerp;
  81. double sublerp, lerp, d;
  82. const animscene_t *scene;
  83. const framegroupblend_t *g;
  84. frameblend_t *blend = frameblend;
  85. memset(blend, 0, MAX_FRAMEBLENDS * sizeof(*blend));
  86. // rpolzer: Not testing isanimated here - a model might have
  87. // "animations" that move no vertices (but only bones), thus rendering
  88. // may assume it's not animated while processing can't.
  89. if (!model)
  90. {
  91. blend[0].lerp = 1;
  92. return;
  93. }
  94. nolerp = (model->type == mod_sprite) ? !r_lerpsprites.integer : !r_lerpmodels.integer;
  95. numframes = model->numframes;
  96. for (k = 0, g = framegroupblend;k < MAX_FRAMEGROUPBLENDS;k++, g++)
  97. {
  98. f = g->frame;
  99. if ((unsigned int)f >= (unsigned int)numframes)
  100. {
  101. if (developer_extra.integer)
  102. Con_DPrintf("VM_FrameBlendFromFrameGroupBlend: no such frame %d in model %s\n", f, model->name);
  103. f = 0;
  104. }
  105. d = lerp = g->lerp;
  106. if (lerp <= 0)
  107. continue;
  108. if (nolerp)
  109. {
  110. if (isfirstframegroup)
  111. {
  112. d = lerp = 1;
  113. isfirstframegroup = false;
  114. }
  115. else
  116. continue;
  117. }
  118. if (model->animscenes)
  119. {
  120. scene = model->animscenes + f;
  121. f = scene->firstframe;
  122. if (scene->framecount > 1)
  123. {
  124. // this code path is only used on .zym models and torches
  125. sublerp = scene->framerate * (curtime - g->start);
  126. f = (int) floor(sublerp);
  127. sublerp -= f;
  128. sub2 = f + 1;
  129. if (sublerp < (1.0 / 65536.0f))
  130. sublerp = 0;
  131. if (sublerp > (65535.0f / 65536.0f))
  132. sublerp = 1;
  133. if (nolerp)
  134. sublerp = 0;
  135. if (scene->loop)
  136. {
  137. f = (f % scene->framecount);
  138. sub2 = (sub2 % scene->framecount);
  139. }
  140. f = bound(0, f, (scene->framecount - 1)) + scene->firstframe;
  141. sub2 = bound(0, sub2, (scene->framecount - 1)) + scene->firstframe;
  142. d = sublerp * lerp;
  143. // two framelerps produced from one animation
  144. if (d > 0)
  145. {
  146. for (i = 0;i < MAX_FRAMEBLENDS;i++)
  147. {
  148. if (blend[i].lerp <= 0 || blend[i].subframe == sub2)
  149. {
  150. blend[i].subframe = sub2;
  151. blend[i].lerp += d;
  152. break;
  153. }
  154. }
  155. }
  156. d = (1 - sublerp) * lerp;
  157. }
  158. }
  159. if (d > 0)
  160. {
  161. for (i = 0;i < MAX_FRAMEBLENDS;i++)
  162. {
  163. if (blend[i].lerp <= 0 || blend[i].subframe == f)
  164. {
  165. blend[i].subframe = f;
  166. blend[i].lerp += d;
  167. break;
  168. }
  169. }
  170. }
  171. }
  172. }
  173. void VM_UpdateEdictSkeleton(prvm_prog_t *prog, prvm_edict_t *ed, const dp_model_t *edmodel, const frameblend_t *frameblend)
  174. {
  175. if (ed->priv.server->skeleton.model != edmodel)
  176. {
  177. VM_RemoveEdictSkeleton(prog, ed);
  178. ed->priv.server->skeleton.model = edmodel;
  179. }
  180. if (!ed->priv.server->skeleton.model || !ed->priv.server->skeleton.model->num_bones)
  181. {
  182. if(ed->priv.server->skeleton.relativetransforms)
  183. Mem_Free(ed->priv.server->skeleton.relativetransforms);
  184. ed->priv.server->skeleton.relativetransforms = NULL;
  185. return;
  186. }
  187. {
  188. int skeletonindex = -1;
  189. skeleton_t *skeleton;
  190. skeletonindex = (int)PRVM_gameedictfloat(ed, skeletonindex) - 1;
  191. if (skeletonindex >= 0 && skeletonindex < MAX_EDICTS && (skeleton = prog->skeletons[skeletonindex]) && skeleton->model->num_bones == ed->priv.server->skeleton.model->num_bones)
  192. {
  193. // custom skeleton controlled by the game (FTE_CSQC_SKELETONOBJECTS)
  194. if (!ed->priv.server->skeleton.relativetransforms)
  195. ed->priv.server->skeleton.relativetransforms = (matrix4x4_t *)Mem_Alloc(prog->progs_mempool, ed->priv.server->skeleton.model->num_bones * sizeof(matrix4x4_t));
  196. memcpy(ed->priv.server->skeleton.relativetransforms, skeleton->relativetransforms, ed->priv.server->skeleton.model->num_bones * sizeof(matrix4x4_t));
  197. }
  198. else
  199. {
  200. if(ed->priv.server->skeleton.relativetransforms)
  201. Mem_Free(ed->priv.server->skeleton.relativetransforms);
  202. ed->priv.server->skeleton.relativetransforms = NULL;
  203. }
  204. }
  205. }
  206. void VM_RemoveEdictSkeleton(prvm_prog_t *prog, prvm_edict_t *ed)
  207. {
  208. if (ed->priv.server->skeleton.relativetransforms)
  209. Mem_Free(ed->priv.server->skeleton.relativetransforms);
  210. memset(&ed->priv.server->skeleton, 0, sizeof(ed->priv.server->skeleton));
  211. }
  212. //============================================================================
  213. //BUILT-IN FUNCTIONS
  214. void VM_VarString(prvm_prog_t *prog, int first, char *out, int outlength)
  215. {
  216. int i;
  217. const char *s;
  218. char *outend;
  219. outend = out + outlength - 1;
  220. for (i = first;i < prog->argc && out < outend;i++)
  221. {
  222. s = PRVM_G_STRING((OFS_PARM0+i*3));
  223. while (out < outend && *s)
  224. *out++ = *s++;
  225. }
  226. *out++ = 0;
  227. }
  228. /*
  229. =================
  230. VM_checkextension
  231. returns true if the extension is supported by the server
  232. checkextension(extensionname)
  233. =================
  234. */
  235. // kind of helper function
  236. static qboolean checkextension(prvm_prog_t *prog, const char *name)
  237. {
  238. int len;
  239. const char *e, *start;
  240. len = (int)strlen(name);
  241. for (e = prog->extensionstring;*e;e++)
  242. {
  243. while (*e == ' ')
  244. e++;
  245. if (!*e)
  246. break;
  247. start = e;
  248. while (*e && *e != ' ')
  249. e++;
  250. if ((e - start) == len && !strncasecmp(start, name, len))
  251. {
  252. #ifdef USEODE
  253. // special sheck for ODE
  254. if (!strncasecmp("DP_PHYSICS_ODE", name, 14))
  255. {
  256. #ifndef LINK_TO_LIBODE
  257. return ode_dll ? true : false;
  258. #else
  259. #ifdef LINK_TO_LIBODE
  260. return true;
  261. #else
  262. return false;
  263. #endif
  264. #endif
  265. }
  266. #endif
  267. // special sheck for d0_blind_id
  268. if (!strcasecmp("DP_CRYPTO", name))
  269. return Crypto_Available();
  270. if (!strcasecmp("DP_QC_DIGEST_SHA256", name))
  271. return Crypto_Available();
  272. return true;
  273. }
  274. }
  275. return false;
  276. }
  277. void VM_checkextension(prvm_prog_t *prog)
  278. {
  279. VM_SAFEPARMCOUNT(1,VM_checkextension);
  280. PRVM_G_FLOAT(OFS_RETURN) = checkextension(prog, PRVM_G_STRING(OFS_PARM0));
  281. }
  282. /*
  283. =================
  284. VM_error
  285. This is a TERMINAL error, which will kill off the entire prog.
  286. Dumps self.
  287. error(value)
  288. =================
  289. */
  290. void VM_error(prvm_prog_t *prog)
  291. {
  292. prvm_edict_t *ed;
  293. char string[VM_STRINGTEMP_LENGTH];
  294. VM_VarString(prog, 0, string, sizeof(string));
  295. Con_Printf("======%s ERROR in %s:\n%s\n", prog->name, PRVM_GetString(prog, prog->xfunction->s_name), string);
  296. ed = PRVM_PROG_TO_EDICT(PRVM_allglobaledict(self));
  297. PRVM_ED_Print(prog, ed, NULL);
  298. prog->error_cmd("%s: Program error in function %s:\n%s\nTip: read above for entity information\n", prog->name, PRVM_GetString(prog, prog->xfunction->s_name), string);
  299. }
  300. /*
  301. =================
  302. VM_objerror
  303. Dumps out self, then an error message. The program is aborted and self is
  304. removed, but the level can continue.
  305. objerror(value)
  306. =================
  307. */
  308. void VM_objerror(prvm_prog_t *prog)
  309. {
  310. prvm_edict_t *ed;
  311. char string[VM_STRINGTEMP_LENGTH];
  312. VM_VarString(prog, 0, string, sizeof(string));
  313. Con_Printf("======OBJECT ERROR======\n"); // , prog->name, PRVM_GetString(prog->xfunction->s_name), string); // or include them? FIXME
  314. ed = PRVM_PROG_TO_EDICT(PRVM_allglobaledict(self));
  315. PRVM_ED_Print(prog, ed, NULL);
  316. PRVM_ED_Free (prog, ed);
  317. Con_Printf("%s OBJECT ERROR in %s:\n%s\nTip: read above for entity information\n", prog->name, PRVM_GetString(prog, prog->xfunction->s_name), string);
  318. }
  319. /*
  320. =================
  321. VM_print
  322. print to console
  323. print(...[string])
  324. =================
  325. */
  326. void VM_print(prvm_prog_t *prog)
  327. {
  328. char string[VM_STRINGTEMP_LENGTH];
  329. VM_VarString(prog, 0, string, sizeof(string));
  330. Con_Print(string);
  331. }
  332. /*
  333. =================
  334. VM_bprint
  335. broadcast print to everyone on server
  336. bprint(...[string])
  337. =================
  338. */
  339. void VM_bprint(prvm_prog_t *prog)
  340. {
  341. char string[VM_STRINGTEMP_LENGTH];
  342. if(!sv.active)
  343. {
  344. VM_Warning(prog, "VM_bprint: game is not server(%s) !\n", prog->name);
  345. return;
  346. }
  347. VM_VarString(prog, 0, string, sizeof(string));
  348. SV_BroadcastPrint(string);
  349. }
  350. /*
  351. =================
  352. VM_sprint (menu & client but only if server.active == true)
  353. single print to a specific client
  354. sprint(float clientnum,...[string])
  355. =================
  356. */
  357. void VM_sprint(prvm_prog_t *prog)
  358. {
  359. client_t *client;
  360. int clientnum;
  361. char string[VM_STRINGTEMP_LENGTH];
  362. VM_SAFEPARMCOUNTRANGE(1, 8, VM_sprint);
  363. //find client for this entity
  364. clientnum = (int)PRVM_G_FLOAT(OFS_PARM0);
  365. if (!sv.active || clientnum < 0 || clientnum >= svs.maxclients || !svs.clients[clientnum].active)
  366. {
  367. VM_Warning(prog, "VM_sprint: %s: invalid client or server is not active !\n", prog->name);
  368. return;
  369. }
  370. client = svs.clients + clientnum;
  371. if (!client->netconnection)
  372. return;
  373. VM_VarString(prog, 1, string, sizeof(string));
  374. MSG_WriteChar(&client->netconnection->message,svc_print);
  375. MSG_WriteString(&client->netconnection->message, string);
  376. }
  377. /*
  378. =================
  379. VM_centerprint
  380. single print to the screen
  381. centerprint(value)
  382. =================
  383. */
  384. void VM_centerprint(prvm_prog_t *prog)
  385. {
  386. char string[VM_STRINGTEMP_LENGTH];
  387. VM_SAFEPARMCOUNTRANGE(1, 8, VM_centerprint);
  388. VM_VarString(prog, 0, string, sizeof(string));
  389. SCR_CenterPrint(string);
  390. }
  391. /*
  392. =================
  393. VM_normalize
  394. vector normalize(vector)
  395. =================
  396. */
  397. void VM_normalize(prvm_prog_t *prog)
  398. {
  399. prvm_vec_t *value1;
  400. vec3_t newvalue;
  401. double f;
  402. VM_SAFEPARMCOUNT(1,VM_normalize);
  403. value1 = PRVM_G_VECTOR(OFS_PARM0);
  404. f = VectorLength2(value1);
  405. if (f)
  406. {
  407. f = 1.0 / sqrt(f);
  408. VectorScale(value1, f, newvalue);
  409. }
  410. else
  411. VectorClear(newvalue);
  412. VectorCopy (newvalue, PRVM_G_VECTOR(OFS_RETURN));
  413. }
  414. /*
  415. =================
  416. VM_vlen
  417. scalar vlen(vector)
  418. =================
  419. */
  420. void VM_vlen(prvm_prog_t *prog)
  421. {
  422. VM_SAFEPARMCOUNT(1,VM_vlen);
  423. PRVM_G_FLOAT(OFS_RETURN) = VectorLength(PRVM_G_VECTOR(OFS_PARM0));
  424. }
  425. /*
  426. =================
  427. VM_vectoyaw
  428. float vectoyaw(vector)
  429. =================
  430. */
  431. void VM_vectoyaw(prvm_prog_t *prog)
  432. {
  433. prvm_vec_t *value1;
  434. prvm_vec_t yaw;
  435. VM_SAFEPARMCOUNT(1,VM_vectoyaw);
  436. value1 = PRVM_G_VECTOR(OFS_PARM0);
  437. if (value1[1] == 0 && value1[0] == 0)
  438. yaw = 0;
  439. else
  440. {
  441. yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
  442. if (yaw < 0)
  443. yaw += 360;
  444. }
  445. PRVM_G_FLOAT(OFS_RETURN) = yaw;
  446. }
  447. /*
  448. =================
  449. VM_vectoangles
  450. vector vectoangles(vector[, vector])
  451. =================
  452. */
  453. void VM_vectoangles(prvm_prog_t *prog)
  454. {
  455. vec3_t result, forward, up;
  456. VM_SAFEPARMCOUNTRANGE(1, 2,VM_vectoangles);
  457. VectorCopy(PRVM_G_VECTOR(OFS_PARM0), forward);
  458. if (prog->argc >= 2)
  459. {
  460. VectorCopy(PRVM_G_VECTOR(OFS_PARM1), up);
  461. AnglesFromVectors(result, forward, up, true);
  462. }
  463. else
  464. AnglesFromVectors(result, forward, NULL, true);
  465. VectorCopy(result, PRVM_G_VECTOR(OFS_RETURN));
  466. }
  467. /*
  468. =================
  469. VM_random
  470. Returns a number from 0<= num < 1
  471. float random()
  472. =================
  473. */
  474. void VM_random(prvm_prog_t *prog)
  475. {
  476. VM_SAFEPARMCOUNT(0,VM_random);
  477. PRVM_G_FLOAT(OFS_RETURN) = lhrandom(0, 1);
  478. }
  479. /*
  480. =========
  481. VM_localsound
  482. localsound(string sample)
  483. =========
  484. */
  485. void VM_localsound(prvm_prog_t *prog)
  486. {
  487. const char *s;
  488. VM_SAFEPARMCOUNT(1,VM_localsound);
  489. s = PRVM_G_STRING(OFS_PARM0);
  490. if(!S_LocalSound (s))
  491. {
  492. PRVM_G_FLOAT(OFS_RETURN) = -4;
  493. VM_Warning(prog, "VM_localsound: Failed to play %s for %s !\n", s, prog->name);
  494. return;
  495. }
  496. PRVM_G_FLOAT(OFS_RETURN) = 1;
  497. }
  498. /*
  499. =================
  500. VM_break
  501. break()
  502. =================
  503. */
  504. void VM_break(prvm_prog_t *prog)
  505. {
  506. prog->error_cmd("%s: break statement", prog->name);
  507. }
  508. //============================================================================
  509. /*
  510. =================
  511. VM_localcmd
  512. Sends text over to the client's execution buffer
  513. [localcmd (string, ...) or]
  514. cmd (string, ...)
  515. =================
  516. */
  517. void VM_localcmd(prvm_prog_t *prog)
  518. {
  519. char string[VM_STRINGTEMP_LENGTH];
  520. VM_SAFEPARMCOUNTRANGE(1, 8, VM_localcmd);
  521. VM_VarString(prog, 0, string, sizeof(string));
  522. Cbuf_AddText(string);
  523. }
  524. static qboolean PRVM_Cvar_ReadOk(const char *string)
  525. {
  526. cvar_t *cvar;
  527. cvar = Cvar_FindVar(string);
  528. return ((cvar) && ((cvar->flags & CVAR_PRIVATE) == 0));
  529. }
  530. /*
  531. =================
  532. VM_cvar
  533. float cvar (string)
  534. =================
  535. */
  536. void VM_cvar(prvm_prog_t *prog)
  537. {
  538. char string[VM_STRINGTEMP_LENGTH];
  539. VM_SAFEPARMCOUNTRANGE(1,8,VM_cvar);
  540. VM_VarString(prog, 0, string, sizeof(string));
  541. VM_CheckEmptyString(prog, string);
  542. PRVM_G_FLOAT(OFS_RETURN) = PRVM_Cvar_ReadOk(string) ? Cvar_VariableValue(string) : 0;
  543. }
  544. /*
  545. =================
  546. VM_cvar
  547. float cvar_type (string)
  548. float CVAR_TYPEFLAG_EXISTS = 1;
  549. float CVAR_TYPEFLAG_SAVED = 2;
  550. float CVAR_TYPEFLAG_PRIVATE = 4;
  551. float CVAR_TYPEFLAG_ENGINE = 8;
  552. float CVAR_TYPEFLAG_HASDESCRIPTION = 16;
  553. float CVAR_TYPEFLAG_READONLY = 32;
  554. =================
  555. */
  556. void VM_cvar_type(prvm_prog_t *prog)
  557. {
  558. char string[VM_STRINGTEMP_LENGTH];
  559. cvar_t *cvar;
  560. int ret;
  561. VM_SAFEPARMCOUNTRANGE(1,8,VM_cvar);
  562. VM_VarString(prog, 0, string, sizeof(string));
  563. VM_CheckEmptyString(prog, string);
  564. cvar = Cvar_FindVar(string);
  565. if(!cvar)
  566. {
  567. PRVM_G_FLOAT(OFS_RETURN) = 0;
  568. return; // CVAR_TYPE_NONE
  569. }
  570. ret = 1; // CVAR_EXISTS
  571. if(cvar->flags & CVAR_SAVE)
  572. ret |= 2; // CVAR_TYPE_SAVED
  573. if(cvar->flags & CVAR_PRIVATE)
  574. ret |= 4; // CVAR_TYPE_PRIVATE
  575. if(!(cvar->flags & CVAR_ALLOCATED))
  576. ret |= 8; // CVAR_TYPE_ENGINE
  577. if(cvar->description != cvar_dummy_description)
  578. ret |= 16; // CVAR_TYPE_HASDESCRIPTION
  579. if(cvar->flags & CVAR_READONLY)
  580. ret |= 32; // CVAR_TYPE_READONLY
  581. PRVM_G_FLOAT(OFS_RETURN) = ret;
  582. }
  583. /*
  584. =================
  585. VM_cvar_string
  586. const string VM_cvar_string (string, ...)
  587. =================
  588. */
  589. void VM_cvar_string(prvm_prog_t *prog)
  590. {
  591. char string[VM_STRINGTEMP_LENGTH];
  592. VM_SAFEPARMCOUNTRANGE(1,8,VM_cvar_string);
  593. VM_VarString(prog, 0, string, sizeof(string));
  594. VM_CheckEmptyString(prog, string);
  595. PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, PRVM_Cvar_ReadOk(string) ? Cvar_VariableString(string) : "");
  596. }
  597. /*
  598. ========================
  599. VM_cvar_defstring
  600. const string VM_cvar_defstring (string, ...)
  601. ========================
  602. */
  603. void VM_cvar_defstring(prvm_prog_t *prog)
  604. {
  605. char string[VM_STRINGTEMP_LENGTH];
  606. VM_SAFEPARMCOUNTRANGE(1,8,VM_cvar_defstring);
  607. VM_VarString(prog, 0, string, sizeof(string));
  608. VM_CheckEmptyString(prog, string);
  609. PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, Cvar_VariableDefString(string));
  610. }
  611. /*
  612. ========================
  613. VM_cvar_defstring
  614. const string VM_cvar_description (string, ...)
  615. ========================
  616. */
  617. void VM_cvar_description(prvm_prog_t *prog)
  618. {
  619. char string[VM_STRINGTEMP_LENGTH];
  620. VM_SAFEPARMCOUNTRANGE(1,8,VM_cvar_description);
  621. VM_VarString(prog, 0, string, sizeof(string));
  622. VM_CheckEmptyString(prog, string);
  623. PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, Cvar_VariableDescription(string));
  624. }
  625. /*
  626. =================
  627. VM_cvar_set
  628. void cvar_set (string,string, ...)
  629. =================
  630. */
  631. void VM_cvar_set(prvm_prog_t *prog)
  632. {
  633. const char *name;
  634. char string[VM_STRINGTEMP_LENGTH];
  635. VM_SAFEPARMCOUNTRANGE(2,8,VM_cvar_set);
  636. VM_VarString(prog, 1, string, sizeof(string));
  637. name = PRVM_G_STRING(OFS_PARM0);
  638. VM_CheckEmptyString(prog, name);
  639. Cvar_Set(name, string);
  640. }
  641. /*
  642. =========
  643. VM_dprint
  644. dprint(...[string])
  645. =========
  646. */
  647. void VM_dprint(prvm_prog_t *prog)
  648. {
  649. char string[VM_STRINGTEMP_LENGTH];
  650. VM_SAFEPARMCOUNTRANGE(1, 8, VM_dprint);
  651. VM_VarString(prog, 0, string, sizeof(string));
  652. #if 1
  653. Con_DPrintf("%s", string);
  654. #else
  655. Con_DPrintf("%s: %s", prog->name, string);
  656. #endif
  657. }
  658. /*
  659. =========
  660. VM_ftos
  661. string ftos(float)
  662. =========
  663. */
  664. void VM_ftos(prvm_prog_t *prog)
  665. {
  666. prvm_vec_t v;
  667. char s[128];
  668. VM_SAFEPARMCOUNT(1, VM_ftos);
  669. v = PRVM_G_FLOAT(OFS_PARM0);
  670. if ((prvm_vec_t)((prvm_int_t)v) == v)
  671. dpsnprintf(s, sizeof(s), "%.0f", v);
  672. else
  673. dpsnprintf(s, sizeof(s), "%f", v);
  674. PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, s);
  675. }
  676. /*
  677. =========
  678. VM_fabs
  679. float fabs(float)
  680. =========
  681. */
  682. void VM_fabs(prvm_prog_t *prog)
  683. {
  684. prvm_vec_t v;
  685. VM_SAFEPARMCOUNT(1,VM_fabs);
  686. v = PRVM_G_FLOAT(OFS_PARM0);
  687. PRVM_G_FLOAT(OFS_RETURN) = fabs(v);
  688. }
  689. /*
  690. =========
  691. VM_vtos
  692. string vtos(vector)
  693. =========
  694. */
  695. void VM_vtos(prvm_prog_t *prog)
  696. {
  697. char s[512];
  698. VM_SAFEPARMCOUNT(1,VM_vtos);
  699. dpsnprintf (s, sizeof(s), "'%5.1f %5.1f %5.1f'", PRVM_G_VECTOR(OFS_PARM0)[0], PRVM_G_VECTOR(OFS_PARM0)[1], PRVM_G_VECTOR(OFS_PARM0)[2]);
  700. PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, s);
  701. }
  702. /*
  703. =========
  704. VM_etos
  705. string etos(entity)
  706. =========
  707. */
  708. void VM_etos(prvm_prog_t *prog)
  709. {
  710. char s[128];
  711. VM_SAFEPARMCOUNT(1, VM_etos);
  712. dpsnprintf (s, sizeof(s), "entity %i", PRVM_G_EDICTNUM(OFS_PARM0));
  713. PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, s);
  714. }
  715. /*
  716. =========
  717. VM_stof
  718. float stof(...[string])
  719. =========
  720. */
  721. void VM_stof(prvm_prog_t *prog)
  722. {
  723. char string[VM_STRINGTEMP_LENGTH];
  724. VM_SAFEPARMCOUNTRANGE(1, 8, VM_stof);
  725. VM_VarString(prog, 0, string, sizeof(string));
  726. PRVM_G_FLOAT(OFS_RETURN) = atof(string);
  727. }
  728. /*
  729. ========================
  730. VM_itof
  731. float itof(int ent)
  732. ========================
  733. */
  734. void VM_itof(prvm_prog_t *prog)
  735. {
  736. VM_SAFEPARMCOUNT(1, VM_itof);
  737. PRVM_G_FLOAT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
  738. }
  739. /*
  740. ========================
  741. VM_ftoe
  742. entity ftoe(float num)
  743. ========================
  744. */
  745. void VM_ftoe(prvm_prog_t *prog)
  746. {
  747. prvm_int_t ent;
  748. VM_SAFEPARMCOUNT(1, VM_ftoe);
  749. ent = (prvm_int_t)PRVM_G_FLOAT(OFS_PARM0);
  750. if (ent < 0 || ent >= prog->max_edicts || PRVM_PROG_TO_EDICT(ent)->priv.required->free)
  751. ent = 0; // return world instead of a free or invalid entity
  752. PRVM_G_INT(OFS_RETURN) = ent;
  753. }
  754. /*
  755. ========================
  756. VM_etof
  757. float etof(entity ent)
  758. ========================
  759. */
  760. void VM_etof(prvm_prog_t *prog)
  761. {
  762. VM_SAFEPARMCOUNT(1, VM_etof);
  763. PRVM_G_FLOAT(OFS_RETURN) = PRVM_G_EDICTNUM(OFS_PARM0);
  764. }
  765. /*
  766. =========
  767. VM_strftime
  768. string strftime(float uselocaltime, string[, string ...])
  769. =========
  770. */
  771. void VM_strftime(prvm_prog_t *prog)
  772. {
  773. time_t t;
  774. #if _MSC_VER >= 1400
  775. struct tm tm;
  776. int tmresult;
  777. #else
  778. struct tm *tm;
  779. #endif
  780. char fmt[VM_STRINGTEMP_LENGTH];
  781. char result[VM_STRINGTEMP_LENGTH];
  782. VM_SAFEPARMCOUNTRANGE(2, 8, VM_strftime);
  783. VM_VarString(prog, 1, fmt, sizeof(fmt));
  784. t = time(NULL);
  785. #if _MSC_VER >= 1400
  786. if (PRVM_G_FLOAT(OFS_PARM0))
  787. tmresult = localtime_s(&tm, &t);
  788. else
  789. tmresult = gmtime_s(&tm, &t);
  790. if (!tmresult)
  791. #else
  792. if (PRVM_G_FLOAT(OFS_PARM0))
  793. tm = localtime(&t);
  794. else
  795. tm = gmtime(&t);
  796. if (!tm)
  797. #endif
  798. {
  799. PRVM_G_INT(OFS_RETURN) = 0;
  800. return;
  801. }
  802. #if _MSC_VER >= 1400
  803. strftime(result, sizeof(result), fmt, &tm);
  804. #else
  805. strftime(result, sizeof(result), fmt, tm);
  806. #endif
  807. PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, result);
  808. }
  809. /*
  810. =========
  811. VM_spawn
  812. entity spawn()
  813. =========
  814. */
  815. void VM_spawn(prvm_prog_t *prog)
  816. {
  817. prvm_edict_t *ed;
  818. VM_SAFEPARMCOUNT(0, VM_spawn);
  819. prog->xfunction->builtinsprofile += 20;
  820. ed = PRVM_ED_Alloc(prog);
  821. VM_RETURN_EDICT(ed);
  822. }
  823. /*
  824. =========
  825. VM_remove
  826. remove(entity e)
  827. =========
  828. */
  829. void VM_remove(prvm_prog_t *prog)
  830. {
  831. prvm_edict_t *ed;
  832. prog->xfunction->builtinsprofile += 20;
  833. VM_SAFEPARMCOUNT(1, VM_remove);
  834. ed = PRVM_G_EDICT(OFS_PARM0);
  835. if( PRVM_NUM_FOR_EDICT(ed) <= prog->reserved_edicts )
  836. {
  837. if (developer.integer > 0)
  838. VM_Warning(prog, "VM_remove: tried to remove the null entity or a reserved entity!\n" );
  839. }
  840. else if( ed->priv.required->free )
  841. {
  842. if (developer.integer > 0)
  843. VM_Warning(prog, "VM_remove: tried to remove an already freed entity!\n" );
  844. }
  845. else
  846. PRVM_ED_Free (prog, ed);
  847. }
  848. /*
  849. =========
  850. VM_find
  851. entity find(entity start, .string field, string match)
  852. =========
  853. */
  854. void VM_find(prvm_prog_t *prog)
  855. {
  856. int e;
  857. int f;
  858. const char *s, *t;
  859. prvm_edict_t *ed;
  860. VM_SAFEPARMCOUNT(3,VM_find);
  861. e = PRVM_G_EDICTNUM(OFS_PARM0);
  862. f = PRVM_G_INT(OFS_PARM1);
  863. s = PRVM_G_STRING(OFS_PARM2);
  864. // LordHavoc: apparently BloodMage does a find(world, weaponmodel, "") and
  865. // expects it to find all the monsters, so we must be careful to support
  866. // searching for ""
  867. for (e++ ; e < prog->num_edicts ; e++)
  868. {
  869. prog->xfunction->builtinsprofile++;
  870. ed = PRVM_EDICT_NUM(e);
  871. if (ed->priv.required->free)
  872. continue;
  873. t = PRVM_E_STRING(ed,f);
  874. if (!t)
  875. t = "";
  876. if (!strcmp(t,s))
  877. {
  878. VM_RETURN_EDICT(ed);
  879. return;
  880. }
  881. }
  882. VM_RETURN_EDICT(prog->edicts);
  883. }
  884. /*
  885. =========
  886. VM_findfloat
  887. entity findfloat(entity start, .float field, float match)
  888. entity findentity(entity start, .entity field, entity match)
  889. =========
  890. */
  891. // LordHavoc: added this for searching float, int, and entity reference fields
  892. void VM_findfloat(prvm_prog_t *prog)
  893. {
  894. int e;
  895. int f;
  896. float s;
  897. prvm_edict_t *ed;
  898. VM_SAFEPARMCOUNT(3,VM_findfloat);
  899. e = PRVM_G_EDICTNUM(OFS_PARM0);
  900. f = PRVM_G_INT(OFS_PARM1);
  901. s = PRVM_G_FLOAT(OFS_PARM2);
  902. for (e++ ; e < prog->num_edicts ; e++)
  903. {
  904. prog->xfunction->builtinsprofile++;
  905. ed = PRVM_EDICT_NUM(e);
  906. if (ed->priv.required->free)
  907. continue;
  908. if (PRVM_E_FLOAT(ed,f) == s)
  909. {
  910. VM_RETURN_EDICT(ed);
  911. return;
  912. }
  913. }
  914. VM_RETURN_EDICT(prog->edicts);
  915. }
  916. /*
  917. =========
  918. VM_findchain
  919. entity findchain(.string field, string match)
  920. =========
  921. */
  922. // chained search for strings in entity fields
  923. // entity(.string field, string match) findchain = #402;
  924. void VM_findchain(prvm_prog_t *prog)
  925. {
  926. int i;
  927. int f;
  928. const char *s, *t;
  929. prvm_edict_t *ent, *chain;
  930. int chainfield;
  931. VM_SAFEPARMCOUNTRANGE(2,3,VM_findchain);
  932. if(prog->argc == 3)
  933. chainfield = PRVM_G_INT(OFS_PARM2);
  934. else
  935. chainfield = prog->fieldoffsets.chain;
  936. if (chainfield < 0)
  937. prog->error_cmd("VM_findchain: %s doesnt have the specified chain field !", prog->name);
  938. chain = prog->edicts;
  939. f = PRVM_G_INT(OFS_PARM0);
  940. s = PRVM_G_STRING(OFS_PARM1);
  941. // LordHavoc: apparently BloodMage does a find(world, weaponmodel, "") and
  942. // expects it to find all the monsters, so we must be careful to support
  943. // searching for ""
  944. ent = PRVM_NEXT_EDICT(prog->edicts);
  945. for (i = 1;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
  946. {
  947. prog->xfunction->builtinsprofile++;
  948. if (ent->priv.required->free)
  949. continue;
  950. t = PRVM_E_STRING(ent,f);
  951. if (!t)
  952. t = "";
  953. if (strcmp(t,s))
  954. continue;
  955. PRVM_EDICTFIELDEDICT(ent,chainfield) = PRVM_NUM_FOR_EDICT(chain);
  956. chain = ent;
  957. }
  958. VM_RETURN_EDICT(chain);
  959. }
  960. /*
  961. =========
  962. VM_findchainfloat
  963. entity findchainfloat(.string field, float match)
  964. entity findchainentity(.string field, entity match)
  965. =========
  966. */
  967. // LordHavoc: chained search for float, int, and entity reference fields
  968. // entity(.string field, float match) findchainfloat = #403;
  969. void VM_findchainfloat(prvm_prog_t *prog)
  970. {
  971. int i;
  972. int f;
  973. float s;
  974. prvm_edict_t *ent, *chain;
  975. int chainfield;
  976. VM_SAFEPARMCOUNTRANGE(2, 3, VM_findchainfloat);
  977. if(prog->argc == 3)
  978. chainfield = PRVM_G_INT(OFS_PARM2);
  979. else
  980. chainfield = prog->fieldoffsets.chain;
  981. if (chainfield < 0)
  982. prog->error_cmd("VM_findchain: %s doesnt have the specified chain field !", prog->name);
  983. chain = (prvm_edict_t *)prog->edicts;
  984. f = PRVM_G_INT(OFS_PARM0);
  985. s = PRVM_G_FLOAT(OFS_PARM1);
  986. ent = PRVM_NEXT_EDICT(prog->edicts);
  987. for (i = 1;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
  988. {
  989. prog->xfunction->builtinsprofile++;
  990. if (ent->priv.required->free)
  991. continue;
  992. if (PRVM_E_FLOAT(ent,f) != s)
  993. continue;
  994. PRVM_EDICTFIELDEDICT(ent,chainfield) = PRVM_EDICT_TO_PROG(chain);
  995. chain = ent;
  996. }
  997. VM_RETURN_EDICT(chain);
  998. }
  999. /*
  1000. ========================
  1001. VM_findflags
  1002. entity findflags(entity start, .float field, float match)
  1003. ========================
  1004. */
  1005. // LordHavoc: search for flags in float fields
  1006. void VM_findflags(prvm_prog_t *prog)
  1007. {
  1008. prvm_int_t e;
  1009. prvm_int_t f;
  1010. prvm_int_t s;
  1011. prvm_edict_t *ed;
  1012. VM_SAFEPARMCOUNT(3, VM_findflags);
  1013. e = PRVM_G_EDICTNUM(OFS_PARM0);
  1014. f = PRVM_G_INT(OFS_PARM1);
  1015. s = (prvm_int_t)PRVM_G_FLOAT(OFS_PARM2);
  1016. for (e++ ; e < prog->num_edicts ; e++)
  1017. {
  1018. prog->xfunction->builtinsprofile++;
  1019. ed = PRVM_EDICT_NUM(e);
  1020. if (ed->priv.required->free)
  1021. continue;
  1022. if (!PRVM_E_FLOAT(ed,f))
  1023. continue;
  1024. if ((prvm_int_t)PRVM_E_FLOAT(ed,f) & s)
  1025. {
  1026. VM_RETURN_EDICT(ed);
  1027. return;
  1028. }
  1029. }
  1030. VM_RETURN_EDICT(prog->edicts);
  1031. }
  1032. /*
  1033. ========================
  1034. VM_findchainflags
  1035. entity findchainflags(.float field, float match)
  1036. ========================
  1037. */
  1038. // LordHavoc: chained search for flags in float fields
  1039. void VM_findchainflags(prvm_prog_t *prog)
  1040. {
  1041. prvm_int_t i;
  1042. prvm_int_t f;
  1043. prvm_int_t s;
  1044. prvm_edict_t *ent, *chain;
  1045. int chainfield;
  1046. VM_SAFEPARMCOUNTRANGE(2, 3, VM_findchainflags);
  1047. if(prog->argc == 3)
  1048. chainfield = PRVM_G_INT(OFS_PARM2);
  1049. else
  1050. chainfield = prog->fieldoffsets.chain;
  1051. if (chainfield < 0)
  1052. prog->error_cmd("VM_findchain: %s doesnt have the specified chain field !", prog->name);
  1053. chain = (prvm_edict_t *)prog->edicts;
  1054. f = PRVM_G_INT(OFS_PARM0);
  1055. s = (prvm_int_t)PRVM_G_FLOAT(OFS_PARM1);
  1056. ent = PRVM_NEXT_EDICT(prog->edicts);
  1057. for (i = 1;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
  1058. {
  1059. prog->xfunction->builtinsprofile++;
  1060. if (ent->priv.required->free)
  1061. continue;
  1062. if (!PRVM_E_FLOAT(ent,f))
  1063. continue;
  1064. if (!((prvm_int_t)PRVM_E_FLOAT(ent,f) & s))
  1065. continue;
  1066. PRVM_EDICTFIELDEDICT(ent,chainfield) = PRVM_EDICT_TO_PROG(chain);
  1067. chain = ent;
  1068. }
  1069. VM_RETURN_EDICT(chain);
  1070. }
  1071. /*
  1072. =========
  1073. VM_precache_sound
  1074. string precache_sound (string sample)
  1075. =========
  1076. */
  1077. void VM_precache_sound(prvm_prog_t *prog)
  1078. {
  1079. const char *s;
  1080. VM_SAFEPARMCOUNT(1, VM_precache_sound);
  1081. s = PRVM_G_STRING(OFS_PARM0);
  1082. PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
  1083. //VM_CheckEmptyString(prog, s);
  1084. if(snd_initialized.integer && !S_PrecacheSound(s, true, true))
  1085. {
  1086. VM_Warning(prog, "VM_precache_sound: Failed to load %s for %s\n", s, prog->name);
  1087. return;
  1088. }
  1089. }
  1090. /*
  1091. =================
  1092. VM_precache_file
  1093. returns the same string as output
  1094. does nothing, only used by qcc to build .pak archives
  1095. =================
  1096. */
  1097. void VM_precache_file(prvm_prog_t *prog)
  1098. {
  1099. VM_SAFEPARMCOUNT(1,VM_precache_file);
  1100. // precache_file is only used to copy files with qcc, it does nothing
  1101. PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
  1102. }
  1103. /*
  1104. =========
  1105. VM_coredump
  1106. coredump()
  1107. =========
  1108. */
  1109. void VM_coredump(prvm_prog_t *prog)
  1110. {
  1111. VM_SAFEPARMCOUNT(0,VM_coredump);
  1112. Cbuf_AddText("prvm_edicts ");
  1113. Cbuf_AddText(prog->name);
  1114. Cbuf_AddText("\n");
  1115. }
  1116. /*
  1117. =========
  1118. VM_stackdump
  1119. stackdump()
  1120. =========
  1121. */
  1122. void VM_stackdump(prvm_prog_t *prog)
  1123. {
  1124. VM_SAFEPARMCOUNT(0, VM_stackdump);
  1125. PRVM_StackTrace(prog);
  1126. }
  1127. /*
  1128. =========
  1129. VM_crash
  1130. crash()
  1131. =========
  1132. */
  1133. void VM_crash(prvm_prog_t *prog)
  1134. {
  1135. VM_SAFEPARMCOUNT(0, VM_crash);
  1136. prog->error_cmd("Crash called by %s",prog->name);
  1137. }
  1138. /*
  1139. =========
  1140. VM_traceon
  1141. traceon()
  1142. =========
  1143. */
  1144. void VM_traceon(prvm_prog_t *prog)
  1145. {
  1146. VM_SAFEPARMCOUNT(0,VM_traceon);
  1147. prog->trace = true;
  1148. }
  1149. /*
  1150. =========
  1151. VM_traceoff
  1152. traceoff()
  1153. =========
  1154. */
  1155. void VM_traceoff(prvm_prog_t *prog)
  1156. {
  1157. VM_SAFEPARMCOUNT(0,VM_traceoff);
  1158. prog->trace = false;
  1159. }
  1160. /*
  1161. =========
  1162. VM_eprint
  1163. eprint(entity e)
  1164. =========
  1165. */
  1166. void VM_eprint(prvm_prog_t *prog)
  1167. {
  1168. VM_SAFEPARMCOUNT(1,VM_eprint);
  1169. PRVM_ED_PrintNum (prog, PRVM_G_EDICTNUM(OFS_PARM0), NULL);
  1170. }
  1171. /*
  1172. =========
  1173. VM_rint
  1174. float rint(float)
  1175. =========
  1176. */
  1177. void VM_rint(prvm_prog_t *prog)
  1178. {
  1179. prvm_vec_t f;
  1180. VM_SAFEPARMCOUNT(1,VM_rint);
  1181. f = PRVM_G_FLOAT(OFS_PARM0);
  1182. if (f > 0)
  1183. PRVM_G_FLOAT(OFS_RETURN) = floor(f + 0.5);
  1184. else
  1185. PRVM_G_FLOAT(OFS_RETURN) = ceil(f - 0.5);
  1186. }
  1187. /*
  1188. =========
  1189. VM_floor
  1190. float floor(float)
  1191. =========
  1192. */
  1193. void VM_floor(prvm_prog_t *prog)
  1194. {
  1195. VM_SAFEPARMCOUNT(1,VM_floor);
  1196. PRVM_G_FLOAT(OFS_RETURN) = floor(PRVM_G_FLOAT(OFS_PARM0));
  1197. }
  1198. /*
  1199. =========
  1200. VM_ceil
  1201. float ceil(float)
  1202. =========
  1203. */
  1204. void VM_ceil(prvm_prog_t *prog)
  1205. {
  1206. VM_SAFEPARMCOUNT(1,VM_ceil);
  1207. PRVM_G_FLOAT(OFS_RETURN) = ceil(PRVM_G_FLOAT(OFS_PARM0));
  1208. }
  1209. /*
  1210. =============
  1211. VM_nextent
  1212. entity nextent(entity)
  1213. =============
  1214. */
  1215. void VM_nextent(prvm_prog_t *prog)
  1216. {
  1217. int i;
  1218. prvm_edict_t *ent;
  1219. VM_SAFEPARMCOUNT(1, VM_nextent);
  1220. i = PRVM_G_EDICTNUM(OFS_PARM0);
  1221. while (1)
  1222. {
  1223. prog->xfunction->builtinsprofile++;
  1224. i++;
  1225. if (i == prog->num_edicts)
  1226. {
  1227. VM_RETURN_EDICT(prog->edicts);
  1228. return;
  1229. }
  1230. ent = PRVM_EDICT_NUM(i);
  1231. if (!ent->priv.required->free)
  1232. {
  1233. VM_RETURN_EDICT(ent);
  1234. return;
  1235. }
  1236. }
  1237. }
  1238. //=============================================================================
  1239. /*
  1240. ==============
  1241. VM_changelevel
  1242. server and menu
  1243. changelevel(string map)
  1244. ==============
  1245. */
  1246. void VM_changelevel(prvm_prog_t *prog)
  1247. {
  1248. char vabuf[1024];
  1249. VM_SAFEPARMCOUNT(1, VM_changelevel);
  1250. if(!sv.active)
  1251. {
  1252. VM_Warning(prog, "VM_changelevel: game is not server (%s)\n", prog->name);
  1253. return;
  1254. }
  1255. // make sure we don't issue two changelevels
  1256. if (svs.changelevel_issued)
  1257. return;
  1258. svs.changelevel_issued = true;
  1259. Cbuf_AddText(va(vabuf, sizeof(vabuf), "changelevel %s\n",PRVM_G_STRING(OFS_PARM0)));
  1260. }
  1261. /*
  1262. =========
  1263. VM_sin
  1264. float sin(float)
  1265. =========
  1266. */
  1267. void VM_sin(prvm_prog_t *prog)
  1268. {
  1269. VM_SAFEPARMCOUNT(1,VM_sin);
  1270. PRVM_G_FLOAT(OFS_RETURN) = sin(PRVM_G_FLOAT(OFS_PARM0));
  1271. }
  1272. /*
  1273. =========
  1274. VM_cos
  1275. float cos(float)
  1276. =========
  1277. */
  1278. void VM_cos(prvm_prog_t *prog)
  1279. {
  1280. VM_SAFEPARMCOUNT(1,VM_cos);
  1281. PRVM_G_FLOAT(OFS_RETURN) = cos(PRVM_G_FLOAT(OFS_PARM0));
  1282. }
  1283. /*
  1284. =========
  1285. VM_sqrt
  1286. float sqrt(float)
  1287. =========
  1288. */
  1289. void VM_sqrt(prvm_prog_t *prog)
  1290. {
  1291. VM_SAFEPARMCOUNT(1,VM_sqrt);
  1292. PRVM_G_FLOAT(OFS_RETURN) = sqrt(PRVM_G_FLOAT(OFS_PARM0));
  1293. }
  1294. /*
  1295. =========
  1296. VM_asin
  1297. float asin(float)
  1298. =========
  1299. */
  1300. void VM_asin(prvm_prog_t *prog)
  1301. {
  1302. VM_SAFEPARMCOUNT(1,VM_asin);
  1303. PRVM_G_FLOAT(OFS_RETURN) = asin(PRVM_G_FLOAT(OFS_PARM0));
  1304. }
  1305. /*
  1306. =========
  1307. VM_acos
  1308. float acos(float)
  1309. =========
  1310. */
  1311. void VM_acos(prvm_prog_t *prog)
  1312. {
  1313. VM_SAFEPARMCOUNT(1,VM_acos);
  1314. PRVM_G_FLOAT(OFS_RETURN) = acos(PRVM_G_FLOAT(OFS_PARM0));
  1315. }
  1316. /*
  1317. =========
  1318. VM_atan
  1319. float atan(float)
  1320. =========
  1321. */
  1322. void VM_atan(prvm_prog_t *prog)
  1323. {
  1324. VM_SAFEPARMCOUNT(1,VM_atan);
  1325. PRVM_G_FLOAT(OFS_RETURN) = atan(PRVM_G_FLOAT(OFS_PARM0));
  1326. }
  1327. /*
  1328. =========
  1329. VM_atan2
  1330. float atan2(float,float)
  1331. =========
  1332. */
  1333. void VM_atan2(prvm_prog_t *prog)
  1334. {
  1335. VM_SAFEPARMCOUNT(2,VM_atan2);
  1336. PRVM_G_FLOAT(OFS_RETURN) = atan2(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1));
  1337. }
  1338. /*
  1339. =========
  1340. VM_tan
  1341. float tan(float)
  1342. =========
  1343. */
  1344. void VM_tan(prvm_prog_t *prog)
  1345. {
  1346. VM_SAFEPARMCOUNT(1,VM_tan);
  1347. PRVM_G_FLOAT(OFS_RETURN) = tan(PRVM_G_FLOAT(OFS_PARM0));
  1348. }
  1349. /*
  1350. =================
  1351. VM_randomvec
  1352. Returns a vector of length < 1 and > 0
  1353. vector randomvec()
  1354. =================
  1355. */
  1356. void VM_randomvec(prvm_prog_t *prog)
  1357. {
  1358. vec3_t temp;
  1359. VM_SAFEPARMCOUNT(0, VM_randomvec);
  1360. VectorRandom(temp);
  1361. VectorCopy(temp, PRVM_G_VECTOR(OFS_RETURN));
  1362. }
  1363. //=============================================================================
  1364. /*
  1365. =========
  1366. VM_registercvar
  1367. float registercvar (string name, string value[, float flags])
  1368. =========
  1369. */
  1370. void VM_registercvar(prvm_prog_t *prog)
  1371. {
  1372. const char *name, *value;
  1373. int flags;
  1374. VM_SAFEPARMCOUNTRANGE(2, 3, VM_registercvar);
  1375. name = PRVM_G_STRING(OFS_PARM0);
  1376. value = PRVM_G_STRING(OFS_PARM1);
  1377. flags = prog->argc >= 3 ? (int)PRVM_G_FLOAT(OFS_PARM2) : 0;
  1378. PRVM_G_FLOAT(OFS_RETURN) = 0;
  1379. if(flags > CVAR_MAXFLAGSVAL)
  1380. return;
  1381. // first check to see if it has already been defined
  1382. if (Cvar_FindVar (name))
  1383. return;
  1384. // check for overlap with a command
  1385. if (Cmd_Exists (name))
  1386. {
  1387. VM_Warning(prog, "VM_registercvar: %s is a command\n", name);
  1388. return;
  1389. }
  1390. Cvar_Get(name, value, flags, NULL);
  1391. PRVM_G_FLOAT(OFS_RETURN) = 1; // success
  1392. }
  1393. /*
  1394. =================
  1395. VM_min
  1396. returns the minimum of two supplied floats
  1397. float min(float a, float b, ...[float])
  1398. =================
  1399. */
  1400. void VM_min(prvm_prog_t *prog)
  1401. {
  1402. VM_SAFEPARMCOUNTRANGE(2, 8, VM_min);
  1403. // LordHavoc: 3+ argument enhancement suggested by FrikaC
  1404. if (prog->argc >= 3)
  1405. {
  1406. int i;
  1407. float f = PRVM_G_FLOAT(OFS_PARM0);
  1408. for (i = 1;i < prog->argc;i++)
  1409. if (f > PRVM_G_FLOAT((OFS_PARM0+i*3)))
  1410. f = PRVM_G_FLOAT((OFS_PARM0+i*3));
  1411. PRVM_G_FLOAT(OFS_RETURN) = f;
  1412. }
  1413. else
  1414. PRVM_G_FLOAT(OFS_RETURN) = min(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1));
  1415. }
  1416. /*
  1417. =================
  1418. VM_max
  1419. returns the maximum of two supplied floats
  1420. float max(float a, float b, ...[float])
  1421. =================
  1422. */
  1423. void VM_max(prvm_prog_t *prog)
  1424. {
  1425. VM_SAFEPARMCOUNTRANGE(2, 8, VM_max);
  1426. // LordHavoc: 3+ argument enhancement suggested by FrikaC
  1427. if (prog->argc >= 3)
  1428. {
  1429. int i;
  1430. float f = PRVM_G_FLOAT(OFS_PARM0);
  1431. for (i = 1;i < prog->argc;i++)
  1432. if (f < PRVM_G_FLOAT((OFS_PARM0+i*3)))
  1433. f = PRVM_G_FLOAT((OFS_PARM0+i*3));
  1434. PRVM_G_FLOAT(OFS_RETURN) = f;
  1435. }
  1436. else
  1437. PRVM_G_FLOAT(OFS_RETURN) = max(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1));
  1438. }
  1439. /*
  1440. =================
  1441. VM_bound
  1442. returns number bounded by supplied range
  1443. float bound(float min, float value, float max)
  1444. =================
  1445. */
  1446. void VM_bound(prvm_prog_t *prog)
  1447. {
  1448. VM_SAFEPARMCOUNT(3,VM_bound);
  1449. PRVM_G_FLOAT(OFS_RETURN) = bound(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1), PRVM_G_FLOAT(OFS_PARM2));
  1450. }
  1451. /*
  1452. =================
  1453. VM_pow
  1454. returns a raised to power b
  1455. float pow(float a, float b)
  1456. =================
  1457. */
  1458. void VM_pow(prvm_prog_t *prog)
  1459. {
  1460. VM_SAFEPARMCOUNT(2,VM_pow);
  1461. PRVM_G_FLOAT(OFS_RETURN) = pow(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1));
  1462. }
  1463. void VM_log(prvm_prog_t *prog)
  1464. {
  1465. VM_SAFEPARMCOUNT(1,VM_log);
  1466. PRVM_G_FLOAT(OFS_RETURN) = log(PRVM_G_FLOAT(OFS_PARM0));
  1467. }
  1468. void VM_Files_Init(prvm_prog_t *prog)
  1469. {
  1470. int i;
  1471. for (i = 0;i < PRVM_MAX_OPENFILES;i++)
  1472. prog->openfiles[i] = NULL;
  1473. }
  1474. void VM_Files_CloseAll(prvm_prog_t *prog)
  1475. {
  1476. int i;
  1477. for (i = 0;i < PRVM_MAX_OPENFILES;i++)
  1478. {
  1479. if (prog->openfiles[i])
  1480. FS_Close(prog->openfiles[i]);
  1481. prog->openfiles[i] = NULL;
  1482. }
  1483. }
  1484. static qfile_t *VM_GetFileHandle(prvm_prog_t *prog, int index)
  1485. {
  1486. if (index < 0 || index >= PRVM_MAX_OPENFILES)
  1487. {
  1488. Con_Printf("VM_GetFileHandle: invalid file handle %i used in %s\n", index, prog->name);
  1489. return NULL;
  1490. }
  1491. if (prog->openfiles[index] == NULL)
  1492. {
  1493. Con_Printf("VM_GetFileHandle: no such file handle %i (or file has been closed) in %s\n", index, prog->name);
  1494. return NULL;
  1495. }
  1496. return prog->openfiles[index];
  1497. }
  1498. /*
  1499. =========
  1500. VM_fopen
  1501. float fopen(string filename, float mode)
  1502. =========
  1503. */
  1504. // float(string filename, float mode) fopen = #110;
  1505. // opens a file inside quake/gamedir/data/ (mode is FILE_READ, FILE_APPEND, or FILE_WRITE),
  1506. // returns fhandle >= 0 if successful, or fhandle < 0 if unable to open file for any reason
  1507. void VM_fopen(prvm_prog_t *prog)
  1508. {
  1509. int filenum, mode;
  1510. const char *modestring, *filename;
  1511. char vabuf[1024];
  1512. VM_SAFEPARMCOUNT(2,VM_fopen);
  1513. for (filenum = 0;filenum < PRVM_MAX_OPENFILES;filenum++)
  1514. if (prog->openfiles[filenum] == NULL)
  1515. break;
  1516. if (filenum >= PRVM_MAX_OPENFILES)
  1517. {
  1518. PRVM_G_FLOAT(OFS_RETURN) = -2;
  1519. VM_Warning(prog, "VM_fopen: %s ran out of file handles (%i)\n", prog->name, PRVM_MAX_OPENFILES);
  1520. return;
  1521. }
  1522. filename = PRVM_G_STRING(OFS_PARM0);
  1523. mode = (int)PRVM_G_FLOAT(OFS_PARM1);
  1524. switch(mode)
  1525. {
  1526. case 0: // FILE_READ
  1527. modestring = "rb";
  1528. prog->openfiles[filenum] = FS_OpenVirtualFile(va(vabuf, sizeof(vabuf), "data/%s", filename), false);
  1529. if (prog->openfiles[filenum] == NULL)
  1530. prog->openfiles[filenum] = FS_OpenVirtualFile(va(vabuf, sizeof(vabuf), "%s", filename), false);
  1531. break;
  1532. case 1: // FILE_APPEND
  1533. modestring = "a";
  1534. prog->openfiles[filenum] = FS_OpenRealFile(va(vabuf, sizeof(vabuf), "data/%s", filename), modestring, false);
  1535. break;
  1536. case 2: // FILE_WRITE
  1537. modestring = "w";
  1538. prog->openfiles[filenum] = FS_OpenRealFile(va(vabuf, sizeof(vabuf), "data/%s", filename), modestring, false);
  1539. break;
  1540. default:
  1541. PRVM_G_FLOAT(OFS_RETURN) = -3;
  1542. VM_Warning(prog, "VM_fopen: %s: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", prog->name, mode);
  1543. return;
  1544. }
  1545. if (prog->openfiles[filenum] == NULL)
  1546. {
  1547. PRVM_G_FLOAT(OFS_RETURN) = -1;
  1548. if (developer_extra.integer)
  1549. VM_Warning(prog, "VM_fopen: %s: %s mode %s failed\n", prog->name, filename, modestring);
  1550. }
  1551. else
  1552. {
  1553. PRVM_G_FLOAT(OFS_RETURN) = filenum;
  1554. if (developer_extra.integer)
  1555. Con_DPrintf("VM_fopen: %s: %s mode %s opened as #%i\n", prog->name, filename, modestring, filenum);
  1556. prog->openfiles_origin[filenum] = PRVM_AllocationOrigin(prog);
  1557. }
  1558. }
  1559. /*
  1560. =========
  1561. VM_fclose
  1562. fclose(float fhandle)
  1563. =========
  1564. */
  1565. //void(float fhandle) fclose = #111; // closes a file
  1566. void VM_fclose(prvm_prog_t *prog)
  1567. {
  1568. int filenum;
  1569. VM_SAFEPARMCOUNT(1,VM_fclose);
  1570. filenum = (int)PRVM_G_FLOAT(OFS_PARM0);
  1571. if (filenum < 0 || filenum >= PRVM_MAX_OPENFILES)
  1572. {
  1573. VM_Warning(prog, "VM_fclose: invalid file handle %i used in %s\n", filenum, prog->name);
  1574. return;
  1575. }
  1576. if (prog->openfiles[filenum] == NULL)
  1577. {
  1578. VM_Warning(prog, "VM_fclose: no such file handle %i (or file has been closed) in %s\n", filenum, prog->name);
  1579. return;
  1580. }
  1581. FS_Close(prog->openfiles[filenum]);
  1582. prog->openfiles[filenum] = NULL;
  1583. if(prog->openfiles_origin[filenum])
  1584. PRVM_Free((char *)prog->openfiles_origin[filenum]);
  1585. if (developer_extra.integer)
  1586. Con_DPrintf("VM_fclose: %s: #%i closed\n", prog->name, filenum);
  1587. }
  1588. /*
  1589. =========
  1590. VM_fgets
  1591. string fgets(float fhandle)
  1592. =========
  1593. */
  1594. //string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring
  1595. void VM_fgets(prvm_prog_t *prog)
  1596. {
  1597. int c, end;
  1598. char string[VM_STRINGTEMP_LENGTH];
  1599. int filenum;
  1600. VM_SAFEPARMCOUNT(1,VM_fgets);
  1601. // set the return value regardless of any possible errors
  1602. PRVM_G_INT(OFS_RETURN) = OFS_NULL;
  1603. filenum = (int)PRVM_G_FLOAT(OFS_PARM0);
  1604. if (filenum < 0 || filenum >= PRVM_MAX_OPENFILES)
  1605. {
  1606. VM_Warning(prog, "VM_fgets: invalid file handle %i used in %s\n", filenum, prog->name);
  1607. return;
  1608. }
  1609. if (prog->openfiles[filenum] == NULL)
  1610. {
  1611. VM_Warning(prog, "VM_fgets: no such file handle %i (or file has been closed) in %s\n", filenum, prog->name);
  1612. return;
  1613. }
  1614. end = 0;
  1615. for (;;)
  1616. {
  1617. c = FS_Getc(prog->openfiles[filenum]);
  1618. if (c == '\r' || c == '\n' || c < 0)
  1619. break;
  1620. if (end < VM_STRINGTEMP_LENGTH - 1)
  1621. string[end++] = c;
  1622. }
  1623. string[end] = 0;
  1624. // remove \n following \r
  1625. if (c == '\r')
  1626. {
  1627. c = FS_Getc(prog->openfiles[filenum]);
  1628. if (c != '\n')
  1629. FS_UnGetc(prog->openfiles[filenum], (unsigned char)c);
  1630. }
  1631. if (developer_extra.integer)
  1632. Con_DPrintf("fgets: %s: %s\n", prog->name, string);
  1633. if (c >= 0 || end)
  1634. PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, string);
  1635. }
  1636. /*
  1637. =========
  1638. VM_fputs
  1639. fputs(float fhandle, string s)
  1640. =========
  1641. */
  1642. //void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file
  1643. void VM_fputs(prvm_prog_t *prog)
  1644. {
  1645. int stringlength;
  1646. char string[VM_STRINGTEMP_LENGTH];
  1647. int filenum;
  1648. VM_SAFEPARMCOUNT(2,VM_fputs);
  1649. filenum = (int)PRVM_G_FLOAT(OFS_PARM0);
  1650. if (filenum < 0 || filenum >= PRVM_MAX_OPENFILES)
  1651. {
  1652. VM_Warning(prog, "VM_fputs: invalid file handle %i used in %s\n", filenum, prog->name);
  1653. return;
  1654. }
  1655. if (prog->openfiles[filenum] == NULL)
  1656. {
  1657. VM_Warning(prog, "VM_fputs: no such file handle %i (or file has been closed) in %s\n", filenum, prog->name);
  1658. return;
  1659. }
  1660. VM_VarString(prog, 1, string, sizeof(string));
  1661. if ((stringlength = (int)strlen(string)))
  1662. FS_Write(prog->openfiles[filenum], string, stringlength);
  1663. if (developer_extra.integer)
  1664. Con_DPrintf("fputs: %s: %s\n", prog->name, string);
  1665. }
  1666. /*
  1667. =========
  1668. VM_writetofile
  1669. writetofile(float fhandle, entity ent)
  1670. =========
  1671. */
  1672. void VM_writetofile(prvm_prog_t *prog)
  1673. {
  1674. prvm_edict_t * ent;
  1675. qfile_t *file;
  1676. VM_SAFEPARMCOUNT(2, VM_writetofile);
  1677. file = VM_GetFileHandle(prog, (int)PRVM_G_FLOAT(OFS_PARM0));
  1678. if( !file )
  1679. {
  1680. VM_Warning(prog, "VM_writetofile: invalid or closed file handle\n");
  1681. return;
  1682. }
  1683. ent = PRVM_G_EDICT(OFS_PARM1);
  1684. if(ent->priv.required->free)
  1685. {
  1686. VM_Warning(prog, "VM_writetofile: %s: entity %i is free !\n", prog->name, PRVM_NUM_FOR_EDICT(ent));
  1687. return;
  1688. }
  1689. PRVM_ED_Write (prog, file, ent);
  1690. }
  1691. // KrimZon - DP_QC_ENTITYDATA
  1692. /*
  1693. =========
  1694. VM_numentityfields
  1695. float() numentityfields
  1696. Return the number of entity fields - NOT offsets
  1697. =========
  1698. */
  1699. void VM_numentityfields(prvm_prog_t *prog)
  1700. {
  1701. PRVM_G_FLOAT(OFS_RETURN) = prog->numfielddefs;
  1702. }
  1703. // KrimZon - DP_QC_ENTITYDATA
  1704. /*
  1705. =========
  1706. VM_entityfieldname
  1707. string(float fieldnum) entityfieldname
  1708. Return name of the specified field as a string, or empty if the field is invalid (warning)
  1709. =========
  1710. */
  1711. void VM_entityfieldname(prvm_prog_t *prog)
  1712. {
  1713. ddef_t *d;
  1714. int i = (int)PRVM_G_FLOAT(OFS_PARM0);
  1715. if (i < 0 || i >= prog->numfielddefs)
  1716. {
  1717. VM_Warning(prog, "VM_entityfieldname: %s: field index out of bounds\n", prog->name);
  1718. PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, "");
  1719. return;
  1720. }
  1721. d = &prog->fielddefs[i];
  1722. PRVM_G_INT(OFS_RETURN) = d->s_name; // presuming that s_name points to a string already
  1723. }
  1724. // KrimZon - DP_QC_ENTITYDATA
  1725. /*
  1726. =========
  1727. VM_entityfieldtype
  1728. float(float fieldnum) entityfieldtype
  1729. =========
  1730. */
  1731. void VM_entityfieldtype(prvm_prog_t *prog)
  1732. {
  1733. ddef_t *d;
  1734. int i = (int)PRVM_G_FLOAT(OFS_PARM0);
  1735. if (i < 0 || i >= prog->numfielddefs)
  1736. {
  1737. VM_Warning(prog, "VM_entityfieldtype: %s: field index out of bounds\n", prog->name);
  1738. PRVM_G_FLOAT(OFS_RETURN) = -1.0;
  1739. return;
  1740. }
  1741. d = &prog->fielddefs[i];
  1742. PRVM_G_FLOAT(OFS_RETURN) = (prvm_vec_t)d->type;
  1743. }
  1744. // KrimZon - DP_QC_ENTITYDATA
  1745. /*
  1746. =========
  1747. VM_getentityfieldstring
  1748. string(float fieldnum, entity ent) getentityfieldstring
  1749. =========
  1750. */
  1751. void VM_getentityfieldstring(prvm_prog_t *prog)
  1752. {
  1753. // put the data into a string
  1754. ddef_t *d;
  1755. int type, j;
  1756. prvm_eval_t *val;
  1757. prvm_edict_t * ent;
  1758. int i = (int)PRVM_G_FLOAT(OFS_PARM0);
  1759. char valuebuf[MAX_INPUTLINE];
  1760. if (i < 0 || i >= prog->numfielddefs)
  1761. {
  1762. VM_Warning(prog, "VM_entityfielddata: %s: field index out of bounds\n", prog->name);
  1763. PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, "");
  1764. return;
  1765. }
  1766. d = &prog->fielddefs[i];
  1767. // get the entity
  1768. ent = PRVM_G_EDICT(OFS_PARM1);
  1769. if(ent->priv.required->free)
  1770. {
  1771. PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, "");
  1772. VM_Warning(prog, "VM_entityfielddata: %s: entity %i is free !\n", prog->name, PRVM_NUM_FOR_EDICT(ent));
  1773. return;
  1774. }
  1775. val = (prvm_eval_t *)(ent->fields.fp + d->ofs);
  1776. // if it's 0 or blank, return an empty string
  1777. type = d->type & ~DEF_SAVEGLOBAL;
  1778. for (j=0 ; j<prvm_type_size[type] ; j++)
  1779. if (val->ivector[j])
  1780. break;
  1781. if (j == prvm_type_size[type])
  1782. {
  1783. PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, "");
  1784. return;
  1785. }
  1786. PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, PRVM_UglyValueString(prog, (etype_t)d->type, val, valuebuf, sizeof(valuebuf)));
  1787. }
  1788. // KrimZon - DP_QC_ENTITYDATA
  1789. /*
  1790. =========
  1791. VM_putentityfieldstring
  1792. float(float fieldnum, entity ent, string s) putentityfieldstring
  1793. =========
  1794. */
  1795. void VM_putentityfieldstring(prvm_prog_t *prog)
  1796. {
  1797. ddef_t *d;
  1798. prvm_edict_t * ent;
  1799. int i = (int)PRVM_G_FLOAT(OFS_PARM0);
  1800. if (i < 0 || i >= prog->numfielddefs)
  1801. {
  1802. VM_Warning(prog, "VM_entityfielddata: %s: field index out of bounds\n", prog->name);
  1803. PRVM_G_FLOAT(OFS_RETURN) = 0.0f;
  1804. return;
  1805. }
  1806. d = &prog->fielddefs[i];
  1807. // get the entity
  1808. ent = PRVM_G_EDICT(OFS_PARM1);
  1809. if(ent->priv.required->free)
  1810. {
  1811. VM_Warning(prog, "VM_entityfielddata: %s: entity %i is free !\n", prog->name, PRVM_NUM_FOR_EDICT(ent));
  1812. PRVM_G_FLOAT(OFS_RETURN) = 0.0f;
  1813. return;
  1814. }
  1815. // parse the string into the value
  1816. PRVM_G_FLOAT(OFS_RETURN) = ( PRVM_ED_ParseEpair(prog, ent, d, PRVM_G_STRING(OFS_PARM2), false) ) ? 1.0f : 0.0f;
  1817. }
  1818. /*
  1819. =========
  1820. VM_strlen
  1821. float strlen(string s)
  1822. =========
  1823. */
  1824. //float(string s) strlen = #114; // returns how many characters are in a string
  1825. void VM_strlen(prvm_prog_t *prog)
  1826. {
  1827. VM_SAFEPARMCOUNT(1,VM_strlen);
  1828. //PRVM_G_FLOAT(OFS_RETURN) = strlen(PRVM_G_STRING(OFS_PARM0));
  1829. PRVM_G_FLOAT(OFS_RETURN) = u8_strlen(PRVM_G_STRING(OFS_PARM0));
  1830. }
  1831. // DRESK - Decolorized String
  1832. /*
  1833. =========
  1834. VM_strdecolorize
  1835. string strdecolorize(string s)
  1836. =========
  1837. */
  1838. // string (string s) strdecolorize = #472; // returns the passed in string with color codes stripped
  1839. void VM_strdecolorize(prvm_prog_t *prog)
  1840. {
  1841. char szNewString[VM_STRINGTEMP_LENGTH];
  1842. const char *szString;
  1843. // Prepare Strings
  1844. VM_SAFEPARMCOUNT(1,VM_strdecolorize);
  1845. szString = PRVM_G_STRING(OFS_PARM0);
  1846. COM_StringDecolorize(szString, 0, szNewString, sizeof(szNewString), TRUE);
  1847. PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, szNewString);
  1848. }
  1849. // DRESK - String Length (not counting color codes)
  1850. /*
  1851. =========
  1852. VM_strlennocol
  1853. float strlennocol(string s)
  1854. =========
  1855. */
  1856. // float(string s) strlennocol = #471; // returns how many characters are in a string not including color codes
  1857. // For example, ^2Dresk returns a length of 5
  1858. void VM_strlennocol(prvm_prog_t *prog)
  1859. {
  1860. const char *szString;
  1861. int nCnt;
  1862. VM_SAFEPARMCOUNT(1,VM_strlennocol);
  1863. szString = PRVM_G_STRING(OFS_PARM0);
  1864. //nCnt = (int)COM_StringLengthNoColors(szString, 0, NULL);
  1865. nCnt = (int)u8_COM_StringLengthNoColors(szString, 0, NULL);
  1866. PRVM_G_FLOAT(OFS_RETURN) = nCnt;
  1867. }
  1868. // DRESK - String to Uppercase and Lowercase
  1869. /*
  1870. =========
  1871. VM_strtolower
  1872. string strtolower(string s)
  1873. =========
  1874. */
  1875. // string (string s) strtolower = #480; // returns passed in string in lowercase form
  1876. void VM_strtolower(prvm_prog_t *prog)
  1877. {
  1878. char szNewString[VM_STRINGTEMP_LENGTH];
  1879. const char *szString;
  1880. // Prepare Strings
  1881. VM_SAFEPARMCOUNT(1,VM_strtolower);
  1882. szString = PRVM_G_STRING(OFS_PARM0);
  1883. COM_ToLowerString(szString, szNewString, sizeof(szNewString) );
  1884. PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, szNewString);
  1885. }
  1886. /*
  1887. =========
  1888. VM_strtoupper
  1889. string strtoupper(string s)
  1890. =========
  1891. */
  1892. // string (string s) strtoupper = #481; // returns passed in string in uppercase form
  1893. void VM_strtoupper(prvm_prog_t *prog)
  1894. {
  1895. char szNewString[VM_STRINGTEMP_LENGTH];
  1896. const char *szString;
  1897. // Prepare Strings
  1898. VM_SAFEPARMCOUNT(1,VM_strtoupper);
  1899. szString = PRVM_G_STRING(OFS_PARM0);
  1900. COM_ToUpperString(szString, szNewString, sizeof(szNewString) );
  1901. PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, szNewString);
  1902. }
  1903. /*
  1904. =========
  1905. VM_strcat
  1906. string strcat(string,string,...[string])
  1907. =========
  1908. */
  1909. //string(string s1, string s2) strcat = #115;
  1910. // concatenates two strings (for example "abc", "def" would return "abcdef")
  1911. // and returns as a tempstring
  1912. void VM_strcat(prvm_prog_t *prog)
  1913. {
  1914. char s[VM_STRINGTEMP_LENGTH];
  1915. VM_SAFEPARMCOUNTRANGE(1, 8, VM_strcat);
  1916. VM_VarString(prog, 0, s, sizeof(s));
  1917. PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog, s);
  1918. }
  1919. /*
  1920. =========
  1921. VM_substring
  1922. string substring(string s, float start, float length)
  1923. =========
  1924. */
  1925. // string(string s, float start, float length) substring = #116;
  1926. // returns a section of a string as a tempstring
  1927. void VM_substring(prvm_prog_t *prog)
  1928. {
  1929. int start, length;
  1930. int u_slength = 0, u_start;
  1931. size_t u_length;
  1932. const char *s;
  1933. char string[VM_STRINGTEMP_LENGTH];
  1934. VM_SAFEPARMCOUNT(3,VM_substring);
  1935. /*
  1936. s = PRVM_G_STRING(OFS_PARM0);
  1937. start = (int)PRVM_G_FLOAT(OFS_PARM1);
  1938. length = (int)PRVM_G_FLOAT(OFS_PARM2);
  1939. slength = strlen(s);
  1940. if (start < 0) // FTE_STRINGS feature
  1941. start += slength;
  1942. start = bound(0, start, slength);
  1943. if (length < 0) // FTE_STRINGS feature
  1944. length += slength - start + 1;
  1945. maxlen = min((int)sizeof(string) - 1, slength - start);
  1946. length = bound(0, length, maxlen);
  1947. memcpy(string, s + start, length);
  1948. string[length] = 0;
  1949. PRVM_G_INT(OFS_RETURN) = PRV…

Large files files are truncated, but you can click here to view the full file