master
Filips Kalniņš 2026-02-11 12:00:14 +02:00
commit cddd6289e6
23 changed files with 911 additions and 0 deletions

5
LICENSE 100644
View File

@ -0,0 +1,5 @@
Copyright (C) 2026 by fkalnins fkalnins.e@rkg.lv
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

2
README.md 100644
View File

@ -0,0 +1,2 @@
# Projectdd

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

21
camera.py 100644
View File

@ -0,0 +1,21 @@
import pygame
from settings import *
class Camera:
def __init__(self, target):
self.target = target
self.offset = pygame.Vector2(0, 0)
def update(self):
# Smooth camera movement
target_x = self.target.rect.centerx - SCREEN_WIDTH // 2
target_y = self.target.rect.centery - SCREEN_HEIGHT // 2
self.offset.x += (target_x - self.offset.x) * CAMERA_SMOOTHING
self.offset.y += (target_y - self.offset.y) * CAMERA_SMOOTHING
def apply(self, rect):
return rect.move(-self.offset.x, -self.offset.y)
def screen_to_world(self, pos):
return (pos[0] + self.offset.x, pos[1] + self.offset.y)

17
enemy.py 100644
View File

@ -0,0 +1,17 @@
import pygame
from settings import *
class Enemy:
def __init__(self, x, y):
self.rect = pygame.Rect(x, y, 28, 48)
self.velocity = pygame.Vector2(0, 0)
def update(self, dt, world, player):
# Basic AI: follow player
if player.rect.x < self.rect.x:
self.rect.x -= ENEMY_SPEED * dt
else:
self.rect.x += ENEMY_SPEED * dt
def draw(self, screen, camera):
pygame.draw.rect(screen, (0, 0, 255), camera.apply(self.rect))

28
enemy_manager.py 100644
View File

@ -0,0 +1,28 @@
import pygame
import random
from settings import *
from enemy import Enemy
class EnemyManager:
def __init__(self, world, player):
self.world = world
self.player = player
self.enemies = []
# spawn a few enemies to start
for _ in range(5):
self.spawn_enemy()
def spawn_enemy(self):
x = random.randint(0, self.world.width * TILE_SIZE)
y = (SURFACE_LEVEL - 5) * TILE_SIZE
self.enemies.append(Enemy(x, y))
def update(self, dt):
for enemy in self.enemies:
enemy.update(dt, self.world, self.player)
def draw(self, screen, camera):
for enemy in self.enemies:
enemy.draw(screen, camera)

143
game.py 100644
View File

@ -0,0 +1,143 @@
import pygame
from settings import *
from world import World
from player import Player
from camera import Camera
from inventory import Inventory
from enemy_manager import EnemyManager
class Game:
def __init__(self):
pygame.init() # <-- IMPORTANT
self.show_inventory = False
# ----------------------------------
# Display Setup
# ----------------------------------
flags = pygame.SCALED
self.screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT), flags)
pygame.display.set_caption(GAME_TITLE)
self.clock = pygame.time.Clock()
self.running = True
self.paused = False
# ----------------------------------
# Core Systems
# ----------------------------------
self.world = World()
self.player = Player(100, 100)
self.camera = Camera(self.player)
self.inventory = Inventory()
self.enemy_manager = EnemyManager(self.world, self.player)
# ----------------------------------
# Debug
self.font = pygame.font.SysFont("consolas", 18)
# ==========================================================
# MAIN LOOP
# ==========================================================
def run(self):
while self.running:
dt = self.clock.tick(FPS) / 1000
self.handle_events()
if not self.paused:
self.update(dt)
self.draw()
pygame.quit()
# ==========================================================
# EVENTS
# ==========================================================
def handle_events(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
self.paused = not self.paused
# Toggle inventory
if event.key == pygame.K_i:
self.show_inventory = not self.show_inventory
# -------------------------------
# Mouse input for breaking/placing
# -------------------------------
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1: # Left click
self.world.break_block(
pygame.mouse.get_pos(),
self.camera,
self.inventory
)
if event.button == 3: # Right click
self.world.place_block(
pygame.mouse.get_pos(),
self.camera
)
# ==========================================================
# UPDATE
# ==========================================================
def update(self, dt):
# If inventory is open, pause gameplay
if self.show_inventory:
return
self.player.update(dt, self.world)
self.camera.update()
self.enemy_manager.update(dt)
# ==========================================================
# DRAW
# ==========================================================
def draw(self):
self.screen.fill(BACKGROUND_COLOR)
# Draw world relative to camera
self.world.draw(self.screen, self.camera)
# Draw entities
self.enemy_manager.draw(self.screen, self.camera)
self.player.draw(self.screen, self.camera)
# UI
if self.show_inventory:
self.inventory.draw(self.screen)
self.draw_ui()
pygame.display.flip()
# ==========================================================
# UI / DEBUG
# ==========================================================
def draw_ui(self):
if SHOW_FPS:
fps = self.clock.get_fps()
fps_text = self.font.render(f"FPS: {int(fps)}", True, (255, 255, 255))
self.screen.blit(fps_text, (10, 10))
if DEBUG_MODE:
debug_text = self.font.render(
f"Player: ({int(self.player.rect.x)}, {int(self.player.rect.y)})",
True,
(255, 255, 255)
)
self.screen.blit(debug_text, (10, 30))
if self.paused:
pause_text = self.font.render("PAUSED", True, (255, 0, 0))
rect = pause_text.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2))
self.screen.blit(pause_text, rect)

