AMXX-BG.INFO chr_engine.inc Raw include

chr_engine.inc

Original include source with line numbers.

Back Download .inc
1 /* CHR Engine - v1.1b
2 *
3 * by GHW_Chronic
4 * 12/2006 - 07/2009
5 *
6 * This file is provided as is (no warranties).
7 *
8 */
9
10 #if defined chr_engine_included
11 #endinput
12 #endif
13 #define chr_engine_included
14
15
16 #include <amxmodx>
17 #include <fakemeta>
18
19
20
21 /*
22 *
23 * Determines velocity (new_velocity) that
24 * you would set an entity to in order for
25 * it to go at "speed" from "origin1" to
26 * "origin2".
27 *
28 */
29
30 stock get_speed_vector(const Float:origin1[3],const Float:origin2[3],Float:speed, Float:new_velocity[3])
31 {
32 new_velocity[0] = origin2[0] - origin1[0]
33 new_velocity[1] = origin2[1] - origin1[1]
34 new_velocity[2] = origin2[2] - origin1[2]
35 new Float:num = floatsqroot(speed*speed / (new_velocity[0]*new_velocity[0] + new_velocity[1]*new_velocity[1] + new_velocity[2]*new_velocity[2]))
36 new_velocity[0] *= num
37 new_velocity[1] *= num
38 new_velocity[2] *= num
39
40 return 1;
41 }
42
43
44
45 /*
46 *
47 * Determines velocity (new_velocity) that
48 * you would set "ent1" to in order for it
49 * to go at "speed" from "ent1"'s origin
50 * to "ent2"'s origin.
51 *
52 */
53
54 stock get_speed_vector2(ent1, ent2, Float:speed, Float:new_velocity[3])
55 {
56 if(!pev_valid(ent1) || !pev_valid(ent2))
57 return 0;
58
59 static Float:origin1[3]
60 pev(ent1,pev_origin,origin1)
61 static Float:origin2[3]
62 pev(ent2,pev_origin,origin2)
63
64 new_velocity[0] = origin2[0] - origin1[0]
65 new_velocity[1] = origin2[1] - origin1[1]
66 new_velocity[2] = origin2[2] - origin1[2]
67 new Float:num = floatsqroot(speed*speed / (new_velocity[0]*new_velocity[0] + new_velocity[1]*new_velocity[1] + new_velocity[2]*new_velocity[2]))
68 new_velocity[0] *= num
69 new_velocity[1] *= num
70 new_velocity[2] *= num
71
72 return 1;
73 }
74
75
76
77 /*
78 *
79 * Determines location ("origin") of an entity
80 * with supplied offset to its original angles.
81 *
82 * Example: You want the location of 30 units
83 * to the left of a model but the model is
84 * turned at an angle so you cannot simply add
85 * the offset to the origin. Then you would use
86 * this.
87 *
88 */
89
90 stock get_offset_origin(ent,const Float:offset[3],Float:origin[3])
91 {
92 if(!pev_valid(ent))
93 return 0;
94
95 new Float:angle[3]
96 pev(ent,pev_origin,origin)
97 pev(ent,pev_angles,angle)
98
99 origin[0] += floatcos(angle[1],degrees) * offset[0]
100 origin[1] += floatsin(angle[1],degrees) * offset[0]
101
102 origin[2] += floatsin(angle[0],degrees) * offset[0]
103 origin[0] += floatcos(angle[0],degrees) * offset[0]
104
105 origin[1] += floatcos(angle[1],degrees) * offset[1]
106 origin[0] -= floatsin(angle[1],degrees) * offset[1]
107
108 origin[2] += floatsin(angle[2],degrees) * offset[1]
109 origin[1] += floatcos(angle[2],degrees) * offset[1]
110
111 origin[2] += floatcos(angle[2],degrees) * offset[2]
112 origin[1] -= floatsin(angle[2],degrees) * offset[2]
113
114 origin[2] += floatcos(angle[0],degrees) * offset[2]
115 origin[0] -= floatsin(angle[0],degrees) * offset[2]
116
117 origin[0] -= offset[0]
118 origin[1] -= offset[1]
119 origin[2] -= offset[2]
120
121 return 1;
122 }
123
124
125
126 /*
127 *
128 * Determines location ("origin") of a monster
129 * or player entity with supplied offset to its
130 * original angles.
131 *
132 * Example: You want the location of 30 units
133 * to the left of a model but the model is
134 * turned at an angle so you cannot simply add
135 * the offset to the origin. Then you would use
136 * this.
137 *
138 * Works same as above but only for players and
139 * monsters.
140 *
141 */
142
143 stock get_offset_origin_body(ent,const Float:offset[3],Float:origin[3])
144 {
145 if(!pev_valid(ent))
146 return 0;
147
148 new Float:angle[3]
149 pev(ent,pev_angles,angle)
150
151 pev(ent,pev_origin,origin)
152
153 origin[0] += floatcos(angle[1],degrees) * offset[0]
154 origin[1] += floatsin(angle[1],degrees) * offset[0]
155
156 origin[1] += floatcos(angle[1],degrees) * offset[1]
157 origin[0] += floatsin(angle[1],degrees) * offset[1]
158
159 return 1;
160 }
161
162
163
164 /*
165 *
166 * Determines if a player is crouching or not.
167 * Return 1 if crouching and 0 if not.
168 *
169 * Set ignoreplayer to 1 if you are using on
170 * a HL monster that can crouch.
171 *
172 */
173
174 stock is_user_crouching(ent,ignoreplayer=0)
175 {
176 if(!is_user_alive(ent) && !ignoreplayer)
177 return 0;
178
179 new Float:minsize[3]
180 pev(ent,pev_mins,minsize)
181
182 if(minsize[2]==-18.0)
183 return 1;
184
185 return 0;
186 }
187
188
189
190 /*
191 *
192 * Returns indexes of players in order according
193 * to how close they are to "origin". Indexes are
194 * stored in "players[32]" and the number of
195 * indexes returned is stored in num[0]. team[] is
196 * used only if flag 'e' is passed.
197 *
198 * Flags:
199 * "a" - Don't return dead players
200 * "b" - Don't return alive players
201 * "c" - Skip bots
202 * "d" - Skip real players
203 * "e" - Match with passed team
204 * "h" - Skip HLTV
205 * "i" - Is in Viewcone
206 * "j" - Is Visible
207 *
208 * If flag 'i' is passed, you must specify into
209 * variable "index" who's viewcone to check if
210 * the returned players are in.
211 *
212 */
213
214 stock get_players_distance(const Float:origin2[3],players[32], &num,const flags[]="",index=0,const team[]="")
215 {
216 new bool:flag1, bool:flag2
217 if(containi(flags,"j")!=-1) flag2 = true
218 if(containi(flags,"i")!=-1)
219 {
220 if(!pev_valid(index))
221 return 0;
222 flag1 = true
223 }
224
225 static Float:origin[3]
226 origin[0] = origin2[0]
227 origin[1] = origin2[1]
228 origin[2] = origin2[2]
229
230 static players2[32]
231 new num2
232 arrayset(players2,0,32)
233 get_players(players2,num2,flags,team)
234 static Float:origin3[3]
235 static Float:distance[32]
236 for(new i=0;i<32;i++) distance[i]=0.0
237 num = num2
238
239 static Float:hit[3]
240 new bool:continuea=true
241 for(new i=0;i<num2;i++)
242 {
243 pev(players2[i],pev_origin,origin3)
244 if(flag2)
245 {
246 engfunc(EngFunc_TraceLine,origin2,origin3,1,index,0)
247 get_tr2(0,TR_vecEndPos,hit)
248 if(hit[0]==origin3[0] && hit[1]==origin3[1] && hit[2]==origin3[2])
249 {
250 distance[i] = vector_distance(origin,origin3)
251 }
252 else
253 {
254 continuea=false
255 distance[i] = 9999999.1337
256 num--
257 }
258 }
259 if(flag1 && continuea)
260 {
261 static Float:angles[3], Float:diff[3], Float:reciprocalsq, Float:norm[3], Float:dot, Float:fov
262 pev(index, pev_angles, angles)
263 engfunc(EngFunc_MakeVectors, angles)
264 global_get(glb_v_forward, angles)
265 angles[2] = 0.0
266
267 pev(index, pev_origin, origin)
268 diff[0] = origin3[0] - origin[0]
269 diff[1] = origin3[1] - origin[1]
270 diff[2] = origin3[2] - origin[2]
271 //diff[2]=0.0// - for 2D viewcone
272
273 reciprocalsq = 1.0 / floatsqroot(diff[0]*diff[0] + diff[1]*diff[1] + diff[2]*diff[2])
274 norm[0] = diff[0] * reciprocalsq
275 norm[1] = diff[1] * reciprocalsq
276 norm[2] = diff[2] * reciprocalsq
277
278 dot = norm[0]*angles[0] + norm[1]*angles[1] + norm[2]*angles[2]
279 pev(index, pev_fov, fov)
280 if(dot >= floatcos(fov * 3.1415926535 / 360.0))
281 {
282 distance[i] = vector_distance(origin,origin3)
283 }
284 else
285 {
286 continuea=false
287 distance[i] = 9999999.1337
288 num--
289 }
290 }
291 if(continuea)
292 {
293 distance[i] = vector_distance(origin,origin3)
294 }
295 }
296 static distance_cnt[32]
297 arrayset(distance_cnt,0,32)
298 for(new i=0;i<num2;i++)
299 {
300 if(distance[i]!=9999999.1337)
301 {
302 for(new i2=0;i2<num;i2++)
303 {
304 if(distance[i2]<distance[i]) distance_cnt[i]++
305 }
306 players[distance_cnt[i]]=players2[i]
307 }
308 }
309 return 1;
310 }
311
312
313
314 /*
315 *
316 * Forces "ent" to aim at "origin"
317 *
318 * Set bone to a positive value to
319 * detect a specific bone the function
320 * should aim from.
321 *
322 */
323
324 stock entity_set_aim(ent,const Float:origin2[3],bone=0)
325 {
326 if(!pev_valid(ent))
327 return 0;
328
329 static Float:origin[3]
330 origin[0] = origin2[0]
331 origin[1] = origin2[1]
332 origin[2] = origin2[2]
333
334 static Float:ent_origin[3], Float:angles[3]
335
336 if(bone)
337 engfunc(EngFunc_GetBonePosition,ent,bone,ent_origin,angles)
338 else
339 pev(ent,pev_origin,ent_origin)
340
341 origin[0] -= ent_origin[0]
342 origin[1] -= ent_origin[1]
343 origin[2] -= ent_origin[2]
344
345 static Float:v_length
346 v_length = vector_length(origin)
347
348 static Float:aim_vector[3]
349 aim_vector[0] = origin[0] / v_length
350 aim_vector[1] = origin[1] / v_length
351 aim_vector[2] = origin[2] / v_length
352
353 static Float:new_angles[3]
354 vector_to_angle(aim_vector,new_angles)
355
356 new_angles[0] *= -1
357
358 if(new_angles[1]>180.0) new_angles[1] -= 360
359 if(new_angles[1]<-180.0) new_angles[1] += 360
360 if(new_angles[1]==180.0 || new_angles[1]==-180.0) new_angles[1]=-179.999999
361
362 set_pev(ent,pev_angles,new_angles)
363 set_pev(ent,pev_fixangle,1)
364
365 return 1;
366 }
367
368
369
370 /*
371 *
372 * If "origin" is in ent's viewcone, the location
373 * of it using the hudmessage grid will be placed
374 * into hudpos[2].
375 *
376 * Returns 0 if "origin" is not on ent's hud.
377 *
378 * ent must be a player (index 1-32).
379 *
380 */
381
382 stock get_hudmessage_locs(ent,const Float:origin[3],Float:hudpos[2])
383 {
384 if(!is_user_connected(ent))
385 return 0;
386
387 static Float:origin2[3]
388 origin2[0] = origin[0]
389 origin2[1] = origin[1]
390 origin2[2] = origin[2]
391
392 static Float:ent_origin[3]
393
394 pev(ent,pev_origin,ent_origin)
395
396 static Float:ent_angles[3]
397
398 pev(ent,pev_v_angle,ent_angles)
399
400 origin2[0] -= ent_origin[0]
401 origin2[1] -= ent_origin[1]
402 origin2[2] -= ent_origin[2]
403
404 new Float:v_length
405 v_length = vector_length(origin2)
406
407 static Float:aim_vector[3]
408 aim_vector[0] = origin2[0] / v_length
409 aim_vector[1] = origin2[1] / v_length
410 aim_vector[2] = origin2[2] / v_length
411
412 static Float:new_angles[3]
413 vector_to_angle(aim_vector,new_angles)
414
415 new_angles[0] *= -1
416
417 if(new_angles[1]>180.0) new_angles[1] -= 360.0
418 if(new_angles[1]<-180.0) new_angles[1] += 360.0
419 if(new_angles[1]==180.0 || new_angles[1]==-180.0) new_angles[1]=-179.999999
420
421 if(new_angles[0]>180.0) new_angles[0] -= 360.0
422 if(new_angles[0]<-180.0) new_angles[0] += 360.0
423 if(new_angles[0]==90.0) new_angles[0]=89.999999
424 else if(new_angles[0]==-90.0) new_angles[0]=-89.999999
425
426 new Float:fov
427 pev(ent,pev_fov,fov)
428
429 if(!fov)
430 fov = 90.0
431
432 if(floatabs(ent_angles[0] - new_angles[0]) <= fov/2 && floatabs((180.0 - floatabs(ent_angles[1])) - (180.0 - floatabs(new_angles[1]))) <= fov/2)
433 {
434 hudpos[1] = 1 - ( ( (ent_angles[0] - new_angles[0]) + fov/2 ) / fov )
435 hudpos[0] = ( (ent_angles[1] - new_angles[1]) + fov/2 ) / fov
436 }
437 else
438 return 0;
439
440 return 1;
441 }
442
443
444
445 /*
446 *
447 * Sets ent's speed in the direction specified
448 * by the mode variable
449 *
450 * Modes:
451 * 0 = In direction ent is currently moving
452 * but not including the z axis
453 * 1 = In direction ent is currently moving
454 * 2 = In direction ent is currently looking
455 * 3 = In direction ent is currently looking
456 * but not including the z axis
457 * 4 = In direction of origin[3]
458 *
459 *
460 * Use a negative speed to go in the opposite
461 * direction of the specified mode.
462 *
463 */
464
465 stock set_speed(ent,Float:speed,mode=0,const Float:origin[3]={0.0,0.0,0.0})
466 {
467 if(!pev_valid(ent))
468 return 0;
469
470 switch(mode)
471 {
472 case 0:
473 {
474 static Float:cur_velo[3]
475
476 pev(ent,pev_velocity,cur_velo)
477
478 new Float:y
479 y = cur_velo[0]*cur_velo[0] + cur_velo[1]*cur_velo[1]
480
481 new Float:x
482 if(y) x = floatsqroot(speed*speed / y)
483
484 cur_velo[0] *= x
485 cur_velo[1] *= x
486
487 if(speed<0.0)
488 {
489 cur_velo[0] *= -1
490 cur_velo[1] *= -1
491 }
492
493 set_pev(ent,pev_velocity,cur_velo)
494 }
495 case 1:
496 {
497 static Float:cur_velo[3]
498
499 pev(ent,pev_velocity,cur_velo)
500
501 new Float:y
502 y = cur_velo[0]*cur_velo[0] + cur_velo[1]*cur_velo[1] + cur_velo[2]*cur_velo[2]
503
504 new Float:x
505 if(y) x = floatsqroot(speed*speed / y)
506
507 cur_velo[0] *= x
508 cur_velo[1] *= x
509 cur_velo[2] *= x
510
511 if(speed<0.0)
512 {
513 cur_velo[0] *= -1
514 cur_velo[1] *= -1
515 cur_velo[2] *= -1
516 }
517
518 set_pev(ent,pev_velocity,cur_velo)
519 }
520 case 2:
521 {
522 static Float:vangle[3]
523 if(ent<=get_maxplayers()) pev(ent,pev_v_angle,vangle)
524 else pev(ent,pev_angles,vangle)
525
526 static Float:new_velo[3]
527
528 angle_vector(vangle,1,new_velo)
529
530 new Float:y
531 y = new_velo[0]*new_velo[0] + new_velo[1]*new_velo[1] + new_velo[2]*new_velo[2]
532
533 new Float:x
534 if(y) x = floatsqroot(speed*speed / y)
535
536 new_velo[0] *= x
537 new_velo[1] *= x
538 new_velo[2] *= x
539
540 if(speed<0.0)
541 {
542 new_velo[0] *= -1
543 new_velo[1] *= -1
544 new_velo[2] *= -1
545 }
546
547 set_pev(ent,pev_velocity,new_velo)
548 }
549 case 3:
550 {
551 static Float:vangle[3]
552 if(ent<=get_maxplayers()) pev(ent,pev_v_angle,vangle)
553 else pev(ent,pev_angles,vangle)
554
555 static Float:new_velo[3]
556
557 pev(ent,pev_velocity,new_velo)
558
559 angle_vector(vangle,1,new_velo)
560
561 new Float:y
562 y = new_velo[0]*new_velo[0] + new_velo[1]*new_velo[1]
563
564 new Float:x
565 if(y) x = floatsqroot(speed*speed / y)
566
567 new_velo[0] *= x
568 new_velo[1] *= x
569
570 if(speed<0.0)
571 {
572 new_velo[0] *= -1
573 new_velo[1] *= -1
574 }
575
576 set_pev(ent,pev_velocity,new_velo)
577 }
578 case 4:
579 {
580 static Float:origin1[3]
581 pev(ent,pev_origin,origin1)
582
583 static Float:new_velo[3]
584
585 new_velo[0] = origin[0] - origin1[0]
586 new_velo[1] = origin[1] - origin1[1]
587 new_velo[2] = origin[2] - origin1[2]
588
589 new Float:y
590 y = new_velo[0]*new_velo[0] + new_velo[1]*new_velo[1] + new_velo[2]*new_velo[2]
591
592 new Float:x
593 if(y) x = floatsqroot(speed*speed / y)
594
595 new_velo[0] *= x
596 new_velo[1] *= x
597 new_velo[2] *= x
598
599 if(speed<0.0)
600 {
601 new_velo[0] *= -1
602 new_velo[1] *= -1
603 new_velo[2] *= -1
604 }
605
606 set_pev(ent,pev_velocity,new_velo)
607 }
608 default: return 0;
609 }
610 return 1;
611 }
612
613
614
615 /*
616 *
617 * Determines if 2 floats are within "difference"
618 * between eachother.
619 *
620 * Example: 2.0 is within 5.0 "difference" of 7.0
621 *
622 */
623
624 stock is_within_difference(Float:number1,Float:number2,Float:difference)
625 {
626 if(floatabs(number2 - number1) <= difference)
627 return 1;
628
629 return 0;
630 }
631
632
633
634 /*
635 *
636 * Determines if point[2] is inside of polygon[20][2].
637 * Returns 1 if it is and 0 if it isn't.
638 *
639 * Any polygon of any shape can be put into the polygon
640 * array. MAX_SIDES define has to be changed for more
641 * than 20 sides.
642 *
643 * numsides if the number of sides put into polygon[20][2].
644 *
645 * Example Usage:
646 *
647 * new Float:square[MAX_SIDES][2], Float:point[2]
648 * point[0] = 0.0
649 * point[1] = 0.0
650 *
651 * //4 sides are made up between the 4 points.
652 * //The sides make up a square if you connect
653 * //the points.
654 * square[0][0] = 10.0
655 * square[0][1] = 10.0
656 * square[1][0] = 10.0
657 * square[1][1] = -10.0
658 * square[2][0] = -10.0
659 * square[2][1] = -10.0
660 * square[3][0] = -10.0
661 * square[3][1] = 10.0
662 *
663 * //will return 1 because (0,0) is
664 * //inside the polygon made by the array.
665 * is_inside(point,square,4)
666 *
667 */
668
669 #define MAX_SIDES 20
670
671 stock is_inside(const Float:point[2],const Float:polygon[MAX_SIDES][2],numsides)
672 {
673 if(numsides>MAX_SIDES || numsides<3)
674 return 0;
675
676 new num, Float:slope1, Float:slope2, Float:x, Float:y, i2
677
678 if(point[0]==100.0)
679 slope2 = (point[1] - 100.0) / 0.000001
680 else
681 slope2 = (point[1] - 100.0) / (point[0] - 100.00)
682
683 for(new i=0;i<numsides;i++)
684 {
685 i2 = i+1
686 if(i2==numsides) i2=0
687
688 if(polygon[i][0]==polygon[i2][0]) polygon[i2][0] += 0.1
689
690 slope1 = (polygon[i][1] - polygon[i2][1]) / (polygon[i][0] - polygon[i2][0])
691
692 if(slope1!=slope2)
693 {
694 x=(polygon[i][1] + slope2*point[0] - point[1] - slope1*polygon[i][0]) / (slope2 - slope1)
695 y = slope2*(x - point[0]) + point[1]
696 if(
697 !(y>polygon[i][1] && y>polygon[i2][1]) &&
698 !(y<polygon[i][1] && y<polygon[i2][1]) &&
699 !(x>polygon[i][0] && x>polygon[i2][0]) &&
700 !(x<polygon[i][0] && x<polygon[i2][0]) &&
701 !(x==polygon[i][0] && y==polygon[i][1]) &&
702 (x>point[0])
703 )
704 {
705 num++
706 }
707 }
708 }
709
710 new Float:num2 = float(num) / 2.0
711
712 if(num2==float(floatround(num2))) return 0;
713
714 return 1;
715 }
716
717
718
719 /*
720 *
721 * Returns the distance origin[3] is at its closest
722 * location to the line drawn from start[3] to end[3]
723 *
724 * &is_visible is filled with 1 if origin[3] is visible
725 * by the line at its nearest point, 0 if it is not
726 *
727 */
728
729 stock Float:distance_from_line(Float:start[3],Float:end[3],Float:origin[3],&is_visible)
730 {
731 new Float:deltas[3]
732 deltas[0] = (start[1] - end[1]) / (start[0] - end[0])
733 deltas[1] = (start[2] - end[2]) / (start[1] - end[1])
734 deltas[2] = (start[1] - end[1]) / (start[2] - end[2])
735
736 static Float:origin2[3]
737 origin2[2] = origin[2]
738 origin2[1] = (deltas[2] * (origin2[2] - start[2])) + start[1]
739 origin2[0] = ((deltas[0] * start[0]) + origin2[1] - start[1]) / deltas[0]
740
741 static Float:hit[3]
742 engfunc(EngFunc_TraceLine,origin,origin2,1,0,0)
743 get_tr2(0,TR_vecEndPos,hit)
744 if(hit[0]==origin2[0] && hit[1]==origin2[1] && hit[2]==origin2[2])
745 is_visible = 1
746 else
747 is_visible = 0
748
749
750 return get_distance_f(origin,origin2)
751 }