mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-01-27 09:23:12 +08:00
Modernized meteor shower code
This commit is contained in:
parent
51468a15f6
commit
7aed70dfb5
@ -4132,16 +4132,16 @@
|
||||
"assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c",
|
||||
"assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb",
|
||||
"assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe",
|
||||
"build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/32/b0/12e2602010f316e3c26da125bf25",
|
||||
"build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/50/12/5a87ef4e3b502f1e62f5f2c65985",
|
||||
"build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/04/0d/5e5e5783775b70d06de5113904d7",
|
||||
"build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ab/46/fd8487f22aaaf68d310e66c8b5de",
|
||||
"build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c8/39/04b55a4b918602fbf06dccc4f3c3",
|
||||
"build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/87/ab/5b265ac08141fae86f6102fb362c",
|
||||
"build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/13/a7/c2f6454984d5639c39abd5bd871f",
|
||||
"build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/cd/3a/f67ce2222af11d3ee614ba55e1f0",
|
||||
"build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/4c/01/f33e921238d1bded473de5964ce4",
|
||||
"build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/ec/1b/16fa91c7ccba5b20ea9a4ca3e0a4",
|
||||
"build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/5c/6a/8e947d1317c67dc84856c5649fee",
|
||||
"build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/7d/aa/901e45f5991e3907f0d9033ccdcf"
|
||||
"build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/22/a3/c6b38e5c76464077f400415eef8f",
|
||||
"build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/35/42/3802bdafafffea388132ccb27197",
|
||||
"build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/90/fb/bbb656b6d0b56ff92d30f13fcb10",
|
||||
"build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/3b/75/2eee67afef4e0f446cba5a466521",
|
||||
"build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b6/31/fe8c9e100c0f99daaf1d11d702c0",
|
||||
"build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/85/27/7ddbe58f02af52884fff485c98dd",
|
||||
"build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d4/11/0f9806ff32156d9af2fb5c88e49c",
|
||||
"build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/9a/55/2cd36310f00e3a187a70b3f122ee",
|
||||
"build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/30/8e/b4d365f9aa49cf247d6a73dfd5ee",
|
||||
"build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/b0/1a/20b48edf6830ad53a1c0049c129b",
|
||||
"build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/00/52/42d85a6502daf27271ce48634b5b",
|
||||
"build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/b2/1c/1afeac6051ad9973e06f945f98ce"
|
||||
}
|
||||
1
.idea/dictionaries/ericf.xml
generated
1
.idea/dictionaries/ericf.xml
generated
@ -1319,6 +1319,7 @@
|
||||
<w>pipname</w>
|
||||
<w>pkey</w>
|
||||
<w>pkgutil</w>
|
||||
<w>playerdata</w>
|
||||
<w>playerlostspaz</w>
|
||||
<w>playernode</w>
|
||||
<w>playerpt</w>
|
||||
|
||||
@ -38,6 +38,7 @@
|
||||
"ba_data/python/ba/__pycache__/_music.cpython-37.opt-1.pyc",
|
||||
"ba_data/python/ba/__pycache__/_netutils.cpython-37.opt-1.pyc",
|
||||
"ba_data/python/ba/__pycache__/_nodeactor.cpython-37.opt-1.pyc",
|
||||
"ba_data/python/ba/__pycache__/_player.cpython-37.opt-1.pyc",
|
||||
"ba_data/python/ba/__pycache__/_playlist.cpython-37.opt-1.pyc",
|
||||
"ba_data/python/ba/__pycache__/_powerup.cpython-37.opt-1.pyc",
|
||||
"ba_data/python/ba/__pycache__/_profile.cpython-37.opt-1.pyc",
|
||||
@ -90,6 +91,7 @@
|
||||
"ba_data/python/ba/_music.py",
|
||||
"ba_data/python/ba/_netutils.py",
|
||||
"ba_data/python/ba/_nodeactor.py",
|
||||
"ba_data/python/ba/_player.py",
|
||||
"ba_data/python/ba/_playlist.py",
|
||||
"ba_data/python/ba/_powerup.py",
|
||||
"ba_data/python/ba/_profile.py",
|
||||
|
||||
@ -167,6 +167,7 @@ SCRIPT_TARGETS_PY_PUBLIC = \
|
||||
build/ba_data/python/ba/_tips.py \
|
||||
build/ba_data/python/ba/_store.py \
|
||||
build/ba_data/python/ba/_activitytypes.py \
|
||||
build/ba_data/python/ba/_player.py \
|
||||
build/ba_data/python/ba/__init__.py \
|
||||
build/ba_data/python/ba/_assetmanager.py \
|
||||
build/ba_data/python/ba/_session.py \
|
||||
@ -392,6 +393,7 @@ SCRIPT_TARGETS_PYC_PUBLIC = \
|
||||
build/ba_data/python/ba/__pycache__/_tips.cpython-37.opt-1.pyc \
|
||||
build/ba_data/python/ba/__pycache__/_store.cpython-37.opt-1.pyc \
|
||||
build/ba_data/python/ba/__pycache__/_activitytypes.cpython-37.opt-1.pyc \
|
||||
build/ba_data/python/ba/__pycache__/_player.cpython-37.opt-1.pyc \
|
||||
build/ba_data/python/ba/__pycache__/__init__.cpython-37.opt-1.pyc \
|
||||
build/ba_data/python/ba/__pycache__/_assetmanager.cpython-37.opt-1.pyc \
|
||||
build/ba_data/python/ba/__pycache__/_session.cpython-37.opt-1.pyc \
|
||||
@ -729,6 +731,11 @@ build/ba_data/python/ba/__pycache__/_activitytypes.cpython-37.opt-1.pyc: \
|
||||
@echo Compiling script: $^
|
||||
@rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@
|
||||
|
||||
build/ba_data/python/ba/__pycache__/_player.cpython-37.opt-1.pyc: \
|
||||
build/ba_data/python/ba/_player.py
|
||||
@echo Compiling script: $^
|
||||
@rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@
|
||||
|
||||
build/ba_data/python/ba/__pycache__/__init__.cpython-37.opt-1.pyc: \
|
||||
build/ba_data/python/ba/__init__.py
|
||||
@echo Compiling script: $^
|
||||
|
||||
@ -40,6 +40,7 @@ from _ba import (CollideModel, Context, ContextCall, Data, InputDevice,
|
||||
charstr, textwidget, time, timer, open_url, widget)
|
||||
from ba._activity import Activity
|
||||
from ba._actor import Actor
|
||||
from ba._player import BasePlayerData
|
||||
from ba._nodeactor import NodeActor
|
||||
from ba._app import App
|
||||
from ba._coopgame import CoopGameActivity
|
||||
|
||||
54
assets/src/ba_data/python/ba/_player.py
Normal file
54
assets/src/ba_data/python/ba/_player.py
Normal file
@ -0,0 +1,54 @@
|
||||
# Copyright (c) 2011-2020 Eric Froemling
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
# -----------------------------------------------------------------------------
|
||||
"""Player related functionality."""
|
||||
from __future__ import annotations
|
||||
from typing import TYPE_CHECKING, TypeVar
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Type
|
||||
import ba
|
||||
|
||||
T = TypeVar('T')
|
||||
|
||||
|
||||
class BasePlayerData:
|
||||
"""Base class for custom player data.
|
||||
|
||||
Category: Gameplay Classes
|
||||
|
||||
A convenience class that can be used as a base class for custom
|
||||
per-game player data. It simply provides the ability to easily fetch
|
||||
an instance of itself for a given ba.Player.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def get(cls: Type[T], player: ba.Player) -> T:
|
||||
"""Return the custom player data associated with a player.
|
||||
|
||||
If one does not exist, it will be created.
|
||||
"""
|
||||
|
||||
# Store/return an instance of ourself in the player's per-game dict.
|
||||
data = player.gamedata.get('playerdata')
|
||||
if data is None:
|
||||
player.gamedata['playerdata'] = data = cls()
|
||||
assert isinstance(data, cls)
|
||||
return data
|
||||
@ -30,23 +30,18 @@ from dataclasses import dataclass
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import ba
|
||||
from bastd.actor import bomb
|
||||
from bastd.actor import playerspaz
|
||||
from bastd.actor.bomb import Bomb
|
||||
from bastd.actor.playerspaz import PlayerSpazDeathMessage
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Tuple, Sequence, Optional, List, Dict, Type
|
||||
from typing import Any, Tuple, Sequence, Optional, List, Dict, Type, Type
|
||||
from bastd.actor.onscreentimer import OnScreenTimer
|
||||
|
||||
|
||||
@dataclass
|
||||
class GameSettings:
|
||||
"""Configurable settings for our game."""
|
||||
epic_mode: bool
|
||||
|
||||
|
||||
@dataclass
|
||||
class PlayerData:
|
||||
class PlayerData(ba.BasePlayerData):
|
||||
"""Data we store per player."""
|
||||
death_time: Optional[float] = None
|
||||
|
||||
|
||||
# ba_meta export game
|
||||
@ -90,23 +85,19 @@ class MeteorShowerGame(ba.TeamGameActivity):
|
||||
def __init__(self, settings: Dict[str, Any]):
|
||||
super().__init__(settings)
|
||||
|
||||
if self.settings_raw['Epic Mode']:
|
||||
self.slow_motion = True
|
||||
|
||||
# Print messages when players die (since its meaningful in this game).
|
||||
self.announce_player_deaths = True
|
||||
|
||||
self._epic_mode = settings.get('Epic Mode', False)
|
||||
self._last_player_death_time: Optional[float] = None
|
||||
self._meteor_time = 2.0
|
||||
self._timer: Optional[OnScreenTimer] = None
|
||||
|
||||
# Called when our game is transitioning in but not ready to start;
|
||||
# ..we can go ahead and set our music and whatnot.
|
||||
def on_transition_in(self) -> None:
|
||||
# Some base class overrides:
|
||||
self.default_music = (ba.MusicType.EPIC
|
||||
if self.settings_raw['Epic Mode'] else
|
||||
ba.MusicType.SURVIVAL)
|
||||
super().on_transition_in()
|
||||
if self._epic_mode else ba.MusicType.SURVIVAL)
|
||||
if self._epic_mode:
|
||||
self.slow_motion = True
|
||||
|
||||
# Print messages when players die (since its meaningful in this game).
|
||||
self.announce_player_deaths = True
|
||||
|
||||
# Called when our game actually starts.
|
||||
def on_begin(self) -> None:
|
||||
@ -118,13 +109,13 @@ class MeteorShowerGame(ba.TeamGameActivity):
|
||||
# between waves ..lets have things increase faster if we have fewer
|
||||
# players.
|
||||
delay = 5.0 if len(self.players) > 2 else 2.5
|
||||
if self.settings_raw['Epic Mode']:
|
||||
if self._epic_mode:
|
||||
delay *= 0.25
|
||||
ba.timer(delay, self._decrement_meteor_time, repeat=True)
|
||||
|
||||
# Kick off the first wave in a few seconds.
|
||||
delay = 3.0
|
||||
if self.settings_raw['Epic Mode']:
|
||||
if self._epic_mode:
|
||||
delay *= 0.25
|
||||
ba.timer(delay, self._set_meteor_timer)
|
||||
|
||||
@ -145,7 +136,7 @@ class MeteorShowerGame(ba.TeamGameActivity):
|
||||
# For score purposes, mark them as having died right as the
|
||||
# game started.
|
||||
assert self._timer is not None
|
||||
player.gamedata['death_time'] = self._timer.getstarttime()
|
||||
PlayerData.get(player).death_time = self._timer.getstarttime()
|
||||
return
|
||||
self.spawn_player(player)
|
||||
|
||||
@ -172,15 +163,15 @@ class MeteorShowerGame(ba.TeamGameActivity):
|
||||
|
||||
# Various high-level game events come through this method.
|
||||
def handlemessage(self, msg: Any) -> Any:
|
||||
if isinstance(msg, playerspaz.PlayerSpazDeathMessage):
|
||||
if isinstance(msg, PlayerSpazDeathMessage):
|
||||
|
||||
# Augment standard behavior.
|
||||
super().handlemessage(msg)
|
||||
|
||||
death_time = ba.time(timeformat=ba.TimeFormat.MILLISECONDS)
|
||||
curtime = ba.time()
|
||||
|
||||
# Record the player's moment of death.
|
||||
msg.spaz.player.gamedata['death_time'] = death_time
|
||||
PlayerData.get(msg.spaz.player).death_time = curtime
|
||||
|
||||
# In co-op mode, end the game the instant everyone dies
|
||||
# (more accurate looking).
|
||||
@ -192,7 +183,7 @@ class MeteorShowerGame(ba.TeamGameActivity):
|
||||
ba.pushcall(self._check_end_game)
|
||||
|
||||
# Also record this for a final setting of the clock.
|
||||
self._last_player_death_time = death_time
|
||||
self._last_player_death_time = curtime
|
||||
else:
|
||||
ba.timer(1.0, self._check_end_game)
|
||||
|
||||
@ -247,36 +238,36 @@ class MeteorShowerGame(ba.TeamGameActivity):
|
||||
|
||||
def _drop_bomb(self, position: Sequence[float],
|
||||
velocity: Sequence[float]) -> None:
|
||||
bomb.Bomb(position=position, velocity=velocity).autoretain()
|
||||
Bomb(position=position, velocity=velocity).autoretain()
|
||||
|
||||
def _decrement_meteor_time(self) -> None:
|
||||
self._meteor_time = max(0.01, self._meteor_time * 0.9)
|
||||
|
||||
def end_game(self) -> None:
|
||||
cur_time = ba.time(timeformat=ba.TimeFormat.MILLISECONDS)
|
||||
cur_time = ba.time()
|
||||
assert self._timer is not None
|
||||
start_time = self._timer.getstarttime(
|
||||
timeformat=ba.TimeFormat.MILLISECONDS)
|
||||
start_time = self._timer.getstarttime()
|
||||
|
||||
# Mark 'death-time' as now for any still-living players
|
||||
# Mark death-time as now for any still-living players
|
||||
# and award players points for how long they lasted.
|
||||
# (these per-player scores are only meaningful in team-games)
|
||||
for team in self.teams:
|
||||
for player in team.players:
|
||||
playerdata = PlayerData.get(player)
|
||||
survived = False
|
||||
|
||||
# Throw an extra fudge factor in so teams that
|
||||
# didn't die come out ahead of teams that did.
|
||||
if 'death_time' not in player.gamedata:
|
||||
player.gamedata['death_time'] = cur_time + 1
|
||||
if playerdata.death_time is None:
|
||||
survived = True
|
||||
playerdata.death_time = cur_time + 1
|
||||
|
||||
# Award a per-player score depending on how many seconds
|
||||
# they lasted (per-player scores only affect teams mode;
|
||||
# everywhere else just looks at the per-team score).
|
||||
score = int(player.gamedata['death_time'] -
|
||||
self._timer.getstarttime(
|
||||
timeformat=ba.TimeFormat.MILLISECONDS))
|
||||
if 'death_time' not in player.gamedata:
|
||||
score += 50 # a bit extra for survivors
|
||||
score = int(playerdata.death_time - self._timer.getstarttime())
|
||||
if survived:
|
||||
score += 50 # A bit extra for survivors.
|
||||
self.stats.player_scored(player, score, screenmessage=False)
|
||||
|
||||
# Stop updating our time text, and set the final time to match
|
||||
@ -294,10 +285,14 @@ class MeteorShowerGame(ba.TeamGameActivity):
|
||||
|
||||
# Set the team score to the max time survived by any player on
|
||||
# that team.
|
||||
longest_life = 0
|
||||
longest_life = 0.0
|
||||
for player in team.players:
|
||||
playerdata = PlayerData.get(player)
|
||||
assert playerdata.death_time is not None
|
||||
longest_life = max(longest_life,
|
||||
player.gamedata['death_time'] - start_time)
|
||||
results.set_team_score(team, longest_life)
|
||||
playerdata.death_time - start_time)
|
||||
|
||||
# Submit the score value in milliseconds.
|
||||
results.set_team_score(team, int(1000.0 * longest_life))
|
||||
|
||||
self.end(results=results)
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
<li><a href="#class_ba_Map">ba.Map</a></li>
|
||||
<li><a href="#class_ba_NodeActor">ba.NodeActor</a></li>
|
||||
</ul>
|
||||
<li><a href="#class_ba_BasePlayerData">ba.BasePlayerData</a></li>
|
||||
<li><a href="#class_ba_Chooser">ba.Chooser</a></li>
|
||||
<li><a href="#class_ba_InputDevice">ba.InputDevice</a></li>
|
||||
<li><a href="#class_ba_Level">ba.Level</a></li>
|
||||
@ -1083,6 +1084,31 @@ when done.</p>
|
||||
|
||||
<p>Behavior is similar to <a href="#function_ba_gettexture">ba.gettexture</a>()</p>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<hr>
|
||||
<h2><strong><a name="class_ba_BasePlayerData">ba.BasePlayerData</a></strong></h3>
|
||||
<p><em><top level class></em>
|
||||
</p>
|
||||
<p>Base class for custom player data.</p>
|
||||
|
||||
<p>Category: <a href="#class_category_Gameplay_Classes">Gameplay Classes</a></p>
|
||||
|
||||
<p> A convenience class that can be used as a base class for custom
|
||||
per-game player data. It simply provides the ability to easily fetch
|
||||
an instance of itself for a given <a href="#class_ba_Player">ba.Player</a>.
|
||||
</p>
|
||||
|
||||
<h3>Methods:</h3>
|
||||
<dl>
|
||||
<dt><h4><a name="method_ba_BasePlayerData__get">get()</a></dt></h4><dd>
|
||||
<h5><span><em><class method></span></em></h5>
|
||||
<p><span>get(player: <a href="#class_ba_Player">ba.Player</a>) -> T </span></p>
|
||||
|
||||
<p>Return the custom player data associated with a player.</p>
|
||||
|
||||
<p>If one does not exist, it will be created.</p>
|
||||
|
||||
</dd>
|
||||
</dl>
|
||||
<hr>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user