90
inventory.py 100644
View File

@ -0,0 +1,90 @@
import pygame
from settings import *
from items import ITEMS, get_item
class Inventory:
def __init__(self):
self.slots = {}
# UI settings
self.width = 420
self.height = 300
self.x = (SCREEN_WIDTH - self.width) // 2
self.y = (SCREEN_HEIGHT - self.height) // 2
self.grid_cols = 8
self.grid_rows = 4
self.cell_size = 40
self.padding = 10
self.cell_padding = 4
def add_item(self, item_id, amount=1):
if item_id in self.slots:
self.slots[item_id] += amount
else:
self.slots[item_id] = amount
def draw(self, screen):
font = pygame.font.SysFont("consolas", 18)
title_font = pygame.font.SysFont("consolas", 24)
# Panel background
panel_rect = pygame.Rect(self.x, self.y, self.width, self.height)
pygame.draw.rect(screen, (30, 30, 30), panel_rect)
pygame.draw.rect(screen, (255, 255, 255), panel_rect, 2)
# Title
title = title_font.render("Inventory", True, (255, 255, 255))
screen.blit(title, (self.x + 15, self.y + 10))
# Close hint
hint = font.render("Press I to close", True, (200, 200, 200))
screen.blit(hint, (self.x + 15, self.y + 40))
# Draw grid
start_x = self.x + self.padding
start_y = self.y + 70
# Convert slots to list for display
items_list = list(self.slots.items())
index = 0
mouse = pygame.mouse.get_pos()
for row in range(self.grid_rows):
for col in range(self.grid_cols):
cell_rect = pygame.Rect(
start_x + col * (self.cell_size + self.cell_padding),
start_y + row * (self.cell_size + self.cell_padding),
self.cell_size,
self.cell_size
)
pygame.draw.rect(screen, (60, 60, 60), cell_rect)
pygame.draw.rect(screen, (120, 120, 120), cell_rect, 2)
if index < len(items_list):
item_id, amount = items_list[index]
item = get_item(item_id)
if item:
# Draw item icon
icon_rect = pygame.Rect(
cell_rect.x + 6,
cell_rect.y + 6,
28,
28
)
pygame.draw.rect(screen, item.color, icon_rect)
# Draw amount
amount_text = font.render(str(amount), True, (255, 255, 255))
screen.blit(amount_text, (cell_rect.x + 2, cell_rect.y + 2))
# Tooltip on hover
if cell_rect.collidepoint(mouse):
tooltip = font.render(item.name, True, (255, 255, 0))
screen.blit(tooltip, (mouse[0] + 10, mouse[1] + 10))
index += 1

68
items.py 100644
View File

