use black as formatter

This commit is contained in:
Mylloon 2023-05-05 16:04:06 +02:00
parent bb7bd4e419
commit 271645a0d6
Signed by: Anri
GPG key ID: A82D63DFF8D1317F
13 changed files with 323 additions and 198 deletions

View file

@ -1,18 +1,22 @@
from glob import glob
from hack import Hack
# Import all cheats
backslash = "\\"
for file in glob("cheats/*.py"):
exec(f"from {file.replace(backslash, '.')[:-3]} import *")
class Cheat(*[child for child in Hack.__subclasses__()]): # type: ignore
class Cheat(*[child for child in Hack.__subclasses__()]):
"""All cheats are loaded in this class"""
def __init__(self, **kwargs) -> None:
super().__init__(**kwargs)
self.cheats_list = [func for func in dir(self)
self.cheats_list = [
func
for func in dir(self)
# Function
if callable(getattr(self, func))
# User defined
@ -22,7 +26,8 @@ class Cheat(*[child for child in Hack.__subclasses__()]): # type: ignore
# Unloaders
if not func.endswith("_unload")
# Utils
if not func.startswith("find_")]
if not func.startswith("find_")
]
self.incompatible = dict.fromkeys(self.cheats_list, [])
@ -32,7 +37,8 @@ class Cheat(*[child for child in Hack.__subclasses__()]): # type: ignore
# Builds the implicit list
for cheat, incompatible_cheat_list in self.incompatible.items():
for incompatible_cheat in incompatible_cheat_list:
if not cheat in self.incompatible[incompatible_cheat]:
if cheat not in self.incompatible[incompatible_cheat]:
# Propagate implicit cheat incompatibilities
self.incompatible[incompatible_cheat] = self.incompatible[incompatible_cheat] + [
cheat]
self.incompatible[incompatible_cheat] = self.incompatible[
incompatible_cheat
] + [cheat]

View file

