game/viecher.py
2024-03-10 16:19:57 +01:00

542 lines
22 KiB
Python

import pygame as pg
from classes import *
from main import *
import random
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_scene, x, y) -> None:
super().__init__(name, ms, sprite, x, y)
self.talking = False
self.hidden = False
self.conversation = Convo(self, convo_scene)
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.name == 'oldlady':
if self.conversation.convo_scene==0 and 'rat' in objects[0][0].killed and objects[1]==[]:
self.conversation.convo_scene=1
if self.lastUpdate + 200 < pg.time.get_ticks():
if self.talking:
self.conversation.update(keys, objects)
self.lastUpdate = pg.time.get_ticks()
else:
touches = pg.sprite.spritecollideany(self, objects[0])
if touches is not None and keys[pg.K_f] and isinstance(touches, MainCharacter):
self.talk(objects)
self.lastUpdate = pg.time.get_ticks()
class Convo(Label):
def __init__(self, npc, convo_scene, text='', x = 140, y = 600, width = 1000, height = 100, font='simple', font_size = 20) -> None:
super().__init__(x, y, width, height, text, font, font_size)
self.convo_act=0
self.npc = npc
self.convo_scene = convo_scene
self.convos = [
['oldlady', 0, ['There are so many rats here.', 'I wish someone would to something against that.','An experienced fighter could kill them.', 'For them it only takes a mouseclick.']],
['oldlady', 1, ['Oh, did you kill all the rats?', 'You must be the chosen one!', 'It would be nice if you would go and talk to the village elder.']],
['elder', 0, ['Who are you?', 'You want to help us?', 'We have a serious problem with some monsters.', 'One day they appeared out of nowhere and started attacking.', 'When you jump into the portal outside,', 'You will be send to some monsters.', 'PLEASE help us!']],
['elder', 1, ['Who are you?', 'You want to help us?', 'We have a serious problem with some monsters.', 'One day they appeared out of nowhere and started attacking.', 'When you jump into the portal outside,', 'You will be send to some monsters.', 'PLEASE help us!']]
]
def draw(self, screen):
self.text = self.findConversation()[2][self.convo_act]
super().draw(screen)
def findConversation(self):
for convo in self.convos:
if convo[0] == self.npc.name and convo[1] == self.convo_scene:
return convo
return ['ERROR']
def update(self, keys, objects):
if keys[pg.K_f]:
convo = self.findConversation()
if self.convo_act+1 < len(convo[2]):
self.text = convo[2][self.convo_act]
self.convo_act += 1
else:
if convo[0] == 'oldlady':
if convo[1] == 0:
for i in range(0,5):
objects[1].append(Rat('rat', random.randint(150,250), 800, 400+i*20, 1, 1, 1, 100, 25))
elif convo[1] == 1:
objects[0][0].level.level = 5
while 'rat' in objects[0][0].killed: objects[0][0].killed.remove('rat')
if convo[0] == 'elder':
if convo[1] == 0:
objects[4].append(Obstacle('portal', 'interactable', 'art/images/background/portal.png', False, 700, 300))
self.convo_scene += 1
self.convo_act = 0
self.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, killed =[]) -> 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, level, 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
self.killed = killed #amount of mobs that were killed
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 obstacle_interaction(self, objects):
touches = pg.sprite.spritecollideany(self, objects[4])
if touches is not None:
if touches.name == 'fireplace':
self.freezing = False
elif touches.name == 'portal' and self.level.level != 1:
return 'play'
elif touches.name == 'house' and self.level.level != 1:
self.x = 500
self.y = 400
return 'house'
elif 'wall' in touches.name:
return 'wall'
else:
return True
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):
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, 10)
else:
weapon = Punch('punch', 100, self.x, self.y, moveto, 1, Mobs, life_ticks=500)
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 'village'
else:
return self.obstacle_interaction(objects)
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, level, 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)
self.level = level
def draw(self, screen):
self.text = f'will to live: {self.level}%'
super().draw(screen)
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 warm up yourself.",
"There you got bored and found and opened me.", "This lead to you being thrown into this world.",
"But you can find a way out of here again."]
self.text_right = ["This book will help you to survive.", "You can open and close me when pressing e.",
"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:
objects[0][0].killed.append(self.name)
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, MainCharacter))
self.lastAttack = pg.time.get_ticks()
class Rat(Mobs):
def __init__(self, name, ms, x, y, health, damage, level, asp, atr, sprite='people/rat.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, MainCharacter))
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
if self in objects[3]:
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=1000) -> 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, kills, sprite = 'weapons/empty.png', life_ticks=100) -> None:
super().__init__(name, ms, sprite, x, y, moveto, damage, life_ticks)
self.kills = kills
def update(self, objects):
self.move(objects)
self.die(objects, self.kills)