@ -0,0 +1,68 @@
from settings import *
class Item:
def __init__(self, item_id, name, color, stack_limit=999, placeable=False, place_tile=None):
self.id = item_id
self.name = name
self.color = color
self.stack_limit = stack_limit
self.placeable = placeable
self.place_tile = place_tile
ITEMS = {
ITEM_WOOD: Item(
ITEM_WOOD,
"Wood",
(160, 82, 45),
stack_limit=999,
placeable=True,
place_tile=WOOD
),
ITEM_STONE: Item(
ITEM_STONE,
"Stone",
(100, 100, 100),
stack_limit=999,
placeable=True,
place_tile=STONE
),
ITEM_COAL: Item(
ITEM_COAL,
"Coal",
(40, 40, 40),
stack_limit=999,
placeable=False
),
ITEM_COPPER: Item(
ITEM_COPPER,
"Copper Ore",
(210, 120, 60),
stack_limit=999,
placeable=False
),
ITEM_IRON: Item(
ITEM_IRON,
"Iron Ore",
(180, 180, 180),
stack_limit=999,
placeable=False
),
ITEM_GOLD: Item(
ITEM_GOLD,
"Gold Ore",
(255, 215, 0),
stack_limit=999,
placeable=False
),
}
def get_item(item_id):
return ITEMS.get(item_id, None)

12
main.py 100644
View File

@ -0,0 +1,12 @@
import traceback
from game import Game
if __name__ == "__main__":
try:
print("Starting game...")
game = Game()
print("Game initialized.")
game.run()
except Exception:
print("An error occurred:")
traceback.print_exc()

111
player.py 100644
View File

@ -0,0 +1,111 @@
import pygame
from settings import *
class Player:
def __init__(self, x, y):
# Position & Size
self.rect = pygame.Rect(x, y, PLAYER_WIDTH, PLAYER_HEIGHT)
# Movement
self.velocity = pygame.Vector2(0, 0)
self.acceleration = pygame.Vector2(0, 0)
# State
self.on_ground = False
self.facing_right = True
# Stats
self.health = MAX_HEALTH
# ==========================================================
# UPDATE
# ==========================================================
def update(self, dt, world):
self.handle_input()
self.apply_physics(dt)
self.handle_collisions(world)
# ==========================================================
# INPUT
# ==========================================================
def handle_input(self):
keys = pygame.key.get_pressed()
self.acceleration.x = 0
# Horizontal movement
if keys[pygame.K_a]:
self.acceleration.x = -PLAYER_ACCELERATION
self.facing_right = False
if keys[pygame.K_d]:
self.acceleration.x = PLAYER_ACCELERATION
self.facing_right = True
# Apply friction
self.acceleration.x += self.velocity.x * PLAYER_FRICTION
# Jump
if keys[pygame.K_SPACE] and self.on_ground:
self.velocity.y = JUMP_FORCE
self.on_ground = False
# ==========================================================
# PHYSICS
# ==========================================================
def apply_physics(self, dt):
# Apply gravity
self.acceleration.y = GRAVITY
# Update velocity
self.velocity += self.acceleration * dt
# Clamp fall speed
if self.velocity.y > MAX_FALL_SPEED:
self.velocity.y = MAX_FALL_SPEED
# Move horizontally
self.rect.x += self.velocity.x * dt
# Move vertically
self.rect.y += self.velocity.y * dt
# ==========================================================
# COLLISIONS
# ==========================================================
def handle_collisions(self, world):
self.on_ground = False
# Get nearby tiles once
nearby_tiles = world.get_nearby_tiles(self.rect)
# Horizontal collisions
for tile in nearby_tiles:
if tile["rect"].colliderect(self.rect) and tile["solid"]:
if self.velocity.x > 0: # Moving right
self.rect.right = tile["rect"].left
elif self.velocity.x < 0: # Moving left
self.rect.left = tile["rect"].right
self.velocity.x = 0
# Vertical collisions
for tile in nearby_tiles:
if tile["rect"].colliderect(self.rect) and tile["solid"]:
if self.velocity.y > 0: # Falling
self.rect.bottom = tile["rect"].top
self.on_ground = True
elif self.velocity.y < 0: # Jumping up
self.rect.top = tile["rect"].bottom
self.velocity.y = 0
# ==========================================================
# DRAW
# ==========================================================
def draw(self, screen, camera):
draw_rect = camera.apply(self.rect)
pygame.draw.rect(screen, (255, 50, 50), draw_rect)
if SHOW_COLLIDERS:
pygame.draw.rect(screen, (0, 255, 0), draw_rect, 2)