@ -9,10 +9,10 @@ class Aimbot(Hack):
super().__init__(**kwargs)
# AimBot FOV, higher = more aggressive
self.__fov_range = 4.
self.__fov_range = 4.0
# Smoothing, more = less efficient
self.__smoothing = 6.
self.__smoothing = 6.0
def aimbot(self) -> None:
# Aliases
@ -36,36 +36,60 @@ class Aimbot(Hack):
# Where are the eyes
local_eye_pos = Vec(
float(mem.read_float(local_player + offset["m_vecOrigin"])),
float(
mem.read_float(
local_player + offset["m_vecOrigin"]),
local_player + offset["m_vecOrigin"] + offset["float"]
)
),
float(
mem.read_float(
local_player + offset["m_vecOrigin"] + offset["float"]),
local_player + offset["m_vecOrigin"] + offset["float"] * 2
)
),
).plus(
Vec(
float(mem.read_float(local_player + offset["m_vecViewOffset"])),
float(
mem.read_float(
local_player + offset["m_vecOrigin"] + offset["float"] * 2)
).plus(Vec(
local_player + offset["m_vecViewOffset"] + offset["float"]
)
),
float(
mem.read_float(
local_player + offset["m_vecViewOffset"]),
mem.read_float(
local_player + offset["m_vecViewOffset"] + offset["float"]),
mem.read_float(
local_player + offset["m_vecViewOffset"] + offset["float"] * 2)
))
local_player
+ offset["m_vecViewOffset"]
+ offset["float"] * 2
)
),
)
)
# Where player is looking
view_angles = Vec(
float(
mem.read_float(client_state + offset["dwClientState_ViewAngles"])
),
float(
mem.read_float(
client_state + offset["dwClientState_ViewAngles"]),
mem.read_float(
client_state + offset["dwClientState_ViewAngles"] + offset["float"])
client_state
+ offset["dwClientState_ViewAngles"]
+ offset["float"]
)
),
)
# How much the view is modified
aim_punch = Vec(
float(mem.read_float(local_player + offset["m_aimPunchAngle"])),
float(
mem.read_float(
local_player + offset["m_aimPunchAngle"]),
mem.read_float(
local_player + offset["m_aimPunchAngle"] + offset["float"])
).times(2.) # server multiple punch by 2
local_player + offset["m_aimPunchAngle"] + offset["float"]
)
),
).times(
2.0
) # server multiple punch by 2
# Will hold info about the closest ennemy
best_distance = self.__fov_range
@ -73,8 +97,11 @@ class Aimbot(Hack):
# Loop all entities
for i in range(1, 32): # 0 is world
entity = mem.read_uint(
client + offset["dwEntityList"] + i * offset["entity_size"])
entity = int(
mem.read_uint(
client + offset["dwEntityList"] + i * offset["entity_size"]
)
)
# Ignore if entity doesn't exist
if not entity:
@ -82,7 +109,8 @@ class Aimbot(Hack):
# Ignore allies
if mem.read_int(entity + offset["m_iTeamNum"]) == (
mem.read_int(local_player + offset["m_iTeamNum"])):
mem.read_int(local_player + offset["m_iTeamNum"])
):
continue
# Ignore dormant
@ -95,40 +123,55 @@ class Aimbot(Hack):
# Don't aim at ennemy behind a wall
if not (
mem.read_int(entity + offset["m_bSpottedByMask"])
&
(1 << mem.read_int(
client_state + offset["dwClientState_GetLocalPlayer"]))
int(mem.read_int(entity + offset["m_bSpottedByMask"]))
& (
1
<< int(
mem.read_int(
client_state + offset["dwClientState_GetLocalPlayer"]
)
)
)
):
continue
# Find head
boneMatrix = mem.read_uint(entity + offset["m_dwBoneMatrix"])
boneMatrix = int(mem.read_uint(entity + offset["m_dwBoneMatrix"]))
ennemy_head = Vec(
float(
mem.read_float(
boneMatrix + offset["head_idx"] + offset["head_x"]),
boneMatrix + offset["head_idx"] + offset["head_x"]
)
),
float(
mem.read_float(
boneMatrix + offset["head_idx"] + offset["head_y"]),
boneMatrix + offset["head_idx"] + offset["head_y"]
)
),
float(
mem.read_float(
boneMatrix + offset["head_idx"] + offset["head_z"])
boneMatrix + offset["head_idx"] + offset["head_z"]
)
),
)
# Angle to ennemy's head
angle = calculate_angle(
local_eye_pos, ennemy_head, view_angles.plus(aim_punch))
local_eye_pos, ennemy_head, view_angles.plus(aim_punch)
)
# Current FOV
distance = hypot(angle.x, angle.y)
# If an ennemy is close
if (distance < best_distance):
if distance < best_distance:
best_distance = distance
best_angle = angle
# We found an ennemy to aim at
if not best_angle.is_zero():
# Apply the smoothing if needed
if self.__smoothing > 0.:
if self.__smoothing > 0.0:
best_angle = best_angle.div(self.__smoothing)
# Angle from player to ennemy's head
@ -139,13 +182,16 @@ class Aimbot(Hack):
# Move player's view angle
mem.write_float(
client_state + offset["dwClientState_ViewAngles"], final_angle.x)
client_state + offset["dwClientState_ViewAngles"], final_angle.x
)
mem.write_float(
client_state + offset["dwClientState_ViewAngles"] + offset["float"], final_angle.y)
client_state + offset["dwClientState_ViewAngles"] + offset["float"],
final_angle.y,
)
self.hack_loop(cheat)
def calculate_angle(local_pos: Vec, ennemy_pos: Vec, angles: Vec) -> Vec:
"""Angle calculation for aimbot"""
return ((ennemy_pos.minus(local_pos).to_angle().minus(angles)))
return ennemy_pos.minus(local_pos).to_angle().minus(angles)

View file

@ -28,7 +28,7 @@ class Bhop(Hack):
return
# Check if player on ground
if mem.read_uint(local_player + offset["m_fFlags"]) & (1 << 0):
if int(mem.read_uint(local_player + offset["m_fFlags"])) & (1 << 0):
mem.write_uint(client + offset["dwForceJump"], 5)
sleep(0.01)
mem.write_uint(client + offset["dwForceJump"], 4)

