/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Bullet class
var Bullet = Container.expand(function () {
var self = Container.call(this);
self.asset = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 48;
self.dir = 0;
self.owner = null; // 'player' or 'police'
self.update = function () {
self.x += Math.cos(self.dir) * self.speed;
self.y += Math.sin(self.dir) * self.speed;
};
return self;
});
// Car (stealable)
var Car = Container.expand(function () {
var self = Container.call(this);
self.asset = self.attachAsset('car', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 0;
self.maxSpeed = 5; // much slower
self.acceleration = 0.2; // slower acceleration
self.deceleration = 0.3; // slower deceleration
self.direction = 0; // radians
self.driver = null; // player if inside
self.isPolice = false;
self.targetDir = 0; // for smooth steering
self.update = function () {
if (self.driver) {
// Smoothly turn toward target direction (set by dragDir)
var diff = self.targetDir - self.direction;
// Normalize angle to [-PI, PI]
while (diff > Math.PI) diff -= 2 * Math.PI;
while (diff < -Math.PI) diff += 2 * Math.PI;
self.direction += diff * 0.2; // smooth steering
// Gradually accelerate to maxSpeed
if (self.speed < self.maxSpeed) {
self.speed += self.acceleration;
if (self.speed > self.maxSpeed) self.speed = self.maxSpeed;
}
// Move in direction
self.x += Math.cos(self.direction) * self.speed;
self.y += Math.sin(self.direction) * self.speed;
} else {
// If no driver, slow down to stop
if (self.speed > 0) {
self.speed -= self.deceleration;
if (self.speed < 0) self.speed = 0;
self.x += Math.cos(self.direction) * self.speed;
self.y += Math.sin(self.direction) * self.speed;
}
}
};
return self;
});
// CityBlock: road or building
var CityBlock = Container.expand(function () {
var self = Container.call(this);
self.type = 'road'; // or 'building'
self.setType = function (type) {
self.type = type;
if (self.asset) {
self.removeChild(self.asset);
}
if (type === 'road') {
self.asset = self.attachAsset('road', {
anchorX: 0.5,
anchorY: 0.5
});
} else {
self.asset = self.attachAsset('building', {
anchorX: 0.5,
anchorY: 0.5
});
}
};
return self;
});
var Civilian = Container.expand(function () {
var self = Container.call(this);
// Pick a random color asset for this civilian
var civAssetIdx = 1 + Math.floor(Math.random() * 6);
var civAssetName = 'civilian' + civAssetIdx;
self.asset = self.attachAsset(civAssetName, {
anchorX: 0.5,
anchorY: 0.5
});
self.asset.alpha = 0.7;
// Add 'npc' label above the civilian
self.npcLabel = new Text2('npc', {
size: 38,
fill: 0xFFFFFF
});
self.npcLabel.anchor.set(0.5, 1);
self.npcLabel.y = -40;
self.addChild(self.npcLabel);
self.speed = 2 + Math.random() * 2;
self.direction = Math.random() * Math.PI * 2;
self.update = function () {
// Move in direction, bounce off buildings
var nx = self.x + Math.cos(self.direction) * self.speed;
var ny = self.y + Math.sin(self.direction) * self.speed;
var onRoad = false;
for (var i = 0; i < cityBlocks.length; i++) {
var b = cityBlocks[i];
if (b.type === 'road') {
var left = b.x - blockSize / 2;
var right = b.x + blockSize / 2;
var top = b.y - blockSize / 2;
var bottom = b.y + blockSize / 2;
if (nx >= left && nx <= right && ny >= top && ny <= bottom) {
onRoad = true;
break;
}
}
}
if (onRoad) {
self.x = nx;
self.y = ny;
} else {
self.direction = Math.random() * Math.PI * 2;
}
};
return self;
});
// Spawn 6 civilians at random road blocks (not near player or police)
// Mission marker
var Mission = Container.expand(function () {
var self = Container.call(this);
self.asset = self.attachAsset('mission', {
anchorX: 0.5,
anchorY: 0.5
});
self.active = true;
return self;
});
// Player character
var Player = Container.expand(function () {
var self = Container.call(this);
self.asset = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
// Add 'you' label above the player
self.youLabel = new Text2('you', {
size: 38,
fill: 0xFFFFFF
});
self.youLabel.anchor.set(0.5, 1);
self.youLabel.y = -80;
self.addChild(self.youLabel);
self.speed = 16;
self.inCar = null; // reference to car if inside
self.direction = 0; // radians, 0 = right
// Add gun to player's hand
self.gun = self.attachAsset('gun', {
anchorX: 0.1,
anchorY: 0.5
});
self.gun.x = 60; // offset from player center
self.gun.y = 0;
self.gun.visible = true;
self.lastShotDir = 0; // radians
self.update = function () {
// If in car, follow car and hide player sprite
if (self.inCar) {
self.x = self.inCar.x;
self.y = self.inCar.y;
self.visible = false;
self.gun.visible = false;
self.youLabel.visible = false;
} else {
self.visible = true;
self.gun.visible = true;
self.youLabel.visible = true;
// Gun follows player hand and points at last shot direction
self.gun.x = 60 * Math.cos(self.lastShotDir);
self.gun.y = 60 * Math.sin(self.lastShotDir);
self.gun.rotation = self.lastShotDir;
}
};
return self;
});
// Police car
var PoliceCar = Container.expand(function () {
var self = Container.call(this);
self.asset = self.attachAsset('police', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 0;
self.maxSpeed = 2.5; // much slower (reduced for slower police)
self.acceleration = 0.08; // slower acceleration
self.deceleration = 0.15; // slower deceleration
self.direction = 0;
self.target = null; // player or car
self.isPolice = true;
self.targetDir = 0;
self.update = function () {
if (self.target) {
// Simple chase logic
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 10) {
self.targetDir = Math.atan2(dy, dx);
// Smoothly turn toward target direction
var diff = self.targetDir - self.direction;
while (diff > Math.PI) diff -= 2 * Math.PI;
while (diff < -Math.PI) diff += 2 * Math.PI;
self.direction += diff * 0.2;
// Accelerate to maxSpeed
if (self.speed < self.maxSpeed) {
self.speed += self.acceleration;
if (self.speed > self.maxSpeed) self.speed = self.maxSpeed;
}
self.x += Math.cos(self.direction) * self.speed;
self.y += Math.sin(self.direction) * self.speed;
} else {
self.speed = 0;
}
} else {
// If no target, slow down to stop
if (self.speed > 0) {
self.speed -= self.deceleration;
if (self.speed < 0) self.speed = 0;
self.x += Math.cos(self.direction) * self.speed;
self.y += Math.sin(self.direction) * self.speed;
}
}
};
return self;
});
// Police shooter class (policeman on foot)
var PoliceShooter = Container.expand(function () {
var self = Container.call(this);
self.asset = self.attachAsset('police', {
anchorX: 0.5,
anchorY: 0.5
});
// Add 'POLIS' label above the police shooter
self.polisLabel = new Text2('POLIS', {
size: 38,
fill: 0xFFFFFF
});
self.polisLabel.anchor.set(0.5, 1);
self.polisLabel.y = -80;
self.addChild(self.polisLabel);
// Add gun to police shooter's hand
self.gun = self.attachAsset('gun', {
anchorX: 0.1,
anchorY: 0.5
});
self.gun.x = 60;
self.gun.y = 0;
self.gun.visible = true;
self.addChild(self.gun);
self.speed = 5; // reduced for slower police
self.target = null;
self.lastShotTick = 0;
self.lastShotDir = 0; // direction of last shot
self.update = function () {
// If not aggro (no target), patrol randomly on roads
if (!self.target) {
if (typeof self.patrolTarget === "undefined" || !self.patrolTarget) {
// Pick a random road block as patrol target
var roadBlocks = [];
for (var k = 0; k < cityBlocks.length; k++) {
if (cityBlocks[k].type === 'road') roadBlocks.push(cityBlocks[k]);
}
if (roadBlocks.length > 0) {
var idx = Math.floor(Math.random() * roadBlocks.length);
self.patrolTarget = {
x: roadBlocks[idx].x + (Math.random() - 0.5) * 100,
y: roadBlocks[idx].y + (Math.random() - 0.5) * 100
};
}
}
if (self.patrolTarget) {
var dx = self.patrolTarget.x - self.x;
var dy = self.patrolTarget.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 10) {
self.direction = Math.atan2(dy, dx);
self.x += Math.cos(self.direction) * self.speed * 0.5;
self.y += Math.sin(self.direction) * self.speed * 0.5;
} else {
// Arrived at patrol target, pick a new one next frame
self.patrolTarget = null;
}
// Gun points in patrol direction
self.lastShotDir = self.direction;
self.gun.x = 60 * Math.cos(self.lastShotDir);
self.gun.y = 60 * Math.sin(self.lastShotDir);
self.gun.rotation = self.lastShotDir;
}
} else {
// Move toward player if target exists
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 120) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
}
// Gun points at player
self.lastShotDir = Math.atan2(dy, dx);
self.gun.x = 60 * Math.cos(self.lastShotDir);
self.gun.y = 60 * Math.sin(self.lastShotDir);
self.gun.rotation = self.lastShotDir;
}
// Firing handled in game.update
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
// No title, no description
// Set backgroundColor to vibrant green for lush map
backgroundColor: 0x1ecb2a
});
/****
* Game Code
****/
// --- Market Setup ---
var marketEntrance = new Container();
marketEntrance.asset = marketEntrance.attachAsset('building', {
anchorX: 0.5,
anchorY: 0.5
});
marketEntrance.asset.width = 300;
marketEntrance.asset.height = 300;
marketEntrance.x = (gridCols - 1) / 2 * blockSize + blockSize / 2 + 300; // rightmost road col + offset
marketEntrance.y = 0 * blockSize + blockSize / 2;
marketEntrance.isMarketEntrance = true;
// Add 'MARKET' label above the market entrance
marketEntrance.marketLabel = new Text2('MARKET', {
size: 90,
fill: "#fff"
});
marketEntrance.marketLabel.anchor.set(0.5, 1);
marketEntrance.marketLabel.x = 0;
marketEntrance.marketLabel.y = -170;
marketEntrance.addChild(marketEntrance.marketLabel);
game.addChild(marketEntrance);
// Market interior (hidden until entered)
var marketInterior = new Container();
marketInterior.asset = marketInterior.attachAsset('building', {
anchorX: 0.5,
anchorY: 0.5
});
marketInterior.asset.width = 800;
marketInterior.asset.height = 800;
marketInterior.x = 2048 / 2;
marketInterior.y = 2732 / 2;
marketInterior.visible = false;
game.addChild(marketInterior);
// Market buy ammo button
var marketBuyBtn = new Text2("₺50'ye 100 mermi al", {
size: 120,
fill: "#fff"
});
marketBuyBtn.anchor.set(0.5, 0.5);
marketBuyBtn.x = marketInterior.x;
marketBuyBtn.y = marketInterior.y + 100;
marketBuyBtn.visible = false;
game.addChild(marketBuyBtn);
// Market exit (door)
var marketExit = new Container();
marketExit.asset = marketExit.attachAsset('road', {
anchorX: 0.5,
anchorY: 0.5
});
marketExit.asset.width = 200;
marketExit.asset.height = 100;
marketExit.x = marketInterior.x;
marketExit.y = marketInterior.y + 350;
marketExit.visible = false;
marketExit.isMarketExit = true;
game.addChild(marketExit);
// Track if player is in market
var playerInMarket = false;
// marketStartPos will be initialized after player is created
var marketStartPos;
// --- Money on ground ---
// Police car - white box with blue
// Car - yellow box
// Player (hero) - red ellipse
// Building - blue box
// City block (road) - gray box
// --- Fixed City Map Setup ---
var blockSize = 400;
var cityBlocks = [];
var cityBlockMap = {}; // key: "col,row" -> CityBlock
// Fixed grid size
var gridCols = 9;
var gridRows = 13;
// Use a simple procedural pattern: every even col/row is road, others are building
function getBlockType(col, row) {
// Make a simple city: roads every 2 blocks, rest are buildings
if (col % 2 === 0 || row % 2 === 0) return 'road';
return 'building';
}
// Helper to get or create a city block at (col, row)
function getOrCreateCityBlock(col, row) {
// Clamp to fixed grid
if (col < -Math.floor(gridCols / 2) || col > Math.floor(gridCols / 2) || row < -Math.floor(gridRows / 2) || row > Math.floor(gridRows / 2)) {
return null;
}
var key = col + ',' + row;
if (cityBlockMap[key]) return cityBlockMap[key];
var block = new CityBlock();
var type = getBlockType(col, row);
block.setType(type);
block.x = col * blockSize + blockSize / 2;
block.y = row * blockSize + blockSize / 2;
cityBlockMap[key] = block;
cityBlocks.push(block);
game.addChild(block);
return block;
}
// Generate fixed grid (centered at 0,0)
var initialCols = gridCols,
initialRows = gridRows;
var centerCol = 0,
centerRow = 0;
for (var row = -Math.floor(initialRows / 2); row <= Math.floor(initialRows / 2); row++) {
for (var col = -Math.floor(initialCols / 2); col <= Math.floor(initialCols / 2); col++) {
getOrCreateCityBlock(col, row);
}
}
// Helper to get all road blocks in a region (for spawning)
function getRoadBlocksInRegion(colMin, colMax, rowMin, rowMax) {
var blocks = [];
for (var row = rowMin; row <= rowMax; row++) {
for (var col = colMin; col <= colMax; col++) {
var block = getOrCreateCityBlock(col, row);
if (block && block.type === 'road') blocks.push(block);
}
}
return blocks;
}
// Helper to get nearest road block col/row for a given x/y
function getColRowForXY(x, y) {
var col = Math.round((x - blockSize / 2) / blockSize);
var row = Math.round((y - blockSize / 2) / blockSize);
// Clamp to grid
col = Math.max(-Math.floor(gridCols / 2), Math.min(Math.floor(gridCols / 2), col));
row = Math.max(-Math.floor(gridRows / 2), Math.min(Math.floor(gridRows / 2), row));
return {
col: col,
row: row
};
}
// --- Player Setup ---
// Spawn player at center of the infinite world (col=0, row=0)
var player = new Player();
player.x = 0 * blockSize + blockSize / 2;
player.y = 0 * blockSize + blockSize / 2;
game.addChild(player);
// Now that player is defined, initialize marketStartPos
marketStartPos = {
x: player.x,
y: player.y
};
// --- Civilians Setup ---
var civilians = [];
// Spawn 6 civilians at random road blocks (not near player or police)
for (var i = 0; i < 6; i++) {
// Use a region around player for infinite world
var playerColRow = getColRowForXY(player.x, player.y);
var roadBlocks = getRoadBlocksInRegion(playerColRow.col - 7, playerColRow.col + 7, playerColRow.row - 7, playerColRow.row + 7);
// Avoid spawn near player
var filtered = [];
for (var j = 0; j < roadBlocks.length; j++) {
var b = roadBlocks[j];
var distToPlayer = Math.sqrt(Math.pow(b.x - player.x, 2) + Math.pow(b.y - player.y, 2));
if (distToPlayer > 400) filtered.push(b);
}
if (filtered.length > 0) {
var idx = Math.floor(Math.random() * filtered.length);
var civ = new Civilian();
civ.x = filtered[idx].x + (Math.random() - 0.5) * 100;
civ.y = filtered[idx].y + (Math.random() - 0.5) * 100;
civilians.push(civ);
game.addChild(civ);
}
}
// --- Cars Setup ---
var cars = [];
function spawnCar(x, y) {
var car = new Car();
car.x = x;
car.y = y;
car.direction = Math.random() * Math.PI * 2;
cars.push(car);
game.addChild(car);
return car;
}
// Place a few cars on roads using fixed world
var roadBlocksForCars = [];
for (var i = 0; i < cityBlocks.length; i++) {
if (cityBlocks[i].type === 'road') {
// Remove player's starting block
if (!(cityBlocks[i].x === player.x && cityBlocks[i].y === player.y)) {
roadBlocksForCars.push(cityBlocks[i]);
}
}
}
// Shuffle
for (var k = roadBlocksForCars.length - 1; k > 0; k--) {
var j = Math.floor(Math.random() * (k + 1));
var temp = roadBlocksForCars[k];
roadBlocksForCars[k] = roadBlocksForCars[j];
roadBlocksForCars[j] = temp;
}
// Spawn up to 4 cars in distinct available road blocks
var carsToSpawn = 4;
for (var i = 0; i < Math.min(carsToSpawn, roadBlocksForCars.length); i++) {
var block = roadBlocksForCars[i];
spawnCar(block.x, block.y);
}
// --- Police Setup ---
var policeCars = [];
function spawnPolice(x, y) {
var police = new PoliceCar();
police.x = x;
police.y = y;
police.direction = 0;
// Police do not chase the player anymore
police.target = null;
policeCars.push(police);
game.addChild(police);
return police;
}
// Start with three police cars at different road blocks
var policeStartBlocks = [];
for (var i = 0; i < cityBlocks.length; i++) {
if (cityBlocks[i].type === 'road') {
policeStartBlocks.push(cityBlocks[i]);
}
}
if (policeStartBlocks.length > 0) {
// Always spawn one at the top left of region
var policeStartX = cityBlocks[0].x;
var policeStartY = cityBlocks[0].y;
spawnPolice(policeStartX, policeStartY);
// Pick two more random road blocks (not the same as above)
var used = {};
used[policeStartX + ',' + policeStartY] = true;
for (var p = 0; p < 2; p++) {
var idx = Math.floor(Math.random() * policeStartBlocks.length);
var b = policeStartBlocks[idx];
var key = b.x + ',' + b.y;
if (!used[key]) {
spawnPolice(b.x, b.y);
used[key] = true;
}
}
}
// --- Mission Setup ---
var mission = new Mission();
// Place mission at far corner of grid
mission.x = cityBlocks[cityBlocks.length - 1].x;
mission.y = cityBlocks[cityBlocks.length - 1].y;
game.addChild(mission);
// --- Money on ground ---
var moneyPickups = [];
function spawnMoney(x, y) {
var m = new Container();
m.asset = m.attachAsset('mission', {
anchorX: 0.5,
anchorY: 0.5
});
m.x = x;
m.y = y;
m.value = 50;
moneyPickups.push(m);
game.addChild(m);
return m;
}
// Place 15 money pickups at random road blocks in grid
var roadBlocksForMoney = [];
for (var i = 0; i < cityBlocks.length; i++) {
if (cityBlocks[i].type === 'road') {
roadBlocksForMoney.push(cityBlocks[i]);
}
}
for (var i = 0; i < 15; i++) {
if (roadBlocksForMoney.length > 0) {
var idx = Math.floor(Math.random() * roadBlocksForMoney.length);
var b = roadBlocksForMoney[idx];
var mx = b.x + (Math.random() - 0.5) * (blockSize - 100);
var my = b.y + (Math.random() - 0.5) * (blockSize - 100);
spawnMoney(mx, my);
}
}
// --- Score and Wanted Level ---
var score = 0;
var wantedLevel = 1; // 1-5
var scoreTxt = new Text2('Score: 0', {
size: 90,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var wantedTxt = new Text2('★', {
size: 80,
fill: "#ff0"
});
wantedTxt.anchor.set(1, 0); // anchor to top right
wantedTxt.x = 0;
wantedTxt.y = 0;
LK.gui.topRight.addChild(wantedTxt);
// (Removed 'elinde akm var' text below the wanted stars)
// --- Timer ---
var timeLeft = 60; // seconds
var timerTxt = new Text2('60', {
size: 80,
fill: "#fff"
});
timerTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(timerTxt);
// --- Touch Controls ---
var dragDir = null; // {dx,dy}
var dragStart = null;
var dragNode = null;
var lastTouchX = 0,
lastTouchY = 0;
// --- Shooting & Health ---
var bullets = [];
var policeBullets = [];
var playerHealth = 5;
// --- Ammo system ---
var playerAmmo = 100;
var ammoTxt = new Text2('Ammo: 100', {
size: 80,
fill: "#fff"
});
// Anchor to top right (same as wanted stars)
ammoTxt.anchor.set(1, 0);
// Place just below the wanted stars (wantedTxt is at y=0, height ~80)
ammoTxt.x = 0;
ammoTxt.y = wantedTxt.y + wantedTxt.height + 10; // 10px below stars
LK.gui.topRight.addChild(ammoTxt);
function updateAmmoDisplay() {
ammoTxt.setText('Ammo: ' + playerAmmo);
}
// Money system
var playerMoney = 0;
var moneyTxt = new Text2('₺ 0', {
size: 120,
fill: 0x44FF44
});
moneyTxt.anchor.set(0, 0);
moneyTxt.x = 100;
moneyTxt.y = 90;
LK.gui.addChild(moneyTxt);
var healthTxt = new Text2('♥♥♥♥♥', {
size: 80,
fill: 0xFF4444
});
healthTxt.anchor.set(0, 0); // anchor top left
// Place health bar at (100,0) to avoid platform menu
healthTxt.x = 100;
healthTxt.y = 0;
LK.gui.addChild(healthTxt);
// Track if police are aggressive (chasing) or passive
var policeAggro = false;
// Helper to update health display
function updateHealthDisplay() {
var hearts = '';
for (var i = 0; i < playerHealth; i++) hearts += '♥';
healthTxt.setText(hearts);
}
function updateMoneyDisplay() {
moneyTxt.setText('₺ ' + playerMoney);
}
var policeShooters = [];
// Spawn a few police shooters at random road blocks, not near player (fixed world)
for (var i = 0; i < 8; i++) {
var roadBlocks = [];
for (var j = 0; j < cityBlocks.length; j++) {
if (cityBlocks[j].type === 'road') {
var b = cityBlocks[j];
var distToPlayer = Math.sqrt(Math.pow(b.x - player.x, 2) + Math.pow(b.y - player.y, 2));
if (distToPlayer > 600) roadBlocks.push(b);
}
}
if (roadBlocks.length > 0) {
var idx = Math.floor(Math.random() * roadBlocks.length);
var shooter = new PoliceShooter();
shooter.x = roadBlocks[idx].x + (Math.random() - 0.5) * 100;
shooter.y = roadBlocks[idx].y + (Math.random() - 0.5) * 100;
shooter.target = null; // Do not target player at start
shooter.wasShotAt = false; // Only shoot if player shoots at them
policeShooters.push(shooter);
game.addChild(shooter);
}
}
// --- Helper Functions ---
function isOnRoad(x, y) {
// Returns true if (x,y) is on a road block (fixed world)
var colRow = getColRowForXY(x, y);
var block = getOrCreateCityBlock(colRow.col, colRow.row);
if (block && block.type === 'road') {
var left = block.x - blockSize / 2;
var right = block.x + blockSize / 2;
var top = block.y - blockSize / 2;
var bottom = block.y + blockSize / 2;
if (x >= left && x <= right && y >= top && y <= bottom) {
return true;
}
}
return false;
}
function clampToRoad(x, y) {
// Snap to nearest road block center (fixed world)
var colRow = getColRowForXY(x, y);
var block = getOrCreateCityBlock(colRow.col, colRow.row);
if (block && block.type === 'road') {
return {
x: block.x,
y: block.y
};
}
// If not road, search nearby
for (var r = -1; r <= 1; r++) {
for (var c = -1; c <= 1; c++) {
var b = getOrCreateCityBlock(colRow.col + c, colRow.row + r);
if (b && b.type === 'road') return {
x: b.x,
y: b.y
};
}
}
// Fallback: return original
return {
x: x,
y: y
};
}
function updateWantedDisplay() {
var stars = '';
for (var i = 0; i < wantedLevel; i++) stars += '★';
wantedTxt.setText(stars);
// Default color
var color = "#ff0";
// If 5 stars, flash red/blue
if (wantedLevel === 5) {
// Show "wandet" text for 3 seconds only on the frame wantedLevel becomes 5
if (typeof wandetTextShown === "undefined") wandetTextShown = false;
if (!wandetTextShown) {
// Remove previous if exists
if (typeof wandetText !== "undefined" && wandetText.parent) {
wandetText.parent.removeChild(wandetText);
wandetText = undefined;
}
wandetText = new Text2("wandet", {
size: 160,
fill: 0xFF2222
});
wandetText.anchor.set(0.5, 0);
wandetText.x = 2048 / 2;
wandetText.y = 500;
LK.gui.addChild(wandetText);
wandetTextShown = true;
LK.setTimeout(function () {
if (wandetText && wandetText.parent) {
wandetText.parent.removeChild(wandetText);
wandetText = undefined;
}
wandetTextShown = false;
}, 3000);
}
// Alternate color every 20 ticks (about 1/3 second at 60fps)
if (LK.ticks % 40 < 20) {
color = "#ff2222"; // red
} else {
color = "#2288ff"; // blue
}
}
if (wantedTxt && wantedTxt.style && typeof wantedTxt.style.fill !== "undefined") {
wantedTxt.style.fill = color;
}
}
function addScore(amt) {
score += amt;
scoreTxt.setText('Score: ' + score);
LK.setScore(score);
}
function resetMission() {
// Place mission at random road block (fixed world)
var roadBlocks = [];
for (var i = 0; i < cityBlocks.length; i++) {
if (cityBlocks[i].type === 'road') {
var b = cityBlocks[i];
var distToPlayer = Math.sqrt(Math.pow(b.x - player.x, 2) + Math.pow(b.y - player.y, 2));
if (distToPlayer > 400) roadBlocks.push(b);
}
}
if (roadBlocks.length > 0) {
var idx = Math.floor(Math.random() * roadBlocks.length);
mission.x = roadBlocks[idx].x;
mission.y = roadBlocks[idx].y;
mission.active = true;
mission.visible = true;
}
}
// --- Game Touch Controls ---
// Drag to move (swipe in direction to move)
game.down = function (x, y, obj) {
// Don't allow drag from top left 100x100
if (x < 100 && y < 100) return;
// --- SHOOTING LOGIC ---
// If not dragging, treat as tap to shoot
if (!dragNode && !dragDir && !player.inCar) {
if (typeof playerAmmo === "undefined") playerAmmo = 0;
if (playerAmmo > 0) {
// Player shoots toward (x, y)
var b = new Bullet();
b.x = player.x;
b.y = player.y;
b.dir = Math.atan2(y - b.y, x - b.x);
b.owner = 'player';
bullets.push(b);
game.addChild(b);
// Update player's gun direction to point at shot
player.lastShotDir = b.dir;
playerAmmo--;
if (typeof updateAmmoDisplay === "function") updateAmmoDisplay();
} else {
// Out of ammo: show "mermi bitti" for 1 second at center-top
if (typeof ammoEmptyText !== "undefined" && ammoEmptyText.parent) {
ammoEmptyText.parent.removeChild(ammoEmptyText);
ammoEmptyText = undefined;
}
ammoEmptyText = new Text2("mermi bitti", {
size: 120,
fill: 0xFF2222
});
ammoEmptyText.anchor.set(0.5, 0);
ammoEmptyText.x = 2048 / 2;
ammoEmptyText.y = 320;
LK.gui.addChild(ammoEmptyText);
LK.setTimeout(function () {
if (ammoEmptyText && ammoEmptyText.parent) {
ammoEmptyText.parent.removeChild(ammoEmptyText);
ammoEmptyText = undefined;
}
}, 1000);
}
// No police aggro or wanted level increase when shooting police
}
// --- DRAG LOGIC (movement) ---
dragStart = {
x: x,
y: y
};
lastTouchX = x;
lastTouchY = y;
dragDir = null;
dragNode = player;
};
game.move = function (x, y, obj) {
if (!dragNode) return;
var dx = x - dragStart.x;
var dy = y - dragStart.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 30) {
dragDir = {
dx: dx,
dy: dy
};
}
lastTouchX = x;
lastTouchY = y;
};
game.up = function (x, y, obj) {
dragNode = null;
dragDir = null;
dragStart = null;
};
// --- Car Enter/Exit Logic ---
// Track tap times for triple-tap exit
var carTapTimes = [];
game.on('down', function (x, y, obj) {
// If player is not in car, check if tap is on car and player is close enough
if (!player.inCar) {
for (var i = 0; i < cars.length; i++) {
var car = cars[i];
var dx = car.x - x;
var dy = car.y - y;
// Tap must be on car
if (Math.abs(dx) < 80 && Math.abs(dy) < 50) {
// Player must be close to car to enter
if (Math.abs(player.x - car.x) < 120 && Math.abs(player.y - car.y) < 80) {
player.inCar = car;
car.driver = player;
// Do not set car.speed here; Car.update will handle acceleration
car.direction = 0;
// Increase wanted level
wantedLevel = Math.min(5, wantedLevel + 1);
updateWantedDisplay();
// Police target car
for (var j = 0; j < policeCars.length; j++) {
policeCars[j].target = car;
}
// Reset tap times for exit
carTapTimes = [];
break;
}
}
}
} else {
// Player is in car: require triple-tap within 1 second to exit
var now = Date.now();
carTapTimes.push(now);
// Only keep last 3 taps
if (carTapTimes.length > 3) carTapTimes.shift();
if (carTapTimes.length === 3) {
// Check if 3 taps are within 1 second
if (carTapTimes[2] - carTapTimes[0] < 1000) {
var car = player.inCar;
player.inCar = null;
car.driver = null;
// Do not set car.speed to 0; Car.update will handle deceleration
// Place player next to car
player.x = car.x + 80;
player.y = car.y;
// Police target player
for (var j = 0; j < policeCars.length; j++) {
policeCars[j].target = player;
}
carTapTimes = [];
}
}
}
});
// --- Game Update Loop ---
game.update = function () {
// Timer
if (LK.ticks % 60 === 0 && timeLeft > 0) {
timeLeft--;
timerTxt.setText(timeLeft + '');
// Do not end the game when timer reaches zero
}
// --- Market logic ---
// If not in market, check for market entrance
if (!playerInMarket) {
// Check if player is at market entrance (right edge)
if (Math.abs(player.x - marketEntrance.x) < 120 && Math.abs(player.y - marketEntrance.y) < 120) {
// Teleport to market interior
playerInMarket = true;
marketStartPos.x = player.x;
marketStartPos.y = player.y;
player.x = marketInterior.x;
player.y = marketInterior.y - 100;
marketInterior.visible = true;
marketBuyBtn.visible = true;
marketExit.visible = true;
// Hide city elements
for (var i = 0; i < cityBlocks.length; i++) cityBlocks[i].visible = false;
for (var i = 0; i < cars.length; i++) cars[i].visible = false;
for (var i = 0; i < civilians.length; i++) civilians[i].visible = false;
for (var i = 0; i < policeCars.length; i++) policeCars[i].visible = false;
for (var i = 0; i < policeShooters.length; i++) policeShooters[i].visible = false;
for (var i = 0; i < moneyPickups.length; i++) moneyPickups[i].visible = false;
if (typeof gunPickups !== "undefined") for (var i = 0; i < gunPickups.length; i++) gunPickups[i].visible = false;
mission.visible = false;
marketEntrance.visible = false;
}
} else {
// In market: only allow movement inside market area
if (dragDir) {
var angle = Math.atan2(dragDir.dy, dragDir.dx);
var nx = player.x + Math.cos(angle) * player.speed;
var ny = player.y + Math.sin(angle) * player.speed;
// Clamp to market interior bounds
var left = marketInterior.x - 350,
right = marketInterior.x + 350;
var top = marketInterior.y - 350,
bottom = marketInterior.y + 350;
if (nx > left && nx < right && ny > top && ny < bottom) {
player.x = nx;
player.y = ny;
}
}
// Check for ammo buy (touch on buy button)
if (Math.abs(player.x - marketBuyBtn.x) < 200 && Math.abs(player.y - marketBuyBtn.y) < 100) {
if (playerMoney >= 50 && playerAmmo < 100) {
playerMoney -= 50;
playerAmmo = 100;
updateMoneyDisplay();
updateAmmoDisplay();
// Show "100 mermi alındı" text
if (typeof marketBuyText !== "undefined" && marketBuyText.parent) {
marketBuyText.parent.removeChild(marketBuyText);
marketBuyText = undefined;
}
marketBuyText = new Text2("100 mermi alındı", {
size: 120,
fill: 0x44FF44
});
marketBuyText.anchor.set(0.5, 0);
marketBuyText.x = 2048 / 2;
marketBuyText.y = 320;
LK.gui.addChild(marketBuyText);
LK.setTimeout(function () {
if (marketBuyText && marketBuyText.parent) {
marketBuyText.parent.removeChild(marketBuyText);
marketBuyText = undefined;
}
}, 1000);
}
}
// Check for exit (touch on exit door)
if (Math.abs(player.x - marketExit.x) < 120 && Math.abs(player.y - marketExit.y) < 80) {
// Teleport back to start
player.x = marketStartPos.x;
player.y = marketStartPos.y;
playerInMarket = false;
marketInterior.visible = false;
marketBuyBtn.visible = false;
marketExit.visible = false;
// Show city elements again
for (var i = 0; i < cityBlocks.length; i++) cityBlocks[i].visible = true;
for (var i = 0; i < cars.length; i++) cars[i].visible = true;
for (var i = 0; i < civilians.length; i++) civilians[i].visible = true;
for (var i = 0; i < policeCars.length; i++) policeCars[i].visible = true;
for (var i = 0; i < policeShooters.length; i++) policeShooters[i].visible = true;
for (var i = 0; i < moneyPickups.length; i++) moneyPickups[i].visible = true;
if (typeof gunPickups !== "undefined") for (var i = 0; i < gunPickups.length; i++) gunPickups[i].visible = true;
mission.visible = true;
marketEntrance.visible = true;
}
}
// Player movement
if (!player.inCar && dragDir && !playerInMarket) {
// Move player in drag direction, but only on road
var angle = Math.atan2(dragDir.dy, dragDir.dx);
var nx = player.x + Math.cos(angle) * player.speed;
var ny = player.y + Math.sin(angle) * player.speed;
if (isOnRoad(nx, ny)) {
player.x = nx;
player.y = ny;
}
// No infinite world: no need to generate new blocks in update
}
// Car movement (if player in car)
for (var i = 0; i < cars.length; i++) {
var car = cars[i];
// If player is driving this car, set car's targetDir to drag direction
if (car.driver === player && dragDir) {
var angle = Math.atan2(dragDir.dy, dragDir.dx);
car.targetDir = angle;
}
car.update();
// Clamp car to road
if (car.driver) {
if (!isOnRoad(car.x, car.y)) {
// Stop car at edge
car.speed = 0;
}
}
}
// Police movement
for (var i = 0; i < policeCars.length; i++) {
var police = policeCars[i];
// Police patrol logic: move randomly on roads if not chasing
if (!policeAggro) {
if (typeof police.patrolTarget === "undefined" || !police.patrolTarget) {
// Pick a random road block as patrol target
var roadBlocks = [];
for (var k = 0; k < cityBlocks.length; k++) {
if (cityBlocks[k].type === 'road') roadBlocks.push(cityBlocks[k]);
}
if (roadBlocks.length > 0) {
var idx = Math.floor(Math.random() * roadBlocks.length);
police.patrolTarget = {
x: roadBlocks[idx].x + (Math.random() - 0.5) * 100,
y: roadBlocks[idx].y + (Math.random() - 0.5) * 100
};
}
}
if (police.patrolTarget) {
var dx = police.patrolTarget.x - police.x;
var dy = police.patrolTarget.y - police.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 10) {
police.direction = Math.atan2(dy, dx);
police.speed = police.maxSpeed * 0.5;
police.x += Math.cos(police.direction) * police.speed;
police.y += Math.sin(police.direction) * police.speed;
} else {
// Arrived at patrol target, pick a new one next frame
police.patrolTarget = null;
police.speed = 0;
}
}
} else {
police.update();
}
// Clamp police to road
if (!isOnRoad(police.x, police.y)) {
police.speed = 0;
}
// Police catch player
var target = police.target;
if (policeAggro && target && Math.abs(police.x - target.x) < 80 && Math.abs(police.y - target.y) < 80) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
}
// Police shooters update
for (var i = policeShooters.length - 1; i >= 0; i--) {
var shooter = policeShooters[i];
shooter.update();
// Remove if off map
if (shooter.x < 0 || shooter.x > 2048 || shooter.y < 0 || shooter.y > 2732) {
shooter.destroy();
policeShooters.splice(i, 1);
continue;
}
// --- Police shooter fires at player only if aggro (wasShotAt or policeAggro) ---
// Only fire if player is within 700px, not in car, and shooter is aggro
if (shooter.wasShotAt || policeAggro) {
var px = player.inCar ? player.inCar.x : player.x;
var py = player.inCar ? player.inCar.y : player.y;
var dx = px - shooter.x;
var dy = py - shooter.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 700 && LK.ticks - shooter.lastShotTick > 60) {
// Fire bullet toward player
var b = new Bullet();
b.x = shooter.x;
b.y = shooter.y;
b.dir = Math.atan2(dy, dx);
b.owner = 'police';
policeBullets.push(b);
game.addChild(b);
shooter.lastShotTick = LK.ticks;
}
}
}
// Bullets update (player)
for (var i = bullets.length - 1; i >= 0; i--) {
var b = bullets[i];
if (b && typeof b.update === "function") {
b.update();
}
// Remove if off screen
if (b && typeof b.x === "number" && typeof b.y === "number" && (b.x < 0 || b.x > 2048 || b.y < 0 || b.y > 2732)) {
b.destroy();
bullets.splice(i, 1);
continue;
}
// --- Police car kill check ---
for (var j = policeCars.length - 1; j >= 0; j--) {
var police = policeCars[j];
// --- Car bullet hit logic ---
if (police && b && typeof police.x === "number" && typeof police.y === "number" && typeof b.x === "number" && typeof b.y === "number" && Math.abs(police.x - b.x) < 60 && Math.abs(police.y - b.y) < 60) {
// Track bullet hits on this car
if (typeof police.bulletHitCount === "undefined") police.bulletHitCount = 0;
police.bulletHitCount++;
// Remove bullet
b.destroy();
bullets.splice(i, 1);
// If hit 30 times, destroy car and show "arba patladı"
if (police.bulletHitCount >= 30) {
// Drop a gun at police car's position
var gunDrop = new Container();
gunDrop.asset = gunDrop.attachAsset('gun', {
anchorX: 0.5,
anchorY: 0.5
});
// Add 'gun' label above the dropped gun
gunDrop.gunLabel = new Text2('gun', {
size: 38,
fill: 0xFFFFFF
});
gunDrop.gunLabel.anchor.set(0.5, 1);
gunDrop.gunLabel.y = -30;
gunDrop.addChild(gunDrop.gunLabel);
gunDrop.x = police.x;
gunDrop.y = police.y;
gunDrop.isGunPickup = true;
game.addChild(gunDrop);
if (typeof gunPickups === "undefined") gunPickups = [];
gunPickups.push(gunDrop);
police.destroy();
policeCars.splice(j, 1);
// Show "arba patladı" text for 2 seconds at center of screen
if (typeof carExplodedText !== "undefined" && carExplodedText.parent) {
carExplodedText.parent.removeChild(carExplodedText);
carExplodedText = undefined;
}
carExplodedText = new Text2("arba patladı", {
size: 160,
fill: 0xFF2222
});
carExplodedText.anchor.set(0.5, 0.5);
carExplodedText.x = 2048 / 2;
carExplodedText.y = 2732 / 2;
LK.gui.addChild(carExplodedText);
LK.setTimeout(function () {
if (carExplodedText && carExplodedText.parent) {
carExplodedText.parent.removeChild(carExplodedText);
carExplodedText = undefined;
}
}, 2000);
addScore(20);
// Increase wanted level by 1 (max 5) when police car is killed
wantedLevel = Math.min(5, wantedLevel + 1);
updateWantedDisplay();
// Only aggro police if wantedLevel is 5
if (wantedLevel === 5 && typeof spawned5StarPolice === "undefined") {
for (var p = 0; p < policeShooters.length; p++) {
policeShooters[p].wasShotAt = true;
policeShooters[p].target = player;
}
for (var p = 0; p < policeCars.length; p++) {
policeCars[p].target = player;
}
policeAggro = true;
// Spawn 20 police cars at random road blocks (not near player)
var roadBlocks = [];
for (var i = 0; i < cityBlocks.length; i++) {
if (cityBlocks[i].type === 'road') {
var distToPlayer = Math.sqrt(Math.pow(cityBlocks[i].x - player.x, 2) + Math.pow(cityBlocks[i].y - player.y, 2));
if (distToPlayer > 400) {
roadBlocks.push(cityBlocks[i]);
}
}
}
for (var s = 0; s < 20; s++) {
if (roadBlocks.length > 0) {
var idx = Math.floor(Math.random() * roadBlocks.length);
var b = roadBlocks[idx];
var newPolice = spawnPolice(b.x, b.y);
newPolice.target = player;
// Remove this block from roadBlocks to avoid double-spawn at same spot
roadBlocks.splice(idx, 1);
}
}
// --- Spawn 40 police shooters at random road blocks, not near player ---
for (var spawnCount = 0; spawnCount < 40; spawnCount++) {
var shooterBlocks = [];
for (var k = 0; k < cityBlocks.length; k++) {
var b2 = cityBlocks[k];
if (b2.type === 'road') {
var distToPlayer = Math.sqrt(Math.pow(b2.x - player.x, 2) + Math.pow(b2.y - player.y, 2));
if (distToPlayer > 600) {
shooterBlocks.push(b2);
}
}
}
if (shooterBlocks.length > 0) {
var idx2 = Math.floor(Math.random() * shooterBlocks.length);
var newShooter = new PoliceShooter();
newShooter.x = shooterBlocks[idx2].x + (Math.random() - 0.5) * 100;
newShooter.y = shooterBlocks[idx2].y + (Math.random() - 0.5) * 100;
newShooter.target = player;
newShooter.wasShotAt = true;
policeShooters.push(newShooter);
game.addChild(newShooter);
shooterBlocks.splice(idx2, 1);
}
}
spawned5StarPolice = true;
}
break;
}
// If not destroyed, do not break, allow other cars to be checked
continue;
}
// --- END Car bullet hit logic ---
}
// --- Police shooter kill check ---
for (var j = policeShooters.length - 1; j >= 0; j--) {
var shooter = policeShooters[j];
if (shooter && b && typeof shooter.x === "number" && typeof shooter.y === "number" && typeof b.x === "number" && typeof b.y === "number" && Math.abs(shooter.x - b.x) < 60 && Math.abs(shooter.y - b.y) < 60) {
// Mark this shooter as shot at, so it will shoot back
shooter.wasShotAt = true;
// --- Police shooter health logic ---
// Instantly kill police shooter with one bullet
b.destroy();
bullets.splice(i, 1);
// Police shooter killed!
// Drop a gun at police shooter's position
var gunDrop = new Container();
gunDrop.asset = gunDrop.attachAsset('gun', {
anchorX: 0.5,
anchorY: 0.5
});
// Add 'gun' label above the dropped gun
gunDrop.gunLabel = new Text2('gun', {
size: 38,
fill: 0xFFFFFF
});
gunDrop.gunLabel.anchor.set(0.5, 1);
gunDrop.gunLabel.y = -30;
gunDrop.addChild(gunDrop.gunLabel);
gunDrop.x = shooter.x;
gunDrop.y = shooter.y;
gunDrop.isGunPickup = true;
game.addChild(gunDrop);
if (typeof gunPickups === "undefined") gunPickups = [];
gunPickups.push(gunDrop);
shooter.destroy();
policeShooters.splice(j, 1);
// --- Spawn TWO new police shooters at random road blocks, not near player ---
for (var spawnCount = 0; spawnCount < 2; spawnCount++) {
var roadBlocks = [];
for (var k = 0; k < cityBlocks.length; k++) {
var b2 = cityBlocks[k];
if (b2.type === 'road') {
var distToPlayer = Math.sqrt(Math.pow(b2.x - player.x, 2) + Math.pow(b2.y - player.y, 2));
if (distToPlayer > 600) {
roadBlocks.push(b2);
}
}
}
if (roadBlocks.length > 0) {
var idx2 = Math.floor(Math.random() * roadBlocks.length);
var newShooter = new PoliceShooter();
newShooter.x = roadBlocks[idx2].x + (Math.random() - 0.5) * 100;
newShooter.y = roadBlocks[idx2].y + (Math.random() - 0.5) * 100;
if (policeAggro) {
newShooter.target = player;
newShooter.wasShotAt = true;
} else {
newShooter.target = null;
newShooter.wasShotAt = false;
}
policeShooters.push(newShooter);
game.addChild(newShooter);
}
}
addScore(15);
// Increase wanted level by 1 (max 5) when police shooter is killed
wantedLevel = Math.min(5, wantedLevel + 1);
updateWantedDisplay();
break;
// If not dead, do not break, allow other shooters to be checked
}
}
}
// Bullets update (police)
for (var i = policeBullets.length - 1; i >= 0; i--) {
var b = policeBullets[i];
if (b && typeof b.update === "function") {
b.update();
}
// Remove if off screen
if (b && typeof b.x === "number" && typeof b.y === "number" && (b.x < 0 || b.x > 2048 || b.y < 0 || b.y > 2732)) {
b.destroy();
policeBullets.splice(i, 1);
continue;
}
// Check hit player
var px = player.inCar ? player.inCar.x : player.x;
var py = player.inCar ? player.inCar.y : player.y;
if (Math.abs(px - b.x) < 60 && Math.abs(py - b.y) < 60) {
// Police bullet hits player: decrease health if not in car
if (!player.inCar && playerHealth > 0) {
playerHealth--;
updateHealthDisplay();
// Optional: flash screen on hit
LK.effects.flashScreen(0xff0000, 200);
// Game over if health reaches 0
if (playerHealth <= 0) {
LK.showGameOver();
return;
}
}
// If player is in car, do not take damage
b.destroy();
policeBullets.splice(i, 1);
}
}
// Player update
player.update();
// Civilians update and check for being shot by player or run over by car
for (var i = civilians.length - 1; i >= 0; i--) {
var civ = civilians[i];
if (civ && typeof civ.update === "function") {
civ.update();
}
var killed = false;
// Check if hit by any player bullet
for (var j = bullets.length - 1; j >= 0; j--) {
var b = bullets[j];
if (Math.abs(civ.x - b.x) < 60 && Math.abs(civ.y - b.y) < 60) {
killed = true;
// Remove bullet
b.destroy();
bullets.splice(j, 1);
break;
}
}
// Check if run over by any car driven by player
if (!killed) {
for (var c = 0; c < cars.length; c++) {
var car = cars[c];
if (car.driver === player) {
// Use a slightly larger hitbox for car
if (Math.abs(civ.x - car.x) < 90 && Math.abs(civ.y - car.y) < 70) {
killed = true;
break;
}
}
}
}
if (killed) {
// Civilian killed
// Drop money at civilian's position
spawnMoney(civ.x, civ.y);
// Respawn civilian at random road block (fixed world)
var roadBlocks = [];
for (var k = 0; k < cityBlocks.length; k++) {
if (cityBlocks[k].type === 'road') {
var b = cityBlocks[k];
var distToPlayer = Math.sqrt(Math.pow(b.x - player.x, 2) + Math.pow(b.y - player.y, 2));
if (distToPlayer > 400) roadBlocks.push(b);
}
}
if (roadBlocks.length > 0) {
var idx = Math.floor(Math.random() * roadBlocks.length);
var newCiv = new Civilian();
newCiv.x = roadBlocks[idx].x + (Math.random() - 0.5) * 100;
newCiv.y = roadBlocks[idx].y + (Math.random() - 0.5) * 100;
civilians.push(newCiv);
game.addChild(newCiv);
}
civ.destroy();
civilians.splice(i, 1);
addScore(10);
// Increase wanted level by 1 every time player kills an NPC, max 5
wantedLevel = Math.min(5, wantedLevel + 1);
updateWantedDisplay();
// Only aggro police if wantedLevel is 5
if (wantedLevel === 5) {
for (var p = 0; p < policeShooters.length; p++) {
policeShooters[p].wasShotAt = true;
policeShooters[p].target = player;
}
for (var p = 0; p < policeCars.length; p++) {
policeCars[p].target = player;
}
policeAggro = true;
}
// No break here: allow this to happen every time an NPC is killed
continue;
}
// --- Police run over by car logic ---
// Player can run over police shooters and police cars when driving a car
for (var c = 0; c < cars.length; c++) {
var car = cars[c];
if (car.driver === player) {
// Run over police shooters
for (var s = policeShooters.length - 1; s >= 0; s--) {
var shooter = policeShooters[s];
if (Math.abs(shooter.x - car.x) < 90 && Math.abs(shooter.y - car.y) < 70) {
// Police shooter killed by car
// Drop a gun at police shooter's position
var gunDrop = new Container();
gunDrop.asset = gunDrop.attachAsset('gun', {
anchorX: 0.5,
anchorY: 0.5
});
gunDrop.gunLabel = new Text2('gun', {
size: 38,
fill: 0xFFFFFF
});
gunDrop.gunLabel.anchor.set(0.5, 1);
gunDrop.gunLabel.y = -30;
gunDrop.addChild(gunDrop.gunLabel);
gunDrop.x = shooter.x;
gunDrop.y = shooter.y;
gunDrop.isGunPickup = true;
game.addChild(gunDrop);
if (typeof gunPickups === "undefined") gunPickups = [];
gunPickups.push(gunDrop);
shooter.destroy();
policeShooters.splice(s, 1);
// Spawn TWO new police shooters at random road blocks, not near player
for (var spawnCount = 0; spawnCount < 2; spawnCount++) {
var roadBlocks = [];
for (var k = 0; k < cityBlocks.length; k++) {
var b2 = cityBlocks[k];
if (b2.type === 'road') {
var distToPlayer = Math.sqrt(Math.pow(b2.x - player.x, 2) + Math.pow(b2.y - player.y, 2));
if (distToPlayer > 600) {
roadBlocks.push(b2);
}
}
}
if (roadBlocks.length > 0) {
var idx2 = Math.floor(Math.random() * roadBlocks.length);
var newShooter = new PoliceShooter();
newShooter.x = roadBlocks[idx2].x + (Math.random() - 0.5) * 100;
newShooter.y = roadBlocks[idx2].y + (Math.random() - 0.5) * 100;
if (policeAggro) {
newShooter.target = player;
newShooter.wasShotAt = true;
} else {
newShooter.target = null;
newShooter.wasShotAt = false;
}
policeShooters.push(newShooter);
game.addChild(newShooter);
}
}
addScore(15);
// Increase wanted level by 1 (max 5) when police shooter is killed
wantedLevel = Math.min(5, wantedLevel + 1);
updateWantedDisplay();
// Only aggro police if wantedLevel is 5
if (wantedLevel === 5) {
for (var p = 0; p < policeShooters.length; p++) {
policeShooters[p].wasShotAt = true;
policeShooters[p].target = player;
}
for (var p = 0; p < policeCars.length; p++) {
policeCars[p].target = player;
}
policeAggro = true;
}
// Only allow one run over per car per frame
break;
}
}
// Run over police cars
for (var pc = policeCars.length - 1; pc >= 0; pc--) {
var police = policeCars[pc];
if (Math.abs(police.x - car.x) < 90 && Math.abs(police.y - car.y) < 70) {
// Police car killed by car
// Drop a gun at police car's position
var gunDrop = new Container();
gunDrop.asset = gunDrop.attachAsset('gun', {
anchorX: 0.5,
anchorY: 0.5
});
gunDrop.gunLabel = new Text2('gun', {
size: 38,
fill: 0xFFFFFF
});
gunDrop.gunLabel.anchor.set(0.5, 1);
gunDrop.gunLabel.y = -30;
gunDrop.addChild(gunDrop.gunLabel);
gunDrop.x = police.x;
gunDrop.y = police.y;
gunDrop.isGunPickup = true;
game.addChild(gunDrop);
if (typeof gunPickups === "undefined") gunPickups = [];
gunPickups.push(gunDrop);
police.destroy();
policeCars.splice(pc, 1);
addScore(20);
// Increase wanted level by 1 (max 5) when police car is killed
wantedLevel = Math.min(5, wantedLevel + 1);
updateWantedDisplay();
// Only aggro police if wantedLevel is 5
if (wantedLevel === 5 && typeof spawned5StarPolice === "undefined") {
for (var p = 0; p < policeShooters.length; p++) {
policeShooters[p].wasShotAt = true;
policeShooters[p].target = player;
}
for (var p = 0; p < policeCars.length; p++) {
policeCars[p].target = player;
}
policeAggro = true;
// Spawn 5 police cars at random road blocks (not near player)
var roadBlocks = [];
for (var i = 0; i < cityBlocks.length; i++) {
if (cityBlocks[i].type === 'road') {
var distToPlayer = Math.sqrt(Math.pow(cityBlocks[i].x - player.x, 2) + Math.pow(cityBlocks[i].y - player.y, 2));
if (distToPlayer > 400) {
roadBlocks.push(cityBlocks[i]);
}
}
}
for (var s = 0; s < 5; s++) {
if (roadBlocks.length > 0) {
var idx = Math.floor(Math.random() * roadBlocks.length);
var b = roadBlocks[idx];
var newPolice = spawnPolice(b.x, b.y);
newPolice.target = player;
// Remove this block from roadBlocks to avoid double-spawn at same spot
roadBlocks.splice(idx, 1);
}
}
spawned5StarPolice = true;
}
// Only allow one run over per car per frame
break;
}
}
}
}
}
// Money pickup check
var px = player.inCar ? player.inCar.x : player.x;
var py = player.inCar ? player.inCar.y : player.y;
for (var i = moneyPickups.length - 1; i >= 0; i--) {
var m = moneyPickups[i];
if (Math.abs(m.x - px) < 60 && Math.abs(m.y - py) < 60) {
playerMoney += m.value;
updateMoneyDisplay();
m.destroy();
moneyPickups.splice(i, 1);
// Show "+50 money" text for 1 second at center-top of screen
if (typeof moneyPickupText !== "undefined" && moneyPickupText.parent) {
moneyPickupText.parent.removeChild(moneyPickupText);
moneyPickupText = undefined;
}
moneyPickupText = new Text2("+50 money", {
size: 120,
fill: 0x44FF44
});
moneyPickupText.anchor.set(0.5, 0);
moneyPickupText.x = 2048 / 2;
moneyPickupText.y = 320;
LK.gui.addChild(moneyPickupText);
LK.setTimeout(function () {
if (moneyPickupText && moneyPickupText.parent) {
moneyPickupText.parent.removeChild(moneyPickupText);
moneyPickupText = undefined;
}
}, 1000);
}
}
// Gun pickup check
if (typeof gunPickups === "undefined") gunPickups = [];
for (var i = gunPickups.length - 1; i >= 0; i--) {
var g = gunPickups[i];
if (Math.abs(g.x - px) < 60 && Math.abs(g.y - py) < 60) {
// Player picks up gun: restore ammo to 100
playerAmmo = 100;
if (typeof updateAmmoDisplay === "function") updateAmmoDisplay();
g.destroy();
gunPickups.splice(i, 1);
// Show "+1 gun" text for 1 second at center-top of screen
if (typeof gunPickupText !== "undefined" && gunPickupText.parent) {
gunPickupText.parent.removeChild(gunPickupText);
gunPickupText = undefined;
}
gunPickupText = new Text2("+1 gun", {
size: 120,
fill: 0xFFF700
});
gunPickupText.anchor.set(0.5, 0);
// Place at top center, but not in top left 100x100
gunPickupText.x = 2048 / 2;
gunPickupText.y = 180;
LK.gui.addChild(gunPickupText);
// Remove after 1 second
LK.setTimeout(function () {
if (gunPickupText && gunPickupText.parent) {
gunPickupText.parent.removeChild(gunPickupText);
gunPickupText = undefined;
}
}, 1000);
// Optionally: add logic for ammo, weapon upgrade, etc.
}
}
// Mission check
if (mission.active) {
var px = player.inCar ? player.inCar.x : player.x;
var py = player.inCar ? player.inCar.y : player.y;
if (Math.abs(mission.x - px) < 80 && Math.abs(mission.y - py) < 80) {
// Complete mission
addScore(10 * wantedLevel);
mission.active = false;
mission.visible = false;
// Increase wanted level, spawn more police
wantedLevel = Math.min(5, wantedLevel + 1);
updateWantedDisplay();
if (wantedLevel > policeCars.length) {
// Spawn new police at random road
var roadBlocks = [];
for (var i = 0; i < cityBlocks.length; i++) {
if (cityBlocks[i].type === 'road') roadBlocks.push(cityBlocks[i]);
}
var idx = Math.floor(Math.random() * roadBlocks.length);
var b = roadBlocks[idx];
spawnPolice(b.x, b.y);
}
// Next mission after short delay
LK.setTimeout(function () {
resetMission();
}, 1200);
}
}
// Win condition removed: game never ends when score >= 100
};
// --- Start State ---
addScore(0);
updateWantedDisplay();
timerTxt.setText(timeLeft + '');
resetMission();
playerHealth = 5;
updateHealthDisplay();
playerMoney = 0;
updateMoneyDisplay();
policeAggro = false;
var policeHitCount = 0;
;
; /****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
// Bullet class
var Bullet = Container.expand(function () {
var self = Container.call(this);
self.asset = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 48;
self.dir = 0;
self.owner = null; // 'player' or 'police'
self.update = function () {
self.x += Math.cos(self.dir) * self.speed;
self.y += Math.sin(self.dir) * self.speed;
};
return self;
});
// Car (stealable)
var Car = Container.expand(function () {
var self = Container.call(this);
self.asset = self.attachAsset('car', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 0;
self.maxSpeed = 5; // much slower
self.acceleration = 0.2; // slower acceleration
self.deceleration = 0.3; // slower deceleration
self.direction = 0; // radians
self.driver = null; // player if inside
self.isPolice = false;
self.targetDir = 0; // for smooth steering
self.update = function () {
if (self.driver) {
// Smoothly turn toward target direction (set by dragDir)
var diff = self.targetDir - self.direction;
// Normalize angle to [-PI, PI]
while (diff > Math.PI) diff -= 2 * Math.PI;
while (diff < -Math.PI) diff += 2 * Math.PI;
self.direction += diff * 0.2; // smooth steering
// Gradually accelerate to maxSpeed
if (self.speed < self.maxSpeed) {
self.speed += self.acceleration;
if (self.speed > self.maxSpeed) self.speed = self.maxSpeed;
}
// Move in direction
self.x += Math.cos(self.direction) * self.speed;
self.y += Math.sin(self.direction) * self.speed;
} else {
// If no driver, slow down to stop
if (self.speed > 0) {
self.speed -= self.deceleration;
if (self.speed < 0) self.speed = 0;
self.x += Math.cos(self.direction) * self.speed;
self.y += Math.sin(self.direction) * self.speed;
}
}
};
return self;
});
// CityBlock: road or building
var CityBlock = Container.expand(function () {
var self = Container.call(this);
self.type = 'road'; // or 'building'
self.setType = function (type) {
self.type = type;
if (self.asset) {
self.removeChild(self.asset);
}
if (type === 'road') {
self.asset = self.attachAsset('road', {
anchorX: 0.5,
anchorY: 0.5
});
} else {
self.asset = self.attachAsset('building', {
anchorX: 0.5,
anchorY: 0.5
});
}
};
return self;
});
var Civilian = Container.expand(function () {
var self = Container.call(this);
// Pick a random color asset for this civilian
var civAssetIdx = 1 + Math.floor(Math.random() * 6);
var civAssetName = 'civilian' + civAssetIdx;
self.asset = self.attachAsset(civAssetName, {
anchorX: 0.5,
anchorY: 0.5
});
self.asset.alpha = 0.7;
// Add 'npc' label above the civilian
self.npcLabel = new Text2('npc', {
size: 38,
fill: 0xFFFFFF
});
self.npcLabel.anchor.set(0.5, 1);
self.npcLabel.y = -40;
self.addChild(self.npcLabel);
self.speed = 2 + Math.random() * 2;
self.direction = Math.random() * Math.PI * 2;
self.update = function () {
// Move in direction, bounce off buildings
var nx = self.x + Math.cos(self.direction) * self.speed;
var ny = self.y + Math.sin(self.direction) * self.speed;
var onRoad = false;
for (var i = 0; i < cityBlocks.length; i++) {
var b = cityBlocks[i];
if (b.type === 'road') {
var left = b.x - blockSize / 2;
var right = b.x + blockSize / 2;
var top = b.y - blockSize / 2;
var bottom = b.y + blockSize / 2;
if (nx >= left && nx <= right && ny >= top && ny <= bottom) {
onRoad = true;
break;
}
}
}
if (onRoad) {
self.x = nx;
self.y = ny;
} else {
self.direction = Math.random() * Math.PI * 2;
}
};
return self;
});
// Spawn 6 civilians at random road blocks (not near player or police)
// Mission marker
var Mission = Container.expand(function () {
var self = Container.call(this);
self.asset = self.attachAsset('mission', {
anchorX: 0.5,
anchorY: 0.5
});
self.active = true;
return self;
});
// Player character
var Player = Container.expand(function () {
var self = Container.call(this);
self.asset = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
// Add 'you' label above the player
self.youLabel = new Text2('you', {
size: 38,
fill: 0xFFFFFF
});
self.youLabel.anchor.set(0.5, 1);
self.youLabel.y = -80;
self.addChild(self.youLabel);
self.speed = 16;
self.inCar = null; // reference to car if inside
self.direction = 0; // radians, 0 = right
// Add gun to player's hand
self.gun = self.attachAsset('gun', {
anchorX: 0.1,
anchorY: 0.5
});
self.gun.x = 60; // offset from player center
self.gun.y = 0;
self.gun.visible = true;
self.lastShotDir = 0; // radians
self.update = function () {
// If in car, follow car and hide player sprite
if (self.inCar) {
self.x = self.inCar.x;
self.y = self.inCar.y;
self.visible = false;
self.gun.visible = false;
self.youLabel.visible = false;
} else {
self.visible = true;
self.gun.visible = true;
self.youLabel.visible = true;
// Gun follows player hand and points at last shot direction
self.gun.x = 60 * Math.cos(self.lastShotDir);
self.gun.y = 60 * Math.sin(self.lastShotDir);
self.gun.rotation = self.lastShotDir;
}
};
return self;
});
// Police car
var PoliceCar = Container.expand(function () {
var self = Container.call(this);
self.asset = self.attachAsset('police', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 0;
self.maxSpeed = 2.5; // much slower (reduced for slower police)
self.acceleration = 0.08; // slower acceleration
self.deceleration = 0.15; // slower deceleration
self.direction = 0;
self.target = null; // player or car
self.isPolice = true;
self.targetDir = 0;
self.update = function () {
if (self.target) {
// Simple chase logic
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 10) {
self.targetDir = Math.atan2(dy, dx);
// Smoothly turn toward target direction
var diff = self.targetDir - self.direction;
while (diff > Math.PI) diff -= 2 * Math.PI;
while (diff < -Math.PI) diff += 2 * Math.PI;
self.direction += diff * 0.2;
// Accelerate to maxSpeed
if (self.speed < self.maxSpeed) {
self.speed += self.acceleration;
if (self.speed > self.maxSpeed) self.speed = self.maxSpeed;
}
self.x += Math.cos(self.direction) * self.speed;
self.y += Math.sin(self.direction) * self.speed;
} else {
self.speed = 0;
}
} else {
// If no target, slow down to stop
if (self.speed > 0) {
self.speed -= self.deceleration;
if (self.speed < 0) self.speed = 0;
self.x += Math.cos(self.direction) * self.speed;
self.y += Math.sin(self.direction) * self.speed;
}
}
};
return self;
});
// Police shooter class (policeman on foot)
var PoliceShooter = Container.expand(function () {
var self = Container.call(this);
self.asset = self.attachAsset('police', {
anchorX: 0.5,
anchorY: 0.5
});
// Add 'POLIS' label above the police shooter
self.polisLabel = new Text2('POLIS', {
size: 38,
fill: 0xFFFFFF
});
self.polisLabel.anchor.set(0.5, 1);
self.polisLabel.y = -80;
self.addChild(self.polisLabel);
// Add gun to police shooter's hand
self.gun = self.attachAsset('gun', {
anchorX: 0.1,
anchorY: 0.5
});
self.gun.x = 60;
self.gun.y = 0;
self.gun.visible = true;
self.addChild(self.gun);
self.speed = 5; // reduced for slower police
self.target = null;
self.lastShotTick = 0;
self.lastShotDir = 0; // direction of last shot
self.update = function () {
// If not aggro (no target), patrol randomly on roads
if (!self.target) {
if (typeof self.patrolTarget === "undefined" || !self.patrolTarget) {
// Pick a random road block as patrol target
var roadBlocks = [];
for (var k = 0; k < cityBlocks.length; k++) {
if (cityBlocks[k].type === 'road') roadBlocks.push(cityBlocks[k]);
}
if (roadBlocks.length > 0) {
var idx = Math.floor(Math.random() * roadBlocks.length);
self.patrolTarget = {
x: roadBlocks[idx].x + (Math.random() - 0.5) * 100,
y: roadBlocks[idx].y + (Math.random() - 0.5) * 100
};
}
}
if (self.patrolTarget) {
var dx = self.patrolTarget.x - self.x;
var dy = self.patrolTarget.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 10) {
self.direction = Math.atan2(dy, dx);
self.x += Math.cos(self.direction) * self.speed * 0.5;
self.y += Math.sin(self.direction) * self.speed * 0.5;
} else {
// Arrived at patrol target, pick a new one next frame
self.patrolTarget = null;
}
// Gun points in patrol direction
self.lastShotDir = self.direction;
self.gun.x = 60 * Math.cos(self.lastShotDir);
self.gun.y = 60 * Math.sin(self.lastShotDir);
self.gun.rotation = self.lastShotDir;
}
} else {
// Move toward player if target exists
var dx = self.target.x - self.x;
var dy = self.target.y - self.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 120) {
self.x += dx / dist * self.speed;
self.y += dy / dist * self.speed;
}
// Gun points at player
self.lastShotDir = Math.atan2(dy, dx);
self.gun.x = 60 * Math.cos(self.lastShotDir);
self.gun.y = 60 * Math.sin(self.lastShotDir);
self.gun.rotation = self.lastShotDir;
}
// Firing handled in game.update
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
// No title, no description
// Set backgroundColor to vibrant green for lush map
backgroundColor: 0x1ecb2a
});
/****
* Game Code
****/
// --- Market Setup ---
var marketEntrance = new Container();
marketEntrance.asset = marketEntrance.attachAsset('building', {
anchorX: 0.5,
anchorY: 0.5
});
marketEntrance.asset.width = 300;
marketEntrance.asset.height = 300;
marketEntrance.x = (gridCols - 1) / 2 * blockSize + blockSize / 2 + 300; // rightmost road col + offset
marketEntrance.y = 0 * blockSize + blockSize / 2;
marketEntrance.isMarketEntrance = true;
// Add 'MARKET' label above the market entrance
marketEntrance.marketLabel = new Text2('MARKET', {
size: 90,
fill: "#fff"
});
marketEntrance.marketLabel.anchor.set(0.5, 1);
marketEntrance.marketLabel.x = 0;
marketEntrance.marketLabel.y = -170;
marketEntrance.addChild(marketEntrance.marketLabel);
game.addChild(marketEntrance);
// Market interior (hidden until entered)
var marketInterior = new Container();
marketInterior.asset = marketInterior.attachAsset('building', {
anchorX: 0.5,
anchorY: 0.5
});
marketInterior.asset.width = 800;
marketInterior.asset.height = 800;
marketInterior.x = 2048 / 2;
marketInterior.y = 2732 / 2;
marketInterior.visible = false;
game.addChild(marketInterior);
// Market buy ammo button
var marketBuyBtn = new Text2("₺50'ye 100 mermi al", {
size: 120,
fill: "#fff"
});
marketBuyBtn.anchor.set(0.5, 0.5);
marketBuyBtn.x = marketInterior.x;
marketBuyBtn.y = marketInterior.y + 100;
marketBuyBtn.visible = false;
game.addChild(marketBuyBtn);
// Market exit (door)
var marketExit = new Container();
marketExit.asset = marketExit.attachAsset('road', {
anchorX: 0.5,
anchorY: 0.5
});
marketExit.asset.width = 200;
marketExit.asset.height = 100;
marketExit.x = marketInterior.x;
marketExit.y = marketInterior.y + 350;
marketExit.visible = false;
marketExit.isMarketExit = true;
game.addChild(marketExit);
// Track if player is in market
var playerInMarket = false;
// marketStartPos will be initialized after player is created
var marketStartPos;
// --- Money on ground ---
// Police car - white box with blue
// Car - yellow box
// Player (hero) - red ellipse
// Building - blue box
// City block (road) - gray box
// --- Fixed City Map Setup ---
var blockSize = 400;
var cityBlocks = [];
var cityBlockMap = {}; // key: "col,row" -> CityBlock
// Fixed grid size
var gridCols = 9;
var gridRows = 13;
// Use a simple procedural pattern: every even col/row is road, others are building
function getBlockType(col, row) {
// Make a simple city: roads every 2 blocks, rest are buildings
if (col % 2 === 0 || row % 2 === 0) return 'road';
return 'building';
}
// Helper to get or create a city block at (col, row)
function getOrCreateCityBlock(col, row) {
// Clamp to fixed grid
if (col < -Math.floor(gridCols / 2) || col > Math.floor(gridCols / 2) || row < -Math.floor(gridRows / 2) || row > Math.floor(gridRows / 2)) {
return null;
}
var key = col + ',' + row;
if (cityBlockMap[key]) return cityBlockMap[key];
var block = new CityBlock();
var type = getBlockType(col, row);
block.setType(type);
block.x = col * blockSize + blockSize / 2;
block.y = row * blockSize + blockSize / 2;
cityBlockMap[key] = block;
cityBlocks.push(block);
game.addChild(block);
return block;
}
// Generate fixed grid (centered at 0,0)
var initialCols = gridCols,
initialRows = gridRows;
var centerCol = 0,
centerRow = 0;
for (var row = -Math.floor(initialRows / 2); row <= Math.floor(initialRows / 2); row++) {
for (var col = -Math.floor(initialCols / 2); col <= Math.floor(initialCols / 2); col++) {
getOrCreateCityBlock(col, row);
}
}
// Helper to get all road blocks in a region (for spawning)
function getRoadBlocksInRegion(colMin, colMax, rowMin, rowMax) {
var blocks = [];
for (var row = rowMin; row <= rowMax; row++) {
for (var col = colMin; col <= colMax; col++) {
var block = getOrCreateCityBlock(col, row);
if (block && block.type === 'road') blocks.push(block);
}
}
return blocks;
}
// Helper to get nearest road block col/row for a given x/y
function getColRowForXY(x, y) {
var col = Math.round((x - blockSize / 2) / blockSize);
var row = Math.round((y - blockSize / 2) / blockSize);
// Clamp to grid
col = Math.max(-Math.floor(gridCols / 2), Math.min(Math.floor(gridCols / 2), col));
row = Math.max(-Math.floor(gridRows / 2), Math.min(Math.floor(gridRows / 2), row));
return {
col: col,
row: row
};
}
// --- Player Setup ---
// Spawn player at center of the infinite world (col=0, row=0)
var player = new Player();
player.x = 0 * blockSize + blockSize / 2;
player.y = 0 * blockSize + blockSize / 2;
game.addChild(player);
// Now that player is defined, initialize marketStartPos
marketStartPos = {
x: player.x,
y: player.y
};
// --- Civilians Setup ---
var civilians = [];
// Spawn 6 civilians at random road blocks (not near player or police)
for (var i = 0; i < 6; i++) {
// Use a region around player for infinite world
var playerColRow = getColRowForXY(player.x, player.y);
var roadBlocks = getRoadBlocksInRegion(playerColRow.col - 7, playerColRow.col + 7, playerColRow.row - 7, playerColRow.row + 7);
// Avoid spawn near player
var filtered = [];
for (var j = 0; j < roadBlocks.length; j++) {
var b = roadBlocks[j];
var distToPlayer = Math.sqrt(Math.pow(b.x - player.x, 2) + Math.pow(b.y - player.y, 2));
if (distToPlayer > 400) filtered.push(b);
}
if (filtered.length > 0) {
var idx = Math.floor(Math.random() * filtered.length);
var civ = new Civilian();
civ.x = filtered[idx].x + (Math.random() - 0.5) * 100;
civ.y = filtered[idx].y + (Math.random() - 0.5) * 100;
civilians.push(civ);
game.addChild(civ);
}
}
// --- Cars Setup ---
var cars = [];
function spawnCar(x, y) {
var car = new Car();
car.x = x;
car.y = y;
car.direction = Math.random() * Math.PI * 2;
cars.push(car);
game.addChild(car);
return car;
}
// Place a few cars on roads using fixed world
var roadBlocksForCars = [];
for (var i = 0; i < cityBlocks.length; i++) {
if (cityBlocks[i].type === 'road') {
// Remove player's starting block
if (!(cityBlocks[i].x === player.x && cityBlocks[i].y === player.y)) {
roadBlocksForCars.push(cityBlocks[i]);
}
}
}
// Shuffle
for (var k = roadBlocksForCars.length - 1; k > 0; k--) {
var j = Math.floor(Math.random() * (k + 1));
var temp = roadBlocksForCars[k];
roadBlocksForCars[k] = roadBlocksForCars[j];
roadBlocksForCars[j] = temp;
}
// Spawn up to 4 cars in distinct available road blocks
var carsToSpawn = 4;
for (var i = 0; i < Math.min(carsToSpawn, roadBlocksForCars.length); i++) {
var block = roadBlocksForCars[i];
spawnCar(block.x, block.y);
}
// --- Police Setup ---
var policeCars = [];
function spawnPolice(x, y) {
var police = new PoliceCar();
police.x = x;
police.y = y;
police.direction = 0;
// Police do not chase the player anymore
police.target = null;
policeCars.push(police);
game.addChild(police);
return police;
}
// Start with three police cars at different road blocks
var policeStartBlocks = [];
for (var i = 0; i < cityBlocks.length; i++) {
if (cityBlocks[i].type === 'road') {
policeStartBlocks.push(cityBlocks[i]);
}
}
if (policeStartBlocks.length > 0) {
// Always spawn one at the top left of region
var policeStartX = cityBlocks[0].x;
var policeStartY = cityBlocks[0].y;
spawnPolice(policeStartX, policeStartY);
// Pick two more random road blocks (not the same as above)
var used = {};
used[policeStartX + ',' + policeStartY] = true;
for (var p = 0; p < 2; p++) {
var idx = Math.floor(Math.random() * policeStartBlocks.length);
var b = policeStartBlocks[idx];
var key = b.x + ',' + b.y;
if (!used[key]) {
spawnPolice(b.x, b.y);
used[key] = true;
}
}
}
// --- Mission Setup ---
var mission = new Mission();
// Place mission at far corner of grid
mission.x = cityBlocks[cityBlocks.length - 1].x;
mission.y = cityBlocks[cityBlocks.length - 1].y;
game.addChild(mission);
// --- Money on ground ---
var moneyPickups = [];
function spawnMoney(x, y) {
var m = new Container();
m.asset = m.attachAsset('mission', {
anchorX: 0.5,
anchorY: 0.5
});
m.x = x;
m.y = y;
m.value = 50;
moneyPickups.push(m);
game.addChild(m);
return m;
}
// Place 15 money pickups at random road blocks in grid
var roadBlocksForMoney = [];
for (var i = 0; i < cityBlocks.length; i++) {
if (cityBlocks[i].type === 'road') {
roadBlocksForMoney.push(cityBlocks[i]);
}
}
for (var i = 0; i < 15; i++) {
if (roadBlocksForMoney.length > 0) {
var idx = Math.floor(Math.random() * roadBlocksForMoney.length);
var b = roadBlocksForMoney[idx];
var mx = b.x + (Math.random() - 0.5) * (blockSize - 100);
var my = b.y + (Math.random() - 0.5) * (blockSize - 100);
spawnMoney(mx, my);
}
}
// --- Score and Wanted Level ---
var score = 0;
var wantedLevel = 1; // 1-5
var scoreTxt = new Text2('Score: 0', {
size: 90,
fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
var wantedTxt = new Text2('★', {
size: 80,
fill: "#ff0"
});
wantedTxt.anchor.set(1, 0); // anchor to top right
wantedTxt.x = 0;
wantedTxt.y = 0;
LK.gui.topRight.addChild(wantedTxt);
// (Removed 'elinde akm var' text below the wanted stars)
// --- Timer ---
var timeLeft = 60; // seconds
var timerTxt = new Text2('60', {
size: 80,
fill: "#fff"
});
timerTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(timerTxt);
// --- Touch Controls ---
var dragDir = null; // {dx,dy}
var dragStart = null;
var dragNode = null;
var lastTouchX = 0,
lastTouchY = 0;
// --- Shooting & Health ---
var bullets = [];
var policeBullets = [];
var playerHealth = 5;
// --- Ammo system ---
var playerAmmo = 100;
var ammoTxt = new Text2('Ammo: 100', {
size: 80,
fill: "#fff"
});
// Anchor to top right (same as wanted stars)
ammoTxt.anchor.set(1, 0);
// Place just below the wanted stars (wantedTxt is at y=0, height ~80)
ammoTxt.x = 0;
ammoTxt.y = wantedTxt.y + wantedTxt.height + 10; // 10px below stars
LK.gui.topRight.addChild(ammoTxt);
function updateAmmoDisplay() {
ammoTxt.setText('Ammo: ' + playerAmmo);
}
// Money system
var playerMoney = 0;
var moneyTxt = new Text2('₺ 0', {
size: 120,
fill: 0x44FF44
});
moneyTxt.anchor.set(0, 0);
moneyTxt.x = 100;
moneyTxt.y = 90;
LK.gui.addChild(moneyTxt);
var healthTxt = new Text2('♥♥♥♥♥', {
size: 80,
fill: 0xFF4444
});
healthTxt.anchor.set(0, 0); // anchor top left
// Place health bar at (100,0) to avoid platform menu
healthTxt.x = 100;
healthTxt.y = 0;
LK.gui.addChild(healthTxt);
// Track if police are aggressive (chasing) or passive
var policeAggro = false;
// Helper to update health display
function updateHealthDisplay() {
var hearts = '';
for (var i = 0; i < playerHealth; i++) hearts += '♥';
healthTxt.setText(hearts);
}
function updateMoneyDisplay() {
moneyTxt.setText('₺ ' + playerMoney);
}
var policeShooters = [];
// Spawn a few police shooters at random road blocks, not near player (fixed world)
for (var i = 0; i < 8; i++) {
var roadBlocks = [];
for (var j = 0; j < cityBlocks.length; j++) {
if (cityBlocks[j].type === 'road') {
var b = cityBlocks[j];
var distToPlayer = Math.sqrt(Math.pow(b.x - player.x, 2) + Math.pow(b.y - player.y, 2));
if (distToPlayer > 600) roadBlocks.push(b);
}
}
if (roadBlocks.length > 0) {
var idx = Math.floor(Math.random() * roadBlocks.length);
var shooter = new PoliceShooter();
shooter.x = roadBlocks[idx].x + (Math.random() - 0.5) * 100;
shooter.y = roadBlocks[idx].y + (Math.random() - 0.5) * 100;
shooter.target = null; // Do not target player at start
shooter.wasShotAt = false; // Only shoot if player shoots at them
policeShooters.push(shooter);
game.addChild(shooter);
}
}
// --- Helper Functions ---
function isOnRoad(x, y) {
// Returns true if (x,y) is on a road block (fixed world)
var colRow = getColRowForXY(x, y);
var block = getOrCreateCityBlock(colRow.col, colRow.row);
if (block && block.type === 'road') {
var left = block.x - blockSize / 2;
var right = block.x + blockSize / 2;
var top = block.y - blockSize / 2;
var bottom = block.y + blockSize / 2;
if (x >= left && x <= right && y >= top && y <= bottom) {
return true;
}
}
return false;
}
function clampToRoad(x, y) {
// Snap to nearest road block center (fixed world)
var colRow = getColRowForXY(x, y);
var block = getOrCreateCityBlock(colRow.col, colRow.row);
if (block && block.type === 'road') {
return {
x: block.x,
y: block.y
};
}
// If not road, search nearby
for (var r = -1; r <= 1; r++) {
for (var c = -1; c <= 1; c++) {
var b = getOrCreateCityBlock(colRow.col + c, colRow.row + r);
if (b && b.type === 'road') return {
x: b.x,
y: b.y
};
}
}
// Fallback: return original
return {
x: x,
y: y
};
}
function updateWantedDisplay() {
var stars = '';
for (var i = 0; i < wantedLevel; i++) stars += '★';
wantedTxt.setText(stars);
// Default color
var color = "#ff0";
// If 5 stars, flash red/blue
if (wantedLevel === 5) {
// Show "wandet" text for 3 seconds only on the frame wantedLevel becomes 5
if (typeof wandetTextShown === "undefined") wandetTextShown = false;
if (!wandetTextShown) {
// Remove previous if exists
if (typeof wandetText !== "undefined" && wandetText.parent) {
wandetText.parent.removeChild(wandetText);
wandetText = undefined;
}
wandetText = new Text2("wandet", {
size: 160,
fill: 0xFF2222
});
wandetText.anchor.set(0.5, 0);
wandetText.x = 2048 / 2;
wandetText.y = 500;
LK.gui.addChild(wandetText);
wandetTextShown = true;
LK.setTimeout(function () {
if (wandetText && wandetText.parent) {
wandetText.parent.removeChild(wandetText);
wandetText = undefined;
}
wandetTextShown = false;
}, 3000);
}
// Alternate color every 20 ticks (about 1/3 second at 60fps)
if (LK.ticks % 40 < 20) {
color = "#ff2222"; // red
} else {
color = "#2288ff"; // blue
}
}
if (wantedTxt && wantedTxt.style && typeof wantedTxt.style.fill !== "undefined") {
wantedTxt.style.fill = color;
}
}
function addScore(amt) {
score += amt;
scoreTxt.setText('Score: ' + score);
LK.setScore(score);
}
function resetMission() {
// Place mission at random road block (fixed world)
var roadBlocks = [];
for (var i = 0; i < cityBlocks.length; i++) {
if (cityBlocks[i].type === 'road') {
var b = cityBlocks[i];
var distToPlayer = Math.sqrt(Math.pow(b.x - player.x, 2) + Math.pow(b.y - player.y, 2));
if (distToPlayer > 400) roadBlocks.push(b);
}
}
if (roadBlocks.length > 0) {
var idx = Math.floor(Math.random() * roadBlocks.length);
mission.x = roadBlocks[idx].x;
mission.y = roadBlocks[idx].y;
mission.active = true;
mission.visible = true;
}
}
// --- Game Touch Controls ---
// Drag to move (swipe in direction to move)
game.down = function (x, y, obj) {
// Don't allow drag from top left 100x100
if (x < 100 && y < 100) return;
// --- SHOOTING LOGIC ---
// If not dragging, treat as tap to shoot
if (!dragNode && !dragDir && !player.inCar) {
if (typeof playerAmmo === "undefined") playerAmmo = 0;
if (playerAmmo > 0) {
// Player shoots toward (x, y)
var b = new Bullet();
b.x = player.x;
b.y = player.y;
b.dir = Math.atan2(y - b.y, x - b.x);
b.owner = 'player';
bullets.push(b);
game.addChild(b);
// Update player's gun direction to point at shot
player.lastShotDir = b.dir;
playerAmmo--;
if (typeof updateAmmoDisplay === "function") updateAmmoDisplay();
} else {
// Out of ammo: show "mermi bitti" for 1 second at center-top
if (typeof ammoEmptyText !== "undefined" && ammoEmptyText.parent) {
ammoEmptyText.parent.removeChild(ammoEmptyText);
ammoEmptyText = undefined;
}
ammoEmptyText = new Text2("mermi bitti", {
size: 120,
fill: 0xFF2222
});
ammoEmptyText.anchor.set(0.5, 0);
ammoEmptyText.x = 2048 / 2;
ammoEmptyText.y = 320;
LK.gui.addChild(ammoEmptyText);
LK.setTimeout(function () {
if (ammoEmptyText && ammoEmptyText.parent) {
ammoEmptyText.parent.removeChild(ammoEmptyText);
ammoEmptyText = undefined;
}
}, 1000);
}
// No police aggro or wanted level increase when shooting police
}
// --- DRAG LOGIC (movement) ---
dragStart = {
x: x,
y: y
};
lastTouchX = x;
lastTouchY = y;
dragDir = null;
dragNode = player;
};
game.move = function (x, y, obj) {
if (!dragNode) return;
var dx = x - dragStart.x;
var dy = y - dragStart.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 30) {
dragDir = {
dx: dx,
dy: dy
};
}
lastTouchX = x;
lastTouchY = y;
};
game.up = function (x, y, obj) {
dragNode = null;
dragDir = null;
dragStart = null;
};
// --- Car Enter/Exit Logic ---
// Track tap times for triple-tap exit
var carTapTimes = [];
game.on('down', function (x, y, obj) {
// If player is not in car, check if tap is on car and player is close enough
if (!player.inCar) {
for (var i = 0; i < cars.length; i++) {
var car = cars[i];
var dx = car.x - x;
var dy = car.y - y;
// Tap must be on car
if (Math.abs(dx) < 80 && Math.abs(dy) < 50) {
// Player must be close to car to enter
if (Math.abs(player.x - car.x) < 120 && Math.abs(player.y - car.y) < 80) {
player.inCar = car;
car.driver = player;
// Do not set car.speed here; Car.update will handle acceleration
car.direction = 0;
// Increase wanted level
wantedLevel = Math.min(5, wantedLevel + 1);
updateWantedDisplay();
// Police target car
for (var j = 0; j < policeCars.length; j++) {
policeCars[j].target = car;
}
// Reset tap times for exit
carTapTimes = [];
break;
}
}
}
} else {
// Player is in car: require triple-tap within 1 second to exit
var now = Date.now();
carTapTimes.push(now);
// Only keep last 3 taps
if (carTapTimes.length > 3) carTapTimes.shift();
if (carTapTimes.length === 3) {
// Check if 3 taps are within 1 second
if (carTapTimes[2] - carTapTimes[0] < 1000) {
var car = player.inCar;
player.inCar = null;
car.driver = null;
// Do not set car.speed to 0; Car.update will handle deceleration
// Place player next to car
player.x = car.x + 80;
player.y = car.y;
// Police target player
for (var j = 0; j < policeCars.length; j++) {
policeCars[j].target = player;
}
carTapTimes = [];
}
}
}
});
// --- Game Update Loop ---
game.update = function () {
// Timer
if (LK.ticks % 60 === 0 && timeLeft > 0) {
timeLeft--;
timerTxt.setText(timeLeft + '');
// Do not end the game when timer reaches zero
}
// --- Market logic ---
// If not in market, check for market entrance
if (!playerInMarket) {
// Check if player is at market entrance (right edge)
if (Math.abs(player.x - marketEntrance.x) < 120 && Math.abs(player.y - marketEntrance.y) < 120) {
// Teleport to market interior
playerInMarket = true;
marketStartPos.x = player.x;
marketStartPos.y = player.y;
player.x = marketInterior.x;
player.y = marketInterior.y - 100;
marketInterior.visible = true;
marketBuyBtn.visible = true;
marketExit.visible = true;
// Hide city elements
for (var i = 0; i < cityBlocks.length; i++) cityBlocks[i].visible = false;
for (var i = 0; i < cars.length; i++) cars[i].visible = false;
for (var i = 0; i < civilians.length; i++) civilians[i].visible = false;
for (var i = 0; i < policeCars.length; i++) policeCars[i].visible = false;
for (var i = 0; i < policeShooters.length; i++) policeShooters[i].visible = false;
for (var i = 0; i < moneyPickups.length; i++) moneyPickups[i].visible = false;
if (typeof gunPickups !== "undefined") for (var i = 0; i < gunPickups.length; i++) gunPickups[i].visible = false;
mission.visible = false;
marketEntrance.visible = false;
}
} else {
// In market: only allow movement inside market area
if (dragDir) {
var angle = Math.atan2(dragDir.dy, dragDir.dx);
var nx = player.x + Math.cos(angle) * player.speed;
var ny = player.y + Math.sin(angle) * player.speed;
// Clamp to market interior bounds
var left = marketInterior.x - 350,
right = marketInterior.x + 350;
var top = marketInterior.y - 350,
bottom = marketInterior.y + 350;
if (nx > left && nx < right && ny > top && ny < bottom) {
player.x = nx;
player.y = ny;
}
}
// Check for ammo buy (touch on buy button)
if (Math.abs(player.x - marketBuyBtn.x) < 200 && Math.abs(player.y - marketBuyBtn.y) < 100) {
if (playerMoney >= 50 && playerAmmo < 100) {
playerMoney -= 50;
playerAmmo = 100;
updateMoneyDisplay();
updateAmmoDisplay();
// Show "100 mermi alındı" text
if (typeof marketBuyText !== "undefined" && marketBuyText.parent) {
marketBuyText.parent.removeChild(marketBuyText);
marketBuyText = undefined;
}
marketBuyText = new Text2("100 mermi alındı", {
size: 120,
fill: 0x44FF44
});
marketBuyText.anchor.set(0.5, 0);
marketBuyText.x = 2048 / 2;
marketBuyText.y = 320;
LK.gui.addChild(marketBuyText);
LK.setTimeout(function () {
if (marketBuyText && marketBuyText.parent) {
marketBuyText.parent.removeChild(marketBuyText);
marketBuyText = undefined;
}
}, 1000);
}
}
// Check for exit (touch on exit door)
if (Math.abs(player.x - marketExit.x) < 120 && Math.abs(player.y - marketExit.y) < 80) {
// Teleport back to start
player.x = marketStartPos.x;
player.y = marketStartPos.y;
playerInMarket = false;
marketInterior.visible = false;
marketBuyBtn.visible = false;
marketExit.visible = false;
// Show city elements again
for (var i = 0; i < cityBlocks.length; i++) cityBlocks[i].visible = true;
for (var i = 0; i < cars.length; i++) cars[i].visible = true;
for (var i = 0; i < civilians.length; i++) civilians[i].visible = true;
for (var i = 0; i < policeCars.length; i++) policeCars[i].visible = true;
for (var i = 0; i < policeShooters.length; i++) policeShooters[i].visible = true;
for (var i = 0; i < moneyPickups.length; i++) moneyPickups[i].visible = true;
if (typeof gunPickups !== "undefined") for (var i = 0; i < gunPickups.length; i++) gunPickups[i].visible = true;
mission.visible = true;
marketEntrance.visible = true;
}
}
// Player movement
if (!player.inCar && dragDir && !playerInMarket) {
// Move player in drag direction, but only on road
var angle = Math.atan2(dragDir.dy, dragDir.dx);
var nx = player.x + Math.cos(angle) * player.speed;
var ny = player.y + Math.sin(angle) * player.speed;
if (isOnRoad(nx, ny)) {
player.x = nx;
player.y = ny;
}
// No infinite world: no need to generate new blocks in update
}
// Car movement (if player in car)
for (var i = 0; i < cars.length; i++) {
var car = cars[i];
// If player is driving this car, set car's targetDir to drag direction
if (car.driver === player && dragDir) {
var angle = Math.atan2(dragDir.dy, dragDir.dx);
car.targetDir = angle;
}
car.update();
// Clamp car to road
if (car.driver) {
if (!isOnRoad(car.x, car.y)) {
// Stop car at edge
car.speed = 0;
}
}
}
// Police movement
for (var i = 0; i < policeCars.length; i++) {
var police = policeCars[i];
// Police patrol logic: move randomly on roads if not chasing
if (!policeAggro) {
if (typeof police.patrolTarget === "undefined" || !police.patrolTarget) {
// Pick a random road block as patrol target
var roadBlocks = [];
for (var k = 0; k < cityBlocks.length; k++) {
if (cityBlocks[k].type === 'road') roadBlocks.push(cityBlocks[k]);
}
if (roadBlocks.length > 0) {
var idx = Math.floor(Math.random() * roadBlocks.length);
police.patrolTarget = {
x: roadBlocks[idx].x + (Math.random() - 0.5) * 100,
y: roadBlocks[idx].y + (Math.random() - 0.5) * 100
};
}
}
if (police.patrolTarget) {
var dx = police.patrolTarget.x - police.x;
var dy = police.patrolTarget.y - police.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 10) {
police.direction = Math.atan2(dy, dx);
police.speed = police.maxSpeed * 0.5;
police.x += Math.cos(police.direction) * police.speed;
police.y += Math.sin(police.direction) * police.speed;
} else {
// Arrived at patrol target, pick a new one next frame
police.patrolTarget = null;
police.speed = 0;
}
}
} else {
police.update();
}
// Clamp police to road
if (!isOnRoad(police.x, police.y)) {
police.speed = 0;
}
// Police catch player
var target = police.target;
if (policeAggro && target && Math.abs(police.x - target.x) < 80 && Math.abs(police.y - target.y) < 80) {
LK.effects.flashScreen(0xff0000, 1000);
LK.showGameOver();
return;
}
}
// Police shooters update
for (var i = policeShooters.length - 1; i >= 0; i--) {
var shooter = policeShooters[i];
shooter.update();
// Remove if off map
if (shooter.x < 0 || shooter.x > 2048 || shooter.y < 0 || shooter.y > 2732) {
shooter.destroy();
policeShooters.splice(i, 1);
continue;
}
// --- Police shooter fires at player only if aggro (wasShotAt or policeAggro) ---
// Only fire if player is within 700px, not in car, and shooter is aggro
if (shooter.wasShotAt || policeAggro) {
var px = player.inCar ? player.inCar.x : player.x;
var py = player.inCar ? player.inCar.y : player.y;
var dx = px - shooter.x;
var dy = py - shooter.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist < 700 && LK.ticks - shooter.lastShotTick > 60) {
// Fire bullet toward player
var b = new Bullet();
b.x = shooter.x;
b.y = shooter.y;
b.dir = Math.atan2(dy, dx);
b.owner = 'police';
policeBullets.push(b);
game.addChild(b);
shooter.lastShotTick = LK.ticks;
}
}
}
// Bullets update (player)
for (var i = bullets.length - 1; i >= 0; i--) {
var b = bullets[i];
if (b && typeof b.update === "function") {
b.update();
}
// Remove if off screen
if (b && typeof b.x === "number" && typeof b.y === "number" && (b.x < 0 || b.x > 2048 || b.y < 0 || b.y > 2732)) {
b.destroy();
bullets.splice(i, 1);
continue;
}
// --- Police car kill check ---
for (var j = policeCars.length - 1; j >= 0; j--) {
var police = policeCars[j];
// --- Car bullet hit logic ---
if (police && b && typeof police.x === "number" && typeof police.y === "number" && typeof b.x === "number" && typeof b.y === "number" && Math.abs(police.x - b.x) < 60 && Math.abs(police.y - b.y) < 60) {
// Track bullet hits on this car
if (typeof police.bulletHitCount === "undefined") police.bulletHitCount = 0;
police.bulletHitCount++;
// Remove bullet
b.destroy();
bullets.splice(i, 1);
// If hit 30 times, destroy car and show "arba patladı"
if (police.bulletHitCount >= 30) {
// Drop a gun at police car's position
var gunDrop = new Container();
gunDrop.asset = gunDrop.attachAsset('gun', {
anchorX: 0.5,
anchorY: 0.5
});
// Add 'gun' label above the dropped gun
gunDrop.gunLabel = new Text2('gun', {
size: 38,
fill: 0xFFFFFF
});
gunDrop.gunLabel.anchor.set(0.5, 1);
gunDrop.gunLabel.y = -30;
gunDrop.addChild(gunDrop.gunLabel);
gunDrop.x = police.x;
gunDrop.y = police.y;
gunDrop.isGunPickup = true;
game.addChild(gunDrop);
if (typeof gunPickups === "undefined") gunPickups = [];
gunPickups.push(gunDrop);
police.destroy();
policeCars.splice(j, 1);
// Show "arba patladı" text for 2 seconds at center of screen
if (typeof carExplodedText !== "undefined" && carExplodedText.parent) {
carExplodedText.parent.removeChild(carExplodedText);
carExplodedText = undefined;
}
carExplodedText = new Text2("arba patladı", {
size: 160,
fill: 0xFF2222
});
carExplodedText.anchor.set(0.5, 0.5);
carExplodedText.x = 2048 / 2;
carExplodedText.y = 2732 / 2;
LK.gui.addChild(carExplodedText);
LK.setTimeout(function () {
if (carExplodedText && carExplodedText.parent) {
carExplodedText.parent.removeChild(carExplodedText);
carExplodedText = undefined;
}
}, 2000);
addScore(20);
// Increase wanted level by 1 (max 5) when police car is killed
wantedLevel = Math.min(5, wantedLevel + 1);
updateWantedDisplay();
// Only aggro police if wantedLevel is 5
if (wantedLevel === 5 && typeof spawned5StarPolice === "undefined") {
for (var p = 0; p < policeShooters.length; p++) {
policeShooters[p].wasShotAt = true;
policeShooters[p].target = player;
}
for (var p = 0; p < policeCars.length; p++) {
policeCars[p].target = player;
}
policeAggro = true;
// Spawn 20 police cars at random road blocks (not near player)
var roadBlocks = [];
for (var i = 0; i < cityBlocks.length; i++) {
if (cityBlocks[i].type === 'road') {
var distToPlayer = Math.sqrt(Math.pow(cityBlocks[i].x - player.x, 2) + Math.pow(cityBlocks[i].y - player.y, 2));
if (distToPlayer > 400) {
roadBlocks.push(cityBlocks[i]);
}
}
}
for (var s = 0; s < 20; s++) {
if (roadBlocks.length > 0) {
var idx = Math.floor(Math.random() * roadBlocks.length);
var b = roadBlocks[idx];
var newPolice = spawnPolice(b.x, b.y);
newPolice.target = player;
// Remove this block from roadBlocks to avoid double-spawn at same spot
roadBlocks.splice(idx, 1);
}
}
// --- Spawn 40 police shooters at random road blocks, not near player ---
for (var spawnCount = 0; spawnCount < 40; spawnCount++) {
var shooterBlocks = [];
for (var k = 0; k < cityBlocks.length; k++) {
var b2 = cityBlocks[k];
if (b2.type === 'road') {
var distToPlayer = Math.sqrt(Math.pow(b2.x - player.x, 2) + Math.pow(b2.y - player.y, 2));
if (distToPlayer > 600) {
shooterBlocks.push(b2);
}
}
}
if (shooterBlocks.length > 0) {
var idx2 = Math.floor(Math.random() * shooterBlocks.length);
var newShooter = new PoliceShooter();
newShooter.x = shooterBlocks[idx2].x + (Math.random() - 0.5) * 100;
newShooter.y = shooterBlocks[idx2].y + (Math.random() - 0.5) * 100;
newShooter.target = player;
newShooter.wasShotAt = true;
policeShooters.push(newShooter);
game.addChild(newShooter);
shooterBlocks.splice(idx2, 1);
}
}
spawned5StarPolice = true;
}
break;
}
// If not destroyed, do not break, allow other cars to be checked
continue;
}
// --- END Car bullet hit logic ---
}
// --- Police shooter kill check ---
for (var j = policeShooters.length - 1; j >= 0; j--) {
var shooter = policeShooters[j];
if (shooter && b && typeof shooter.x === "number" && typeof shooter.y === "number" && typeof b.x === "number" && typeof b.y === "number" && Math.abs(shooter.x - b.x) < 60 && Math.abs(shooter.y - b.y) < 60) {
// Mark this shooter as shot at, so it will shoot back
shooter.wasShotAt = true;
// --- Police shooter health logic ---
// Instantly kill police shooter with one bullet
b.destroy();
bullets.splice(i, 1);
// Police shooter killed!
// Drop a gun at police shooter's position
var gunDrop = new Container();
gunDrop.asset = gunDrop.attachAsset('gun', {
anchorX: 0.5,
anchorY: 0.5
});
// Add 'gun' label above the dropped gun
gunDrop.gunLabel = new Text2('gun', {
size: 38,
fill: 0xFFFFFF
});
gunDrop.gunLabel.anchor.set(0.5, 1);
gunDrop.gunLabel.y = -30;
gunDrop.addChild(gunDrop.gunLabel);
gunDrop.x = shooter.x;
gunDrop.y = shooter.y;
gunDrop.isGunPickup = true;
game.addChild(gunDrop);
if (typeof gunPickups === "undefined") gunPickups = [];
gunPickups.push(gunDrop);
shooter.destroy();
policeShooters.splice(j, 1);
// --- Spawn TWO new police shooters at random road blocks, not near player ---
for (var spawnCount = 0; spawnCount < 2; spawnCount++) {
var roadBlocks = [];
for (var k = 0; k < cityBlocks.length; k++) {
var b2 = cityBlocks[k];
if (b2.type === 'road') {
var distToPlayer = Math.sqrt(Math.pow(b2.x - player.x, 2) + Math.pow(b2.y - player.y, 2));
if (distToPlayer > 600) {
roadBlocks.push(b2);
}
}
}
if (roadBlocks.length > 0) {
var idx2 = Math.floor(Math.random() * roadBlocks.length);
var newShooter = new PoliceShooter();
newShooter.x = roadBlocks[idx2].x + (Math.random() - 0.5) * 100;
newShooter.y = roadBlocks[idx2].y + (Math.random() - 0.5) * 100;
if (policeAggro) {
newShooter.target = player;
newShooter.wasShotAt = true;
} else {
newShooter.target = null;
newShooter.wasShotAt = false;
}
policeShooters.push(newShooter);
game.addChild(newShooter);
}
}
addScore(15);
// Increase wanted level by 1 (max 5) when police shooter is killed
wantedLevel = Math.min(5, wantedLevel + 1);
updateWantedDisplay();
break;
// If not dead, do not break, allow other shooters to be checked
}
}
}
// Bullets update (police)
for (var i = policeBullets.length - 1; i >= 0; i--) {
var b = policeBullets[i];
if (b && typeof b.update === "function") {
b.update();
}
// Remove if off screen
if (b && typeof b.x === "number" && typeof b.y === "number" && (b.x < 0 || b.x > 2048 || b.y < 0 || b.y > 2732)) {
b.destroy();
policeBullets.splice(i, 1);
continue;
}
// Check hit player
var px = player.inCar ? player.inCar.x : player.x;
var py = player.inCar ? player.inCar.y : player.y;
if (Math.abs(px - b.x) < 60 && Math.abs(py - b.y) < 60) {
// Police bullet hits player: decrease health if not in car
if (!player.inCar && playerHealth > 0) {
playerHealth--;
updateHealthDisplay();
// Optional: flash screen on hit
LK.effects.flashScreen(0xff0000, 200);
// Game over if health reaches 0
if (playerHealth <= 0) {
LK.showGameOver();
return;
}
}
// If player is in car, do not take damage
b.destroy();
policeBullets.splice(i, 1);
}
}
// Player update
player.update();
// Civilians update and check for being shot by player or run over by car
for (var i = civilians.length - 1; i >= 0; i--) {
var civ = civilians[i];
if (civ && typeof civ.update === "function") {
civ.update();
}
var killed = false;
// Check if hit by any player bullet
for (var j = bullets.length - 1; j >= 0; j--) {
var b = bullets[j];
if (Math.abs(civ.x - b.x) < 60 && Math.abs(civ.y - b.y) < 60) {
killed = true;
// Remove bullet
b.destroy();
bullets.splice(j, 1);
break;
}
}
// Check if run over by any car driven by player
if (!killed) {
for (var c = 0; c < cars.length; c++) {
var car = cars[c];
if (car.driver === player) {
// Use a slightly larger hitbox for car
if (Math.abs(civ.x - car.x) < 90 && Math.abs(civ.y - car.y) < 70) {
killed = true;
break;
}
}
}
}
if (killed) {
// Civilian killed
// Drop money at civilian's position
spawnMoney(civ.x, civ.y);
// Respawn civilian at random road block (fixed world)
var roadBlocks = [];
for (var k = 0; k < cityBlocks.length; k++) {
if (cityBlocks[k].type === 'road') {
var b = cityBlocks[k];
var distToPlayer = Math.sqrt(Math.pow(b.x - player.x, 2) + Math.pow(b.y - player.y, 2));
if (distToPlayer > 400) roadBlocks.push(b);
}
}
if (roadBlocks.length > 0) {
var idx = Math.floor(Math.random() * roadBlocks.length);
var newCiv = new Civilian();
newCiv.x = roadBlocks[idx].x + (Math.random() - 0.5) * 100;
newCiv.y = roadBlocks[idx].y + (Math.random() - 0.5) * 100;
civilians.push(newCiv);
game.addChild(newCiv);
}
civ.destroy();
civilians.splice(i, 1);
addScore(10);
// Increase wanted level by 1 every time player kills an NPC, max 5
wantedLevel = Math.min(5, wantedLevel + 1);
updateWantedDisplay();
// Only aggro police if wantedLevel is 5
if (wantedLevel === 5) {
for (var p = 0; p < policeShooters.length; p++) {
policeShooters[p].wasShotAt = true;
policeShooters[p].target = player;
}
for (var p = 0; p < policeCars.length; p++) {
policeCars[p].target = player;
}
policeAggro = true;
}
// No break here: allow this to happen every time an NPC is killed
continue;
}
// --- Police run over by car logic ---
// Player can run over police shooters and police cars when driving a car
for (var c = 0; c < cars.length; c++) {
var car = cars[c];
if (car.driver === player) {
// Run over police shooters
for (var s = policeShooters.length - 1; s >= 0; s--) {
var shooter = policeShooters[s];
if (Math.abs(shooter.x - car.x) < 90 && Math.abs(shooter.y - car.y) < 70) {
// Police shooter killed by car
// Drop a gun at police shooter's position
var gunDrop = new Container();
gunDrop.asset = gunDrop.attachAsset('gun', {
anchorX: 0.5,
anchorY: 0.5
});
gunDrop.gunLabel = new Text2('gun', {
size: 38,
fill: 0xFFFFFF
});
gunDrop.gunLabel.anchor.set(0.5, 1);
gunDrop.gunLabel.y = -30;
gunDrop.addChild(gunDrop.gunLabel);
gunDrop.x = shooter.x;
gunDrop.y = shooter.y;
gunDrop.isGunPickup = true;
game.addChild(gunDrop);
if (typeof gunPickups === "undefined") gunPickups = [];
gunPickups.push(gunDrop);
shooter.destroy();
policeShooters.splice(s, 1);
// Spawn TWO new police shooters at random road blocks, not near player
for (var spawnCount = 0; spawnCount < 2; spawnCount++) {
var roadBlocks = [];
for (var k = 0; k < cityBlocks.length; k++) {
var b2 = cityBlocks[k];
if (b2.type === 'road') {
var distToPlayer = Math.sqrt(Math.pow(b2.x - player.x, 2) + Math.pow(b2.y - player.y, 2));
if (distToPlayer > 600) {
roadBlocks.push(b2);
}
}
}
if (roadBlocks.length > 0) {
var idx2 = Math.floor(Math.random() * roadBlocks.length);
var newShooter = new PoliceShooter();
newShooter.x = roadBlocks[idx2].x + (Math.random() - 0.5) * 100;
newShooter.y = roadBlocks[idx2].y + (Math.random() - 0.5) * 100;
if (policeAggro) {
newShooter.target = player;
newShooter.wasShotAt = true;
} else {
newShooter.target = null;
newShooter.wasShotAt = false;
}
policeShooters.push(newShooter);
game.addChild(newShooter);
}
}
addScore(15);
// Increase wanted level by 1 (max 5) when police shooter is killed
wantedLevel = Math.min(5, wantedLevel + 1);
updateWantedDisplay();
// Only aggro police if wantedLevel is 5
if (wantedLevel === 5) {
for (var p = 0; p < policeShooters.length; p++) {
policeShooters[p].wasShotAt = true;
policeShooters[p].target = player;
}
for (var p = 0; p < policeCars.length; p++) {
policeCars[p].target = player;
}
policeAggro = true;
}
// Only allow one run over per car per frame
break;
}
}
// Run over police cars
for (var pc = policeCars.length - 1; pc >= 0; pc--) {
var police = policeCars[pc];
if (Math.abs(police.x - car.x) < 90 && Math.abs(police.y - car.y) < 70) {
// Police car killed by car
// Drop a gun at police car's position
var gunDrop = new Container();
gunDrop.asset = gunDrop.attachAsset('gun', {
anchorX: 0.5,
anchorY: 0.5
});
gunDrop.gunLabel = new Text2('gun', {
size: 38,
fill: 0xFFFFFF
});
gunDrop.gunLabel.anchor.set(0.5, 1);
gunDrop.gunLabel.y = -30;
gunDrop.addChild(gunDrop.gunLabel);
gunDrop.x = police.x;
gunDrop.y = police.y;
gunDrop.isGunPickup = true;
game.addChild(gunDrop);
if (typeof gunPickups === "undefined") gunPickups = [];
gunPickups.push(gunDrop);
police.destroy();
policeCars.splice(pc, 1);
addScore(20);
// Increase wanted level by 1 (max 5) when police car is killed
wantedLevel = Math.min(5, wantedLevel + 1);
updateWantedDisplay();
// Only aggro police if wantedLevel is 5
if (wantedLevel === 5 && typeof spawned5StarPolice === "undefined") {
for (var p = 0; p < policeShooters.length; p++) {
policeShooters[p].wasShotAt = true;
policeShooters[p].target = player;
}
for (var p = 0; p < policeCars.length; p++) {
policeCars[p].target = player;
}
policeAggro = true;
// Spawn 5 police cars at random road blocks (not near player)
var roadBlocks = [];
for (var i = 0; i < cityBlocks.length; i++) {
if (cityBlocks[i].type === 'road') {
var distToPlayer = Math.sqrt(Math.pow(cityBlocks[i].x - player.x, 2) + Math.pow(cityBlocks[i].y - player.y, 2));
if (distToPlayer > 400) {
roadBlocks.push(cityBlocks[i]);
}
}
}
for (var s = 0; s < 5; s++) {
if (roadBlocks.length > 0) {
var idx = Math.floor(Math.random() * roadBlocks.length);
var b = roadBlocks[idx];
var newPolice = spawnPolice(b.x, b.y);
newPolice.target = player;
// Remove this block from roadBlocks to avoid double-spawn at same spot
roadBlocks.splice(idx, 1);
}
}
spawned5StarPolice = true;
}
// Only allow one run over per car per frame
break;
}
}
}
}
}
// Money pickup check
var px = player.inCar ? player.inCar.x : player.x;
var py = player.inCar ? player.inCar.y : player.y;
for (var i = moneyPickups.length - 1; i >= 0; i--) {
var m = moneyPickups[i];
if (Math.abs(m.x - px) < 60 && Math.abs(m.y - py) < 60) {
playerMoney += m.value;
updateMoneyDisplay();
m.destroy();
moneyPickups.splice(i, 1);
// Show "+50 money" text for 1 second at center-top of screen
if (typeof moneyPickupText !== "undefined" && moneyPickupText.parent) {
moneyPickupText.parent.removeChild(moneyPickupText);
moneyPickupText = undefined;
}
moneyPickupText = new Text2("+50 money", {
size: 120,
fill: 0x44FF44
});
moneyPickupText.anchor.set(0.5, 0);
moneyPickupText.x = 2048 / 2;
moneyPickupText.y = 320;
LK.gui.addChild(moneyPickupText);
LK.setTimeout(function () {
if (moneyPickupText && moneyPickupText.parent) {
moneyPickupText.parent.removeChild(moneyPickupText);
moneyPickupText = undefined;
}
}, 1000);
}
}
// Gun pickup check
if (typeof gunPickups === "undefined") gunPickups = [];
for (var i = gunPickups.length - 1; i >= 0; i--) {
var g = gunPickups[i];
if (Math.abs(g.x - px) < 60 && Math.abs(g.y - py) < 60) {
// Player picks up gun: restore ammo to 100
playerAmmo = 100;
if (typeof updateAmmoDisplay === "function") updateAmmoDisplay();
g.destroy();
gunPickups.splice(i, 1);
// Show "+1 gun" text for 1 second at center-top of screen
if (typeof gunPickupText !== "undefined" && gunPickupText.parent) {
gunPickupText.parent.removeChild(gunPickupText);
gunPickupText = undefined;
}
gunPickupText = new Text2("+1 gun", {
size: 120,
fill: 0xFFF700
});
gunPickupText.anchor.set(0.5, 0);
// Place at top center, but not in top left 100x100
gunPickupText.x = 2048 / 2;
gunPickupText.y = 180;
LK.gui.addChild(gunPickupText);
// Remove after 1 second
LK.setTimeout(function () {
if (gunPickupText && gunPickupText.parent) {
gunPickupText.parent.removeChild(gunPickupText);
gunPickupText = undefined;
}
}, 1000);
// Optionally: add logic for ammo, weapon upgrade, etc.
}
}
// Mission check
if (mission.active) {
var px = player.inCar ? player.inCar.x : player.x;
var py = player.inCar ? player.inCar.y : player.y;
if (Math.abs(mission.x - px) < 80 && Math.abs(mission.y - py) < 80) {
// Complete mission
addScore(10 * wantedLevel);
mission.active = false;
mission.visible = false;
// Increase wanted level, spawn more police
wantedLevel = Math.min(5, wantedLevel + 1);
updateWantedDisplay();
if (wantedLevel > policeCars.length) {
// Spawn new police at random road
var roadBlocks = [];
for (var i = 0; i < cityBlocks.length; i++) {
if (cityBlocks[i].type === 'road') roadBlocks.push(cityBlocks[i]);
}
var idx = Math.floor(Math.random() * roadBlocks.length);
var b = roadBlocks[idx];
spawnPolice(b.x, b.y);
}
// Next mission after short delay
LK.setTimeout(function () {
resetMission();
}, 1200);
}
}
// Win condition removed: game never ends when score >= 100
};
// --- Start State ---
addScore(0);
updateWantedDisplay();
timerTxt.setText(timeLeft + '');
resetMission();
playerHealth = 5;
updateHealthDisplay();
playerMoney = 0;
updateMoneyDisplay();
policeAggro = false;
var policeHitCount = 0;
;
;