173
settings.py 100644
View File

@ -0,0 +1,173 @@
# ==========================================
# WINDOW / DISPLAY SETTINGS
# ==========================================
SCREEN_WIDTH = 1280
SCREEN_HEIGHT = 720
FPS = 60
VSYNC = True
GAME_TITLE = "Terraria Clone"
BACKGROUND_COLOR = (135, 206, 235) # Sky blue
# ==========================================
# TILE SETTINGS
# ==========================================
TILE_SIZE = 32
CHUNK_SIZE = 16 # 16x16 tiles per chunk
RENDER_DISTANCE = 3 # how many chunks visible around player
# Tile IDs
# Tiles
AIR = 0
DIRT = 1
GRASS = 2
STONE = 3
WOOD = 4
LEAVES = 5
IRON_ORE = 6
GOLD_ORE = 7
COPPER_ORE = 8
COAL_ORE = 9
# Items
ITEM_WOOD = 100
ITEM_STONE = 101
ITEM_IRON = 102
ITEM_GOLD = 103
ITEM_COPPER = 104
ITEM_COAL = 105
# Tile properties
TILE_PROPERTIES = {
AIR: {"solid": False, "color": (0, 0, 0), "drop": None},
DIRT: {"solid": True, "color": (139, 69, 19), "drop": ITEM_STONE},
GRASS: {"solid": True, "color": (34, 177, 76), "drop": ITEM_STONE},
STONE: {"solid": True, "color": (100, 100, 100), "drop": ITEM_STONE},
WOOD: {"solid": True, "color": (160, 82, 45), "drop": ITEM_WOOD},
LEAVES: {"solid": False, "color": (34, 139, 34), "drop": None},
# ORES
IRON_ORE: {"solid": True, "color": (180, 180, 180), "drop": ITEM_IRON},
GOLD_ORE: {"solid": True, "color": (255, 215, 0), "drop": ITEM_GOLD},
COPPER_ORE: {"solid": True, "color": (210, 120, 60), "drop": ITEM_COPPER},
COAL_ORE: {"solid": True, "color": (40, 40, 40), "drop": ITEM_COAL},
}
# ==========================================
# WORLD GENERATION
# ==========================================
WORLD_WIDTH = 200 # in tiles
WORLD_HEIGHT = 100 # in tiles
SEED = 42
SURFACE_LEVEL = 40
CAVE_THRESHOLD = 0.4
ORE_THRESHOLD = 0.75
NOISE_SCALE = 0.05
OCTAVES = 4
# ==========================================
# PLAYER SETTINGS
# ==========================================
PLAYER_WIDTH = 28
PLAYER_HEIGHT = 48
PLAYER_SPEED = 250
PLAYER_ACCELERATION = 2000
PLAYER_FRICTION = -0.15
GRAVITY = 1500
MAX_FALL_SPEED = 1000
JUMP_FORCE = -500
DOUBLE_JUMP = False
MAX_HEALTH = 100
# ==========================================
# CAMERA SETTINGS
# ==========================================
CAMERA_SMOOTHING = 0.1
CAMERA_OFFSET_Y = -100
# ==========================================
# INVENTORY SETTINGS
# ==========================================
INVENTORY_SIZE = 40
HOTBAR_SIZE = 10
STACK_LIMIT = 999
INVENTORY_SLOT_SIZE = 40
INVENTORY_PADDING = 4
# ==========================================
# BLOCK BREAKING / PLACING
# ==========================================
BREAK_RANGE = 5 # tiles
BREAK_TIME = {
DIRT: 0.3,
GRASS: 0.3,
STONE: 0.8,
WOOD: 0.5,
IRON_ORE: 1.2,
GOLD_ORE: 1.5,
COPPER_ORE: 1.0,
COAL_ORE: 0.9,
}
PLACE_RANGE = 5
# ==========================================
# ENEMY SETTINGS
# ==========================================
MAX_ENEMIES = 10
ENEMY_SPAWN_RATE = 5 # seconds
ENEMY_SPEED = 100
ENEMY_DAMAGE = 10
ENEMY_HEALTH = 50
# ==========================================
# PHYSICS SETTINGS
# ==========================================
TERMINAL_VELOCITY = 1200
COLLISION_STEPS = 4
# ==========================================
# LIGHTING (for future use)
# ==========================================
ENABLE_LIGHTING = False
LIGHT_RADIUS = 5
# ==========================================
# DEBUG SETTINGS
# ==========================================
DEBUG_MODE = True
SHOW_FPS = True
SHOW_COLLIDERS = False
SHOW_CHUNK_BORDERS = False