View file

@ -8,7 +8,7 @@ class Chams(Hack):
def __init__(self, **kwargs) -> None:
super().__init__(**kwargs)
self.__color = (Color3i(255, 255, 0), 5.)
self.__color = (Color3i(255, 255, 0), 5.0)
self.__default_color = None
def chams(self) -> None:
@ -30,51 +30,70 @@ class Chams(Hack):
def cheat():
# Loop all entities
for i in range(1, 32): # 0 is world
entity = mem.read_uint(
client + offset["dwEntityList"] + i * offset["entity_size"])
entity = int(
mem.read_uint(
client + offset["dwEntityList"] + i * offset["entity_size"]
)
)
# Ignore if entity doesn't exist
if not entity:
continue
# Ignore allies
if mem.read_int(entity + offset["m_iTeamNum"]) == mem.read_int(local_player + offset["m_iTeamNum"]):
if mem.read_int(entity + offset["m_iTeamNum"]) == mem.read_int(
local_player + offset["m_iTeamNum"]
):
continue
# Space between values
i = mem.read_int(
entity + offset["m_iGlowIndex"]) * offset["glow_obj_size"]
i = (
int(mem.read_int(entity + offset["m_iGlowIndex"]))
* offset["glow_obj_size"]
)
if not self.__default_color:
self.__default_color = (
Color3i(
int(
mem.read_uint(
entity + offset["m_clrRender"] + offset["render_R"]),
mem.read_uint(
entity + offset["m_clrRender"] + offset["render_G"]),
mem.read_uint(
entity + offset["m_clrRender"] + offset["render_B"])
entity + offset["m_clrRender"] + offset["render_R"]
)
),
mem.read_int(engine + offset["model_ambient_min"])
int(
mem.read_uint(
entity + offset["m_clrRender"] + offset["render_G"]
)
),
int(
mem.read_uint(
entity + offset["m_clrRender"] + offset["render_B"]
)
),
),
mem.read_int(engine + offset["model_ambient_min"]),
)
# Change color
if color.r > 0:
mem.write_uint(
entity + offset["m_clrRender"] + offset["render_R"], color.r)
entity + offset["m_clrRender"] + offset["render_R"], color.r
)
if color.g > 0:
mem.write_uint(
entity + offset["m_clrRender"] + offset["render_G"], color.g)
entity + offset["m_clrRender"] + offset["render_G"], color.g
)
if color.b > 0:
mem.write_uint(
entity + offset["m_clrRender"] + offset["render_B"], color.b)
entity + offset["m_clrRender"] + offset["render_B"], color.b
)
# Override the brightness of models by increasing
# the minimal brightness value
mem.write_int(
engine + offset["model_ambient_min"],
int.from_bytes(pack("f", brightness), byteorder='little') ^ (
engine + offset["model_ambient_min"] - 0x2C)
int.from_bytes(pack("f", brightness), byteorder="little")
^ (engine + offset["model_ambient_min"] - 0x2C),
)
self.hack_loop(cheat)
@ -94,8 +113,11 @@ class Chams(Hack):
# Loop all entities
for i in range(1, 32): # 0 is world
entity = mem.read_uint(
client + offset["dwEntityList"] + i * offset["entity_size"])
entity = int(
mem.read_uint(
client + offset["dwEntityList"] + i * offset["entity_size"]
)
)
# Ignore if entity doesn't exist
if not entity:
@ -104,12 +126,15 @@ class Chams(Hack):
# Reset to default value if needed
if color.r > 0:
mem.write_uint(
entity + offset["m_clrRender"] + offset["render_R"], color.r)
entity + offset["m_clrRender"] + offset["render_R"], color.r
)
if color.g > 0:
mem.write_uint(
entity + offset["m_clrRender"] + offset["render_G"], color.g)
entity + offset["m_clrRender"] + offset["render_G"], color.g
)
if color.b > 0:
mem.write_uint(
entity + offset["m_clrRender"] + offset["render_B"], color.b)
entity + offset["m_clrRender"] + offset["render_B"], color.b
)
mem.write_int(engine + offset["model_ambient_min"], brightness)

