forked from InfoProjekt/game
Dem Gegner kann jetzt durch Main Angriff Schaden zugefügt werden und er kann sterben Das Buch kann durch Drücken von e geöffnet werden, das Spiel hält an Der Main kann (nachdem mit NPC geredet) Feuerbälle mit f schießen (Schussrichtung adden!!) Ein NPC wurde hinzugefügt, der steht. Main redet automatisch mit ihm wenn main reinläuft. Durch Leertaste wird Unterhaltung beendet.
361 lines
12 KiB
Python
361 lines
12 KiB
Python
import pygame as pg
|
|
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.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)
|
|
|
|
class NPC(Objects):
|
|
def __init__(self, name, ms, sprite, convo_act, x, y) -> None:
|
|
self.talking = False
|
|
self.hidden = True
|
|
super().__init__(name, ms, sprite, x, y)
|
|
self.conversation = Convo('Hello, you can shoot fireballs with f now.', convo_act, 'person')
|
|
|
|
def talk(self, objects):
|
|
self.talking = True
|
|
objects[0][0].talking = True
|
|
self.conversation.hidden = False
|
|
|
|
def draw(self, screen):
|
|
super().draw(screen)
|
|
if self.talking == True:
|
|
self.conversation.draw(screen)
|
|
|
|
def update(self, keys, objects):
|
|
if self.talking:
|
|
self.conversation.update(keys, objects)
|
|
|
|
class Convo():
|
|
def __init__(self, text, convo_act, person, x = 140, y = 600, width = 1000, height = 100, font='simple', font_size = 20) -> None:
|
|
self.x = x
|
|
self.y = y
|
|
self.width = width
|
|
self.height = height
|
|
self.hidden = False
|
|
self.font = pg.font.Font(f'fonts/{fonts[font]}', font_size)
|
|
with open('art/images/label.png', 'r') as tb:
|
|
self.box = pg.image.load(tb)
|
|
self.box = pg.transform.scale(self.box, (width, height))
|
|
self.labelRect = pg.Rect(self.x, self.y, self.width, self.height)
|
|
self.labelSurf = self.font.render(text, True, '#1E90FF')
|
|
|
|
|
|
def draw(self, screen):
|
|
if self.hidden:
|
|
return
|
|
self.box.blit(self.labelSurf, [
|
|
self.labelRect.width/2 - self.labelSurf.get_rect().width/2,
|
|
self.labelRect.height/2 - self.labelSurf.get_rect().height/2
|
|
])
|
|
screen.blit(self.box, self.labelRect)
|
|
|
|
def update(self, keys, objects):
|
|
if keys[pg.K_SPACE]:
|
|
objects[0][0].book.addspell('fireball')
|
|
self.talking = False
|
|
objects[0][0].talking = False
|
|
self.hidden = True
|
|
|
|
|
|
|
|
|
|
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, level, 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)
|
|
|
|
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)
|
|
|
|
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[1] + objects[2])
|
|
if touches is not None:
|
|
self.x -= moveto[0]*1.5 / fps #change later
|
|
self.y -= moveto[1]*1.5 / fps #change later
|
|
if isinstance(touches, NPC):
|
|
touches.talk(objects)
|
|
|
|
def attack(self, obj, moveto = vec(0,1)):
|
|
if self.lastAttack + self.attack_speed * 1000 < pg.time.get_ticks():
|
|
if self.book.current_sp == 'fireball':
|
|
weapon = Fireball('fb1', 100, self.x, self.y, moveto, 5)
|
|
else:
|
|
return
|
|
obj[3].append(weapon)
|
|
self.lastAttack = pg.time.get_ticks()
|
|
|
|
def update(self, keys, objects):
|
|
if not self.talking:
|
|
self.walk(keys, objects)
|
|
if keys[pg.K_f]:
|
|
self.attack(objects)
|
|
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/{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/{parts}') as i:
|
|
self.sprite.append(pg.image.load(i))
|
|
|
|
|
|
class Level():
|
|
def __init__(self, x, y, level, width, height, text, font, font_size) -> None:
|
|
self.x = x
|
|
self.y = y
|
|
self.level = level
|
|
self.width = width
|
|
self.height = height
|
|
self.font = pg.font.Font(f'fonts/{fonts[font]}', font_size)
|
|
self.hidden = False
|
|
with open('art/images/label.png', 'r') as tb:
|
|
self.box = pg.image.load(tb)
|
|
self.box = pg.transform.scale(self.box, (width, height))
|
|
self.labelRect = pg.Rect(self.x, self.y, self.width, self.height)
|
|
self.labelSurf = self.font.render(text, True, '#1E90FF')
|
|
|
|
def draw(self, screen):
|
|
self.box.blit(self.labelSurf, [
|
|
self.labelRect.width / 2 - self.labelSurf.get_rect().width / 2,
|
|
self.labelRect.height / 2 - self.labelSurf.get_rect().height / 2
|
|
])
|
|
screen.blit(self.box, self.labelRect)
|
|
|
|
class Book():
|
|
def __init__(self, x, y, spells, current_spell, current_shield) -> None:
|
|
with open(f'art/images/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 = True
|
|
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
|
|
|
|
def draw(self, screen):
|
|
if self.hidden:
|
|
return
|
|
self.rect.x, self.rect.y = self.x, self.y
|
|
screen.blit(self.sprite, self.rect)
|
|
|
|
def addspell(self, spell):
|
|
if spell not in self.sp_list:
|
|
self.sp_list.append(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)
|
|
|
|
class Skeleton(Mobs):
|
|
def __init__(self, name, ms, sprite, x, y, health, damage, level, asp, atr, drops=0) -> None:
|
|
super().__init__(name, ms, sprite, x, y, health, damage, level, asp, atr, drops)
|
|
|
|
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
|
|
else:
|
|
self.attack(moveto, obj)
|
|
|
|
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()
|
|
|
|
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 Weapons(Objects):
|
|
def __init__(self, name, ms, sprite, x, y, moveto, damage) -> None:
|
|
super().__init__(name, ms, sprite, x, y)
|
|
self.moveto = moveto
|
|
self.damage = damage
|
|
pos = vec(1,0)
|
|
angle = pos.angle_to(moveto)
|
|
with open(f'art/images/{sprite}') as i:
|
|
self.sprite = pg.transform.rotate(pg.image.load(i), -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)
|
|
|
|
class Spells(Weapons):
|
|
def __init__(self, name, ms, sprite, x, y, moveto, damage) -> None:
|
|
super().__init__(name, ms, sprite, x, y, moveto, damage)
|
|
|
|
class Fireball(Spells):
|
|
def __init__(self, name, ms, x, y, moveto, damage, sprite = 'fireball.png') -> None:
|
|
super().__init__(name, ms, sprite, x, y, moveto, damage)
|
|
|
|
def move(self):
|
|
self.moveto.scale_to_length(self.speed)
|
|
self.x += self.moveto[0] / fps
|
|
self.y += self.moveto[1] / fps
|
|
|
|
def update(self, objects):
|
|
self.move()
|
|
self.die(objects, Mobs)
|
|
|
|
class Arrow(Weapons):
|
|
def __init__(self, name, ms, x, y, moveto, damage, sprite = 'arrow.png') -> None:
|
|
super().__init__(name, ms, sprite, x, y, moveto, damage)
|
|
|
|
def move(self):
|
|
self.moveto.scale_to_length(self.speed)
|
|
self.x += self.moveto[0] / fps
|
|
self.y += self.moveto[1] / fps
|
|
|
|
def update(self, objects):
|
|
self.move()
|
|
self.die(objects, MainCharacter)
|