38
tiles.py 100644
View File

@ -0,0 +1,38 @@
from settings import *
class Tile:
def __init__(self, tile_id, name, collidable, color, hardness=1.0, drop=None):
self.id = tile_id
self.name = name
self.collidable = collidable
self.color = color
self.hardness = hardness
self.drop = drop
TILE_TYPES = {
AIR: Tile(AIR, "Air", False, (0,0,0), hardness=0, drop=None),
DIRT: Tile(DIRT, "Dirt", True, (139,69,19), hardness=0.4, drop=ITEM_STONE),
GRASS: Tile(GRASS, "Grass", True, (34,177,76), hardness=0.4, drop=ITEM_STONE),
STONE: Tile(STONE, "Stone", True, (100,100,100), hardness=0.8, drop=ITEM_STONE),
WOOD: Tile(WOOD, "Wood", True, (160,82,45), hardness=0.5, drop=ITEM_WOOD),
LEAVES: Tile(LEAVES, "Leaves", False, (34,139,34), hardness=0.2, drop=None),
IRON_ORE: Tile(IRON_ORE, "Iron Ore", True, (180,180,180), hardness=1.2, drop=ITEM_IRON),
GOLD_ORE: Tile(GOLD_ORE, "Gold Ore", True, (255,215,0), hardness=1.5, drop=ITEM_GOLD),
COPPER_ORE: Tile(COPPER_ORE, "Copper Ore", True, (210,120,60), hardness=1.0, drop=ITEM_COPPER),
COAL_ORE: Tile(COAL_ORE, "Coal Ore", True, (40,40,40), hardness=0.9, drop=ITEM_COAL),
}
# ----------------------------
# Compatibility for world.py
# ----------------------------
TILE_PROPERTIES = {
tile_id: {
"solid": tile.collidable,
"color": tile.color,
"drop": tile.drop
}
for tile_id, tile in TILE_TYPES.items()
}
def get_tile(tile_id):
return TILE_TYPES.get(tile_id, TILE_TYPES[AIR])

203
world.py 100644
View File