View file

@ -28,7 +28,7 @@ class Fov(Hack):
self.__fov = self.find_uint(local_player, offset["m_iDefaultFOV"])
def cheat():
if self.__fov == None:
if self.__fov is None:
raise ValueError("FOV isn't defined.")
fov = self.__fov
@ -47,8 +47,7 @@ class Fov(Hack):
# If modified
if fov != self.__fov:
# Override the FOV value
mem.write_int(
local_player + offset["m_iDefaultFOV"], self.__fov)
mem.write_int(local_player + offset["m_iDefaultFOV"], self.__fov)
self.hack_loop(cheat)
@ -64,5 +63,4 @@ class Fov(Hack):
# Reset to default value if changed
if self.__fov not in [None, self.__default_fov]:
mem.write_int(
local_player + offset["m_iDefaultFOV"], self.__default_fov)
mem.write_int(local_player + offset["m_iDefaultFOV"], self.__default_fov)

View file

@ -6,7 +6,7 @@ class Glow(Hack):
def __init__(self, **kwargs) -> None:
super().__init__(**kwargs)
self.__color = Color4f(1., 0., 0., .8)
self.__color = Color4f(1.0, 0.0, 0.0, 0.8)
def glow(self) -> None:
# Aliases
@ -20,21 +20,25 @@ class Glow(Hack):
local_player = self.find_uint(client, offset["dwLocalPlayer"])
# Get glow object manager
glow_obj_manager = self.find_uint(
client, offset["dwGlowObjectManager"])
glow_obj_manager = self.find_uint(client, offset["dwGlowObjectManager"])
def cheat():
# Loop all entities
for i in range(1, 32): # 0 is world
entity = mem.read_uint(
client + offset["dwEntityList"] + i * offset["entity_size"])
entity = int(
mem.read_uint(
client + offset["dwEntityList"] + i * offset["entity_size"]
)
)
# Ignore if entity doesn't exist
if not entity:
continue
# Ignore allies
if mem.read_int(entity + offset["m_iTeamNum"]) == mem.read_int(local_player + offset["m_iTeamNum"]):
if mem.read_int(entity + offset["m_iTeamNum"]) == mem.read_int(
local_player + offset["m_iTeamNum"]
):
continue
# Ignore dormant
@ -46,28 +50,33 @@ class Glow(Hack):
continue
# Space between values
i = mem.read_int(
entity + offset["m_iGlowIndex"]) * offset["glow_obj_size"]
i = (
int(mem.read_int(entity + offset["m_iGlowIndex"]))
* offset["glow_obj_size"]
)
# Change color glow
if self.__color.r > 0.:
mem.write_float(glow_obj_manager + i +
offset["glow_R"], self.__color.r)
if self.__color.g > 0.:
mem.write_float(glow_obj_manager + i +
offset["glow_G"], self.__color.g)
if self.__color.b > 0.:
mem.write_float(glow_obj_manager + i +
offset["glow_B"], self.__color.b)
if self.__color.a > 0.:
mem.write_float(glow_obj_manager + i +
offset["glow_A"], self.__color.a)
if self.__color.r > 0.0:
mem.write_float(
glow_obj_manager + i + offset["glow_R"], self.__color.r
)
if self.__color.g > 0.0:
mem.write_float(
glow_obj_manager + i + offset["glow_G"], self.__color.g
)
if self.__color.b > 0.0:
mem.write_float(
glow_obj_manager + i + offset["glow_B"], self.__color.b
)
if self.__color.a > 0.0:
mem.write_float(
glow_obj_manager + i + offset["glow_A"], self.__color.a
)
# Render when not visible
mem.write_bool(glow_obj_manager + i + offset["GOM_wall"], True)
# Render when visible
mem.write_bool(glow_obj_manager + i +
offset["GOM_visible"], True)
mem.write_bool(glow_obj_manager + i + offset["GOM_visible"], True)
self.hack_loop(cheat)

View file

