Merge branch 'master' into map_generation

# Conflicts:
#	squirrelbattle/entities/player.py
#	squirrelbattle/game.py
#	squirrelbattle/interfaces.py
#	squirrelbattle/tests/game_test.py
This commit is contained in:
Yohann D'ANELLO
2021-01-10 22:16:11 +01:00
54 changed files with 1909 additions and 934 deletions

View File

@ -1,13 +1,14 @@
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
# Copyright (C) 2020-2021 by ÿnérant, eichhornchen, nicomarg, charlse
# SPDX-License-Identifier: GPL-3.0-or-later
from enum import Enum, auto
from math import ceil, sqrt
from itertools import product
from random import choice, randint
from typing import List, Optional, Any, Dict, Tuple
from queue import PriorityQueue
from copy import deepcopy
from enum import auto, Enum
from functools import reduce
from itertools import product
from math import ceil, sqrt
from queue import PriorityQueue
from random import choice, choices, randint
from typing import Any, Dict, List, Optional, Tuple
from .display.texturepack import TexturePack
from .translations import gettext as _
@ -180,6 +181,16 @@ class Map:
return "\n".join("".join(tile.char(pack) for tile in line)
for line in self.tiles)
def is_visible_from(self, starty: int, startx: int, desty: int, destx: int,
max_range: int) -> bool:
oldvisibility = deepcopy(self.visibility)
oldseen = deepcopy(self.seen_tiles)
self.compute_visibility(starty, startx, max_range)
result = self.visibility[desty][destx]
self.visibility = oldvisibility
self.seen_tiles = oldseen
return result
def compute_visibility(self, y: int, x: int, max_range: int) -> None:
"""
Sets the visible tiles to be the ones visible by an entity at point
@ -233,9 +244,9 @@ class Map:
continue
is_opaque = self.is_wall(y, x, octant, origin)
is_visible = is_opaque\
or ((y != top_y or top > Slope(y * 4 - 1, x * 4 + 1))
or ((y != top_y or top >= Slope(y, x))
and (y != bottom_y
or bottom < Slope(y * 4 + 1, x * 4 - 1)))
or bottom <= Slope(y, x)))
# is_visible = is_opaque\
# or ((y != top_y or top >= Slope(y, x))
# and (y != bottom_y or bottom <= Slope(y, x)))
@ -603,6 +614,13 @@ class Entity:
from squirrelbattle.entities.friendly import Merchant
return isinstance(self, Merchant)
def is_chest(self) -> bool:
"""
Is this entity a chest?
"""
from squirrelbattle.entities.friendly import Chest
return isinstance(self, Chest)
@property
def translated_name(self) -> str:
"""
@ -619,9 +637,10 @@ class Entity:
from squirrelbattle.entities.monsters import Tiger, Hedgehog, \
Rabbit, TeddyBear, GiantSeaEagle
from squirrelbattle.entities.friendly import Merchant, Sunflower, \
Trumpet
return [BodySnatchPotion, Bomb, Heart, Hedgehog, Rabbit, TeddyBear,
Sunflower, Tiger, Merchant, GiantSeaEagle, Trumpet]
Trumpet, Chest
return [BodySnatchPotion, Bomb, Chest, GiantSeaEagle, Heart,
Hedgehog, Merchant, Rabbit, Sunflower, TeddyBear, Tiger,
Trumpet]
@staticmethod
def get_weights() -> list:
@ -629,8 +648,7 @@ class Entity:
Returns a weigth list associated to the above function, to
be used to spawn random entities with a certain probability.
"""
return [3, 5, 6, 5, 5, 5,
5, 4, 4, 1, 2]
return [30, 80, 50, 1, 100, 100, 60, 70, 70, 20, 40, 40]
@staticmethod
def get_all_entity_classes_in_a_dict() -> dict:
@ -641,30 +659,37 @@ class Entity:
from squirrelbattle.entities.monsters import Tiger, Hedgehog, Rabbit, \
TeddyBear, GiantSeaEagle
from squirrelbattle.entities.friendly import Merchant, Sunflower, \
Trumpet
Trumpet, Chest
from squirrelbattle.entities.items import BodySnatchPotion, Bomb, \
Heart, Monocle, Sword, Shield, Chestplate, Helmet, \
RingCritical, RingXP
Heart, Sword, Shield, Chestplate, Helmet, RingCritical, RingXP, \
ScrollofDamage, ScrollofWeakening, Ruler, Bow, FireBallStaff, \
Monocle
return {
"Bomb": Bomb,
"Chestplate": Chestplate,
"Heart": Heart,
"BodySnatchPotion": BodySnatchPotion,
"Eagle": GiantSeaEagle,
"Bomb": Bomb,
"Bow": Bow,
"Chest": Chest,
"Chestplate": Chestplate,
"FireBallStaff": FireBallStaff,
"GiantSeaEagle": GiantSeaEagle,
"Heart": Heart,
"Hedgehog": Hedgehog,
"Helmet": Helmet,
"Player": Player,
"Merchant": Merchant,
"Monocle": Monocle,
"Sunflower": Sunflower,
"Sword": Sword,
"Trumpet": Trumpet,
"Shield": Shield,
"TeddyBear": TeddyBear,
"Tiger": Tiger,
"Player": Player,
"Rabbit": Rabbit,
"RingCritical": RingCritical,
"RingXP": RingXP,
"Ruler": Ruler,
"ScrollofDamage": ScrollofDamage,
"ScrollofWeakening": ScrollofWeakening,
"Shield": Shield,
"Sunflower": Sunflower,
"Sword": Sword,
"Trumpet": Trumpet,
"TeddyBear": TeddyBear,
"Tiger": Tiger,
}
def save_state(self) -> dict:
@ -692,6 +717,7 @@ class FightingEntity(Entity):
constitution: int
level: int
critical: int
confused: int # Seulement 0 ou 1
def __init__(self, maxhealth: int = 0, health: Optional[int] = None,
strength: int = 0, intelligence: int = 0, charisma: int = 0,
@ -707,6 +733,8 @@ class FightingEntity(Entity):
self.constitution = constitution
self.level = level
self.critical = critical
self.effects = [] # effects = temporary buff or weakening of the stats.
self.confused = 0
@property
def dead(self) -> bool:
@ -715,13 +743,31 @@ class FightingEntity(Entity):
"""
return self.health <= 0
def act(self, m: Map) -> None:
"""
Refreshes all current effects.
"""
for i in range(len(self.effects)):
self.effects[i][2] -= 1
copy = self.effects[:]
for i in range(len(copy)):
if copy[i][2] <= 0:
setattr(self, copy[i][0],
getattr(self, copy[i][0]) - copy[i][1])
self.effects.remove(copy[i])
def hit(self, opponent: "FightingEntity") -> str:
"""
The entity deals damage to the opponent
based on their respective stats.
"""
if self.confused:
return _("{name} is confused, it can not hit {opponent}.")\
.format(name=_(self.translated_name.capitalize()),
opponent=_(opponent.translated_name))
diceroll = randint(1, 100)
damage = self.strength
damage = max(0, self.strength)
string = " "
if diceroll <= self.critical: # It is a critical hit
damage *= 4
@ -736,7 +782,9 @@ class FightingEntity(Entity):
The entity takes damage from the attacker
based on their respective stats.
"""
damage = max(0, amount - self.constitution)
damage = 0
if amount != 0:
damage = max(1, amount - self.constitution)
self.health -= damage
if self.health <= 0:
self.die()