@ -0,0 +1,203 @@
import pygame
import random
from settings import *
from tiles import get_tile
class World:
def __init__(self):
self.width = WORLD_WIDTH
self.height = WORLD_HEIGHT
# 2D grid: world[y][x]
self.grid = [
[AIR for _ in range(self.width)]
for _ in range(self.height)
]
self.generate_world()
# ==========================================================
# WORLD GENERATION
# ==========================================================
def generate_world(self):
# First generate terrain
for x in range(self.width):
# Simple terrain height variation
surface_height = SURFACE_LEVEL + random.randint(-3, 3)
for y in range(self.height):
if y < surface_height:
self.grid[y][x] = AIR
elif y == surface_height:
self.grid[y][x] = GRASS
elif y < surface_height + 5:
self.grid[y][x] = DIRT
else:
self.grid[y][x] = STONE
# Then add trees + ores
self.generate_trees()
self.generate_ores()
# ==========================================================
# DRAW
# ==========================================================
def draw(self, screen, camera):
# Determine visible tile range
start_x = max(0, camera.offset.x // TILE_SIZE)
end_x = min(self.width, (camera.offset.x + SCREEN_WIDTH) // TILE_SIZE + 2)
start_y = max(0, camera.offset.y // TILE_SIZE)
end_y = min(self.height, (camera.offset.y + SCREEN_HEIGHT) // TILE_SIZE + 2)
for y in range(int(start_y), int(end_y)):
for x in range(int(start_x), int(end_x)):
tile_id = self.grid[y][x]
if tile_id != AIR:
color = get_tile(tile_id).color # FIXED: no more KeyError
world_rect = pygame.Rect(
x * TILE_SIZE,
y * TILE_SIZE,
TILE_SIZE,
TILE_SIZE
)
screen_rect = camera.apply(world_rect)
pygame.draw.rect(screen, color, screen_rect)
# ==========================================================
# COLLISION SUPPORT
# ==========================================================
def get_nearby_tiles(self, rect):
tiles = []
# Determine tile range around player
start_x = max(0, rect.left // TILE_SIZE - 1)
end_x = min(self.width, rect.right // TILE_SIZE + 2)
start_y = max(0, rect.top // TILE_SIZE - 1)
end_y = min(self.height, rect.bottom // TILE_SIZE + 2)
for y in range(start_y, end_y):
for x in range(start_x, end_x):
tile_id = self.grid[y][x]
if tile_id != AIR:
tile_rect = pygame.Rect(
x * TILE_SIZE,
y * TILE_SIZE,
TILE_SIZE,
TILE_SIZE
)
tiles.append({
"rect": tile_rect,
"solid": get_tile(tile_id).collidable,
"id": tile_id,
"x": x,
"y": y
})
return tiles
# ==========================================================
# BLOCK BREAKING
# ==========================================================
def break_block(self, mouse_pos, camera, inventory):
world_x, world_y = camera.screen_to_world(mouse_pos)
tile_x = int(world_x // TILE_SIZE)
tile_y = int(world_y // TILE_SIZE)
if self.in_bounds(tile_x, tile_y):
tile_id = self.grid[tile_y][tile_x]
tile = get_tile(tile_id)
if tile_id != AIR:
if tile.drop:
inventory.add_item(tile.drop, 1)
self.grid[tile_y][tile_x] = AIR
# ==========================================================
# BLOCK PLACING
# ==========================================================
def place_block(self, mouse_pos, camera, block_type=DIRT):
world_x, world_y = camera.screen_to_world(mouse_pos)
tile_x = int(world_x // TILE_SIZE)
tile_y = int(world_y // TILE_SIZE)
if self.in_bounds(tile_x, tile_y):
if self.grid[tile_y][tile_x] == AIR:
self.grid[tile_y][tile_x] = block_type
# ==========================================================
# UTIL
# ==========================================================
def in_bounds(self, x, y):
return 0 <= x < self.width and 0 <= y < self.height
# ==========================================================
# NEW: Get surface height for player spawn
# ==========================================================
def get_surface_height(self, x):
for y in range(self.height):
if self.grid[y][x] != AIR:
return y
return self.height - 1
# ==========================================================
# TREE GENERATION
# ==========================================================
def generate_trees(self):
for x in range(0, self.width, 6):
if random.random() < 0.25: # 25% chance
# find surface
for y in range(self.height):
if self.grid[y][x] == GRASS:
self.spawn_tree(x, y)
break
def spawn_tree(self, x, surface_y):
# trunk height
height = random.randint(4, 7)
for i in range(height):
self.grid[surface_y - 1 - i][x] = WOOD
# leaves
leaf_start = surface_y - height - 1
for y in range(leaf_start, leaf_start - 4, -1):
for lx in range(x - 2, x + 3):
if 0 <= lx < self.width and 0 <= y < self.height:
if random.random() > 0.25:
self.grid[y][lx] = LEAVES
# ==========================================================
# ORE GENERATION
# ==========================================================
def generate_ores(self):
for _ in range(250):
x = random.randint(0, self.width - 1)
y = random.randint(SURFACE_LEVEL + 5, self.height - 1)
if self.grid[y][x] == STONE:
r = random.random()
if r < 0.5:
self.grid[y][x] = COAL_ORE
elif r < 0.75:
self.grid[y][x] = COPPER_ORE
elif r < 0.9:
self.grid[y][x] = IRON_ORE
else:
self.grid[y][x] = GOLD_ORE