Source code

Revision control

1
// vim: set ts=4 sw=4 tw=99 noet:
2
//
3
// AMX Mod X, based on AMX Mod by Aleksander Naszko ("OLO").
4
// Copyright (C) The AMX Mod X Development Team.
5
//
6
// This software is licensed under the GNU General Public License, version 3 or higher.
7
// Additional exceptions apply. For full license details, see LICENSE.txt or visit:
9
10
//
11
// Engine Module
12
//
13
14
#include "engine.h"
15
16
struct usercmd_s *g_cmd;
17
struct PlayerInfo plinfo[33];
18
struct GlobalInfo glinfo;
19
20
int g_CameraCount;
21
22
TraceResult g_tr;
23
24
char g_buffer[1024];
25
26
void UTIL_SetSize(edict_t *pev, const Vector &vecMin, const Vector &vecMax)
27
{
28
SET_SIZE(ENT(pev), vecMin, vecMax);
29
}
30
31
edict_t *UTIL_FindEntityInSphere(edict_t *pStart, const Vector &vecCenter, float flRadius) {
32
if (!pStart) pStart = NULL;
33
34
pStart = FIND_ENTITY_IN_SPHERE(pStart, vecCenter, flRadius);
35
36
if (!FNullEnt(pStart)) return pStart;
37
return NULL;
38
}
39
40
static cell AMX_NATIVE_CALL register_think(AMX *amx, cell *params)
41
{
42
int len;
43
44
EntClass *p = new EntClass;
45
const char *clsname = MF_GetAmxString(amx, params[1], 0, &len);
46
p->Class = clsname;
47
48
p->Forward = MF_RegisterSPForwardByName(amx, MF_GetAmxString(amx, params[2], 0, &len), FP_CELL, FP_DONE);
49
50
Thinks.append(p);
51
52
if (!g_pFunctionTable->pfnThink)
53
g_pFunctionTable->pfnThink=Think;
54
55
return p->Forward;
56
}
57
58
static cell AMX_NATIVE_CALL unregister_think(AMX *amx, cell *params)
59
{
60
int fwd = params[1];
61
for (size_t i = 0; i < Thinks.length(); ++i)
62
{
63
EntClass *p = Thinks.at(i);
64
if (p->Forward == fwd)
65
{
66
Thinks.remove(i);
67
delete p;
68
69
if (!Thinks.length())
70
g_pFunctionTable->pfnThink = NULL;
71
72
return 1;
73
}
74
}
75
76
return 0;
77
}
78
79
static cell AMX_NATIVE_CALL register_impulse(AMX *amx, cell *params)
80
{
81
int len;
82
83
Impulse *p = new Impulse;
84
p->Check = params[1];
85
86
p->Forward = MF_RegisterSPForwardByName(amx, MF_GetAmxString(amx, params[2], 0, &len), FP_CELL, FP_CELL, FP_DONE);
87
88
Impulses.append(p);
89
90
if (!g_pFunctionTable->pfnCmdStart)
91
g_pFunctionTable->pfnCmdStart=CmdStart;
92
93
return p->Forward;
94
}
95
96
static cell AMX_NATIVE_CALL unregister_impulse(AMX *amx, cell *params)
97
{
98
int fwd = params[1];
99
for (size_t i = 0; i < Impulses.length(); ++i)
100
{
101
Impulse *p = Impulses.at(i);
102
if (p->Forward == fwd)
103
{
104
Impulses.remove(i);
105
delete p;
106
107
if (!Impulses.length())
108
g_pFunctionTable->pfnCmdStart = NULL;
109
110
return 1;
111
}
112
}
113
114
return 0;
115
}
116
117
static cell AMX_NATIVE_CALL register_touch(AMX *amx, cell *params)
118
{
119
int len;
120
121
char *Toucher = MF_GetAmxString(amx, params[1], 0, &len);
122
char *Touched = MF_GetAmxString(amx, params[2], 1, &len);
123
124
Touch *p = new Touch;
125
126
if (!strlen(Toucher) || strcmp(Toucher, "*")==0) {
127
p->Toucher = "";
128
} else {
129
p->Toucher = Toucher;
130
}
131
if (!strlen(Touched) || strcmp(Touched, "*")==0) {
132
p->Touched = "";
133
} else {
134
p->Touched = Touched;
135
}
136
137
p->Forward = MF_RegisterSPForwardByName(amx, MF_GetAmxString(amx, params[3], 2, &len), FP_CELL, FP_CELL, FP_DONE);
138
139
Touches.append(p);
140
141
if (!g_pFunctionTable->pfnTouch)
142
g_pFunctionTable->pfnTouch=pfnTouch;
143
144
return p->Forward;
145
}
146
147
static cell AMX_NATIVE_CALL unregister_touch(AMX *amx, cell *params)
148
{
149
int fwd = params[1];
150
for (size_t i = 0; i < Touches.length(); ++i)
151
{
152
Touch *p = Touches.at(i);
153
if (p->Forward == fwd)
154
{
155
Touches.remove(i);
156
delete p;
157
158
if (!Touches.length())
159
g_pFunctionTable->pfnTouch = NULL;
160
161
return 1;
162
}
163
}
164
165
return 0;
166
}
167
168
static cell AMX_NATIVE_CALL halflife_time(AMX *amx, cell *params)
169
{
170
REAL fVal = gpGlobals->time;
171
172
return amx_ftoc(fVal);
173
}
174
175
// RadiusDamage. Damages players within a certain radius. ToDo: add the
176
// damage messaging so players know where the damage is coming from
177
// (the red arrow-like things on the screen).
178
static cell AMX_NATIVE_CALL RadiusDamage(AMX *amx, cell *params)
179
{
180
cell *cAddr = MF_GetAmxAddr(amx,params[1]);
181
182
REAL fCurrentX = amx_ctof(cAddr[0]);
183
REAL fCurrentY = amx_ctof(cAddr[1]);
184
REAL fCurrentZ = amx_ctof(cAddr[2]);
185
int iDamageMultiplier = params[2];
186
int iRadiusMultiplier = params[3];
187
188
Vector vOrigin = Vector(fCurrentX, fCurrentY, fCurrentZ);
189
190
edict_t *pSearchEnt = NULL;
191
while ((pSearchEnt = UTIL_FindEntityInSphere(pSearchEnt, vOrigin, 5 * iRadiusMultiplier)) != NULL)
192
{
193
if (FStrEq(STRING(pSearchEnt->v.classname), "player"))
194
{
195
if (pSearchEnt->v.takedamage != DAMAGE_NO)
196
{
197
pSearchEnt->v.health -= 10 + RANDOM_FLOAT(0, 1 * iDamageMultiplier);
198
if (pSearchEnt->v.health < 1)
199
{
200
MDLL_ClientKill(pSearchEnt);
201
}
202
}
203
}
204
}
205
206
pSearchEnt = NULL;
207
208
while ((pSearchEnt = UTIL_FindEntityInSphere(pSearchEnt, vOrigin, 4 * iRadiusMultiplier)) != NULL)
209
{
210
if (FStrEq(STRING(pSearchEnt->v.classname), "player"))
211
{
212
if (pSearchEnt->v.takedamage != DAMAGE_NO)
213
{
214
pSearchEnt->v.health -= 25 + RANDOM_FLOAT(0, 2 * iDamageMultiplier);
215
if (pSearchEnt->v.health < 1)
216
{
217
MDLL_ClientKill(pSearchEnt);
218
}
219
}
220
}
221
}
222
223
pSearchEnt = NULL;
224
225
while ((pSearchEnt = UTIL_FindEntityInSphere(pSearchEnt, vOrigin, 3 * iRadiusMultiplier)) != NULL)
226
{
227
if (FStrEq(STRING(pSearchEnt->v.classname), "player"))
228
{
229
if (pSearchEnt->v.takedamage != DAMAGE_NO)
230
{
231
pSearchEnt->v.health -= 50 + RANDOM_FLOAT(0, 3 * iDamageMultiplier);
232
if (pSearchEnt->v.health < 1)
233
{
234
MDLL_ClientKill(pSearchEnt);
235
}
236
}
237
}
238
}
239
240
pSearchEnt = NULL;
241
242
while ((pSearchEnt = UTIL_FindEntityInSphere(pSearchEnt, vOrigin, 2 * iRadiusMultiplier)) != NULL)
243
{
244
if (FStrEq(STRING(pSearchEnt->v.classname), "player"))
245
{
246
if (pSearchEnt->v.takedamage != DAMAGE_NO)
247
{
248
MDLL_ClientKill(pSearchEnt);
249
}
250
}
251
}
252
253
return 1;
254
}
255
256
static cell AMX_NATIVE_CALL PointContents(AMX *amx, cell *params)
257
{
258
cell *cAddr = MF_GetAmxAddr(amx, params[1]);
259
260
REAL fX = amx_ctof(cAddr[0]);
261
REAL fY = amx_ctof(cAddr[1]);
262
REAL fZ = amx_ctof(cAddr[2]);
263
264
Vector vPoint = Vector(fX, fY, fZ);
265
266
return POINT_CONTENTS(vPoint);
267
}
268
269
static cell AMX_NATIVE_CALL trace_normal(AMX *amx, cell *params)
270
{
271
int iEnt = params[1];
272
if (iEnt > 0) {
273
CHECK_ENTITY(iEnt);
274
}
275
276
cell *cStart = MF_GetAmxAddr(amx, params[2]);
277
cell *cEnd = MF_GetAmxAddr(amx, params[3]);
278
REAL fStartX = amx_ctof(cStart[0]);
279
REAL fStartY = amx_ctof(cStart[1]);
280
REAL fStartZ = amx_ctof(cStart[2]);
281
REAL fEndX = amx_ctof(cEnd[0]);
282
REAL fEndY = amx_ctof(cEnd[1]);
283
REAL fEndZ = amx_ctof(cEnd[2]);
284
285
cell *vRet = MF_GetAmxAddr(amx, params[4]);
286
287
Vector vStart = Vector(fStartX, fStartY, fStartZ);
288
Vector vEnd = Vector(fEndX, fEndY, fEndZ);
289
290
TRACE_LINE(vStart, vEnd, dont_ignore_monsters, iEnt > 0 ? TypeConversion.id_to_edict(iEnt) : NULL, &g_tr);
291
292
vRet[0] = amx_ftoc(g_tr.vecPlaneNormal.x);
293
vRet[1] = amx_ftoc(g_tr.vecPlaneNormal.y);
294
vRet[2] = amx_ftoc(g_tr.vecPlaneNormal.z);
295
296
if (g_tr.flFraction >= 1.0)
297
return 0;
298
299
return 1;
300
}
301
302
static cell AMX_NATIVE_CALL trace_line(AMX *amx, cell *params)
303
{
304
int iEnt = params[1];
305
if (iEnt > 0) {
306
CHECK_ENTITY(iEnt);
307
}
308
309
cell *cStart = MF_GetAmxAddr(amx, params[2]);
310
cell *cEnd = MF_GetAmxAddr(amx, params[3]);
311
REAL fStartX = amx_ctof(cStart[0]);
312
REAL fStartY = amx_ctof(cStart[1]);
313
REAL fStartZ = amx_ctof(cStart[2]);
314
REAL fEndX = amx_ctof(cEnd[0]);
315
REAL fEndY = amx_ctof(cEnd[1]);
316
REAL fEndZ = amx_ctof(cEnd[2]);
317
318
cell *vRet = MF_GetAmxAddr(amx, params[4]);
319
320
Vector vStart = Vector(fStartX, fStartY, fStartZ);
321
Vector vEnd = Vector(fEndX, fEndY, fEndZ);
322
323
if (iEnt > 0)
324
TRACE_LINE(vStart, vEnd, dont_ignore_monsters, TypeConversion.id_to_edict(iEnt), &g_tr);
325
else
326
TRACE_LINE(vStart, vEnd, ignore_monsters, NULL, &g_tr);
327
328
edict_t *pHit = g_tr.pHit;
329
330
vRet[0] = amx_ftoc(g_tr.vecEndPos.x);
331
vRet[1] = amx_ftoc(g_tr.vecEndPos.y);
332
vRet[2] = amx_ftoc(g_tr.vecEndPos.z);
333
334
if (FNullEnt(pHit))
335
return 0;
336
337
return TypeConversion.edict_to_id(pHit);
338
}
339
340
static cell AMX_NATIVE_CALL set_speak(AMX *amx, cell *params) {
341
int iIndex = params[1];
342
int iNewSpeakFlags = params[2];
343
344
if (iIndex > gpGlobals->maxClients || !MF_IsPlayerIngame(iIndex)) {
345
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid player %d", iIndex);
346
return 0;
347
}
348
349
plinfo[iIndex].iSpeakFlags = iNewSpeakFlags;
350
351
return 1;
352
}
353
354
static cell AMX_NATIVE_CALL get_speak(AMX *amx, cell *params) {
355
int iIndex = params[1];
356
357
if (iIndex > gpGlobals->maxClients || !MF_IsPlayerIngame(iIndex)) {
358
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid player %d", iIndex);
359
return 0;
360
}
361
362
return plinfo[iIndex].iSpeakFlags;
363
}
364
365
static cell AMX_NATIVE_CALL get_decal_index(AMX *amx, cell *params)
366
{
367
int len;
368
char *szDecal = MF_GetAmxString(amx, params[1], 0, &len);
369
return DECAL_INDEX(szDecal);
370
}
371
372
static cell AMX_NATIVE_CALL get_info_keybuffer(AMX *amx, cell *params)
373
{
374
int iEnt = params[1];
375
if (iEnt != -1) {
376
CHECK_ENTITY(iEnt);
377
}
378
379
char *info = GETINFOKEYBUFFER((iEnt == -1) ? NULL : TypeConversion.id_to_edict(iEnt));
380
381
return MF_SetAmxStringUTF8Char(amx, params[2], info, strlen(info), params[3]);
382
}
383
384
//from jghg, who says it doesn't work
385
// it works, it's just a picky engine call -sawce
386
static cell AMX_NATIVE_CALL drop_to_floor(AMX *amx, cell *params)
387
{
388
int iEnt = params[1];
389
390
CHECK_ENTITY(iEnt);
391
392
edict_t *e = TypeConversion.id_to_edict(iEnt);
393
394
return DROP_TO_FLOOR(e);
395
}
396
397
// Attachview, this allows you to attach a player's view to an entity.
398
// use AttachView(player, player) to reset view.
399
//(vexd)
400
static cell AMX_NATIVE_CALL attach_view(AMX *amx, cell *params)
401
{
402
int iIndex = params[1];
403
int iTargetIndex = params[2];
404
405
CHECK_ENTITY(iIndex);
406
CHECK_ENTITY(iTargetIndex);
407
408
SET_VIEW(TypeConversion.id_to_edict(iIndex), TypeConversion.id_to_edict(iTargetIndex));
409
410
return 1;
411
}
412
413
// SetView, this sets the view of a player. This is done by
414
// Creating a camera entity, which follows the player.
415
//(vexd)
416
static cell AMX_NATIVE_CALL set_view(AMX *amx, cell *params) {
417
int iIndex = params[1];
418
int iCameraType = params[2];
419
420
if (iIndex > gpGlobals->maxClients || !MF_IsPlayerIngame(iIndex)) {
421
MF_LogError(amx, AMX_ERR_NATIVE, "Invalid player %d", iIndex);
422
return 0;
423
}
424
425
edict_t *pPlayer = TypeConversion.id_to_edict(iIndex);
426
edict_t *pNewCamera;
427
428
switch(iCameraType)
429
{
430
case CAMERA_NONE:
431
SET_VIEW(pPlayer, pPlayer);
432
if(plinfo[iIndex].pViewEnt) {
433
REMOVE_ENTITY(plinfo[iIndex].pViewEnt);
434
}
435
if (plinfo[iIndex].iViewType != CAMERA_NONE) // Verify that they were originally in a modified view
436
{
437
g_CameraCount--;
438
if (g_CameraCount < 0)
439
g_CameraCount=0;
440
if (g_CameraCount==0) // Reset the AddToFullPack pointer if there's no more cameras in use...
441
g_pFunctionTable->pfnAddToFullPack=NULL;
442
}
443
444
plinfo[iIndex].iViewType = CAMERA_NONE;
445
plinfo[iIndex].pViewEnt = NULL;
446
return 1;
447
break;
448
case CAMERA_3RDPERSON:
449
if(plinfo[iIndex].iViewType != CAMERA_NONE) {
450
plinfo[iIndex].iViewType = CAMERA_3RDPERSON;
451
return 1;
452
}
453
g_CameraCount++;
454
g_pFunctionTable_Post->pfnAddToFullPack=AddToFullPack_Post;
455
g_pFunctionTable_Post->pfnPlayerPostThink=PlayerPostThink_Post;
456
457
plinfo[iIndex].iViewType = CAMERA_3RDPERSON;
458
pNewCamera = CREATE_NAMED_ENTITY(MAKE_STRING("info_target"));
459
460
if (!pNewCamera)
461
{
462
MF_LogError(amx, AMX_ERR_NATIVE, "Could not create camera entity.");
463
return 0;
464
}
465
466
pNewCamera->v.classname = MAKE_STRING("VexdCam");
467
468
SET_MODEL(pNewCamera, "models/rpgrocket.mdl");
469
SET_SIZE(pNewCamera, Vector(0, 0, 0), Vector(0, 0, 0));
470
471
pNewCamera->v.movetype = MOVETYPE_NOCLIP;
472
pNewCamera->v.solid = SOLID_NOT;
473
pNewCamera->v.takedamage = DAMAGE_NO;
474
pNewCamera->v.gravity = 0;
475
pNewCamera->v.owner = pPlayer;
476
pNewCamera->v.rendermode = kRenderTransColor;
477
pNewCamera->v.renderamt = 0;
478
pNewCamera->v.renderfx = kRenderFxNone;
479
480
SET_VIEW(pPlayer, pNewCamera);
481
482
plinfo[iIndex].pViewEnt = pNewCamera;
483
break;
484
case CAMERA_UPLEFT:
485
if(plinfo[iIndex].iViewType != CAMERA_NONE) {
486
plinfo[iIndex].iViewType = CAMERA_UPLEFT;
487
return 1;
488
}
489
490
g_CameraCount++;
491
g_pFunctionTable_Post->pfnAddToFullPack=AddToFullPack_Post;
492
g_pFunctionTable_Post->pfnPlayerPostThink=PlayerPostThink_Post;
493
494
plinfo[iIndex].iViewType = CAMERA_UPLEFT;
495
pNewCamera = CREATE_NAMED_ENTITY(MAKE_STRING("info_target"));
496
497
if (!pNewCamera)
498
{
499
MF_LogError(amx, AMX_ERR_NATIVE, "Could not create camera entity.");
500
return 0;
501
}
502
503
pNewCamera->v.classname = MAKE_STRING("VexdCam");
504
505
SET_MODEL(pNewCamera, "models/rpgrocket.mdl");
506
SET_SIZE(pNewCamera, Vector(0, 0, 0), Vector(0, 0, 0));
507
508
pNewCamera->v.movetype = MOVETYPE_NOCLIP;
509
pNewCamera->v.solid = SOLID_NOT;
510
pNewCamera->v.takedamage = DAMAGE_NO;
511
pNewCamera->v.gravity = 0;
512
pNewCamera->v.owner = pPlayer;
513
pNewCamera->v.rendermode = kRenderTransColor;
514
pNewCamera->v.renderamt = 0;
515
pNewCamera->v.renderfx = kRenderFxNone;
516
517
SET_VIEW(pPlayer, pNewCamera);
518
519
plinfo[iIndex].pViewEnt = pNewCamera;
520
break;
521
case CAMERA_TOPDOWN:
522
if(plinfo[iIndex].iViewType != CAMERA_NONE) {
523
plinfo[iIndex].iViewType = CAMERA_TOPDOWN;
524
return 1;
525
}
526
527
g_CameraCount++;
528
g_pFunctionTable_Post->pfnAddToFullPack=AddToFullPack_Post;
529
g_pFunctionTable_Post->pfnPlayerPostThink=PlayerPostThink_Post;
530
531
plinfo[iIndex].iViewType = CAMERA_TOPDOWN;
532
pNewCamera = CREATE_NAMED_ENTITY(MAKE_STRING("info_target"));
533
534
if (!pNewCamera)
535
{
536
MF_LogError(amx, AMX_ERR_NATIVE, "Could not create camera entity.");
537
return 0;
538
}
539
540
pNewCamera->v.classname = MAKE_STRING("VexdCam");
541
542
SET_MODEL(pNewCamera, "models/rpgrocket.mdl");
543
SET_SIZE(pNewCamera, Vector(0, 0, 0), Vector(0, 0, 0));
544
545
pNewCamera->v.movetype = MOVETYPE_NOCLIP;
546
pNewCamera->v.solid = SOLID_NOT;
547
pNewCamera->v.takedamage = DAMAGE_NO;
548
pNewCamera->v.gravity = 0;
549
pNewCamera->v.owner = pPlayer;
550
pNewCamera->v.rendermode = kRenderTransColor;
551
pNewCamera->v.renderamt = 0;
552
pNewCamera->v.renderfx = kRenderFxNone;
553
554
SET_VIEW(pPlayer, pNewCamera);
555
556
plinfo[iIndex].pViewEnt = pNewCamera;
557
break;
558
default:
559
break;
560
}
561
562
return 1;
563
}
564
565
// SetLights, this sets the lights for the map.
566
//(vexd)
567
static cell AMX_NATIVE_CALL set_lights(AMX *amx, cell *params) {
568
int iLength;
569
char *szLights = MF_GetAmxString(amx, params[1], 0, &iLength);
570
571
if (FStrEq(szLights, "#OFF")) {
572
glinfo.bCheckLights = false;
573
memset(glinfo.szLastLights, 0x0, 128);
574
LIGHT_STYLE(0, glinfo.szRealLights);
575
return 1;
576
}
577
578
glinfo.bCheckLights = true;
579
580
//Reset LastLights and store custom lighting
581
ke::SafeStrcpy(glinfo.szLastLights, sizeof(glinfo.szLastLights), szLights);
582
583
LightStyleDetour->DisableDetour();
584
LIGHT_STYLE(0, glinfo.szLastLights);
585
LightStyleDetour->EnableDetour();
586
587
// These make it so that players/weaponmodels look like whatever the lighting is
588
// at. otherwise it would color players under the skybox to these values.
589
SERVER_COMMAND("sv_skycolor_r 0\n");
590
SERVER_COMMAND("sv_skycolor_g 0\n");
591
SERVER_COMMAND("sv_skycolor_b 0\n");
592
593
return 1;
594
}
595
596
//(mahnsawce)
597
static cell AMX_NATIVE_CALL trace_hull(AMX *amx,cell *params)
598
{
599
int iEnt = params[3];
600
if (iEnt > 0) {
601
CHECK_ENTITY(iEnt);
602
}
603
604
int iResult=0;
605
Vector vStart;
606
Vector vEnd;
607
cell *vCell;
608
609
vCell = MF_GetAmxAddr(amx, params[1]);
610
611
vStart.x = amx_ctof(vCell[0]);
612
vStart.y = amx_ctof(vCell[1]);
613
vStart.z = amx_ctof(vCell[2]);
614
615
if (params[0] / sizeof(cell) >= 5 && (vCell = MF_GetAmxVectorNull(amx, params[5])))
616
{
617
618
vEnd.x = amx_ctof(vCell[0]);
619
vEnd.y = amx_ctof(vCell[1]);
620
vEnd.z = amx_ctof(vCell[2]);
621
}
622
else
623
vEnd = vStart;
624
625
626
TRACE_HULL(vStart, vEnd, params[4], params[2], iEnt > 0 ? TypeConversion.id_to_edict(iEnt) : NULL, &g_tr);
627
628
if (g_tr.fStartSolid) {
629
iResult += 1;
630
}
631
if (g_tr.fAllSolid) {
632
iResult += 2;
633
}
634
if (!g_tr.fInOpen) {
635
iResult += 4;
636
}
637
return iResult;
638
}
639
640
//(mahnsawce)
641
static cell AMX_NATIVE_CALL playback_event(AMX *amx, cell *params)
642
{
643
/* Params:
644
* native playback_event(flags,invoker,eventindex,Float:delay,Float:origin[3],Float:angles[3],Float:fparam1,Float:fparam2,iparam1,iparam2,bparam1,bparam2)
645
* 1 2 3 4 5 6 7 8 9 10 11 12
646
*/
647
int flags;
648
edict_t *pInvoker;
649
unsigned short eventindex;
650
REAL delay;
651
vec3_t origin;
652
vec3_t angles;
653
REAL fparam1;
654
REAL fparam2;
655
int iparam1;
656
int iparam2;
657
int bparam1;
658
int bparam2;
659
flags = params[1];
660
if (params[2] > 0) {
661
CHECK_ENTITY(params[2]);
662
}
663
pInvoker=TypeConversion.id_to_edict(params[2]);
664
eventindex=params[3];
665
delay=amx_ctof(params[4]);
666
cell *cOrigin=MF_GetAmxAddr(amx, params[5]);
667
cell *cAngles=MF_GetAmxAddr(amx, params[6]);
668
origin.x=amx_ctof(cOrigin[0]);
669
origin.y=amx_ctof(cOrigin[1]);
670
origin.z=amx_ctof(cOrigin[2]);
671
angles.x=amx_ctof(cAngles[0]);
672
angles.y=amx_ctof(cAngles[1]);
673
angles.z=amx_ctof(cAngles[2]);
674
fparam1=amx_ctof(params[7]);
675
fparam2=amx_ctof(params[8]);
676
iparam1=params[9];
677
iparam2=params[10];
678
bparam1=params[11];
679
bparam2=params[12];
680
PLAYBACK_EVENT_FULL(flags, pInvoker,eventindex, delay, origin, angles, fparam1, fparam2, iparam1, iparam2, bparam1, bparam2);
681
return 1;
682
}
683
684
//(mahnsawce)
685
static cell AMX_NATIVE_CALL get_usercmd(AMX *amx, cell *params)
686
{
687
if (!incmd)
688
return 0;
689
int type = params[1];
690
if (type > usercmd_int_start && type < usercmd_int_end)
691
{
692
// Requesting an integer value...
693
switch(type)
694
{
695
case usercmd_lerp_msec:
696
return g_cmd->lerp_msec;
697
case usercmd_msec:
698
return g_cmd->msec;
699
case usercmd_lightlevel:
700
return g_cmd->lightlevel;
701
case usercmd_buttons:
702
return g_cmd->buttons;
703
case usercmd_weaponselect:
704
return g_cmd->weaponselect;
705
case usercmd_impact_index:
706
return g_cmd->impact_index;
707
default:
708
return 0;
709
}
710
}
711
else if (type > usercmd_float_start && type < usercmd_float_end)
712
{
713
// Requesting a single float value
714
// The second parameter needs to be the float variable.
715
716
cell *cRet = MF_GetAmxAddr(amx, params[2]);
717
switch(type)
718
{
719
case usercmd_forwardmove:
720
*cRet = amx_ftoc(g_cmd->forwardmove);
721
return 1;
722
case usercmd_sidemove:
723
*cRet = amx_ftoc(g_cmd->sidemove);
724
return 1;
725
case usercmd_upmove:
726
*cRet = amx_ftoc(g_cmd->upmove);
727
return 1;
728
default:
729
return 0;
730
}
731
}
732
else if (type > usercmd_vec_start && type < usercmd_vec_end)
733
{
734
// Requesting a Vector value.
735
cell *cRet = MF_GetAmxAddr(amx,params[2]);
736
switch (type)
737
{
738
case usercmd_viewangles:
739
cRet[0] = amx_ftoc(g_cmd->viewangles.x);
740
cRet[1] = amx_ftoc(g_cmd->viewangles.y);
741
cRet[2] = amx_ftoc(g_cmd->viewangles.z);
742
return 1;
743
case usercmd_impact_position:
744
cRet[0] = amx_ftoc(g_cmd->impact_position.x);
745
cRet[1] = amx_ftoc(g_cmd->impact_position.y);
746
cRet[2] = amx_ftoc(g_cmd->impact_position.z);
747
return 1;
748
default:
749
return 0;
750
}
751
}
752
return 1;
753
}
754
755
static cell AMX_NATIVE_CALL set_usercmd(AMX *amx, cell *params)
756
{
757
if (!incmd)
758
return 0;
759
int type = params[1];
760
if (type > usercmd_int_start && type < usercmd_int_end)
761
{
762
// Setting an integer value...
763
cell *blah = MF_GetAmxAddr(amx,params[2]);
764
int iValue = blah[0];
765
switch(type)
766
{
767
case usercmd_lerp_msec:
768
g_cmd->lerp_msec = iValue;
769
return 1;
770
case usercmd_msec:
771
g_cmd->msec = iValue;
772
return 1;
773
case usercmd_lightlevel:
774
g_cmd->lightlevel = iValue;
775
return 1;
776
case usercmd_buttons:
777
g_cmd->buttons = iValue;
778
return 1;
779
case usercmd_weaponselect:
780
g_cmd->weaponselect = iValue;
781
return 1;
782
case usercmd_impact_index:
783
g_cmd->impact_index = iValue;
784
return 1;
785
default:
786
return 0;
787
}
788
}
789
else if (type > usercmd_float_start && type < usercmd_float_end)
790
{
791
// Requesting a single float value
792
// The second parameter needs to be the float variable.
793
794
cell *blah = MF_GetAmxAddr(amx,params[2]);
795
REAL fValue = amx_ctof(blah[0]);
796
switch(type)
797
{
798
case usercmd_forwardmove:
799
g_cmd->forwardmove = fValue;
800
return 1;
801
case usercmd_sidemove:
802
g_cmd->sidemove = fValue;
803
return 1;
804
case usercmd_upmove:
805
g_cmd->upmove = fValue;
806
return 1;
807
default:
808
return 0;
809
}
810
}
811
else if (type > usercmd_vec_start && type < usercmd_vec_end)
812
{
813
// Requesting a Vector value.
814
Vector vValue;
815
cell *blah = MF_GetAmxAddr(amx,params[2]);
816
vValue.x = amx_ctof(blah[0]);
817
vValue.y = amx_ctof(blah[1]);
818
vValue.z = amx_ctof(blah[2]);
819
switch (type)
820
{
821
case usercmd_viewangles:
822
g_cmd->viewangles = vValue;
823
return 1;
824
case usercmd_impact_position:
825
g_cmd->impact_position = vValue;
826
return 1;
827
default:
828
return 0;
829
}
830
}
831
return 1;
832
}
833
834
static cell AMX_NATIVE_CALL is_visible(AMX *amx, cell *params)
835
{
836
int src = params[1];
837
int dest = params[2];
838
CHECK_ENTITY(src);
839
CHECK_ENTITY(dest);
840
841
edict_t *pEntity = TypeConversion.id_to_edict(src);
842
edict_t *pTarget = TypeConversion.id_to_edict(dest);
843
844
if (pTarget->v.flags & FL_NOTARGET)
845
return 0;
846
847
Vector vLooker = pEntity->v.origin + pEntity->v.view_ofs;
848
Vector vTarget = pTarget->v.origin + pTarget->v.view_ofs;
849
850
TraceResult tr;
851
852
auto oldSolid = pTarget->v.solid;
853
pTarget->v.solid = SOLID_NOT;
854
TRACE_LINE(vLooker, vTarget, FALSE, pEntity, &tr);
855
pTarget->v.solid = oldSolid;
856
857
if (tr.fInOpen && tr.fInWater)
858
return 0;
859
else if (tr.flFraction == 1.0)
860
return 1;
861
862
return 0;
863
}
864
865
//taken from dlls\combat.cpp
866
static cell AMX_NATIVE_CALL in_view_cone(AMX *amx, cell *params)
867
{
868
int src = params[1];
869
870
CHECK_ENTITY(src);
871
872
edict_t *pEdictSrc = TypeConversion.id_to_edict(src);
873
874
Vector vecLOS, vecForward;
875
float flDot;
876
877
cell *addr = MF_GetAmxAddr(amx, params[2]);
878
Vector origin(amx_ctof(addr[0]), amx_ctof(addr[1]), amx_ctof(addr[2]));
879
880
bool use2D = (params[0] / sizeof(cell)) == 2 || params[3] == 0;
881
882
if (use2D)
883
{
884
MAKE_VECTORS(pEdictSrc->v.angles);
885
vecForward = gpGlobals->v_forward;
886
887
vecLOS = origin - pEdictSrc->v.origin;
888
889
vecForward.z = 0;
890
vecLOS.z = 0;
891
}
892
else
893
{
894
MAKE_VECTORS(pEdictSrc->v.v_angle);
895
vecForward = gpGlobals->v_forward;
896
897
vecLOS = origin - (pEdictSrc->v.origin + pEdictSrc->v.view_ofs);
898
}
899
900
vecLOS = vecLOS.Normalize();
901
902
flDot = DotProduct(vecLOS, vecForward);
903
904
/* Dividing fov by two and then converting it to radians - don't ask about this ever again, please :\ */
905
if (flDot >= cos(pEdictSrc->v.fov * (M_PI / 360)))
906
return 1;
907
else
908
return 0;
909
}
910
911
static cell AMX_NATIVE_CALL traceresult(AMX *amx, cell *params)
912
{
913
int type = params[1];
914
cell *cRet;
915
/*
916
TR_AllSolid, // (int) if true, plane is not valid
917
TR_StartSolid, // (int) if true, the initial point was in a solid area
918
TR_InOpen, // (int)
919
TR_InWater, // (int)
920
TR_Fraction, // (float) time completed, 1.0 = didn't hit anything
921
TR_EndPos, // (vector) final position
922
TR_PlaneDist, // (float)
923
TR_PlaneNormal, // (vector) surface normal at impact
924
TR_Hit, // (entity) entity the surface is on
925
TR_Hitgroup // (int) 0 == generic, non zero is specific body part
926
*/
927
switch (type)
928
{
929
case TR_AllSolid:
930
return g_tr.fAllSolid;
931
case TR_StartSolid:
932
return g_tr.fStartSolid;
933
case TR_InOpen:
934
return g_tr.fInOpen;
935
case TR_InWater:
936
return g_tr.fInWater;
937
case TR_Hitgroup:
938
return g_tr.iHitgroup;
939
case TR_Hit:
940
if (!FNullEnt(g_tr.pHit))
941
return TypeConversion.edict_to_id(g_tr.pHit);
942
else
943
return -1;
944
case TR_Fraction:
945
cRet = MF_GetAmxAddr(amx,params[2]);
946
cRet[0] = amx_ftoc(g_tr.flFraction);
947
return 1;
948
case TR_EndPos:
949
cRet = MF_GetAmxAddr(amx,params[2]);
950
cRet[0] = amx_ftoc(g_tr.vecEndPos[0]);
951
cRet[1] = amx_ftoc(g_tr.vecEndPos[1]);
952
cRet[2] = amx_ftoc(g_tr.vecEndPos[2]);
953
return 1;
954
case TR_PlaneDist:
955
cRet = MF_GetAmxAddr(amx,params[2]);
956
cRet[0] = amx_ftoc(g_tr.flPlaneDist);
957
return 1;
958
case TR_PlaneNormal:
959
cRet = MF_GetAmxAddr(amx,params[2]);
960
cRet[0] = amx_ftoc(g_tr.vecPlaneNormal[0]);
961
cRet[1] = amx_ftoc(g_tr.vecPlaneNormal[1]);
962
cRet[2] = amx_ftoc(g_tr.vecPlaneNormal[2]);
963
return 1;
964
}
965
return 0;
966
}
967
968
// (jghg)
969
static cell AMX_NATIVE_CALL get_string(AMX *amx, cell *params) // (string, returnstring[], length)
970
{
971
ke::SafeSprintf(g_buffer, sizeof(g_buffer), "%s", STRING(params[1]));
972
return MF_SetAmxString(amx, params[2], g_buffer, params[3]);
973
}
974
975
//contributed by twistedeuphoria
976
static cell AMX_NATIVE_CALL trace_forward(AMX *amx, cell *params)
977
//native trace_forward(Float:start[3], Float:angles[3], give, ignoreEnt, &Float:hitX, &Float:hitY, &Float:shortestDistance, &Float:shortestDistLow, &Float:shortestDistHigh)
978
{
979
cell *cStart = MF_GetAmxAddr(amx, params[1]);
980
cell *cAngles = MF_GetAmxAddr(amx, params[2]);
981
REAL fGive = amx_ctof(params[3]);
982
int iIgnoreEnt = params[4];
983
if (iIgnoreEnt > 0) {
984
CHECK_ENTITY(iIgnoreEnt);
985
}
986
987
cell *hitX = MF_GetAmxAddr(amx, params[5]);
988
cell *hitY = MF_GetAmxAddr(amx, params[6]);
989
cell *shortestDistance = MF_GetAmxAddr(amx, params[7]);
990
cell *shortestDistLow = MF_GetAmxAddr(amx, params[8]);
991
cell *shortestDistHigh = MF_GetAmxAddr(amx, params[9]);
992
993
if(fGive < 0.0)
994
fGive = 20.0;
995
996
REAL fStartX = amx_ctof(cStart[0]);
997
REAL fStartY = amx_ctof(cStart[1]);
998
REAL fStartZ = amx_ctof(cStart[2]);
999
1000
REAL fAnglesX = amx_ctof(cAngles[0]);
1001
REAL fAnglesY = amx_ctof(cAngles[1]);
1002
REAL fAnglesZ = amx_ctof(cAngles[2]);
1003
Vector playerAngleVector = Vector(fAnglesX,fAnglesY,fAnglesZ);
1004
MAKE_VECTORS(playerAngleVector);
1005
1006
Vector forwardVector = gpGlobals->v_forward;
1007
REAL fEndX = forwardVector[0] * 4000;
1008
REAL fEndY = forwardVector[1] * 4000;
1009
1010
REAL fClosestDist = 999999.9;
1011
REAL fClosestLow = 0.0;
1012
REAL fClosestHigh = 0.0;
1013
REAL fClosestX = 0.0;
1014
REAL fClosestY = 0.0;
1015
TraceResult tr;
1016
REAL fRetX;
1017
REAL fRetY;
1018
REAL fRetZ;
1019
1020
for(int inum=-36;inum<=36;inum++)
1021
{
1022
REAL fUseZ = fStartZ + (REAL)inum;
1023
Vector vStart = Vector(fStartX, fStartY, fUseZ);
1024
Vector vEnd = Vector(fEndX, fEndY, fUseZ);
1025
if(iIgnoreEnt > 0)
1026
TRACE_LINE(vStart, vEnd, dont_ignore_monsters, TypeConversion.id_to_edict(iIgnoreEnt), &tr);
1027
else
1028
TRACE_LINE(vStart, vEnd, ignore_monsters, NULL, &tr);
1029
fRetX = tr.vecEndPos.x;
1030
fRetY = tr.vecEndPos.y;
1031
fRetZ = tr.vecEndPos.z;
1032
Vector vHit = Vector(fRetX, fRetY, fRetZ);
1033
1034
REAL fLength = (vStart - vHit).Length();
1035
if(fabs(fLength - fClosestDist) < fGive)
1036
fClosestHigh = fUseZ - fStartZ;
1037
else if(fLength < fClosestDist)
1038
{
1039
fClosestDist = fLength;
1040
fClosestLow = fUseZ - fStartZ;
1041
fClosestHigh = fUseZ - fStartZ;
1042
fClosestX = fRetX;
1043
fClosestY = fRetY;
1044
}
1045
}
1046
fClosestLow += 36.0;
1047
fClosestHigh += 36.0;
1048
1049
*hitX = amx_ftoc(fClosestX);
1050
*hitY = amx_ftoc(fClosestY);
1051
*shortestDistance = amx_ftoc(fClosestDist);
1052
*shortestDistLow = amx_ftoc(fClosestLow);
1053
*shortestDistHigh = amx_ftoc(fClosestHigh);
1054
return 1;
1055
}
1056
1057
AMX_NATIVE_INFO engine_NewNatives[] =
1058
{
1059
{"trace_line", trace_line},
1060
{NULL, NULL}
1061
};
1062
1063
AMX_NATIVE_INFO engine_Natives[] = {
1064
{"halflife_time", halflife_time},
1065
1066
//These are mostly from original VexD
1067
1068
{"radius_damage", RadiusDamage},
1069
{"point_contents", PointContents},
1070
{"trace_normal", trace_normal},
1071
{"trace_hull", trace_hull},
1072
{"traceresult", traceresult},
1073
1074
{"set_speak", set_speak},
1075
{"get_speak", get_speak},
1076
1077
{"playback_event", playback_event},
1078
1079
{"set_view", set_view},
1080
{"attach_view", attach_view},
1081
1082
{"get_decal_index", get_decal_index},
1083
{"get_info_keybuffer", get_info_keybuffer},
1084
{"set_lights", set_lights},
1085
{"drop_to_floor", drop_to_floor},
1086
1087
{"get_usercmd", get_usercmd},
1088
{"set_usercmd", set_usercmd},
1089
1090
{"register_impulse", register_impulse},
1091
{"register_think", register_think},
1092
{"register_touch", register_touch},
1093
{"unregister_impulse", unregister_impulse},
1094
{"unregister_think", unregister_think},
1095
{"unregister_touch", unregister_touch},
1096
1097
{"eng_get_string", get_string},
1098
{"is_in_viewcone", in_view_cone},
1099
{"is_visible", is_visible},
1100
{"trace_forward", trace_forward},
1101
1102
{NULL, NULL}
1103
///////////////////
1104
};