@ -6,8 +6,8 @@ class Noflash(Hack):
def __init__(self, **kwargs) -> None:
super().__init__(**kwargs)
self.__brightness = 30.
self.__default_brightness = 255.
self.__brightness = 30.0
self.__default_brightness = 255.0
def noflash(self) -> None:
# Aliases
@ -24,7 +24,8 @@ class Noflash(Hack):
def cheat():
# Override the brightness value
mem.write_float(
local_player + offset["m_flFlashMaxAlpha"], self.__brightness)
local_player + offset["m_flFlashMaxAlpha"], self.__brightness
)
# Value only overrided on first flash or when server fullupdate
sleep(10)
@ -43,4 +44,5 @@ class Noflash(Hack):
# Reset to default value
mem.write_float(
local_player + offset["m_flFlashMaxAlpha"], self.__default_brightness)
local_player + offset["m_flFlashMaxAlpha"], self.__default_brightness
)

View file

@ -22,37 +22,52 @@ class Norecoil(Hack):
local_player = self.find_uint(client, offset["dwLocalPlayer"])
# Get client state
client_state = mem.read_uint(engine + offset["dwClientState"])
client_state = int(mem.read_uint(engine + offset["dwClientState"]))
def cheat():
# Check if player is shooting
if mem.read_int(local_player + offset["m_iShotsFired"]):
# Where player is looking
view_angles = Vec(
float(
mem.read_float(
client_state + offset["dwClientState_ViewAngles"]),
client_state + offset["dwClientState_ViewAngles"]
)
),
float(
mem.read_float(
client_state + offset["dwClientState_ViewAngles"] + offset["float"])
client_state
+ offset["dwClientState_ViewAngles"]
+ offset["float"]
)
),
)
# Bullet shift
aim_punch = Vec(
float(mem.read_float(local_player + offset["m_aimPunchAngle"])),
float(
mem.read_float(
local_player + offset["m_aimPunchAngle"]),
mem.read_float(
local_player + offset["m_aimPunchAngle"] + offset["float"])
).times(2.) # server multiple punch by 2
local_player + offset["m_aimPunchAngle"] + offset["float"]
)
),
).times(
2.0
) # server multiple punch by 2
# New angles
new_angle = angle_normalizer(view_angles.plus(
self.__old_punch).minus(aim_punch))
new_angle = angle_normalizer(
view_angles.plus(self.__old_punch).minus(aim_punch)
)
# Cancel recoil by moving the player view angle
mem.write_float(
client_state + offset["dwClientState_ViewAngles"], new_angle.x)
client_state + offset["dwClientState_ViewAngles"], new_angle.x
)
mem.write_float(
client_state + offset["dwClientState_ViewAngles"] + offset["float"], new_angle.y)
client_state + offset["dwClientState_ViewAngles"] + offset["float"],
new_angle.y,
)
# Save the current spray value for the next bullet
self.__old_punch = aim_punch

View file

@ -19,15 +19,20 @@ class Radarhack(Hack):
def cheat():
# Loop all entities
for i in range(1, 32): # 0 is world
entity = mem.read_uint(
client + offset["dwEntityList"] + i * offset["entity_size"])
entity = int(
mem.read_uint(
client + offset["dwEntityList"] + i * offset["entity_size"]
)
)
# Ignore if entity doesn't exist
if not entity:
continue
# Ignore allies
if mem.read_int(entity + offset["m_iTeamNum"]) == mem.read_int(local_player + offset["m_iTeamNum"]):
if mem.read_int(entity + offset["m_iTeamNum"]) == mem.read_int(
local_player + offset["m_iTeamNum"]
):
continue
# Ignore dormant

View file

