From cb9462ce9b64918c8d517377d9ee71740c9ab8a5 Mon Sep 17 00:00:00 2001
From: Wizzard <rich@bandaholics.cash>
Date: Sat, 15 Mar 2025 17:50:46 -0400
Subject: [PATCH] Add: Show money on radar

---
 src/comms.rs           | 37 ++++++++++++++++++--
 src/dma/context/mod.rs | 13 +++++++
 src/dma/mod.rs         | 11 +++---
 webradar/index.html    |  4 +++
 webradar/script.js     | 79 ++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 138 insertions(+), 6 deletions(-)

diff --git a/src/comms.rs b/src/comms.rs
index a310690..67963ba 100755
--- a/src/comms.rs
+++ b/src/comms.rs
@@ -23,11 +23,40 @@ pub struct PlayerData {
 
     #[serde(rename = "weaponId")]
     weapon_id: i16,
+
+    #[serde(rename = "money", default)]
+    money: i32,
 }
 
 impl PlayerData {
-    pub fn new(pos: Vec3, yaw: f32, player_type: PlayerType, has_bomb: bool, has_awp: bool, is_scoped: bool, player_name: String, weapon_id: i16) -> PlayerData {
-        PlayerData { pos, yaw, player_type, has_bomb, has_awp, is_scoped, player_name, weapon_id }
+    pub fn new(pos: Vec3, yaw: f32, player_type: PlayerType, has_bomb: bool, has_awp: bool,
+               is_scoped: bool, player_name: String, weapon_id: i16) -> PlayerData {
+        PlayerData {
+            pos,
+            yaw,
+            player_type,
+            has_bomb,
+            has_awp,
+            is_scoped,
+            player_name,
+            weapon_id,
+            money: 0
+        }
+    }
+
+    pub fn new_with_money(pos: Vec3, yaw: f32, player_type: PlayerType, has_bomb: bool, has_awp: bool,
+                    is_scoped: bool, player_name: String, weapon_id: i16, money: i32) -> PlayerData {
+        PlayerData {
+            pos,
+            yaw,
+            player_type,
+            has_bomb,
+            has_awp,
+            is_scoped,
+            player_name,
+            weapon_id,
+            money
+        }
     }
 }
 
@@ -55,12 +84,16 @@ pub enum EntityData {
 pub struct CheatOptions {
     #[serde(rename = "revealMoney")]
     pub reveal_money: bool,
+
+    #[serde(rename = "displayMoney")]
+    pub display_money: bool,
 }
 
 impl Default for CheatOptions {
     fn default() -> Self {
         Self {
             reveal_money: false,
+            display_money: true,
         }
     }
 }
diff --git a/src/dma/context/mod.rs b/src/dma/context/mod.rs
index 27b1d11..43498a3 100755
--- a/src/dma/context/mod.rs
+++ b/src/dma/context/mod.rs
@@ -98,6 +98,8 @@ impl DmaCtx {
         let mut clipping_weapon = 0u64;
         let mut is_scoped = 0u8;
         let mut player_name_ptr = 0u64;
+        let mut money = 0i32;
+        let mut money_services_ptr = 0u64;
 
         {
             let mut batcher = MemoryViewBatcher::new(&mut self.process);
@@ -108,6 +110,15 @@ impl DmaCtx {
             batcher.read_into(pawn + cs2dumper::client::C_CSPlayerPawnBase::m_pClippingWeapon, &mut clipping_weapon);
             batcher.read_into(pawn + cs2dumper::client::C_CSPlayerPawn::m_bIsScoped, &mut is_scoped);
             batcher.read_into(controller + cs2dumper::client::CCSPlayerController::m_sSanitizedPlayerName, &mut player_name_ptr);
+
+            batcher.read_into(controller + cs2dumper::client::CCSPlayerController::m_pInGameMoneyServices, &mut money_services_ptr);
+        }
+
+        if money_services_ptr != 0 {
+            let money_addr: Address = money_services_ptr.into();
+            money = self.process.read(money_addr + cs2dumper::client::CCSPlayerController_InGameMoneyServices::m_iAccount)?;
+
+            log::debug!("Read money value: {} for player", money);
         }
 
         let player_name = if player_name_ptr != 0 {
@@ -145,6 +156,7 @@ impl DmaCtx {
             is_scoped: is_scoped != 0,
             player_name,
             weapon_id,
+            money,
         })
     }
 
@@ -273,4 +285,5 @@ pub struct BatchedPlayerData {
     pub is_scoped: bool,
     pub player_name: String,
     pub weapon_id: i16,
+    pub money: i32,
 }
\ No newline at end of file
diff --git a/src/dma/mod.rs b/src/dma/mod.rs
index 7e4bc42..0a97471 100755
--- a/src/dma/mod.rs
+++ b/src/dma/mod.rs
@@ -196,7 +196,7 @@ pub async fn run(radar_data: ArcRwlockRadarData, connector: Connector, pcileech_
 
                 entity_data.push(
                     EntityData::Player(
-                        PlayerData::new(
+                        PlayerData::new_with_money(
                             local_data.pos,
                             local_data.yaw,
                             PlayerType::Local,
@@ -204,10 +204,12 @@ pub async fn run(radar_data: ArcRwlockRadarData, connector: Connector, pcileech_
                             local_data.has_awp,
                             local_data.is_scoped,
                             local_data.player_name,
-                            local_data.weapon_id
+                            local_data.weapon_id,
+                            local_data.money
                         )
                     )
                 );
+                log::debug!("Added local player with money: {}", local_data.money);
             }
 
             // Other players
@@ -235,7 +237,7 @@ pub async fn run(radar_data: ArcRwlockRadarData, connector: Connector, pcileech_
 
                         entity_data.push(
                             EntityData::Player(
-                                PlayerData::new(
+                                PlayerData::new_with_money(
                                     player_data.pos,
                                     player_data.yaw,
                                     player_type,
@@ -243,7 +245,8 @@ pub async fn run(radar_data: ArcRwlockRadarData, connector: Connector, pcileech_
                                     player_data.has_awp,
                                     player_data.is_scoped,
                                     player_data.player_name,
-                                    player_data.weapon_id
+                                    player_data.weapon_id,
+                                    player_data.money
                                 )
                             )
                         );
diff --git a/webradar/index.html b/webradar/index.html
index 8682068..26d3f73 100644
--- a/webradar/index.html
+++ b/webradar/index.html
@@ -36,6 +36,10 @@
                     <input type="checkbox" onclick="toggleCentered()" id="centerCheck" name="center" checked />
                     <label for="centerCheck">Player Centered</label>
                 </div>
+                <div>
+                    <input type="checkbox" onclick="toggleDisplayMoney()" id="moneyDisplay" name="money-display" checked />
+                    <label for="moneyDisplay">Display Money</label>
+                </div>
 
                 <button id="showDangerousBtn" onclick="toggleDangerousOptions()">Show Dangerous Options</button>
 
diff --git a/webradar/script.js b/webradar/script.js
index b5fd4ae..410e43d 100644
--- a/webradar/script.js
+++ b/webradar/script.js
@@ -13,6 +13,7 @@ playerCentered = true
 drawStats = true
 drawNames = true
 drawGuns = true
+drawMoney = true;
 
 // Common
 canvas = null
@@ -274,6 +275,16 @@ function render() {
                                 data.Player.playerType
                             );
                         }
+
+                        if (drawMoney && !data.Player.isDormant && typeof data.Player.money === 'number') {
+                            console.log(`[radarflow] Drawing money for ${data.Player.playerName}: $${data.Player.money}`);
+                            drawPlayerMoney(
+                                data.Player.pos,
+                                data.Player.playerType,
+                                data.Player.money,
+                                data.Player.hasBomb
+                            );
+                        }
                     }
                 });
             }
@@ -457,6 +468,64 @@ function drawPlayerName(pos, playerName, playerType, hasAwp, hasBomb, isScoped)
     ctx.fillText(displayName, mapPos.x, textY);
 }
 
+function drawPlayerMoney(pos, playerType, money, hasBomb) {
+    if (!map) return;
+
+    console.log(`[radarflow] Drawing money: $${money} for ${playerType}`);
+
+    let mapPos = mapCoordinates(pos);
+    let textSize;
+
+    if (zoomSet) {
+        mapPos = boundingCoordinates(mapPos, boundingRect);
+        textSize = boundingScale(10, boundingRect);
+    } else if (playerCentered && localPlayerPos) {
+        const playerMapPos = mapCoordinates(localPlayerPos);
+        const zoomLevel = 0.5;
+        const viewWidth = image.width * zoomLevel;
+        const viewHeight = image.height * zoomLevel;
+
+        mapPos.x = (mapPos.x - (playerMapPos.x - viewWidth / 2)) * canvas.width / viewWidth;
+        mapPos.y = (mapPos.y - (playerMapPos.y - viewHeight / 2)) * canvas.height / viewHeight;
+        textSize = 10;
+    } else {
+        mapPos.x = mapPos.x * canvas.width / image.width;
+        mapPos.y = mapPos.y * canvas.height / image.height;
+        textSize = 10;
+    }
+
+    if (rotateMap) {
+        const canvasCenter = { x: canvas.width / 2, y: canvas.height / 2 };
+        mapPos = rotatePoint(canvasCenter.x, canvasCenter.y, mapPos.x, mapPos.y, localYaw + 270);
+    }
+
+    let extraOffset = 0;
+    if (drawNames) extraOffset += 15;
+    if (drawGuns) extraOffset += 15;
+    if (hasBomb) extraOffset += 15;
+
+    let textY = mapPos.y + 20 + extraOffset;
+
+    const formattedMoney = '$' + (money || 0).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
+
+    if (money >= 10000) {
+        ctx.fillStyle = "#32CD32";
+    } else if (money >= 4500) {
+        ctx.fillStyle = "#FFFF00";
+    } else {
+        ctx.fillStyle = "#FF4500";
+    }
+
+    ctx.font = `${textSize}px Arial`;
+    ctx.textAlign = "center";
+    ctx.textBaseline = "top";
+
+    ctx.lineWidth = 2;
+    ctx.strokeStyle = "black";
+    ctx.strokeText(formattedMoney, mapPos.x, textY);
+    ctx.fillText(formattedMoney, mapPos.x, textY);
+}
+
 function drawPlayerWeapon(pos, playerType, weaponId) {
     if (!map) return;
 
@@ -853,6 +922,7 @@ addEventListener("DOMContentLoaded", (e) => {
     document.getElementById("moneyReveal").checked = false;
     document.getElementById("rotateCheck").checked = true;
     document.getElementById("centerCheck").checked = true;
+    document.getElementById("moneyDisplay").checked = true;
 
     canvas = document.getElementById('canvas');
     canvas.width = 1024;
@@ -892,4 +962,13 @@ function toggleMoneyReveal() {
     if (websocket && websocket.readyState === WebSocket.OPEN) {
         websocket.send("toggleMoneyReveal");
     }
+}
+
+function toggleDisplayMoney() {
+    drawMoney = !drawMoney;
+    update = true;
+
+    console.log("[radarflow] Money display toggled:", drawMoney);
+
+    localStorage.setItem('drawMoney', drawMoney ? 'true' : 'false');
 }
\ No newline at end of file