-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathesp.lua
1150 lines (927 loc) · 39.3 KB
/
esp.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
local scriptver = 'v1.2.1'
if ( _G.RadarKill ) then
_G.RadarKill()
end
--- Settings ---
local existingSettings = _G.RadarSettings or {}
local settings = {
-- Radar settings
RADAR_LINES = true; -- Displays distance rings
RADAR_SCALE = 1; -- Controls how "zoomed in" the radar display is
RADAR_RADIUS = 125; -- The size of the radar itself
RADAR_LINE_DISTANCE = 50; -- The distance between each line
RADAR_ROTATION = true; -- Toggles radar rotation. Looks kinda trippy when disabled
SMOOTH_ROT = true; -- Rotates the radar smoothly
SMOOTH_ROT_AMNT = 20; -- Lower number is smoother, higher number is snappier
CARDINAL_DISPLAY = true; -- Displays each cardinal direction (NSWE) around the radar
-- Marker settings
USE_QUADS = true; -- Displays radar markers as arrows instead of dots
OFFSCREEN_TRANSPARENCY = 0.3; -- Transparency of offscreen markers
DISPLAY_TEAM_COLORS = true; -- Sets the radar markers' color to their player's team color
DISPLAY_OFFSCREEN = true; -- Leaves offscreen markers visible
DISPLAY_TEAMMATES = true; -- Shows your teammates' markers
MARKER_SCALEMIN = 0.75; -- Minimium scale radar markers can be. Marker falloff bypasses this limit!
MARKER_SCALEMAX = 1.75; -- Maximum scale radar markers can be. Marker falloff bypasses this limit!
MARKER_FALLOFF = false; -- Affects the markers' scale depending on how far away the player is
MARKER_FALLOFF_AMNT = 500; -- How close someone has to be for falloff to start affecting them
-- Theme
RADAR_THEME = {
Outline = Color3.fromRGB(35, 35, 45); -- Radar outline
Background = Color3.fromRGB(25, 25, 35); -- Radar background
DragHandle = Color3.fromRGB(50, 50, 255); -- Drag handle
Cardinal_Lines = Color3.fromRGB(110, 110, 120); -- Color of the horizontal and vertical lines
Distance_Lines = Color3.fromRGB(65, 65, 75); -- Color of the distance rings
Generic_Marker = Color3.fromRGB(255, 25, 115); -- Color of a player marker without a team
Local_Marker = Color3.fromRGB(115, 25, 255); -- Color of your marker, regardless of team
};
}
for k, v in pairs(existingSettings) do
if ( v ~= nil ) then
settings[k] = v
end
end
-- localize each setting (settings aren't meant to be changed during runtime)
local RADAR_LINES = settings.RADAR_LINES
local RADAR_SCALE = settings.RADAR_SCALE
local RADAR_RADIUS = settings.RADAR_RADIUS
local RADAR_LINE_DISTANCE = settings.RADAR_LINE_DISTANCE
local RADAR_ROTATION = settings.RADAR_ROTATION
local SMOOTH_ROT = settings.SMOOTH_ROT
local SMOOTH_ROT_AMNT = settings.SMOOTH_ROT_AMNT
local CARDINAL_DISPLAY = settings.CARDINAL_DISPLAY
local USE_QUADS = settings.USE_QUADS
local OFFSCREEN_TRANSPARENCY = settings.OFFSCREEN_TRANSPARENCY
local DISPLAY_TEAM_COLORS = settings.DISPLAY_TEAM_COLORS
local DISPLAY_OFFSCREEN = settings.DISPLAY_OFFSCREEN
local DISPLAY_TEAMMATES = settings.DISPLAY_TEAMMATES
local MARKER_SCALEMIN = settings.MARKER_SCALEMIN
local MARKER_SCALEMAX = settings.MARKER_SCALEMAX
local MARKER_FALLOFF = settings.MARKER_FALLOFF
local MARKER_FALLOFF_AMNT = settings.MARKER_FALLOFF_AMNT
local RADAR_THEME = settings.RADAR_THEME
--- Services ---
local inputService = game:GetService('UserInputService')
local runService = game:GetService('RunService')
local playerService = game:GetService('Players')
--- Localization ---
local newV2 = Vector2.new
local newV3 = Vector3.new
local mathSin = math.sin
local mathCos = math.cos
local mathExp = math.exp
--- Script connections ---
local scriptCns = {}
--- Other variables
local markerScale = math.clamp(RADAR_SCALE, MARKER_SCALEMIN, MARKER_SCALEMAX)
local scaleVec = newV2(markerScale, markerScale)
local quadPointA = newV2(0, 5) * scaleVec
local quadPointB = newV2(4, -5) * scaleVec
local quadPointC = newV2(0, -3) * scaleVec
local quadPointD = newV2(-4, -5) * scaleVec
--- Drawing setup ---
local drawObjects = {}
local function newDrawObj(objectClass, objectProperties) -- this method is cringe but it's easy to work with
local obj = Drawing.new(objectClass)
table.insert(drawObjects, obj)
for i, v in pairs(objectProperties) do
obj[i] = v
end
objectProperties = nil
return obj
end
-- Drawing tween function
local drawingTween do -- obj property dest time
local function numLerp(a, b, c)
return (1 - c) * a + c * b
end
local tweenTypes = {}
tweenTypes.Vector2 = Vector2.zero.Lerp
tweenTypes.number = numLerp
tweenTypes.Color3 = Color3.new().Lerp
function drawingTween(obj, property, dest, duration)
task.spawn(function()
local initialVal = obj[property]
local tweenTime = 0
local lerpFunc = tweenTypes[typeof(dest)]
while ( tweenTime < duration ) do
obj[property] = lerpFunc(initialVal, dest, 1 - math.pow(2, -10 * tweenTime / duration))
local deltaTime = task.wait()
tweenTime += deltaTime
end
obj[property] = dest
end)
end
end
--- Local object manager ---
local clientPlayer = playerService.LocalPlayer
local clientRoot, clientHumanoid do
scriptCns.charRespawn = clientPlayer.CharacterAdded:Connect(function(newChar)
clientRoot = newChar:WaitForChild('HumanoidRootPart')
clientHumanoid = newChar:WaitForChild('Humanoid')
end)
if ( clientPlayer.Character ) then
clientRoot = clientPlayer.Character:FindFirstChild('HumanoidRootPart')
clientHumanoid = clientPlayer.Character:FindFirstChild('Humanoid')
end
end
local clientCamera do
scriptCns.cameraUpdate = workspace:GetPropertyChangedSignal('CurrentCamera'):Connect(function()
clientCamera = workspace.CurrentCamera or workspace:FindFirstChildOfClass('Camera')
end)
clientCamera = workspace.CurrentCamera or workspace:FindFirstChildOfClass('Camera')
end
local clientTeam do
scriptCns.teamUpdate = clientPlayer:GetPropertyChangedSignal('Team'):Connect(function()
clientTeam = clientPlayer.Team
end)
clientTeam = clientPlayer.Team
end
--- PlaceID Check ---
do
local id = game.PlaceId
if ( id == 292439477 or id == 3233893879 ) then
local notif = Drawing.new('Text')
notif.Center = true
notif.Color = Color3.fromRGB(255, 255, 255)
notif.Font = Drawing.Fonts.UI
notif.Outline = true
notif.Position = newV2(clientCamera.ViewportSize.X / 2, 200)
notif.Size = 30
notif.Text = 'Games with custom character systems\naren\'t supported. Sorry!'
notif.Transparency = 0
notif.Visible = true
drawingTween(notif, 'Transparency', 1, 0.25)
drawingTween(notif, 'Position', newV2(clientCamera.ViewportSize.X / 2, 150), 0.25)
task.wait(5)
drawingTween(notif, 'Position', newV2(clientCamera.ViewportSize.X / 2, 200), 0.25)
drawingTween(notif, 'Transparency', 0, 0.25)
task.wait(3)
for _, con in pairs(scriptCns) do
con:Disconnect()
end
notif:Remove()
return
else
-- might as well place control notification here
local notif = Drawing.new('Text')
notif.Center = true
notif.Color = Color3.fromRGB(255, 255, 255)
notif.Font = Drawing.Fonts.UI
notif.Outline = true
notif.Position = newV2(clientCamera.ViewportSize.X / 2, 200)
notif.Size = 22
notif.Text = ('Loaded Drawing Radar %s\n\nControls:\n[-]: zoom out [+]: zoom in [End]: exit script'):format(scriptver)
notif.Transparency = 0
notif.Visible = true
task.spawn(function()
task.wait(1)
drawingTween(notif, 'Transparency', 1, 0.25)
drawingTween(notif, 'Position', newV2(clientCamera.ViewportSize.X / 2, 150), 0.25)
task.wait(8)
drawingTween(notif, 'Position', newV2(clientCamera.ViewportSize.X / 2, 200), 0.25)
drawingTween(notif, 'Transparency', 0, 0.25)
task.wait(1)
if ( workspace.StreamingEnabled ) then
notif.Text = 'It looks like this game uses StreamingEnabled, which may mess with the radar!\nSorry if it doesn\'t work!'
drawingTween(notif, 'Transparency', 1, 0.25)
drawingTween(notif, 'Position', newV2(clientCamera.ViewportSize.X / 2, 150), 0.25)
task.wait(5)
drawingTween(notif, 'Position', newV2(clientCamera.ViewportSize.X / 2, 200), 0.25)
drawingTween(notif, 'Transparency', 0, 0.25)
task.wait(1)
end
notif:Remove()
end)
end
end
--- Player managers ---
local playerManagers = {}
do
local function removePlayer(player)
local thisName = player.Name
local thisManager = playerManagers[thisName]
local thisPlayerCns = thisManager.Cns
if ( thisManager.onLeave ) then
thisManager.onLeave()
end
for _, con in pairs(thisPlayerCns) do
con:Disconnect()
end
thisManager.onDeath = nil
thisManager.onLeave = nil
thisManager.onRemoval = nil
thisManager.onRespawn = nil
thisManager.onTeamChange = nil
thisManager.Player = nil
playerManagers[thisName] = nil
end
local function readyPlayer(thisPlayer)
local thisName = thisPlayer.Name
local thisManager = {}
local thisPlayerCns = {}
local function deathFunc() -- Reusable on-death function - done so the same function doesnt get made 9138589135 times
if ( thisManager.onDeath ) then
thisManager.onDeath()
end
end
-- Setup connections
thisPlayerCns['chr-add'] = thisPlayer.CharacterAdded:Connect(function(newChar) -- This handles when a player respawns
-- Get some important instances
local RootPart = newChar:WaitForChild('HumanoidRootPart')
local Humanoid = newChar:WaitForChild('Humanoid')
-- Call onRespawn
if ( thisManager.onRespawn ) then
thisManager.onRespawn(newChar, RootPart, Humanoid)
end
-- Update manager values
thisManager.Character = newChar
thisManager.RootPart = RootPart
thisManager.Humanoid = Humanoid
-- Re-connect the death connection
if ( thisPlayerCns['chr-die'] ) then
thisPlayerCns['chr-die']:Disconnect()
end
thisPlayerCns['chr-die'] = Humanoid.Died:Connect(deathFunc)
end)
thisPlayerCns['chr-remove'] = thisPlayer.CharacterRemoving:Connect(function() -- This handles when a player's character gets removed
-- Call onRemoval
if ( thisManager.onRemoval ) then
thisManager.onRemoval()
end
-- Update manager values
thisManager.Character = nil
thisManager.RootPart = nil
thisManager.Humanoid = nil
end)
thisPlayerCns['team'] = thisPlayer:GetPropertyChangedSignal('Team'):Connect(function() -- This handles team changing, self explanatory
thisManager.Team = thisPlayer.Team
if ( thisManager.onTeamChange ) then
thisManager.onTeamChange(thisManager.Team)
end
end)
-- Check for an existing character
if ( thisPlayer.Character ) then
-- Fetch some stuff
local Character = thisPlayer.Character
local Humanoid = Character:FindFirstChild('Humanoid')
local RootPart = Character:FindFirstChild('HumanoidRootPart')
-- Set manager values
thisManager.Character = Character
thisManager.RootPart = RootPart
thisManager.Humanoid = Humanoid
if ( Humanoid ) then
-- Setup death connection *only if the humanoid exists*
-- This previously wasn't checked for which probably constantly errored, oops 🗿
thisPlayerCns['chr-die'] = Humanoid.Died:Connect(deathFunc)
end
end
-- Set existing values
thisManager.Team = thisPlayer.Team
thisManager.Player = thisPlayer
thisManager.Name = thisName
thisManager.DisplayName = thisPlayer.DisplayName
-- Finalize
thisManager.Cns = thisPlayerCns
playerManagers[thisName] = thisManager
end
-- Setup managers for every existing player
for _, player in ipairs(playerService:GetPlayers()) do
if ( player ~= clientPlayer ) then
readyPlayer(player)
end
end
-- Setup managers for joining players, and clean managers for leaving players
scriptCns.pm_playerAdd = playerService.PlayerAdded:Connect(readyPlayer)
scriptCns.pm_playerRemove = playerService.PlayerRemoving:Connect(removePlayer)
end
--- Plugin managers ---
-- The ability to make custom plugins / add-ons for the radar
-- (to add stuff like npc support) might be developed eventually!
--- Radar UI ---
local radarLines = {}
local radarObjects = {}
local radarPosition = newV2(300, 250)
radarObjects.main = newDrawObj('Circle', {
Color = RADAR_THEME.Background;
Position = radarPosition;
Filled = true;
Visible = true;
NumSides = 40;
Radius = RADAR_RADIUS;
ZIndex = 300;
})
radarObjects.outline = newDrawObj('Circle', {
Color = RADAR_THEME.Outline;
Position = radarPosition;
Filled = false;
Visible = true;
NumSides = 40;
Thickness = 10;
Radius = RADAR_RADIUS;
ZIndex = 299;
})
radarObjects.dragHandle = newDrawObj('Circle', {
Color = RADAR_THEME.DragHandle;
Position = radarPosition;
Filled = false;
Visible = false;
NumSides = 40;
Radius = RADAR_RADIUS;
Thickness = 3;
ZIndex = 325;
})
radarObjects.zoomText = newDrawObj('Text', {
Center = true;
Color = Color3.fromRGB(255, 255, 255);
Font = Drawing.Fonts.UI;
Outline = true;
Size = 20;
Transparency = 0;
Visible = true;
ZIndex = 305;
})
radarObjects.hoverText = newDrawObj('Text', {
Center = true;
Color = Color3.fromRGB(255, 255, 255);
Font = Drawing.Fonts.UI;
Outline = true;
Size = 16;
Transparency = 1;
Visible = true;
ZIndex = 305;
})
-- center marker
if ( USE_QUADS ) then
radarObjects.centerMark = newDrawObj('Quad', {
Color = RADAR_THEME.Local_Marker;
PointA = radarPosition + quadPointA;
PointB = radarPosition + quadPointB;
PointC = radarPosition + quadPointC;
PointD = radarPosition + quadPointD;
Filled = true;
Visible = true;
ZIndex = 303;
Thickness = 2;
})
else
radarObjects.centerMark = newDrawObj('Circle', {
Color = RADAR_THEME.Local_Marker;
Position = radarPosition;
Filled = true;
Visible = true;
NumSides = 20;
Radius = 3 * markerScale;
Thickness = 2;
ZIndex = 303;
})
end
-- lines
if ( RADAR_LINES ) then
for i = 0, RADAR_RADIUS, RADAR_SCALE * RADAR_LINE_DISTANCE do
local thisLine = newDrawObj('Circle', {
Color = RADAR_THEME.Distance_Lines;
Position = radarPosition;
Radius = i;
Filled = false;
Visible = true;
Transparency = ((i / RADAR_LINE_DISTANCE) % 4 == 0) and 0.8 or 0.2;
NumSides = 40;
Thickness = 1;
ZIndex = 300;
})
table.insert(radarLines, thisLine)
end
radarObjects.horizontalLine = newDrawObj('Line', {
Color = RADAR_THEME.Cardinal_Lines;
From = radarPosition - newV2(RADAR_RADIUS, 0);
To = radarPosition + newV2(RADAR_RADIUS, 0);
Visible = true;
Thickness = 1;
Transparency = 0.2;
ZIndex = 300;
})
radarObjects.verticalLine = newDrawObj('Line', {
Color = RADAR_THEME.Cardinal_Lines;
From = radarPosition - newV2(0, RADAR_RADIUS);
To = radarPosition + newV2(0, RADAR_RADIUS);
Visible = true;
Thickness = 1;
Transparency = 0.2;
ZIndex = 300;
})
else
radarLines = nil
end
-- NSWE display
if ( CARDINAL_DISPLAY ) then
radarObjects.directionN = newDrawObj('Text', {
Center = true;
Color = Color3.fromRGB(255, 255, 255);
Font = Drawing.Fonts.UI;
Outline = true;
Size = 16;
Text = 'N';
Transparency = 1;
Visible = true;
ZIndex = 303;
})
radarObjects.directionS = newDrawObj('Text', {
Center = true;
Color = Color3.fromRGB(255, 255, 255);
Font = Drawing.Fonts.UI;
Outline = true;
Size = 16;
Text = 'S';
Transparency = 1;
Visible = true;
ZIndex = 303;
})
radarObjects.directionW = newDrawObj('Text', {
Center = true;
Color = Color3.fromRGB(255, 255, 255);
Font = Drawing.Fonts.UI;
Outline = true;
Size = 16;
Text = 'W';
Transparency = 1;
Visible = true;
ZIndex = 303;
})
radarObjects.directionE = newDrawObj('Text', {
Center = true;
Color = Color3.fromRGB(255, 255, 255);
Font = Drawing.Fonts.UI;
Outline = true;
Size = 16;
Text = 'E';
Transparency = 1;
Visible = true;
ZIndex = 303;
})
end
--- Other functions
local destroying = false
local function killScript()
if ( destroying ) then
return
end
destroying = true
for _, con in pairs(scriptCns) do
con:Disconnect()
end
task.wait()
for name, manager in pairs(playerManagers) do
for _, con in pairs(manager.Cns) do
con:Disconnect()
end
-- just in case
playerManagers.onDeath = nil
playerManagers.onLeave = nil
playerManagers.onRespawn = nil
playerManagers.onRemoval = nil
playerManagers.onTeamChange = nil
playerManagers[name] = nil
end
for _, obj in ipairs(drawObjects) do
drawingTween(obj, 'Transparency', 0, 0.5)
end
task.wait(1)
if ( not drawObjects ) then
return
end
for _, obj in ipairs(drawObjects) do
obj:Remove()
_G.RadarKill = nil
end
drawObjects = nil
end
local function setRadarScale()
markerScale = math.clamp(RADAR_SCALE, MARKER_SCALEMIN, MARKER_SCALEMAX)
if ( RADAR_LINES ) then
-- Calculate how many radar lines can fit at this scale
local lineCount = math.floor(RADAR_RADIUS / (RADAR_SCALE * RADAR_LINE_DISTANCE))
-- If more lines can fit than there are made, make more
if ( lineCount > #radarLines ) then
for i = 1, lineCount - #radarLines do
local thisLine = newDrawObj('Circle', {
Color = RADAR_THEME.Distance_Lines;
Position = radarPosition;
Filled = false;
Visible = true;
NumSides = 40;
Thickness = 1;
ZIndex = 300;
})
table.insert(radarLines, thisLine)
end
end
-- Position every single line
for idx, line in ipairs(radarLines) do
if ( idx > lineCount ) then
-- This line wont fit, hide it
line.Visible = false
else
-- This line fits, set its radius and display it
line.Radius = idx * (RADAR_SCALE * RADAR_LINE_DISTANCE)
line.Transparency = (idx % 4 == 0) and 0.8 or 0.2
line.Visible = true
end
end
end
if ( USE_QUADS ) then
scaleVec = newV2(markerScale, markerScale)
quadPointA = newV2(0, 5) * scaleVec
quadPointB = newV2(4, -5) * scaleVec
quadPointC = newV2(0, -3) * scaleVec
quadPointD = newV2(-4, -5) * scaleVec
else
radarObjects.centerMark.Radius = 3 * markerScale
end
end
local function setRadarPosition(newPosition)
radarPosition = newPosition
radarObjects.main.Position = newPosition
radarObjects.outline.Position = newPosition
if ( RADAR_LINES ) then
for _, line in ipairs(radarLines) do
line.Position = newPosition
end
radarObjects.horizontalLine.From = newPosition - newV2(RADAR_RADIUS, 0);
radarObjects.horizontalLine.To = newPosition + newV2(RADAR_RADIUS, 0);
radarObjects.verticalLine.From = newPosition - newV2(0, RADAR_RADIUS);
radarObjects.verticalLine.To = newPosition + newV2(0, RADAR_RADIUS);
end
end
--- Input and drag handling
do
local radarDragging = false
local radarHovering = false
local zoomingIn = false
local zoomingOut = false
-- The keycode is only checked if its found in this dictionary,
-- just so a giant elif chain isnt done on every keypress
local keysToCheck = {
End = true;
Equals = true;
Minus = true;
}
scriptCns.inputBegan = inputService.InputBegan:Connect(function(io)
local inputType = io.UserInputType.Name
if ( inputType == 'Keyboard' ) then
local keyCode = io.KeyCode.Name
if ( not keysToCheck[keyCode] ) then
return
end
if ( keyCode == 'End' ) then
killScript()
elseif ( keyCode == 'Equals' ) then
zoomingIn = true
local zoomText = radarObjects.zoomText
zoomText.Position = radarPosition + newV2(0, RADAR_RADIUS + 25)
drawingTween(zoomText, 'Transparency', 1, 0.3)
local accel = 0.1
scriptCns.zoomInCn = runService.Heartbeat:Connect(function(deltaTime)
RADAR_SCALE = math.clamp(RADAR_SCALE + (deltaTime * accel), 0.02, 3)
accel += deltaTime
zoomText.Text = ('Scale: %.2f'):format(RADAR_SCALE)
setRadarScale()
end)
elseif ( keyCode == 'Minus' ) then
zoomingOut = true
local zoomText = radarObjects.zoomText
zoomText.Position = radarPosition + newV2(0, RADAR_RADIUS + 25)
drawingTween(zoomText, 'Transparency', 1, 0.3)
local accel = 0.1
scriptCns.zoomOutCn = runService.Heartbeat:Connect(function(deltaTime)
RADAR_SCALE = math.clamp(RADAR_SCALE - (deltaTime * accel), 0.02, 3)
accel += deltaTime
zoomText.Text = ('Scale: %.2f'):format(RADAR_SCALE)
setRadarScale()
end)
end
elseif ( inputType == 'MouseButton1' ) then
local mousePos = inputService:GetMouseLocation()
if ( (mousePos - radarPosition).Magnitude < RADAR_RADIUS ) then
radarDragging = true
radarObjects.dragHandle.Visible = true
scriptCns.dragCn = inputService.InputChanged:Connect(function(io)
if ( io.UserInputType.Name == 'MouseMovement' ) then
local mousePos = inputService:GetMouseLocation()
radarObjects.dragHandle.Position = mousePos
end
end)
end
end
end)
scriptCns.inputEnded = inputService.InputEnded:Connect(function(io)
local inputType = io.UserInputType.Name
if ( inputType == 'Keyboard' ) then
local keyCode = io.KeyCode.Name
if ( not keysToCheck[keyCode] ) then
return
end
if ( keyCode == 'Equals' ) then
zoomingIn = false
drawingTween(radarObjects.zoomText, 'Transparency', 0, 0.3)
local zoomCn = scriptCns.zoomInCn
if ( zoomCn and zoomCn.Connected ) then
zoomCn:Disconnect()
end
elseif ( keyCode == 'Minus' ) then
zoomingOut = false
drawingTween(radarObjects.zoomText, 'Transparency', 0, 0.3)
local zoomCn = scriptCns.zoomOutCn
if ( zoomCn and zoomCn.Connected ) then
zoomCn:Disconnect()
end
end
elseif ( inputType == 'MouseButton1' ) then
if ( radarDragging ) then
scriptCns.dragCn:Disconnect()
radarDragging = false
setRadarPosition(radarObjects.dragHandle.Position)
radarObjects.dragHandle.Visible = false
end
end
end)
end
--- Player marker setup
local playerMarks = {} do
local function initMark(thisPlayer)
local thisName = thisPlayer.Name
local thisManager = playerManagers[thisName]
local mark
local text
if ( USE_QUADS ) then
mark = Drawing.new('Quad')
mark.Filled = true
mark.Thickness = 2
mark.Visible = true
mark.ZIndex = 302
else
mark = Drawing.new('Circle')
mark.Filled = true
mark.NumSides = 20
mark.Radius = 3 * markerScale
mark.Thickness = 2
mark.Visible = true
mark.ZIndex = 302
end
text = Drawing.new('Text')
text.Center = true
text.Color = Color3.fromRGB(255, 255, 255)
text.Font = Drawing.Fonts.UI
text.Outline = true
text.Size = 15
text.Text = thisPlayer.DisplayName or thisName
text.Visible = false
text.ZIndex = 305
if ( DISPLAY_TEAM_COLORS ) then
mark.Color = thisManager.Player.TeamColor.Color
else
mark.Color = RADAR_THEME.Generic_Marker
end
table.insert(drawObjects, mark)
table.insert(drawObjects, text)
playerMarks[thisName] = mark
thisManager.onDeath = function()
mark.Filled = false
end
thisManager.onRespawn = function()
mark.Filled = true
end
thisManager.onLeave = function()
table.remove(drawObjects, table.find(drawObjects, mark))
table.remove(drawObjects, table.find(drawObjects, text))
task.spawn(function()
drawingTween(mark, 'Transparency', 0, 1)
task.wait(1.3)
mark:Remove()
end)
text:Remove()
playerMarks[thisName] = nil
end
if ( DISPLAY_TEAM_COLORS ) then
thisManager.onTeamChange = function(team)
mark.Color = team.TeamColor.Color
end
end
end
for _, manager in pairs(playerManagers) do
initMark(manager.Player)
end
scriptCns.addMarks = playerService.PlayerAdded:Connect(function(player)
task.wait(0.1) -- This will hopefully prevent loading issues
initMark(player)
end)
end
local hoverPlayer
-- Hover display
do
local lastCheckTime = 0
scriptCns.inputChanged = inputService.InputChanged:Connect(function(input)
local nowTime = tick() -- Funky optimization
if ( nowTime - lastCheckTime > 0.05 and input.UserInputType.Name == 'MouseMovement' ) then
lastCheckTime = nowTime
local mousePos = inputService:GetMouseLocation()
-- Check if the mouse is inside of the radar
if ( (mousePos - radarPosition).Magnitude < RADAR_RADIUS ) then
-- Get the closest player and set the hover text to their name
local distanceThresh = 900 -- math.huge 🤓🤓🤓🤓🤓🤓🤓
hoverPlayer = nil
for thisName in pairs(playerManagers) do
local thisMark = playerMarks[thisName]
-- safety marker check, in case the player hasnt finished loading in
if ( not thisMark ) then
continue
end
local markPos = thisMark[USE_QUADS and 'PointC' or 'Position']
local distance = (mousePos - markPos).Magnitude
if ( distance < distanceThresh ) then
distanceThresh = distance
hoverPlayer = thisName
end
end
else
hoverPlayer = nil
radarObjects.hoverText.Visible = false
end
end
end)
end
--- Main radar loop
-- Coordinate conversion functions
local function cartToPolar(x, y)
return math.sqrt(x^2 + y^2), math.atan2(y, x)
end
local function polarToCart(r, t)
return r * mathCos(t), r * mathSin(t)
end
do
local finalLookVec = Vector3.zero
local hOffset = newV2(RADAR_RADIUS, 0) -- Horizontal offset
local vOffset = newV2(0, RADAR_RADIUS) -- Vertical offset
local textOffset = newV2(0, 5)
local rad90 = math.rad(90)
local rad180 = math.rad(180)
scriptCns.radarLoop = runService.Heartbeat:Connect(function(deltaTime)
-- Safety rootpart check
if ( not clientRoot ) then
return
end
local selfPos = clientRoot.Position
local camAngle = 0
-- Camera angle
do
if ( RADAR_ROTATION ) then
local cameraLookVec = clientCamera.CFrame.LookVector
local fixedLookVec = newV3(cameraLookVec.X, 0, cameraLookVec.Z).Unit
if ( SMOOTH_ROT ) then
finalLookVec = finalLookVec:Lerp(fixedLookVec, 1 - mathExp(-SMOOTH_ROT_AMNT * deltaTime))
else
finalLookVec = fixedLookVec
end
camAngle = math.atan2(finalLookVec.X, finalLookVec.Z)
end
end
-- Vertical and horizontal lines
do
if ( RADAR_LINES ) then
local top = -vOffset
local bottom = vOffset
local left = -hOffset
local right = hOffset
local angleCos = mathCos(-camAngle)
local angleSin = mathSin(-camAngle)
local fixedTop = radarPosition + newV2((top.X * angleSin) - (top.Y * angleCos), (top.X * angleCos) + (top.Y * angleSin))
local fixedBottom = radarPosition + newV2((bottom.X * angleSin) - (bottom.Y * angleCos), (bottom.X * angleCos) + (bottom.Y * angleSin))
local fixedLeft = radarPosition + newV2((left.X * angleSin) - (left.Y * angleCos), (left.X * angleCos) + (left.Y * angleSin))
local fixedRight = radarPosition + newV2((right.X * angleSin) - (right.Y * angleCos), (right.X * angleCos) + (right.Y * angleSin))
local hLine, vLine = radarObjects.horizontalLine, radarObjects.verticalLine
hLine.From = fixedLeft
hLine.To = fixedRight