@ -28,16 +28,20 @@ class Trigger(Hack):
return
# Get crosshair info about what we aiming at
crosshair_id = mem.read_int(
local_player + offset["m_iCrosshairId"])
crosshair_id = int(mem.read_int(local_player + offset["m_iCrosshairId"]))
# 0 is wall, +64 isn't a player
if (crosshair_id == 0) or (crosshair_id > 64):
return
# Get ennemy under crosshair
ennemy = mem.read_uint(
client + offset["dwEntityList"] + (crosshair_id - 1) * offset["entity_size"])
ennemy = int(
mem.read_uint(
client
+ offset["dwEntityList"]
+ (crosshair_id - 1) * offset["entity_size"]
)
)
# Ignore dormant
if mem.read_bool(ennemy + offset["m_bDormant"]):
@ -48,7 +52,9 @@ class Trigger(Hack):
return
# Ignore allies
if mem.read_int(ennemy + offset["m_iTeamNum"]) == mem.read_int(local_player + offset["m_iTeamNum"]):
if mem.read_int(ennemy + offset["m_iTeamNum"]) == mem.read_int(
local_player + offset["m_iTeamNum"]
):
return
# Shoot

23
hack.py
View file

@ -5,7 +5,7 @@ from pymem import Pymem
from requests import get
class Hack():
class Hack:
"""Base class for playing with CSGO memory"""
def __init__(self, offline: bool = False) -> None:
@ -29,10 +29,14 @@ class Hack():
serial_data = load(f)
else:
hazedumper_data = get(
"https://raw.githubusercontent.com/frk1/hazedumper/master/csgo.min.json")
"https://raw.githubusercontent.com/frk1/hazedumper/master/csgo.min.json"
)
serial_data = loads(hazedumper_data.text)
return serial_data["signatures"] | serial_data["netvars"] | {
return (
serial_data["signatures"]
| serial_data["netvars"]
| {
"entity_size": 0x10,
"glow_obj_size": 0x38,
"glow_R": 0x8,
@ -50,6 +54,7 @@ class Hack():
"head_y": 0x1C,
"head_z": 0x2C,
}
)
def _find_keys(self) -> dict[str, int]:
"""https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes"""
@ -65,14 +70,13 @@ class Hack():
def _find_process(self, verbose: bool = False) -> Pymem:
"""Find game process"""
process_found = False
print("Looking for process... ", end="",
flush=True) if verbose else None
print("Looking for process... ", end="", flush=True) if verbose else None
pm = None
while not process_found:
try:
pm = Pymem("csgo.exe")
except:
except: # noqa: E722
try:
sleep(self.timeout)
except KeyboardInterrupt:
@ -97,7 +101,8 @@ class Hack():
return found
else:
raise MemoryError(
"Maybe the game isn't fully loaded yet? Wait for menu screen")
"Maybe the game isn't fully loaded yet? Wait for menu screen"
)
def find_uint(self, base, offset: int) -> int:
"""Find unsigned integer in memory for sure"""
@ -107,11 +112,11 @@ class Hack():
sleep(self.timeout)
return local_element
return int(local_element)
def hack_loop(self, method, time: float | None = None):
"""Run the hack loop"""
if time == None:
if time is None:
time = self.wait_time
while True:

17
main.py
View file

@ -22,15 +22,16 @@ if __name__ == "__main__":
args = {}
wanted_list = []
if (len(argv) > 1):
if len(argv) > 1:
# User wanna use offline offsets
if "--offline" in argv:
args["offline"] = True
# User gave a list of cheats
# Will bypass the interactive selection
wanted_list = [j for j in [i for i in argv if i.startswith(
"--list=")][0][7:].split(",")]
wanted_list = [
j for j in [i for i in argv if i.startswith("--list=")][0][7:].split(",")
]
# Load cheat class
c = Cheat(**args)
@ -39,9 +40,11 @@ if __name__ == "__main__":
c_id = [c.cheats_list.index(cheat) for cheat in wanted_list]
# Interactive selection
if (c_id == []):
if c_id == []:
# Cheat list
print("You can run multiples cheat at once, separate your choices with a space.")
print(
"You can run multiples cheat at once, separate your choices with a space."
)
print("Available cheats:")
for idx, cheat in enumerate(c.cheats_list):
print(f"#{idx + 1} - {cheat}")
@ -50,13 +53,13 @@ if __name__ == "__main__":
try:
response = [int(i) for i in input("Enter ID: ").split(" ")]
for i in response:
if (i > len(c.cheats_list) or i <= 0):
if i > len(c.cheats_list) or i <= 0:
raise IndexError
c_id.append(i - 1)
except KeyboardInterrupt:
print("Bye")
exit(1)
except:
except: # noqa: E722
c_id = []
print("Invalid ID.")

