import pygame as pg from classes import * from main import * vec = pg.math.Vector2 fps = 60 pg.font.init() fonts = { 'medieval': 'medieval.ttf', 'minecraft': 'Minecraft Evenings.otf', '3dpixel': '3D-Pixel.ttf', '8bit': '8bitlim.ttf', '8bito': '8blimro.ttf', 'arcade': 'ARCADECLASSIC.ttf', 'modern_game': 'astron boy video.otf', 'modern': 'astron boy.otf', 'wonder': 'Beyond Wonderland.ttf', 'curved': 'Digitag.ttf', 'simple': 'DisposableDroidBB.ttf', 'rounded': 'dpcomic.ttf', 'playfull': 'Endalian Script.ttf', 'blocky': 'FREAKSOFNATURE.ttf', 'catchy': 'Future TimeSplitters.otf', 'simple_wide': 'Halo3.ttf', 'simple_fat': 'INVASION2000.ttf', 'very_gamy': 'ka1.ttf', 'simple_round': 'Karma Suture.otf', 'mono': 'manaspc.ttf', 'damaged': 'Merchant Copy.ttf', 'big_natural': 'MorialCitadel.TTF', 'spacy': 'nasalization-rg.otf', 'sci-fi': 'neuropol.otf', 'hollow_big_edge': 'papercut.ttf', 'space_shuttle': 'pdark.ttf', 'thin': 'PixelFJVerdana12pt.ttf', 'random': 'Seattle Avenue.ttf', 'pixel': 'yoster.ttf' } class Objects(): def __init__(self, name, ms, sprite, x, y) -> None: self.name = name self.speed = ms with open(f'art/images/{sprite}') as i: self.sprite = pg.transform.scale2x(pg.image.load(i)) self.x = x self.y = y self.hidden = False self.rect = pg.Rect(self.x, self.y, self.sprite.get_width(), self.sprite.get_height()) def draw(self, screen): if self.hidden: return self.rect.x, self.rect.y = self.x, self.y screen.blit(self.sprite, self.rect) pg.draw.rect(screen, '#ef0120', self.rect, 2) class NPC(Objects): def __init__(self, name, ms, sprite, convo_act, x, y) -> None: super().__init__(name, ms, sprite, x, y) self.talking = False self.hidden = False self.conversation = Convo('Hello, you can shoot fireballs with f now.', convo_act, 'person') self.lastUpdate = pg.time.get_ticks() def talk(self, objects): self.talking = True objects[0][0].talking = True def draw(self, screen): super().draw(screen) if self.talking: self.conversation.draw(screen) def update(self, keys, objects): if self.lastUpdate + 200 < pg.time.get_ticks(): if self.talking: self.conversation.update(keys, objects, self) self.lastUpdate = pg.time.get_ticks() else: touches = pg.sprite.spritecollideany(self, objects[0]) if touches is not None and keys[pg.K_SPACE] and isinstance(touches, MainCharacter): self.talk(objects) self.lastUpdate = pg.time.get_ticks() class Convo(Label): def __init__(self, text, convo_act, person, x = 140, y = 600, width = 1000, height = 100, font='simple', font_size = 20) -> None: super().__init__(x, y, width, height, text, font, font_size) def update(self, keys, objects, npc): if keys[pg.K_SPACE]: objects[0][0].book.addspell('fireball') npc.talking = False objects[0][0].talking = False class Fighter(Objects): def __init__(self, name, ms, sprite, x, y, health, damage, level, asp, atr) -> None: super().__init__(name, ms, sprite, x, y) self.health = health self.damage = damage self.level = level self.attack_speed = asp self.attack_range = atr self.lastHurt = pg.time.get_ticks() self.lastAttack = pg.time.get_ticks() self.hurtCooldown = 0 class MainCharacter(Fighter): def __init__(self, name, ms, sprite, x, y, health, damage, level, asp, atr) -> None: super().__init__(name, ms, sprite, x, y, health, damage, level, asp, atr) self.book = Book(0, 0, [], None, None) self.talking = False self.level = Level(1000, 38, 150, 40, f'will to live: {level}%', 'simple', 20, ) self.health = Hearts(health, sprite=['fullheart.png', 'fullheart.png', 'fullheart.png', 'fullheart.png', 'fullheart.png'], x=900, y= 50, hurtCooldown=self.hurtCooldown) self.thinks = Thinks(self.x+20, self.y-50, 150, 100, 'brr Im freezing') self.freezing = True def draw(self, screen): if self.hidden: return self.rect.x, self.rect.y = self.x, self.y screen.blit(self.sprite, self.rect) self.health.draw(screen) self.level.draw(screen) self.book.draw(screen) pg.draw.rect(screen, '#e900fa', self.rect, 2) if self.thinks.hidden == False: self.thinks.draw(screen, self.x+20, self.y-100) def hurt(self, damage, objects): if not self.talking: self.health.hurt(damage) def walk(self, keys, objects): moveto = vec(0, 0) if keys[pg.K_w] or keys[pg.K_UP]: moveto += vec(0, -1) if keys[pg.K_a] or keys[pg.K_LEFT]: moveto += vec(-1, 0) if keys[pg.K_s] or keys[pg.K_DOWN]: moveto += vec(0, 1) if keys[pg.K_d] or keys[pg.K_RIGHT]: moveto += vec(1, 0) if not moveto == vec(0, 0): moveto.scale_to_length(self.speed) self.x += moveto[0] / fps self.y += moveto[1] / fps touches = pg.sprite.spritecollideany(self, objects[2] + objects[4]) if touches is not None and not isinstance(touches, Weapons): if isinstance(touches, Obstacle): if not touches.collision: print(touches.name) return if touches.type == 'wall': if touches.name == 'wall_l': self.x += (2 + (self.x - touches.rect.x)) elif touches.name == 'wall_r': self.x -= (2 + self.rect.width - (touches.rect.x - self.x)) if touches.name == 'wall_t': self.y += (2 + (self.y - touches.rect.y)) elif touches.name == 'wall_b': self.y -= (2 + self.rect.height - (touches.rect.y - self.y)) return elif isinstance(touches, NPC): if keys[pg.K_f]: touches.talk(objects) return else: return if self.x <= touches.rect.x: self.x -= (self.rect.width - (touches.rect.x - self.x)) elif self.x > touches.rect.x: self.x += (self.rect.width - (self.x - touches.rect.x - touches.rect.width * 0.66)) #if self.y <= touches.y: pass #elif self.y > touches.y: pass #self.x -= moveto[0] * 2 / fps #self.y -= moveto[1] * 2 / fps """ if self.x <= 32: self.x = 33 elif self.x >= objects[3][0].width - 32: self.x = objects[3][0].width - 32 - self.rect.width + 1 if self.y <= 32: self.y = 33 elif self.y >= objects[3][0].height - 32: self.y = objects[3][0].height - 32 - self.rect.height + 1 """ def attack(self, obj, mouse): if self.lastAttack + self.attack_speed * 1000 < pg.time.get_ticks(): moveto = mouse - vec(self.x, self.y) if self.book.current_sp == 'fireball': weapon = Fireball('fb1', 100, self.x, self.y, moveto, 5) elif self.book.current_sp == 'windslash': weapon = Windslash('ws1', 100, self.x, self.y, moveto, 5) else: return obj[3].append(weapon) self.lastAttack = pg.time.get_ticks() def update(self, keys, mouse, objects): if not self.talking: self.walk(keys, objects) if pg.mouse.get_pressed()[0]: self.attack(objects, vec(mouse)) self.thinks.update(self) if self.health.health <= 0: return False else: return True class Hearts(): def __init__(self, health, sprite, x, y, hurtCooldown) -> None: self.x = x self.y = y self.health = health self.lastHurt = pg.time.get_ticks() self.hurtCooldown = hurtCooldown self.hidden = False self.sprite=[] for parts in sprite: with open(f'art/images/main_attributes/{parts}') as i: self.sprite.append(pg.image.load(i)) self.rect = [] for each in self.sprite: self.rect.append(pg.Rect(self.x, self.y, each.get_width(), each.get_height())) def hurt(self,damage): if self.lastHurt + self.hurtCooldown < pg.time.get_ticks(): self.health -= damage self.lastHurt = pg.time.get_ticks() self.update() def draw(self, screen): if self.hidden: return for i in range(0, 5): self.rect[i].x, self.rect[i].y = self.x + i * 20, self.y screen.blit(self.sprite[i], self.rect[i]) def update(self): sprite = [] for i in range(0, 5): if self.health >= 4 + 4 * i: sprite.append('fullheart.png') elif self.health == 3 + 4 * i: sprite.append('dreiviertelheart.png') elif self.health >= 2 + 4 * i: sprite.append('halfheart.png') elif self.health >= 1 + 4 * i: sprite.append('viertelheart.png') elif self.health <= 4 * i: sprite.append('noheart.png') self.sprite = [] for parts in sprite: with open(f'art/images/main_attributes/{parts}') as i: self.sprite.append(pg.image.load(i)) class Level(Label): def __init__(self, x, y, width, height, text, font='simple', font_size=20, font_color='#1e90ff', sprite='label.png') -> None: super().__init__(x, y, width, height, text, font, font_size, font_color, sprite) class Thinks(Label): def __init__(self, x, y, width, height, text, font='simple', font_size=15, font_color='#000000', sprite='thinks.png') -> None: super().__init__(x, y, width, height, text, font, font_size, font_color, sprite) def draw(self, screen, x, y): if self.hidden: return self.x = x self.y = y super().draw(screen) def update(self, main): if not self.hidden: if not main.freezing: self.hidden = True class Book(): def __init__(self, x, y, spells, current_spell, current_shield) -> None: with open(f'art/images/main_attributes/book.png') as i: self.sprite = pg.image.load(i) self.sprite = pg.transform.scale(self.sprite, (1280, 720)) self.x = x self.y = y self.hidden = False self.rect = pg.Rect(self.x, self.y, self.sprite.get_width(), self.sprite.get_height()) self.sp_list = spells self.current_sp = current_spell self.text_left = ["Dear User, ", "in case you fell on the ground too hard,", "here is a quick reminder:", "You are a homeless person.","One cold day you went to the library to get warm.", "There you saw and opened me out of boedom.", "This lead to you being thrown in this world.", "But you can find a way out of here again."] self.text_right = ["This book will help you to survive.", "Click on a picture to choose your spell.", "Talk to fairies to unlock new spells!"] self.buttons=[] self.buttons_y = 400 self.buttons_x = 800 def draw(self, screen): if self.hidden: return self.rect.x, self.rect.y = self.x, self.y screen.blit(self.sprite, self.rect) text_left_y = 100 text_right_y = 100 for text in self.text_left: label = Label(100, text_left_y, 500, 50, text, font_color='#000000', sprite='empty.png') label.draw(screen) text_left_y += 50 for text in self.text_right: label = Label(680, text_right_y, 500, 50, text, font_color='#000000', sprite='empty.png') label.draw(screen) text_right_y += 50 for button in self.buttons: button.update(screen) def addspell(self, spell): if spell not in self.sp_list: self.sp_list.append(spell) self.current_sp = spell self.buttons.append(Button(self.buttons_x, self.buttons_y, 58, 50, f'{spell}_icon.png', 'medieval', 23, attributes=[spell], onclickFunction=self.update_spell)) self.buttons_y += 100 def update_spell(self, spell): self.current_sp = spell def update(self): pass class Mobs(Fighter): def __init__(self, name, ms, sprite, x, y, health, damage, level, asp, atr, drops) -> None: super().__init__(name, ms, sprite, x, y, health, damage, level, asp, atr) self.drops = drops * (self.level / 2) def chase(self, obj): x = obj[0][0].x y = obj[0][0].y moveto = vec(x, y) - vec(self.x, self.y) if not (moveto).length() <= self.attack_range: moveto.scale_to_length(self.speed) self.x += moveto[0] / fps self.y += moveto[1] / fps touches = pg.sprite.spritecollideany(self, obj[4]) if touches is not None and not isinstance(touches, Weapons): if isinstance(touches, Obstacle): if not touches.collision: return if touches.type == 'wall': if touches.name == 'wall_l': self.x += (2 + (self.x - touches.rect.x)) elif touches.name == 'wall_r': self.x -= (2 + self.rect.width - (touches.rect.x - self.x)) if touches.name == 'wall_t': self.y += (2 + (self.y - touches.rect.y)) elif touches.name == 'wall_b': self.y -= (2 + self.rect.height - (touches.rect.y - self.y)) if self.x <= touches.rect.x: self.x -= (self.rect.width - (touches.rect.x - self.x)) elif self.x > touches.rect.x: self.x += (self.rect.width - (self.x - touches.rect.x - touches.rect.width * 0.66)) else: self.attack(moveto, obj) def hurt(self, damage, objects): self.health -= damage if self.health <= 0: self.hidden = True objects[1].remove(self) def update(self, obj): self.chase(obj) class Skeleton(Mobs): def __init__(self, name, ms, x, y, health, damage, level, asp, atr, sprite = 'people/skeleton.png', drops=0) -> None: super().__init__(name, ms, sprite, x, y, health, damage, level, asp, atr, drops) def attack(self, moveto, obj): if self.lastAttack + self.attack_speed * 1000 < pg.time.get_ticks(): obj[3].append(Arrow("arrow", 200, self.x, self.y, moveto, self.damage)) self.lastAttack = pg.time.get_ticks() class Zombie(Mobs): def __init__(self, name, ms, x, y, health, damage, level, asp, atr, sprite='people/zombie.png', drops=0) -> None: super().__init__(name, ms, sprite, x, y, health, damage, level, asp, atr, drops) def attack(self, moveto, obj): if self.lastAttack + self.attack_speed * 1000 < pg.time.get_ticks(): obj[3].append(Punch('punch', 100, self.x, self.y, moveto, self.damage)) self.lastAttack = pg.time.get_ticks() class Weapons(Objects): def __init__(self, name, ms, sprite, x, y, moveto, damage, life_ticks) -> None: super().__init__(name, ms, sprite, x, y) self.moveto = moveto self.damage = damage self.life_ticks= life_ticks self.spawn_tick = pg.time.get_ticks() pos = vec(1,0) angle = pos.angle_to(moveto) self.sprite = pg.transform.rotate(self.sprite, -angle) def die(self, objects, kills): touches = pg.sprite.spritecollideany(self, objects[0] + objects[1]) if touches is not None and isinstance(touches, kills): touches.hurt(self.damage, objects) self.hidden = True objects[3].remove(self) def move(self, objects): self.moveto.scale_to_length(self.speed) self.x += self.moveto[0] / fps self.y += self.moveto[1] / fps if pg.time.get_ticks() - self.spawn_tick > self.life_ticks: self.hidden = True objects[3].remove(self) class Spells(Weapons): def __init__(self, name, ms, sprite, x, y, moveto, damage, life_ticks) -> None: super().__init__(name, ms, sprite, x, y, moveto, damage, life_ticks) class Fireball(Spells): def __init__(self, name, ms, x, y, moveto, damage, sprite = 'weapons/fireball.png', life_ticks=5000) -> None: super().__init__(name, ms, sprite, x, y, moveto, damage, life_ticks) def update(self, objects): self.move(objects) self.die(objects, Mobs) class Windslash(Spells): def __init__(self, name, ms, x, y, moveto, damage, sprite = 'weapons/windslash.png', life_ticks=700) -> None: super().__init__(name, ms, sprite, x, y, moveto, damage, life_ticks) def update(self, objects): self.move(objects) self.die(objects, Mobs) def move(self, objects): super().move(objects) self.moveto = self.moveto.rotate(5) class Arrow(Weapons): def __init__(self, name, ms, x, y, moveto, damage, sprite = 'weapons/arrow.png', life_ticks=5000) -> None: super().__init__(name, ms, sprite, x, y, moveto, damage, life_ticks) def update(self, objects): self.move(objects) self.die(objects, MainCharacter) class Punch(Weapons): def __init__(self, name, ms, x, y, moveto, damage, sprite = 'weapons/empty.png', life_ticks=100) -> None: super().__init__(name, ms, sprite, x, y, moveto, damage, life_ticks) def update(self, objects): self.move(objects) self.die(objects, MainCharacter) class Fire(Objects): def __init__(self, name, ms, x, y, sprite='background/fireplace.png') -> None: super().__init__(name, ms, sprite, x, y) def warming(self, objects): touches = pg.sprite.spritecollideany(self, objects[0]) if touches is not None and isinstance(touches, MainCharacter): touches.freezing = False def update(self, objects): self.warming(objects) return False class Portal(Objects): def __init__(self, name, ms, x, y, sprite='portal.png') -> None: super().__init__(name, ms, sprite, x, y) def update(self, objects): touches = pg.sprite.spritecollideany(self, objects[0]) if touches is not None and isinstance(touches, MainCharacter): return True else: return False