XTaylorSpenceX

Theft Auto Grand

Sep 18th, 2025
87
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
HTML 37.01 KB | None | 0 0
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6.     <title>Theft Auto Grand - 盗窃汽车大</title>
  7.     <style>
  8.         * {
  9.             margin: 0;
  10.             padding: 0;
  11.             box-sizing: border-box;
  12.         }
  13.  
  14.         body {
  15.             background: #000;
  16.             font-family: 'Courier New', monospace;
  17.             overflow: hidden;
  18.             color: white;
  19.         }
  20.  
  21.         #gameCanvas {
  22.             display: block;
  23.             border: 2px solid #333;
  24.         }
  25.  
  26.         #ui {
  27.             position: absolute;
  28.             top: 10px;
  29.             left: 10px;
  30.             z-index: 100;
  31.         }
  32.  
  33.         #healthBar, #shieldBar {
  34.             width: 200px;
  35.             height: 20px;
  36.             border: 2px solid #fff;
  37.             margin-bottom: 5px;
  38.             background: #333;
  39.         }
  40.  
  41.         #healthFill {
  42.             height: 100%;
  43.             background: linear-gradient(90deg, #ff0000, #ff4444);
  44.             transition: width 0.3s;
  45.         }
  46.  
  47.         #shieldFill {
  48.             height: 100%;
  49.             background: linear-gradient(90deg, #0066ff, #4488ff);
  50.             transition: width 0.3s;
  51.         }
  52.  
  53.         #weaponInfo {
  54.             color: #fff;
  55.             font-size: 14px;
  56.             margin-top: 5px;
  57.         }
  58.  
  59.         #wantedStars {
  60.             margin-top: 10px;
  61.         }
  62.  
  63.         .star {
  64.             color: #ffdd00;
  65.             font-size: 20px;
  66.             margin-right: 5px;
  67.         }
  68.  
  69.         #terminal {
  70.             position: absolute;
  71.             bottom: 0;
  72.             left: 50%;
  73.             transform: translateX(-50%);
  74.             width: 80%;
  75.             background: rgba(0, 0, 0, 0.8);
  76.             border: 2px solid #00ff00;
  77.             display: none;
  78.             z-index: 200;
  79.         }
  80.  
  81.         #terminalOutput {
  82.             height: 200px;
  83.             overflow-y: auto;
  84.             padding: 10px;
  85.             color: #00ff00;
  86.             font-size: 12px;
  87.             background: rgba(0, 20, 0, 0.9);
  88.         }
  89.  
  90.         #terminalInput {
  91.             width: 100%;
  92.             padding: 10px;
  93.             background: #000;
  94.             color: #00ff00;
  95.             border: none;
  96.             font-family: 'Courier New', monospace;
  97.             font-size: 14px;
  98.         }
  99.  
  100.         #intellisense {
  101.             position: absolute;
  102.             background: rgba(0, 50, 0, 0.95);
  103.             border: 1px solid #00ff00;
  104.             max-height: 150px;
  105.             overflow-y: auto;
  106.             color: #00ff00;
  107.             font-size: 12px;
  108.             display: none;
  109.         }
  110.  
  111.         .intellisense-item {
  112.             padding: 5px 10px;
  113.             cursor: pointer;
  114.         }
  115.  
  116.         .intellisense-item:hover {
  117.             background: rgba(0, 100, 0, 0.5);
  118.         }
  119.  
  120.         #instructions {
  121.             position: absolute;
  122.             top: 10px;
  123.             right: 10px;
  124.             color: #fff;
  125.             font-size: 12px;
  126.             background: rgba(0, 0, 0, 0.7);
  127.             padding: 10px;
  128.             border-radius: 5px;
  129.             max-width: 300px;
  130.         }
  131.     </style>
  132. </head>
  133. <body>
  134.     <canvas id="gameCanvas" width="1200" height="800"></canvas>
  135.    
  136.     <div id="ui">
  137.         <div id="shieldBar">
  138.             <div id="shieldFill" style="width: 100%"></div>
  139.         </div>
  140.         <div id="healthBar">
  141.             <div id="healthFill" style="width: 100%"></div>
  142.         </div>
  143.         <div id="weaponInfo">Weapon: Fists (0/∞)</div>
  144.         <div id="wantedStars"></div>
  145.     </div>
  146.  
  147.     <div id="instructions">
  148.         <strong>盗窃汽车大 - Theft Auto Grand</strong><br>
  149.         WASD: Move | Space: Enter/Exit Vehicle<br>
  150.         Mouse: Aim/Shoot | 1-8: Select Weapons<br>
  151.         9: Random Weapon | ~: Terminal<br>
  152.         Japanese/Chinese Market Edition
  153.     </div>
  154.  
  155.     <div id="terminal">
  156.         <div id="terminalOutput"></div>
  157.         <div id="intellisense"></div>
  158.         <input type="text" id="terminalInput" placeholder="Type command... (try 'help')">
  159.     </div>
  160.  
  161.     <script>
  162.         class Game {
  163.             constructor() {
  164.                 this.canvas = document.getElementById('gameCanvas');
  165.                 this.ctx = this.canvas.getContext('2d');
  166.                 this.width = this.canvas.width;
  167.                 this.height = this.canvas.height;
  168.                
  169.                 this.player = {
  170.                     x: 600,
  171.                     y: 400,
  172.                     size: 12,
  173.                     speed: 3,
  174.                     health: 100,
  175.                     shield: 100,
  176.                     maxHealth: 100,
  177.                     maxShield: 100,
  178.                     angle: 0,
  179.                     inVehicle: false,
  180.                     vehicle: null,
  181.                     godMode: false
  182.                 };
  183.                
  184.                 this.weapons = [
  185.                     { name: 'Fists', damage: 5, range: 30, ammo: Infinity, fireRate: 500 },
  186.                     { name: 'Machete', damage: 999, range: 40, ammo: Infinity, fireRate: 400 },
  187.                     { name: 'Pistol', damage: 20, range: 250, ammo: 120, fireRate: 300 },
  188.                     { name: 'SMG', damage: 15, range: 150, ammo: 250, fireRate: 100 },
  189.                     { name: 'AK-47', damage: 30, range: 200, ammo: 180, fireRate: 150 },
  190.                     { name: 'MP-6', damage: 20, range: 120, ammo: 200, fireRate: 80 },
  191.                     { name: 'Machine Gun', damage: 25, range: 180, ammo: 500, fireRate: 60 },
  192.                     { name: 'Rocket Launcher', damage: 100, range: 250, ammo: 10, fireRate: 1000 }
  193.                 ];
  194.                
  195.                 this.currentWeapon = 0;
  196.                 this.lastShot = 0;
  197.                 this.wantedLevel = 0;
  198.                 this.killCount = 0;
  199.                
  200.                 this.npcs = [];
  201.                 this.vehicles = [];
  202.                 this.bullets = [];
  203.                 this.enemies = [];
  204.                 this.buildings = [];
  205.                
  206.                 this.camera = { x: 0, y: 0 };
  207.                 this.keys = {};
  208.                 this.mouse = { x: 0, y: 0, down: false };
  209.                
  210.                 this.terminalOpen = false;
  211.                 this.terminalHistory = [];
  212.                
  213.                 this.initializeWorld();
  214.                 this.setupEventListeners();
  215.                 this.initializeTerminal();
  216.                 this.gameLoop();
  217.             }
  218.            
  219.             initializeWorld() {
  220.                 // Generate buildings
  221.                 for (let i = 0; i < 50; i++) {
  222.                    this.buildings.push({
  223.                        x: Math.random() * 2000,
  224.                        y: Math.random() * 2000,
  225.                        width: 60 + Math.random() * 40,
  226.                        height: 60 + Math.random() * 40,
  227.                        color: `rgb(${50 + Math.random() * 100}, ${50 + Math.random() * 100}, ${50 + Math.random() * 100})`
  228.                    });
  229.                }
  230.                
  231.                // Generate NPCs (UltraSims)
  232.                for (let i = 0; i < 100; i++) {
  233.                    this.npcs.push({
  234.                        x: Math.random() * 2000,
  235.                        y: Math.random() * 2000,
  236.                        vx: (Math.random() - 0.5) * 2,
  237.                        vy: (Math.random() - 0.5) * 2,
  238.                        health: 100,
  239.                        alive: true,
  240.                        type: 'civilian'
  241.                    });
  242.                }
  243.                
  244.                // Generate Estal vehicles
  245.                for (let i = 0; i < 30; i++) {
  246.                    this.vehicles.push({
  247.                        x: Math.random() * 2000,
  248.                        y: Math.random() * 2000,
  249.                        width: 40,
  250.                        height: 20,
  251.                        angle: Math.random() * Math.PI * 2,
  252.                        speed: 1 + Math.random() * 2,
  253.                        occupied: false,
  254.                        color: `hsl(${Math.random() * 360}, 70%, 50%)`
  255.                    });
  256.                }
  257.            }
  258.            
  259.            setupEventListeners() {
  260.                document.addEventListener('keydown', (e) => {
  261.                     this.keys[e.key.toLowerCase()] = true;
  262.                    
  263.                     if (e.key === '`' || e.key === '~') {
  264.                         this.toggleTerminal();
  265.                     }
  266.                    
  267.                     if (!this.terminalOpen) {
  268.                         // Weapon selection
  269.                         const weaponKeys = ['1', '2', '3', '4', '5', '6', '7', '8'];
  270.                         if (weaponKeys.includes(e.key)) {
  271.                             this.currentWeapon = parseInt(e.key) - 1;
  272.                         }
  273.                         if (e.key === '9') {
  274.                             this.currentWeapon = Math.floor(Math.random() * 8);
  275.                         }
  276.                     }
  277.                 });
  278.                
  279.                 document.addEventListener('keyup', (e) => {
  280.                     this.keys[e.key.toLowerCase()] = false;
  281.                 });
  282.                
  283.                 this.canvas.addEventListener('mousemove', (e) => {
  284.                     const rect = this.canvas.getBoundingClientRect();
  285.                     this.mouse.x = e.clientX - rect.left;
  286.                     this.mouse.y = e.clientY - rect.top;
  287.                 });
  288.                
  289.                 this.canvas.addEventListener('mousedown', () => {
  290.                     this.mouse.down = true;
  291.                 });
  292.                
  293.                 this.canvas.addEventListener('mouseup', () => {
  294.                     this.mouse.down = false;
  295.                 });
  296.             }
  297.            
  298.             initializeTerminal() {
  299.                 const input = document.getElementById('terminalInput');
  300.                 const output = document.getElementById('terminalOutput');
  301.                 const intellisense = document.getElementById('intellisense');
  302.                
  303.                 const commands = [
  304.                     'help', 'add health', 'add shield', 'godmode', 'clear wanted', 'spawn vehicle',
  305.                     'spawn weapon', 'teleport', 'kill all', 'explode all', 'weather rain',
  306.                     'weather clear', 'time day', 'time night', 'invincible', 'unlimited ammo',
  307.                     'max wanted', 'clear npcs', 'spawn army', 'nuke city', 'matrix mode',
  308.                     'slow motion', 'fast forward', 'invisible', 'super speed', 'mega jump'
  309.                 ];
  310.                
  311.                 input.addEventListener('keydown', (e) => {
  312.                     if (e.key === 'Enter') {
  313.                         this.executeCommand(input.value);
  314.                         input.value = '';
  315.                         intellisense.style.display = 'none';
  316.                     }
  317.                 });
  318.                
  319.                 input.addEventListener('input', (e) => {
  320.                     const value = e.target.value.toLowerCase();
  321.                     const matches = commands.filter(cmd => cmd.startsWith(value));
  322.                    
  323.                     if (matches.length > 0 && value.length > 0) {
  324.                        intellisense.innerHTML = matches.map(cmd =>
  325.                            `<div class="intellisense-item" onclick="this.selectCommand('${cmd}')">${cmd}</div>`
  326.                        ).join('');
  327.                         intellisense.style.display = 'block';
  328.                     } else {
  329.                         intellisense.style.display = 'none';
  330.                     }
  331.                 });
  332.                
  333.                 window.selectCommand = (cmd) => {
  334.                     input.value = cmd;
  335.                     intellisense.style.display = 'none';
  336.                     input.focus();
  337.                 };
  338.             }
  339.            
  340.             toggleTerminal() {
  341.                 this.terminalOpen = !this.terminalOpen;
  342.                 const terminal = document.getElementById('terminal');
  343.                 terminal.style.display = this.terminalOpen ? 'block' : 'none';
  344.                
  345.                 if (this.terminalOpen) {
  346.                     document.getElementById('terminalInput').focus();
  347.                 }
  348.             }
  349.            
  350.             executeCommand(cmd) {
  351.                 const output = document.getElementById('terminalOutput');
  352.                 const parts = cmd.toLowerCase().split(' ');
  353.                 let response = '';
  354.                
  355.                 switch (parts[0]) {
  356.                     case 'help':
  357.                         response = 'Available commands:\nadd health [amount] - Add health\nadd shield [amount] - Add shield\ngodmode - Toggle invincibility\nclear wanted - Reset wanted level\nspawn vehicle - Spawn nearby vehicle\nteleport [x] [y] - Teleport to coordinates\nkill all - Eliminate all NPCs\nexplode all - Explode all vehicles\nweather [rain/clear] - Change weather\ntime [day/night] - Change time\nunlimited ammo - Toggle infinite ammo\nmax wanted - Set max wanted level\nsuper speed - Toggle super speed';
  358.                         break;
  359.                     case 'add':
  360.                         if (parts[1] === 'health') {
  361.                             const amount = parseInt(parts[2]) || 50;
  362.                             this.player.health = Math.min(this.player.maxHealth, this.player.health + amount);
  363.                             response = `Added ${amount} health. Current: ${this.player.health}/${this.player.maxHealth}`;
  364.                         } else if (parts[1] === 'shield') {
  365.                             const amount = parseInt(parts[2]) || 50;
  366.                             this.player.shield = Math.min(this.player.maxShield, this.player.shield + amount);
  367.                             response = `Added ${amount} shield. Current: ${this.player.shield}/${this.player.maxShield}`;
  368.                         }
  369.                         break;
  370.                     case 'godmode':
  371.                         this.player.godMode = !this.player.godMode;
  372.                         response = `God mode: ${this.player.godMode ? 'ON' : 'OFF'}`;
  373.                         break;
  374.                     case 'clear':
  375.                         if (parts[1] === 'wanted') {
  376.                             this.wantedLevel = 0;
  377.                             this.enemies = [];
  378.                             response = 'Wanted level cleared';
  379.                         }
  380.                         break;
  381.                     case 'spawn':
  382.                         if (parts[1] === 'vehicle') {
  383.                             this.vehicles.push({
  384.                                 x: this.player.x + 50,
  385.                                 y: this.player.y,
  386.                                 width: 40,
  387.                                 height: 20,
  388.                                 angle: 0,
  389.                                 speed: 2,
  390.                                 occupied: false,
  391.                                 color: `hsl(${Math.random() * 360}, 70%, 50%)`
  392.                             });
  393.                             response = 'Vehicle spawned nearby';
  394.                         }
  395.                         break;
  396.                     case 'teleport':
  397.                         const x = parseInt(parts[1]) || 0;
  398.                         const y = parseInt(parts[2]) || 0;
  399.                         this.player.x = x;
  400.                         this.player.y = y;
  401.                         response = `Teleported to (${x}, ${y})`;
  402.                         break;
  403.                     case 'kill':
  404.                         if (parts[1] === 'all') {
  405.                             this.npcs.forEach(npc => npc.alive = false);
  406.                             response = 'All NPCs eliminated';
  407.                         }
  408.                         break;
  409.                     case 'max':
  410.                         if (parts[1] === 'wanted') {
  411.                             this.wantedLevel = 5;
  412.                             response = 'Wanted level set to maximum!';
  413.                         }
  414.                         break;
  415.                     default:
  416.                         response = `Unknown command: ${cmd}. Type 'help' for available commands.`;
  417.                 }
  418.                
  419.                 output.innerHTML += `> ${cmd}\n${response}\n\n`;
  420.                 output.scrollTop = output.scrollHeight;
  421.             }
  422.            
  423.             update() {
  424.                 // Only update game state when terminal is closed
  425.                 if (!this.terminalOpen) {
  426.                     this.updatePlayer();
  427.                     this.updateNPCs();
  428.                     this.updateVehicles();
  429.                     this.updateBullets();
  430.                     this.updateEnemies();
  431.                     this.updateCamera();
  432.                     this.updateWantedLevel();
  433.                    
  434.                     if (this.mouse.down) {
  435.                         this.shoot();
  436.                     }
  437.                 }
  438.                
  439.                 // Always update UI regardless of terminal state
  440.                 this.updateUI();
  441.             }
  442.            
  443.             updatePlayer() {
  444.                 let moveX = 0, moveY = 0;
  445.                
  446.                 if (this.keys['w']) moveY -= 1;
  447.                 if (this.keys['s']) moveY += 1;
  448.                 if (this.keys['a']) moveX -= 1;
  449.                 if (this.keys['d']) moveX += 1;
  450.                
  451.                 if (this.keys[' ']) {
  452.                     this.toggleVehicle();
  453.                     this.keys[' '] = false; // Prevent continuous triggering
  454.                 }
  455.                
  456.                 const speed = this.player.inVehicle ? 5 : this.player.speed;
  457.                
  458.                 if (moveX !== 0 || moveY !== 0) {
  459.                     const length = Math.sqrt(moveX * moveX + moveY * moveY);
  460.                     moveX /= length;
  461.                     moveY /= length;
  462.                    
  463.                     this.player.x += moveX * speed;
  464.                     this.player.y += moveY * speed;
  465.                    
  466.                     if (this.player.inVehicle && this.player.vehicle) {
  467.                        this.player.vehicle.x = this.player.x;
  468.                         this.player.vehicle.y = this.player.y;
  469.                         this.player.vehicle.angle = Math.atan2(moveY, moveX);
  470.                     }
  471.                 }
  472.                
  473.                 // Update player angle based on mouse position
  474.                 const worldMouseX = this.mouse.x + this.camera.x;
  475.                 const worldMouseY = this.mouse.y + this.camera.y;
  476.                 this.player.angle = Math.atan2(worldMouseY - this.player.y, worldMouseX - this.player.x);
  477.             }
  478.            
  479.             toggleVehicle() {
  480.                 if (this.player.inVehicle) {
  481.                     // Exit vehicle
  482.                     this.player.inVehicle = false;
  483.                     if (this.player.vehicle) {
  484.                         this.player.vehicle.occupied = false;
  485.                         this.player.vehicle = null;
  486.                     }
  487.                 } else {
  488.                     // Find nearby vehicle
  489.                     for (let vehicle of this.vehicles) {
  490.                         const dist = Math.sqrt((vehicle.x - this.player.x) ** 2 + (vehicle.y - this.player.y) ** 2);
  491.                         if (dist < 50 && !vehicle.occupied) {
  492.                            this.player.inVehicle = true;
  493.                            this.player.vehicle = vehicle;
  494.                            vehicle.occupied = true;
  495.                            this.player.x = vehicle.x;
  496.                            this.player.y = vehicle.y;
  497.                            break;
  498.                        }
  499.                    }
  500.                }
  501.            }
  502.            
  503.            updateNPCs() {
  504.                this.npcs.forEach((npc, index) => {
  505.                     if (!npc.alive) return;
  506.                    
  507.                     // Simple AI movement
  508.                     npc.x += npc.vx;
  509.                     npc.y += npc.vy;
  510.                    
  511.                     // Boundary check
  512.                     if (npc.x < 0 || npc.x > 2000) npc.vx *= -1;
  513.                     if (npc.y < 0 || npc.y > 2000) npc.vy *= -1;
  514.                    
  515.                     // Random direction change
  516.                     if (Math.random() < 0.01) {
  517.                        npc.vx = (Math.random() - 0.5) * 2;
  518.                        npc.vy = (Math.random() - 0.5) * 2;
  519.                    }
  520.                });
  521.            }
  522.            
  523.            updateVehicles() {
  524.                this.vehicles.forEach(vehicle => {
  525.                     if (!vehicle.occupied) {
  526.                         // Estal AI driving
  527.                         vehicle.x += Math.cos(vehicle.angle) * vehicle.speed;
  528.                         vehicle.y += Math.sin(vehicle.angle) * vehicle.speed;
  529.                        
  530.                         // Random steering
  531.                         if (Math.random() < 0.02) {
  532.                            vehicle.angle += (Math.random() - 0.5) * 0.5;
  533.                        }
  534.                        
  535.                        // Boundary wrap
  536.                        if (vehicle.x < 0) vehicle.x = 2000;
  537.                        if (vehicle.x > 2000) vehicle.x = 0;
  538.                         if (vehicle.y < 0) vehicle.y = 2000;
  539.                        if (vehicle.y > 2000) vehicle.y = 0;
  540.                        
  541.                         // Check for NPC collisions (Estal vehicles can be dangerous)
  542.                         this.npcs.forEach(npc => {
  543.                             if (!npc.alive) return;
  544.                             const dist = Math.sqrt((vehicle.x - npc.x) ** 2 + (vehicle.y - npc.y) ** 2);
  545.                             if (dist < 25) {
  546.                                npc.alive = false;
  547.                                this.killCount++;
  548.                            }
  549.                        });
  550.                    }
  551.                });
  552.            }
  553.            
  554.            updateBullets() {
  555.                this.bullets.forEach((bullet, index) => {
  556.                     bullet.x += bullet.vx;
  557.                     bullet.y += bullet.vy;
  558.                     bullet.life--;
  559.                    
  560.                     if (bullet.life <= 0) {
  561.                        this.bullets.splice(index, 1);
  562.                        return;
  563.                    }
  564.                    
  565.                    // Check NPC hits
  566.                    this.npcs.forEach(npc => {
  567.                         if (!npc.alive) return;
  568.                         const dist = Math.sqrt((bullet.x - npc.x) ** 2 + (bullet.y - npc.y) ** 2);
  569.                         if (dist < 15) {
  570.                            npc.alive = false;
  571.                            this.bullets.splice(index, 1);
  572.                            this.killCount++;
  573.                        }
  574.                    });
  575.                    
  576.                    // Check enemy hits
  577.                    this.enemies.forEach((enemy, enemyIndex) => {
  578.                         const dist = Math.sqrt((bullet.x - enemy.x) ** 2 + (bullet.y - enemy.y) ** 2);
  579.                         if (dist < 15) {
  580.                            enemy.health -= bullet.damage;
  581.                            this.bullets.splice(index, 1);
  582.                            if (enemy.health <= 0) {
  583.                                this.enemies.splice(enemyIndex, 1);
  584.                            }
  585.                        }
  586.                    });
  587.                });
  588.            }
  589.            
  590.            updateEnemies() {
  591.                // Spawn enemies based on wanted level
  592.                if (this.wantedLevel > 0 && this.enemies.length < this.wantedLevel * 5) {
  593.                    const spawnDistance = 300 + Math.random() * 200;
  594.                     const angle = Math.random() * Math.PI * 2;
  595.                    
  596.                     let enemyType = 'police';
  597.                     let health = 100;
  598.                     let damage = 10;
  599.                    
  600.                     if (this.wantedLevel >= 2) enemyType = 'armored_police', health = 150;
  601.                     if (this.wantedLevel >= 3) enemyType = 'swat', health = 200, damage = 15;
  602.                     if (this.wantedLevel >= 4) enemyType = 'fbi', health = 250, damage = 20;
  603.                     if (this.wantedLevel >= 5) enemyType = 'army', health = 300, damage = 25;
  604.                    
  605.                     this.enemies.push({
  606.                         x: this.player.x + Math.cos(angle) * spawnDistance,
  607.                         y: this.player.y + Math.sin(angle) * spawnDistance,
  608.                         health: health,
  609.                         maxHealth: health,
  610.                         type: enemyType,
  611.                         damage: damage,
  612.                         lastShot: 0,
  613.                         angle: 0
  614.                     });
  615.                 }
  616.                
  617.                 // Update enemy AI
  618.                 this.enemies.forEach((enemy, index) => {
  619.                     // Move toward player
  620.                     const dx = this.player.x - enemy.x;
  621.                     const dy = this.player.y - enemy.y;
  622.                     const dist = Math.sqrt(dx * dx + dy * dy);
  623.                    
  624.                     if (dist > 0) {
  625.                         const speed = enemy.type === 'army' ? 2 : 1.5;
  626.                         enemy.x += (dx / dist) * speed;
  627.                         enemy.y += (dy / dist) * speed;
  628.                         enemy.angle = Math.atan2(dy, dx);
  629.                     }
  630.                    
  631.                     // Shoot at player
  632.                     if (dist < 200 && Date.now() - enemy.lastShot > 800) {
  633.                         const bulletSpeed = 8;
  634.                         this.bullets.push({
  635.                             x: enemy.x,
  636.                             y: enemy.y,
  637.                             vx: Math.cos(enemy.angle) * bulletSpeed,
  638.                             vy: Math.sin(enemy.angle) * bulletSpeed,
  639.                             life: 100,
  640.                             damage: enemy.damage,
  641.                             fromEnemy: true
  642.                         });
  643.                         enemy.lastShot = Date.now();
  644.                     }
  645.                 });
  646.                
  647.                 // Check enemy bullets hitting player
  648.                 this.bullets.forEach((bullet, index) => {
  649.                     if (!bullet.fromEnemy) return;
  650.                    
  651.                     const dist = Math.sqrt((bullet.x - this.player.x) ** 2 + (bullet.y - this.player.y) ** 2);
  652.                     if (dist < 15) {
  653.                        if (!this.player.godMode) {
  654.                            if (this.player.shield > 0) {
  655.                                 this.player.shield -= bullet.damage;
  656.                                 if (this.player.shield < 0) {
  657.                                    this.player.health += this.player.shield;
  658.                                    this.player.shield = 0;
  659.                                }
  660.                            } else {
  661.                                this.player.health -= bullet.damage;
  662.                            }
  663.                        }
  664.                        this.bullets.splice(index, 1);
  665.                    }
  666.                });
  667.            }
  668.            
  669.            updateWantedLevel() {
  670.                let newWantedLevel = 0;
  671.                if (this.killCount >= 1) newWantedLevel = 1;
  672.                 if (this.killCount >= 5) newWantedLevel = 2;
  673.                 if (this.killCount >= 15) newWantedLevel = 3;
  674.                 if (this.killCount >= 30) newWantedLevel = 4;
  675.                 if (this.killCount >= 60) newWantedLevel = 5;
  676.                
  677.                 this.wantedLevel = newWantedLevel;
  678.             }
  679.            
  680.             shoot() {
  681.                 const weapon = this.weapons[this.currentWeapon];
  682.                 if (Date.now() - this.lastShot < weapon.fireRate) return;
  683.                if (weapon.ammo <= 0) return;
  684.                
  685.                const bulletSpeed = 10;
  686.                const spread = weapon.name === 'SMG' || weapon.name === 'Machine Gun' ? 0.1 : 0.02;
  687.                const angle = this.player.angle + (Math.random() - 0.5) * spread;
  688.                
  689.                this.bullets.push({
  690.                    x: this.player.x,
  691.                    y: this.player.y,
  692.                    vx: Math.cos(angle) * bulletSpeed,
  693.                    vy: Math.sin(angle) * bulletSpeed,
  694.                    life: weapon.range / bulletSpeed,
  695.                    damage: weapon.damage,
  696.                    fromEnemy: false
  697.                });
  698.                
  699.                if (weapon.ammo !== Infinity) {
  700.                    weapon.ammo--;
  701.                }
  702.                
  703.                this.lastShot = Date.now();
  704.            }
  705.            
  706.            updateCamera() {
  707.                this.camera.x = this.player.x - this.width / 2;
  708.                this.camera.y = this.player.y - this.height / 2;
  709.            }
  710.            
  711.            updateUI() {
  712.                document.getElementById('healthFill').style.width = (this.player.health / this.player.maxHealth * 100) + '%';
  713.                document.getElementById('shieldFill').style.width = (this.player.shield / this.player.maxShield * 100) + '%';
  714.                
  715.                const weapon = this.weapons[this.currentWeapon];
  716.                document.getElementById('weaponInfo').textContent =
  717.                    `Weapon: ${weapon.name} (${weapon.ammo === Infinity ? '∞' : weapon.ammo}/${weapon.ammo === Infinity ? '∞' : weapon.ammo})`;
  718.                
  719.                const starsHtml = '★'.repeat(this.wantedLevel) + '☆'.repeat(5 - this.wantedLevel);
  720.                document.getElementById('wantedStars').innerHTML = `<div class="star">Wanted: ${starsHtml}</div>`;
  721.             }
  722.            
  723.             render() {
  724.                 this.ctx.fillStyle = '#2a4a2a';
  725.                 this.ctx.fillRect(0, 0, this.width, this.height);
  726.                
  727.                 this.ctx.save();
  728.                 this.ctx.translate(-this.camera.x, -this.camera.y);
  729.                
  730.                 // Draw buildings
  731.                 this.buildings.forEach(building => {
  732.                     this.ctx.fillStyle = building.color;
  733.                     this.ctx.fillRect(building.x, building.y, building.width, building.height);
  734.                     this.ctx.strokeStyle = '#000';
  735.                     this.ctx.strokeRect(building.x, building.y, building.width, building.height);
  736.                 });
  737.                
  738.                 // Draw NPCs
  739.                 this.npcs.forEach(npc => {
  740.                     if (!npc.alive) return;
  741.                     this.ctx.fillStyle = '#ff9999';
  742.                     this.ctx.beginPath();
  743.                     this.ctx.arc(npc.x, npc.y, 8, 0, Math.PI * 2);
  744.                     this.ctx.fill();
  745.                    
  746.                     // UltraSim label
  747.                     this.ctx.fillStyle = '#fff';
  748.                     this.ctx.font = '8px Arial';
  749.                     this.ctx.fillText('US', npc.x - 8, npc.y - 12);
  750.                 });
  751.                
  752.                 // Draw vehicles
  753.                 this.vehicles.forEach(vehicle => {
  754.                     this.ctx.save();
  755.                     this.ctx.translate(vehicle.x, vehicle.y);
  756.                     this.ctx.rotate(vehicle.angle);
  757.                    
  758.                     this.ctx.fillStyle = vehicle.color;
  759.                     this.ctx.fillRect(-vehicle.width/2, -vehicle.height/2, vehicle.width, vehicle.height);
  760.                     this.ctx.strokeStyle = '#000';
  761.                     this.ctx.strokeRect(-vehicle.width/2, -vehicle.height/2, vehicle.width, vehicle.height);
  762.                    
  763.                     // Estal brand logo
  764.                     this.ctx.fillStyle = '#fff';
  765.                     this.ctx.font = '6px Arial';
  766.                     this.ctx.fillText('ESTAL', -12, 2);
  767.                    
  768.                     this.ctx.restore();
  769.                 });
  770.                
  771.                 // Draw bullets
  772.                 this.bullets.forEach(bullet => {
  773.                     this.ctx.fillStyle = bullet.fromEnemy ? '#ff4444' : '#ffff44';
  774.                     this.ctx.beginPath();
  775.                     this.ctx.arc(bullet.x, bullet.y, 2, 0, Math.PI * 2);
  776.                     this.ctx.fill();
  777.                 });
  778.                
  779.                 // Draw enemies
  780.                 this.enemies.forEach(enemy => {
  781.                     let color = '#4444ff';
  782.                     if (enemy.type === 'armored_police') color = '#666699';
  783.                     if (enemy.type === 'swat') color = '#333366';
  784.                     if (enemy.type === 'fbi') color = '#000033';
  785.                     if (enemy.type === 'army') color = '#006600';
  786.                    
  787.                     this.ctx.fillStyle = color;
  788.                     this.ctx.beginPath();
  789.                     this.ctx.arc(enemy.x, enemy.y, 10, 0, Math.PI * 2);
  790.                     this.ctx.fill();
  791.                    
  792.                     // Health bar
  793.                     const barWidth = 20;
  794.                     const healthPercent = enemy.health / enemy.maxHealth;
  795.                     this.ctx.fillStyle = '#333';
  796.                     this.ctx.fillRect(enemy.x - barWidth/2, enemy.y - 18, barWidth, 4);
  797.                     this.ctx.fillStyle = '#ff0000';
  798.                     this.ctx.fillRect(enemy.x - barWidth/2, enemy.y - 18, barWidth * healthPercent, 4);
  799.                    
  800.                     // Type label
  801.                     this.ctx.fillStyle = '#fff';
  802.                     this.ctx.font = '8px Arial';
  803.                     this.ctx.fillText(enemy.type.toUpperCase(), enemy.x - 15, enemy.y + 20);
  804.                 });
  805.                
  806.                 // Draw player
  807.                 if (this.player.inVehicle && this.player.vehicle) {
  808.                    // Player is in vehicle, draw vehicle differently
  809.                    const vehicle = this.player.vehicle;
  810.                     this.ctx.save();
  811.                     this.ctx.translate(vehicle.x, vehicle.y);
  812.                     this.ctx.rotate(vehicle.angle);
  813.                    
  814.                     this.ctx.fillStyle = '#ffaa00'; // Player vehicle highlight
  815.                     this.ctx.fillRect(-vehicle.width/2, -vehicle.height/2, vehicle.width, vehicle.height);
  816.                     this.ctx.strokeStyle = '#fff';
  817.                     this.ctx.lineWidth = 2;
  818.                     this.ctx.strokeRect(-vehicle.width/2, -vehicle.height/2, vehicle.width, vehicle.height);
  819.                    
  820.                     this.ctx.restore();
  821.                 } else {
  822.                     // Draw player on foot
  823.                     this.ctx.save();
  824.                     this.ctx.translate(this.player.x, this.player.y);
  825.                     this.ctx.rotate(this.player.angle);
  826.                    
  827.                     // Player body
  828.                     this.ctx.fillStyle = this.player.godMode ? '#00ffff' : '#ffaa00';
  829.                     this.ctx.beginPath();
  830.                     this.ctx.arc(0, 0, this.player.size, 0, Math.PI * 2);
  831.                     this.ctx.fill();
  832.                    
  833.                     // Weapon indicator
  834.                     const weapon = this.weapons[this.currentWeapon];
  835.                     this.ctx.strokeStyle = '#fff';
  836.                     this.ctx.lineWidth = 2;
  837.                     this.ctx.beginPath();
  838.                     this.ctx.moveTo(0, 0);
  839.                     this.ctx.lineTo(weapon.range / 10, 0);
  840.                     this.ctx.stroke();
  841.                    
  842.                     this.ctx.restore();
  843.                    
  844.                     // Player name
  845.                     this.ctx.fillStyle = '#fff';
  846.                     this.ctx.font = '10px Arial';
  847.                     this.ctx.fillText('UltraSim™ Player', this.player.x - 30, this.player.y - 20);
  848.                 }
  849.                
  850.                 this.ctx.restore();
  851.                
  852.                 // Game over check
  853.                 if (this.player.health <= 0) {
  854.                    this.ctx.fillStyle = 'rgba(0, 0, 0, 0.8)';
  855.                    this.ctx.fillRect(0, 0, this.width, this.height);
  856.                    
  857.                    this.ctx.fillStyle = '#ff0000';
  858.                    this.ctx.font = '48px Arial';
  859.                    this.ctx.textAlign = 'center';
  860.                    this.ctx.fillText('WASTED', this.width/2, this.height/2);
  861.                    this.ctx.fillText('盗窃汽车大', this.width/2, this.height/2 + 60);
  862.                    
  863.                    this.ctx.fillStyle = '#fff';
  864.                    this.ctx.font = '16px Arial';
  865.                    this.ctx.fillText('Press F5 to restart', this.width/2, this.height/2 + 100);
  866.                    this.ctx.textAlign = 'left';
  867.                }
  868.            }
  869.            
  870.            gameLoop() {
  871.                this.update();
  872.                this.render();
  873.                requestAnimationFrame(() => this.gameLoop());
  874.             }
  875.         }
  876.        
  877.         // Initialize game when page loads
  878.         window.addEventListener('load', () => {
  879.             new Game();
  880.         });
  881.        
  882.         // Prevent context menu on canvas
  883.         document.getElementById('gameCanvas').addEventListener('contextmenu', (e) => {
  884.             e.preventDefault();
  885.         });
  886.     </script>
  887. </body>
  888. </html>
  889.  
Advertisement
Add Comment
Please, Sign In to add comment