forgot to add da cookie.
This commit is contained in:
parent
4e3884b55a
commit
24d5711d82
0
src/scon/stuff/__init__.py
Normal file
0
src/scon/stuff/__init__.py
Normal file
208
src/scon/stuff/ship_battle.py
Normal file
208
src/scon/stuff/ship_battle.py
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
import random
|
||||||
|
|
||||||
|
class ShipModule(object):
|
||||||
|
""" A generic ship module equippable on a ship """
|
||||||
|
name = 'Module' # class based variable. all ShipModule's share this one string.
|
||||||
|
def __init__(self):
|
||||||
|
self.ship = None # instance based variable. every instance has its own ship.
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
""" This function is called by the ship every gamestep """
|
||||||
|
pass
|
||||||
|
|
||||||
|
class DefensiveLayer(ShipModule):
|
||||||
|
""" some kind of defensive layer. a ship will use its defensive layers against incoming damage """
|
||||||
|
name = 'Armor'
|
||||||
|
|
||||||
|
def __init__(self, maximal,
|
||||||
|
resistances=None,
|
||||||
|
current=None):
|
||||||
|
super(DefensiveLayer, self).__init__() # === ShipModule.__init__(self)
|
||||||
|
self.maximal = maximal
|
||||||
|
self.resistances = resistances or {}
|
||||||
|
self.current = current or maximal
|
||||||
|
|
||||||
|
def reduce_damage(self, damage, damage_type=None):
|
||||||
|
# reduces incoming damage by absorbing it somehow.
|
||||||
|
if self.current > 0:
|
||||||
|
# only resist if i have still current.
|
||||||
|
if damage_type:
|
||||||
|
# if there was a damage type, we look up in our resistances:
|
||||||
|
res = self.resistances.get(damage_type, 0)
|
||||||
|
if res:
|
||||||
|
damage -= damage * res
|
||||||
|
# we call get_damage to absorb damage, and it returns the rest of the damage.
|
||||||
|
return self.get_damage(damage)
|
||||||
|
else:
|
||||||
|
# we have no life, damage passes through.
|
||||||
|
return damage
|
||||||
|
|
||||||
|
def get_damage(self, damage):
|
||||||
|
# the module itself gets an amount of damage.
|
||||||
|
self.current -= damage
|
||||||
|
if self.current <= 0:
|
||||||
|
rest_damage = 0 - self.current
|
||||||
|
self.current = 0
|
||||||
|
return rest_damage
|
||||||
|
return 0
|
||||||
|
|
||||||
|
class Shields(DefensiveLayer):
|
||||||
|
""" Shields can recharge after a delay. """
|
||||||
|
name = 'Shields'
|
||||||
|
RECHARGE_DELAY = 5
|
||||||
|
|
||||||
|
def __init__(self, maximal,
|
||||||
|
resistances=None, current=None, recharge=0):
|
||||||
|
super(Shields, self).__init__(maximal, resistances, current)
|
||||||
|
self.recharge = recharge
|
||||||
|
# we save this little integer, which if bigger than zero, indicates there was a hit not long ago.
|
||||||
|
self._last_hit = 0
|
||||||
|
|
||||||
|
def get_damage(self, damage):
|
||||||
|
# we override get_damage to remember we got hit.
|
||||||
|
self._last_hit = self.RECHARGE_DELAY
|
||||||
|
return super(Shields, self).get_damage(damage)
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
# we override update function to implement a recharge, and slowly reset the _last_hit.
|
||||||
|
if self._last_hit > 0:
|
||||||
|
self._last_hit -= 1
|
||||||
|
else:
|
||||||
|
if self.current < self.maximal:
|
||||||
|
self.current += self.recharge
|
||||||
|
self.current = min(self.current, self.maximal)
|
||||||
|
|
||||||
|
class Weapon(ShipModule):
|
||||||
|
""" Weapons can fire
|
||||||
|
On this class we save some class variables, which act as default values.
|
||||||
|
- we can subclass different weapons overriding those values for all weapons of that kind.
|
||||||
|
- we can still make individual weapons with different stats.
|
||||||
|
"""
|
||||||
|
name = 'Weapon'
|
||||||
|
DEFAULT_DAMAGE = 10
|
||||||
|
DEFAULT_COOLDOWN = 10
|
||||||
|
DEFAULT_DAMAGE_TYPE = None
|
||||||
|
|
||||||
|
def __init__(self, ammo,
|
||||||
|
damage=None,
|
||||||
|
cooldown=None,
|
||||||
|
damage_type=None):
|
||||||
|
super(Weapon, self).__init__()
|
||||||
|
self.damage = damage or self.DEFAULT_DAMAGE
|
||||||
|
self.cooldown = cooldown or self.DEFAULT_COOLDOWN
|
||||||
|
self.damage_type = damage_type or self.DEFAULT_DAMAGE_TYPE
|
||||||
|
self._heat = 0
|
||||||
|
self.ammo = ammo
|
||||||
|
|
||||||
|
|
||||||
|
def fire(self, other_ship, me=None):
|
||||||
|
if not other_ship:
|
||||||
|
return
|
||||||
|
if self._heat == 0:
|
||||||
|
other_ship.on_hit(self.damage, self.damage_type, me or self.ship)
|
||||||
|
self._heat = self.cooldown
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
if self._heat > 0:
|
||||||
|
self._heat -= 1
|
||||||
|
|
||||||
|
##########################################################################
|
||||||
|
class Spaceship(object):
|
||||||
|
|
||||||
|
def __init__(self, name, modules=None):
|
||||||
|
self.name = name
|
||||||
|
self.modules = modules or []
|
||||||
|
self.alive = True
|
||||||
|
# we define an additional automatically called function
|
||||||
|
self.equip_default()
|
||||||
|
|
||||||
|
def equip_default(self):
|
||||||
|
# you can use this to equip stuff by default in a subclass, without the need to override __init__.
|
||||||
|
pass
|
||||||
|
|
||||||
|
# we define some methods, that get called by the game itself:
|
||||||
|
def on_spawn(self):
|
||||||
|
print(f"{self.name} appears in space.")
|
||||||
|
|
||||||
|
def on_hit(self, damage, damage_type, source):
|
||||||
|
for mod in self.modules:
|
||||||
|
if isinstance(mod, DefensiveLayer):
|
||||||
|
damage = mod.reduce_damage(damage, damage_type)
|
||||||
|
if damage == 0:
|
||||||
|
return
|
||||||
|
if damage > 0:
|
||||||
|
# i am dead.
|
||||||
|
self.alive = False
|
||||||
|
|
||||||
|
def health_status(self):
|
||||||
|
for mod in self.modules:
|
||||||
|
if isinstance(mod, DefensiveLayer):
|
||||||
|
if mod.current < mod.maximal:
|
||||||
|
print (f'{mod.name} has sustained {mod.maximal-mod.current} damage')
|
||||||
|
|
||||||
|
def fire(self, target):
|
||||||
|
for mod in self.modules:
|
||||||
|
if isinstance(mod, Weapon):
|
||||||
|
mod.fire(target, self)
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
for mod in self.modules:
|
||||||
|
if isinstance(mod, ShipModule):
|
||||||
|
mod.update()
|
||||||
|
|
||||||
|
class FreeForAll(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.ships = []
|
||||||
|
self.running = False
|
||||||
|
|
||||||
|
def add_ship(self, ship):
|
||||||
|
self.ships.append(ship)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
for ship in self.ships:
|
||||||
|
ship.on_spawn()
|
||||||
|
all_dead = False
|
||||||
|
while not all_dead:
|
||||||
|
all_dead = True
|
||||||
|
for ship in self.ships:
|
||||||
|
if ship.alive:
|
||||||
|
all_dead = False
|
||||||
|
targets = list(set(self.ships))
|
||||||
|
targets.remove(ship)
|
||||||
|
if len(targets) > 0:
|
||||||
|
ship.fire(random.choice(targets))
|
||||||
|
else:
|
||||||
|
print (f'{ship.name} has won!')
|
||||||
|
return
|
||||||
|
if ship.alive:
|
||||||
|
ship.update()
|
||||||
|
self.describe()
|
||||||
|
|
||||||
|
def describe(self):
|
||||||
|
if len(self.ships) == 0:
|
||||||
|
print("There are no ships left.")
|
||||||
|
self.running = False
|
||||||
|
return
|
||||||
|
for ship in self.ships:
|
||||||
|
if not ship.alive:
|
||||||
|
print(f'The ship {ship.name} is destroyed.')
|
||||||
|
self.ships.remove(ship)
|
||||||
|
continue
|
||||||
|
print(f'Current ship {ship.name} status report:')
|
||||||
|
ship.health_status()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
game = FreeForAll()
|
||||||
|
game.add_ship(Spaceship('Rocinante', modules=[DefensiveLayer(350), Weapon(100), Weapon(100)]))
|
||||||
|
game.add_ship(Spaceship('Protoss Carrier', modules=[Shields(1000), DefensiveLayer(100), Weapon(15, 2), Weapon(15, 2)]))
|
||||||
|
|
||||||
|
# and add 100 raptors.
|
||||||
|
for x in range(1, 100):
|
||||||
|
game.add_ship(Spaceship(f'Raptor {x}', modules=[Shields(100), DefensiveLayer(50), Weapon(10,5), Weapon(10,5)]))
|
||||||
|
|
||||||
|
game.run()
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
|
Loading…
Reference in New Issue
Block a user