bombsquad-plugin-manager/plugins/minigames/extinction.py

254 lines
8.1 KiB
Python
Raw Normal View History

2024-02-01 11:57:50 +03:00
# Ported to api 8 by brostos using baport.(https://github.com/bombsquad-community/baport)
"""For 1.7.33"""
# ba_meta require api 8
from __future__ import annotations
from typing import TYPE_CHECKING
import babase
import bauiv1 as bui
import bascenev1 as bs
import random
from bascenev1lib.actor.bomb import BombFactory, Blast, ImpactMessage
from bascenev1lib.actor.onscreentimer import OnScreenTimer
from bascenev1lib.gameutils import SharedObjects
if TYPE_CHECKING:
from typing import Any, Sequence, Optional, Type
def ba_get_api_version():
return 8
def ba_get_levels():
return [babase._level.Level(
'Extinction',
gametype=NewMeteorShowerGame,
settings={'Epic Mode': False},
preview_texture_name='footballStadiumPreview'),
babase._level.Level(
'Epic Extinction',
gametype=NewMeteorShowerGame,
settings={'Epic Mode': True},
preview_texture_name='footballStadiumPreview')]
class Meteor(bs.Actor):
"""A giant meteor instead of bombs."""
def __init__(self,
pos: Sequence[float] = (0.0, 1.0, 0.0),
velocity: Sequence[float] = (0.0, 0.0, 0.0)):
super().__init__()
shared = SharedObjects.get()
factory = BombFactory.get()
materials = (shared.object_material,
factory.impact_blast_material)
self.pos = (pos[0], pos[1], pos[2])
self.velocity = (velocity[0], velocity[1], velocity[2])
self.node = bs.newnode(
'prop',
delegate=self,
attrs={
'position': self.pos,
'velocity': self.velocity,
'mesh': factory.sticky_bomb_mesh,
'color_texture': factory.tnt_tex,
'mesh_scale': 3.0,
'body_scale': 2.99,
'body': 'sphere',
'shadow_size': 0.5,
'reflection': 'soft',
'reflection_scale': [0.45],
'materials': materials
})
def explode(self) -> None:
Blast(position=self.node.position,
velocity=self.node.velocity,
blast_type='tnt',
blast_radius=2.0)
def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, bs.DieMessage):
if self.node:
self.node.delete()
elif isinstance(msg, ImpactMessage):
self.explode()
self.handlemessage(bs.DieMessage())
else:
super().handlemessage(msg)
class Player(bs.Player['Team']):
"""Our player type for this game."""
def __init__(self):
super().__init__()
self.death_time: Optional[float] = None
class Team(bs.Team[Player]):
"""Our team type for this game."""
# ba_meta export bascenev1.GameActivity
class NewMeteorShowerGame(bs.TeamGameActivity[Player, Team]):
"""Minigame by Jetz."""
name = 'Extinction'
description = 'Survive the Extinction.'
available_settings = [
bs.BoolSetting('Epic Mode', default=False)]
announce_player_deaths = True
@classmethod
def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]:
return ['Football Stadium']
@classmethod
def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool:
return (issubclass(sessiontype, bs.FreeForAllSession)
or issubclass(sessiontype, bs.DualTeamSession))
def __init__(self, settings: dict):
super().__init__(settings)
self._epic_mode = bool(settings['Epic Mode'])
self._last_player_death_time: Optiobal[float] = None
self._meteor_time = 2.0
self._timer: Optional[OnScreenTimer] = None
self.default_music = (bs.MusicType.EPIC
if self._epic_mode else bs.MusicType.SURVIVAL)
if self._epic_mode:
self.slow_motion = True
def on_begin(self) -> None:
super().on_begin()
delay = 5.0 if len(self.players) > 2 else 2.5
if self._epic_mode:
delay *= 0.25
bs.timer(delay, self._decrement_meteor_time, repeat=True)
delay = 3.0
if self._epic_mode:
delay *= 0.25
bs.timer(delay, self._set_meteor_timer)
self._timer = OnScreenTimer()
self._timer.start()
self._check_end_game()
def on_player_join(self, player: Player) -> None:
if self.has_begun():
bs.broadcastmessage(
babase.Lstr(resource='playerDelayedJoinText',
subs=[('${PLAYER}', player.getname(full=True))]),
color=(0, 1, 0),
)
assert self._timer is not None
player.death_time = self._timer.getstarttime()
return
self.spawn_player(player)
def spawn_player(self, player: Player) -> None:
spaz = self.spawn_player_spaz(player)
spaz.connect_controls_to_player(enable_punch=False,
enable_pickup=False,
enable_bomb=False,
enable_jump=False)
spaz.play_big_death_sound = True
return spaz
def on_player_leave(self, player: Player) -> None:
super().on_player_leave(player)
self._check_end_game()
def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, bs.PlayerDiedMessage):
curtime = bs.time()
msg.getplayer(Player).death_time = curtime
bs.timer(1.0, self._check_end_game)
else:
return super().handlemessage(msg)
def _spawn_meteors(self) -> None:
pos = (random.randint(-6, 7), 12,
random.uniform(-2, 1))
velocity = (random.randint(-11, 11), 0,
random.uniform(-5, 5))
Meteor(pos=pos, velocity=velocity).autoretain()
def _spawn_meteors_cluster(self) -> None:
delay = 0.0
for _i in range(random.randrange(1, 3)):
bs.timer(delay, self._spawn_meteors)
delay += 1
self._set_meteor_timer()
def _decrement_meteor_time(self) -> None:
self._meteor_time = max(0.01, self._meteor_time * 0.9)
def _set_meteor_timer(self) -> None:
bs.timer((1.0 + 0.2 * random.random()) * self._meteor_time,
self._spawn_meteors_cluster)
def _check_end_game(self) -> None:
living_team_count = 0
for team in self.teams:
for player in team.players:
if player.is_alive():
living_team_count += 1
break
if isinstance(self.session, bs.CoopSession):
if living_team_count <= 0:
self.end_game()
else:
if living_team_count <= 1:
self.end_game()
def end_game(self) -> None:
cur_time = bs.time()
assert self._timer is not None
start_time = self._timer.getstarttime()
for team in self.teams:
for player in team.players:
survived = False
if player.death_time is None:
survived = True
player.death_time = cur_time + 1
score = int(player.death_time - self._timer.getstarttime())
if survived:
score += 50
self.stats.player_scored(player, score, screenmessage=False)
self._timer.stop(endtime=self._last_player_death_time)
results = bs.GameResults()
for team in self.teams:
longest_life = 0.0
for player in team.players:
assert player.death_time is not None
longest_life = max(longest_life,
player.death_time - start_time)
results.set_team_score(team, int(1000.0 * longest_life))
self.end(results=results)