View file

@ -4,8 +4,13 @@ from math import atan2, hypot, pi
class Vec:
"""Support : `Vec2i | Vec2f | Vec3i | Vec3f`"""
def __init__(self, x: int | float | None = None, y: int | float | None = None, z: int | float | None = None) -> None:
if x != None:
def __init__(
self,
x: int | float | None = None,
y: int | float | None = None,
z: int | float | None = None,
) -> None:
if x is not None:
self.new(x, y, z)
else:
self.x = 0
@ -14,7 +19,7 @@ class Vec:
def new(self, x: int | float, y: int | float | None, z: int | float | None) -> None:
"""Change values of Vector"""
if y == None:
if y is None:
raise TypeError
# Determine type of class
@ -29,7 +34,7 @@ class Vec:
self.x = self.type(x)
self.y = self.type(y)
if z == None:
if z is None:
self.z = None
else:
self.z = self.type(z)
@ -39,84 +44,84 @@ class Vec:
x = round(self.x, max_precision)
y = round(self.y, max_precision)
z = None if self.z == None else round(self.z, max_precision)
z = None if self.z is None else round(self.z, max_precision)
return f"{self.__class__.__name__}({x}, {y}{'' if z == None else f', {z}'})"
return f"{self.__class__.__name__}({x}, {y}{'' if z is None else f', {z}'})"
def plus(self, other: 'Vec') -> 'Vec':
def plus(self, other: "Vec") -> "Vec":
"""Add 2 vectors"""
x = self.x + other.x
y = self.y + other.y
if self.z == None or other.z == None:
if self.z is None or other.z is None:
return Vec(x, y)
return Vec(x, y, self.z + other.z)
def minus(self, other: 'Vec') -> 'Vec':
def minus(self, other: "Vec") -> "Vec":
"""Subtracts 2 vectors"""
x = self.x - other.x
y = self.y - other.y
if self.z == None or other.z == None:
if self.z is None or other.z is None:
return Vec(x, y)
return Vec(x, y, self.z - other.z)
def times(self, factor: float) -> 'Vec':
def times(self, factor: float) -> "Vec":
"""Multiplies 2 vectors"""
x = self.x * factor
y = self.y * factor
if self.z == None:
if self.z is None:
return Vec(x, y)
return Vec(x, y, self.z * factor)
def div(self, factor: float) -> 'Vec':
def div(self, factor: float) -> "Vec":
"""Divides 2 vectors"""
x = self.x / factor
y = self.y / factor
if self.z == None:
if self.z is None:
return Vec(x, y)
return Vec(x, y, self.z / factor)
def to_angle(self):
"""Transforms a Vec3 into a Vec2 angle"""
if self.z == None:
if self.z is None:
raise TypeError
deg_to_rad = (180. / pi)
deg_to_rad = 180.0 / pi
return Vec(
atan2(-self.z, hypot(self.x, self.y)) * deg_to_rad,
atan2(self.y, self.x) * deg_to_rad
atan2(self.y, self.x) * deg_to_rad,
)
def is_zero(self):
"""Check if the vector is zero"""
xy = (float(self.x) == 0.) and (float(self.y) == 0.)
if self.z == None:
xy = (float(self.x) == 0.0) and (float(self.y) == 0.0)
if self.z is None:
return xy
return xy and float(self.z) == 0.
return xy and float(self.z) == 0.0
def angle_normalizer(angle: Vec) -> Vec:
"""Force the angle to respect game limitation"""
# Limit of pitch in game is ]-89; 180[
if angle.x > 89.:
angle.x = 89.
if angle.x < -89.:
if angle.x > 89.0:
angle.x = 89.0
if angle.x < -89.0:
angle.x = -89
# Limit of yaw in game is ]-180; 360[
while (angle.y > 180.):
angle.y -= 360.
while (angle.y < -180.):
angle.y += 360.
while angle.y > 180.0:
angle.y -= 360.0
while angle.y < -180.0:
angle.y += 360.0
return angle