mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-02-04 22:43:17 +08:00
More modernizing and cleanup
This commit is contained in:
parent
72be5c0b8d
commit
808ea7dcdd
@ -420,7 +420,7 @@
|
|||||||
"assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/75/1d/868bb04cf691736035c917d02762",
|
"assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/75/1d/868bb04cf691736035c917d02762",
|
||||||
"assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/44/2a/8535b446284235cb503947ece074",
|
"assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/44/2a/8535b446284235cb503947ece074",
|
||||||
"assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/f5/d3/8e941851c4310465646c4167afc1",
|
"assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/f5/d3/8e941851c4310465646c4167afc1",
|
||||||
"assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/e2/2c/e609bb55002f672528428db9306c",
|
"assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/da/06/8e06488b46a0a213abde3cfeb364",
|
||||||
"assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/b8/ed/e18bec56ff1d094aae86517a7854",
|
"assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/b8/ed/e18bec56ff1d094aae86517a7854",
|
||||||
"assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/49/5f/b29bb65369040892fe6601801637",
|
"assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/49/5f/b29bb65369040892fe6601801637",
|
||||||
"assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/0c/cd/798753aa6c55f3a4cdccda0b23ab",
|
"assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/0c/cd/798753aa6c55f3a4cdccda0b23ab",
|
||||||
@ -442,7 +442,7 @@
|
|||||||
"assets/build/ba_data/data/languages/korean.json": "https://files.ballistica.net/cache/ba1/0a/84/bbb6ed2abf66509406f534cbbb52",
|
"assets/build/ba_data/data/languages/korean.json": "https://files.ballistica.net/cache/ba1/0a/84/bbb6ed2abf66509406f534cbbb52",
|
||||||
"assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/c2/fc/dd1c15cf9ecb411d9defbd000c06",
|
"assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/c2/fc/dd1c15cf9ecb411d9defbd000c06",
|
||||||
"assets/build/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/db/eb/324f86a4b714240ae50ffeeed2f8",
|
"assets/build/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/db/eb/324f86a4b714240ae50ffeeed2f8",
|
||||||
"assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/6c/35/cc4d440d0c7a613860c3898e81d7",
|
"assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/a9/bc/ea61ebd23066c685fb779e23d10f",
|
||||||
"assets/build/ba_data/data/languages/romanian.json": "https://files.ballistica.net/cache/ba1/f6/d0/335b952306d211d56172b5c72d8c",
|
"assets/build/ba_data/data/languages/romanian.json": "https://files.ballistica.net/cache/ba1/f6/d0/335b952306d211d56172b5c72d8c",
|
||||||
"assets/build/ba_data/data/languages/russian.json": "https://files.ballistica.net/cache/ba1/78/5e/d24967ddaa15e0a574bd274544db",
|
"assets/build/ba_data/data/languages/russian.json": "https://files.ballistica.net/cache/ba1/78/5e/d24967ddaa15e0a574bd274544db",
|
||||||
"assets/build/ba_data/data/languages/serbian.json": "https://files.ballistica.net/cache/ba1/e7/d8/ace32888249fc8b8cca0e2edb48b",
|
"assets/build/ba_data/data/languages/serbian.json": "https://files.ballistica.net/cache/ba1/e7/d8/ace32888249fc8b8cca0e2edb48b",
|
||||||
@ -4132,16 +4132,16 @@
|
|||||||
"assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c",
|
"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/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",
|
"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/5a/42/5238d5de1cf94a07a513ea2b3e1b",
|
"build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e4/f0/c3261a8a7391a2b654da82c35c21",
|
||||||
"build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/39/48/2f0e4350a080373301de625e2cc4",
|
"build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/33/e2/85a8cbf23404612e6761cf02348b",
|
||||||
"build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/c0/1d/dbc0a5e2ca05b626cbeffd6def6c",
|
"build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/5b/0d/d906be5fc2a75b5214a94cafe6ca",
|
||||||
"build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ec/a8/5c58d6b5e1d844640334c35ad3af",
|
"build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/6b/53/72d665caf5dfed84312ae6862642",
|
||||||
"build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3d/0a/76b615f9bcb9bf4f0ca745060d40",
|
"build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d9/68/2d98f2d1ee67b6d54adbdf76c863",
|
||||||
"build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/01/6b/0f623ac481e3553e352c1cd3cb7e",
|
"build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e5/3a/33f8f311260542126acea44d05e2",
|
||||||
"build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/c4/a5/3cad1ced77551369dc56c6bca5fb",
|
"build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/18/eb/dd39bcfa33983864089d3fb7f666",
|
||||||
"build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/3b/3f/55094817619cae66f941a9f6db8c",
|
"build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/f8/1d/3440010fcbcf18c5a6b2966f7fca",
|
||||||
"build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/ec/6b/7aa29831a746672f9984cbb1dbf1",
|
"build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/9b/fa/b4ad4b8b82fefe1faad610065b9f",
|
||||||
"build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/07/4c/00a6136d0bd5573946d10e294720",
|
"build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/7f/b9/03af92db6140135ddfa467a1545d",
|
||||||
"build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/8d/8d/af068e67244cbb28444b27ae66d7",
|
"build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/69/b9/687fc5fa38c3faf7a47eb4241a3c",
|
||||||
"build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/f4/62/eb7cb26c952df481b757dcf53f9c"
|
"build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/cf/2b/589db924b489972981e10850a4e3"
|
||||||
}
|
}
|
||||||
5
.idea/dictionaries/ericf.xml
generated
5
.idea/dictionaries/ericf.xml
generated
@ -416,6 +416,7 @@
|
|||||||
<w>deathmatch</w>
|
<w>deathmatch</w>
|
||||||
<w>deek</w>
|
<w>deek</w>
|
||||||
<w>defs</w>
|
<w>defs</w>
|
||||||
|
<w>defsline</w>
|
||||||
<w>deivit</w>
|
<w>deivit</w>
|
||||||
<w>depcls</w>
|
<w>depcls</w>
|
||||||
<w>depdata</w>
|
<w>depdata</w>
|
||||||
@ -749,6 +750,7 @@
|
|||||||
<w>getclass</w>
|
<w>getclass</w>
|
||||||
<w>getcollide</w>
|
<w>getcollide</w>
|
||||||
<w>getcollidemodel</w>
|
<w>getcollidemodel</w>
|
||||||
|
<w>getcollision</w>
|
||||||
<w>getconf</w>
|
<w>getconf</w>
|
||||||
<w>getconfig</w>
|
<w>getconfig</w>
|
||||||
<w>getcurrency</w>
|
<w>getcurrency</w>
|
||||||
@ -1285,6 +1287,7 @@
|
|||||||
<w>outname</w>
|
<w>outname</w>
|
||||||
<w>outpath</w>
|
<w>outpath</w>
|
||||||
<w>ouya</w>
|
<w>ouya</w>
|
||||||
|
<w>overloadsigs</w>
|
||||||
<w>packagedir</w>
|
<w>packagedir</w>
|
||||||
<w>packagedirs</w>
|
<w>packagedirs</w>
|
||||||
<w>packagename</w>
|
<w>packagename</w>
|
||||||
@ -1888,6 +1891,7 @@
|
|||||||
<w>toplevel</w>
|
<w>toplevel</w>
|
||||||
<w>totaldudes</w>
|
<w>totaldudes</w>
|
||||||
<w>totalpts</w>
|
<w>totalpts</w>
|
||||||
|
<w>totalwaves</w>
|
||||||
<w>totype</w>
|
<w>totype</w>
|
||||||
<w>touchpad</w>
|
<w>touchpad</w>
|
||||||
<w>tournamententry</w>
|
<w>tournamententry</w>
|
||||||
@ -2022,6 +2026,7 @@
|
|||||||
<w>waaah</w>
|
<w>waaah</w>
|
||||||
<w>wanttype</w>
|
<w>wanttype</w>
|
||||||
<w>wasdead</w>
|
<w>wasdead</w>
|
||||||
|
<w>wavenum</w>
|
||||||
<w>weakref</w>
|
<w>weakref</w>
|
||||||
<w>weakrefs</w>
|
<w>weakrefs</w>
|
||||||
<w>weakrefset</w>
|
<w>weakrefset</w>
|
||||||
|
|||||||
@ -13,6 +13,7 @@
|
|||||||
"ba_data/python/ba/__pycache__/_assetmanager.cpython-37.opt-1.pyc",
|
"ba_data/python/ba/__pycache__/_assetmanager.cpython-37.opt-1.pyc",
|
||||||
"ba_data/python/ba/__pycache__/_benchmark.cpython-37.opt-1.pyc",
|
"ba_data/python/ba/__pycache__/_benchmark.cpython-37.opt-1.pyc",
|
||||||
"ba_data/python/ba/__pycache__/_campaign.cpython-37.opt-1.pyc",
|
"ba_data/python/ba/__pycache__/_campaign.cpython-37.opt-1.pyc",
|
||||||
|
"ba_data/python/ba/__pycache__/_collision.cpython-37.opt-1.pyc",
|
||||||
"ba_data/python/ba/__pycache__/_coopgame.cpython-37.opt-1.pyc",
|
"ba_data/python/ba/__pycache__/_coopgame.cpython-37.opt-1.pyc",
|
||||||
"ba_data/python/ba/__pycache__/_coopsession.cpython-37.opt-1.pyc",
|
"ba_data/python/ba/__pycache__/_coopsession.cpython-37.opt-1.pyc",
|
||||||
"ba_data/python/ba/__pycache__/_dependency.cpython-37.opt-1.pyc",
|
"ba_data/python/ba/__pycache__/_dependency.cpython-37.opt-1.pyc",
|
||||||
@ -67,6 +68,7 @@
|
|||||||
"ba_data/python/ba/_assetmanager.py",
|
"ba_data/python/ba/_assetmanager.py",
|
||||||
"ba_data/python/ba/_benchmark.py",
|
"ba_data/python/ba/_benchmark.py",
|
||||||
"ba_data/python/ba/_campaign.py",
|
"ba_data/python/ba/_campaign.py",
|
||||||
|
"ba_data/python/ba/_collision.py",
|
||||||
"ba_data/python/ba/_coopgame.py",
|
"ba_data/python/ba/_coopgame.py",
|
||||||
"ba_data/python/ba/_coopsession.py",
|
"ba_data/python/ba/_coopsession.py",
|
||||||
"ba_data/python/ba/_dependency.py",
|
"ba_data/python/ba/_dependency.py",
|
||||||
|
|||||||
@ -153,6 +153,7 @@ SCRIPT_TARGETS_PY_PUBLIC = \
|
|||||||
build/ba_data/python/ba/_coopgame.py \
|
build/ba_data/python/ba/_coopgame.py \
|
||||||
build/ba_data/python/ba/_meta.py \
|
build/ba_data/python/ba/_meta.py \
|
||||||
build/ba_data/python/ba/_math.py \
|
build/ba_data/python/ba/_math.py \
|
||||||
|
build/ba_data/python/ba/_collision.py \
|
||||||
build/ba_data/python/ba/_servermode.py \
|
build/ba_data/python/ba/_servermode.py \
|
||||||
build/ba_data/python/ba/_appconfig.py \
|
build/ba_data/python/ba/_appconfig.py \
|
||||||
build/ba_data/python/ba/_gameresults.py \
|
build/ba_data/python/ba/_gameresults.py \
|
||||||
@ -380,6 +381,7 @@ SCRIPT_TARGETS_PYC_PUBLIC = \
|
|||||||
build/ba_data/python/ba/__pycache__/_coopgame.cpython-37.opt-1.pyc \
|
build/ba_data/python/ba/__pycache__/_coopgame.cpython-37.opt-1.pyc \
|
||||||
build/ba_data/python/ba/__pycache__/_meta.cpython-37.opt-1.pyc \
|
build/ba_data/python/ba/__pycache__/_meta.cpython-37.opt-1.pyc \
|
||||||
build/ba_data/python/ba/__pycache__/_math.cpython-37.opt-1.pyc \
|
build/ba_data/python/ba/__pycache__/_math.cpython-37.opt-1.pyc \
|
||||||
|
build/ba_data/python/ba/__pycache__/_collision.cpython-37.opt-1.pyc \
|
||||||
build/ba_data/python/ba/__pycache__/_servermode.cpython-37.opt-1.pyc \
|
build/ba_data/python/ba/__pycache__/_servermode.cpython-37.opt-1.pyc \
|
||||||
build/ba_data/python/ba/__pycache__/_appconfig.cpython-37.opt-1.pyc \
|
build/ba_data/python/ba/__pycache__/_appconfig.cpython-37.opt-1.pyc \
|
||||||
build/ba_data/python/ba/__pycache__/_gameresults.cpython-37.opt-1.pyc \
|
build/ba_data/python/ba/__pycache__/_gameresults.cpython-37.opt-1.pyc \
|
||||||
@ -663,6 +665,11 @@ build/ba_data/python/ba/__pycache__/_math.cpython-37.opt-1.pyc: \
|
|||||||
@echo Compiling script: $^
|
@echo Compiling script: $^
|
||||||
@rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@
|
@rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@
|
||||||
|
|
||||||
|
build/ba_data/python/ba/__pycache__/_collision.cpython-37.opt-1.pyc: \
|
||||||
|
build/ba_data/python/ba/_collision.py
|
||||||
|
@echo Compiling script: $^
|
||||||
|
@rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@
|
||||||
|
|
||||||
build/ba_data/python/ba/__pycache__/_servermode.cpython-37.opt-1.pyc: \
|
build/ba_data/python/ba/__pycache__/_servermode.cpython-37.opt-1.pyc: \
|
||||||
build/ba_data/python/ba/_servermode.py
|
build/ba_data/python/ba/_servermode.py
|
||||||
@echo Compiling script: $^
|
@echo Compiling script: $^
|
||||||
|
|||||||
@ -34,7 +34,7 @@ NOTE: This file was autogenerated by gendummymodule; do not edit by hand.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# (hash we can use to see if this file is out of date)
|
# (hash we can use to see if this file is out of date)
|
||||||
# SOURCES_HASH=146544975806995156523304218095856323339
|
# SOURCES_HASH=164420280597992494471294420110866243586
|
||||||
|
|
||||||
# I'm sorry Pylint. I know this file saddens you. Be strong.
|
# I'm sorry Pylint. I know this file saddens you. Be strong.
|
||||||
# pylint: disable=useless-suppression
|
# pylint: disable=useless-suppression
|
||||||
@ -51,16 +51,19 @@ NOTE: This file was autogenerated by gendummymodule; do not edit by hand.
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import TYPE_CHECKING, overload, Sequence
|
from typing import TYPE_CHECKING, overload, Sequence, TypeVar
|
||||||
|
|
||||||
from ba._enums import TimeFormat, TimeType
|
from ba._enums import TimeFormat, TimeType
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from typing import (Any, Dict, Callable, Tuple, List, Optional, Union,
|
from typing import (Any, Dict, Callable, Tuple, List, Optional, Union,
|
||||||
List, Type)
|
List, Type)
|
||||||
|
from typing_extensions import Literal
|
||||||
from ba._app import App
|
from ba._app import App
|
||||||
import ba
|
import ba
|
||||||
|
|
||||||
|
_T = TypeVar('_T')
|
||||||
|
|
||||||
app: App
|
app: App
|
||||||
|
|
||||||
|
|
||||||
@ -713,13 +716,26 @@ class Node:
|
|||||||
"""
|
"""
|
||||||
return str()
|
return str()
|
||||||
|
|
||||||
def getdelegate(self) -> Any:
|
@overload
|
||||||
"""getdelegate() -> Any
|
def getdelegate(self,
|
||||||
|
type: Type[_T],
|
||||||
|
doraise: Literal[False] = False) -> Optional[_T]:
|
||||||
|
...
|
||||||
|
|
||||||
Returns the node's current delegate, which is the Python object
|
@overload
|
||||||
designated to handle the Node's messages.
|
def getdelegate(self, type: Type[_T], doraise: Literal[True]) -> _T:
|
||||||
|
...
|
||||||
|
|
||||||
|
def getdelegate(self, type: Any, doraise: bool = False) -> Any:
|
||||||
|
"""getdelegate(type: Type, doraise: bool = False) -> <varies>
|
||||||
|
|
||||||
|
Return the node's current delegate object if it matches a certain type.
|
||||||
|
|
||||||
|
If the node has no delegate or it is not an instance of the passed
|
||||||
|
type, then None will be returned. If 'doraise' is True, then an
|
||||||
|
Exception will be raised instead in such cases.
|
||||||
"""
|
"""
|
||||||
return _uninferrable()
|
return None
|
||||||
|
|
||||||
def getnodetype(self) -> str:
|
def getnodetype(self) -> str:
|
||||||
"""getnodetype() -> str
|
"""getnodetype() -> str
|
||||||
|
|||||||
@ -30,13 +30,13 @@ In some specific cases you may need to pull in individual submodules instead.
|
|||||||
from _ba import (CollideModel, Context, ContextCall, Data, InputDevice,
|
from _ba import (CollideModel, Context, ContextCall, Data, InputDevice,
|
||||||
Material, Model, Node, SessionPlayer, Sound, Texture, Timer,
|
Material, Model, Node, SessionPlayer, Sound, Texture, Timer,
|
||||||
Vec3, Widget, buttonwidget, camerashake, checkboxwidget,
|
Vec3, Widget, buttonwidget, camerashake, checkboxwidget,
|
||||||
columnwidget, containerwidget, do_once, emitfx,
|
columnwidget, containerwidget, do_once, emitfx, getactivity,
|
||||||
get_collision_info, getactivity, getcollidemodel, getmodel,
|
getcollidemodel, getmodel, getnodes, getsession, getsound,
|
||||||
getnodes, getsession, getsound, gettexture, hscrollwidget,
|
gettexture, hscrollwidget, imagewidget, log, new_activity,
|
||||||
imagewidget, log, new_activity, newnode, playsound,
|
newnode, playsound, printnodes, printobjects, pushcall, quit,
|
||||||
printnodes, printobjects, pushcall, quit, rowwidget,
|
rowwidget, safecolor, screenmessage, scrollwidget,
|
||||||
safecolor, screenmessage, scrollwidget, set_analytics_screen,
|
set_analytics_screen, charstr, textwidget, time, timer,
|
||||||
charstr, textwidget, time, timer, open_url, widget)
|
open_url, widget)
|
||||||
from ba._activity import Activity
|
from ba._activity import Activity
|
||||||
from ba._actor import Actor
|
from ba._actor import Actor
|
||||||
from ba._player import Player, playercast, playercast_o
|
from ba._player import Player, playercast, playercast_o
|
||||||
@ -87,6 +87,7 @@ from ba._music import setmusic, MusicPlayer, MusicType, MusicPlayMode
|
|||||||
from ba._powerup import PowerupMessage, PowerupAcceptMessage
|
from ba._powerup import PowerupMessage, PowerupAcceptMessage
|
||||||
from ba._multiteamsession import MultiTeamSession
|
from ba._multiteamsession import MultiTeamSession
|
||||||
from ba.ui import Window, UIController, uicleanupcheck
|
from ba.ui import Window, UIController, uicleanupcheck
|
||||||
|
from ba._collision import Collision, getcollision
|
||||||
|
|
||||||
app: App
|
app: App
|
||||||
|
|
||||||
|
|||||||
@ -343,7 +343,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
|
|||||||
raise TypeError('non-actor passed to retain_actor')
|
raise TypeError('non-actor passed to retain_actor')
|
||||||
if (self.has_transitioned_in()
|
if (self.has_transitioned_in()
|
||||||
and _ba.time() - self._last_prune_dead_actors_time > 10.0):
|
and _ba.time() - self._last_prune_dead_actors_time > 10.0):
|
||||||
print_error('it looks like nodes/actors are not'
|
print_error('It looks like nodes/actors are not'
|
||||||
' being pruned in your activity;'
|
' being pruned in your activity;'
|
||||||
' did you call Activity.on_transition_in()'
|
' did you call Activity.on_transition_in()'
|
||||||
' from your subclass?; ' + str(self) + ' (loc. a)')
|
' from your subclass?; ' + str(self) + ' (loc. a)')
|
||||||
@ -775,12 +775,12 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
|
|||||||
|
|
||||||
# Send expire notices to all remaining actors.
|
# Send expire notices to all remaining actors.
|
||||||
for actor_ref in self._actor_weak_refs:
|
for actor_ref in self._actor_weak_refs:
|
||||||
try:
|
actor = actor_ref()
|
||||||
actor = actor_ref()
|
if actor is not None:
|
||||||
if actor is not None:
|
try:
|
||||||
actor.on_expire()
|
actor.on_expire()
|
||||||
except Exception:
|
except Exception:
|
||||||
print_exception(f'Error expiring Actor {actor_ref()}')
|
print_exception(f'Error expiring Actor {actor_ref()}')
|
||||||
|
|
||||||
# Reset all Players.
|
# Reset all Players.
|
||||||
# (releases any attached actors, clears game-data, etc)
|
# (releases any attached actors, clears game-data, etc)
|
||||||
@ -804,7 +804,6 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
|
|||||||
sessionteam.reset_gamedata()
|
sessionteam.reset_gamedata()
|
||||||
except SessionTeamNotFoundError:
|
except SessionTeamNotFoundError:
|
||||||
pass
|
pass
|
||||||
# print_exception(f'Error resetting Team {team}')
|
|
||||||
except Exception:
|
except Exception:
|
||||||
print_exception(f'Error resetting Team {team}')
|
print_exception(f'Error resetting Team {team}')
|
||||||
|
|
||||||
@ -819,6 +818,12 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]):
|
|||||||
'Error during ba.Activity._expire() destroying data:')
|
'Error during ba.Activity._expire() destroying data:')
|
||||||
|
|
||||||
def _prune_dead_actors(self) -> None:
|
def _prune_dead_actors(self) -> None:
|
||||||
self._actor_refs = [a for a in self._actor_refs if a]
|
|
||||||
self._actor_weak_refs = [a for a in self._actor_weak_refs if a()]
|
|
||||||
self._last_prune_dead_actors_time = _ba.time()
|
self._last_prune_dead_actors_time = _ba.time()
|
||||||
|
|
||||||
|
# Prune our strong refs when the Actor's exists() call gives False
|
||||||
|
self._actor_refs = [a for a in self._actor_refs if a.exists()]
|
||||||
|
|
||||||
|
# Prune our weak refs once the Actor object has been freed.
|
||||||
|
self._actor_weak_refs = [
|
||||||
|
a for a in self._actor_weak_refs if a() is not None
|
||||||
|
]
|
||||||
|
|||||||
84
assets/src/ba_data/python/ba/_collision.py
Normal file
84
assets/src/ba_data/python/ba/_collision.py
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
# 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.
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
"""Collision related functionality."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
import _ba
|
||||||
|
from ba._error import NodeNotFoundError
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
import ba
|
||||||
|
|
||||||
|
|
||||||
|
class Collision:
|
||||||
|
"""A class providing info about occurring collisions."""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def position(self) -> ba.Vec3:
|
||||||
|
"""The position of the current collision."""
|
||||||
|
return _ba.Vec3(_ba.get_collision_info('position'))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def source_node(self) -> ba.Node:
|
||||||
|
"""The node containing the material triggering the current callback.
|
||||||
|
|
||||||
|
Throws a ba.NodeNotFoundError if the node does not exist, though
|
||||||
|
the node should always exist (at least at the start of the collision
|
||||||
|
callback).
|
||||||
|
"""
|
||||||
|
node = _ba.get_collision_info('source_node')
|
||||||
|
assert isinstance(node, (_ba.Node, type(None)))
|
||||||
|
if not node:
|
||||||
|
raise NodeNotFoundError()
|
||||||
|
return node
|
||||||
|
|
||||||
|
@property
|
||||||
|
def opposing_node(self) -> ba.Node:
|
||||||
|
"""The node the current callback material node is hitting.
|
||||||
|
|
||||||
|
Throws a ba.NodeNotFoundError if the node does not exist.
|
||||||
|
This can be expected in some cases such as in 'disconnect'
|
||||||
|
callbacks triggered by deleting a currently-colliding node.
|
||||||
|
"""
|
||||||
|
node = _ba.get_collision_info('opposing_node')
|
||||||
|
assert isinstance(node, (_ba.Node, type(None)))
|
||||||
|
if not node:
|
||||||
|
raise NodeNotFoundError()
|
||||||
|
return node
|
||||||
|
|
||||||
|
@property
|
||||||
|
def opposing_body(self) -> int:
|
||||||
|
"""The body index on the opposing node in the current collision."""
|
||||||
|
body = _ba.get_collision_info('opposing_body')
|
||||||
|
assert isinstance(body, int)
|
||||||
|
return body
|
||||||
|
|
||||||
|
|
||||||
|
# Simply recycle one instance...
|
||||||
|
_collision = Collision()
|
||||||
|
|
||||||
|
|
||||||
|
def getcollision() -> Collision:
|
||||||
|
"""Return the in-progress collision."""
|
||||||
|
return _collision
|
||||||
@ -447,7 +447,6 @@ def cameraflash(duration: float = 999.0) -> None:
|
|||||||
# Store this on the current activity so we only have one at a time.
|
# Store this on the current activity so we only have one at a time.
|
||||||
# FIXME: Need a type safe way to do this.
|
# FIXME: Need a type safe way to do this.
|
||||||
activity = _ba.getactivity()
|
activity = _ba.getactivity()
|
||||||
# noinspection PyTypeHints
|
|
||||||
activity.camera_flash_data = [] # type: ignore
|
activity.camera_flash_data = [] # type: ignore
|
||||||
for i in range(6):
|
for i in range(6):
|
||||||
light = NodeActor(
|
light = NodeActor(
|
||||||
|
|||||||
@ -226,6 +226,5 @@ def playercast_o(totype: Type[PlayerType],
|
|||||||
|
|
||||||
Category: Gameplay Functions
|
Category: Gameplay Functions
|
||||||
"""
|
"""
|
||||||
# noinspection PyTypeHints
|
|
||||||
assert isinstance(player, (totype, type(None)))
|
assert isinstance(player, (totype, type(None)))
|
||||||
return player
|
return player
|
||||||
|
|||||||
@ -19,6 +19,7 @@
|
|||||||
# SOFTWARE.
|
# SOFTWARE.
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
"""Powerup related functionality."""
|
"""Powerup related functionality."""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|||||||
@ -265,7 +265,6 @@ class BombFactory:
|
|||||||
actions=('message', 'our_node', 'at_connect', SplatMessage()))
|
actions=('message', 'our_node', 'at_connect', SplatMessage()))
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyTypeHints
|
|
||||||
def get_factory() -> BombFactory:
|
def get_factory() -> BombFactory:
|
||||||
"""Get/create a shared bastd.actor.bomb.BombFactory object."""
|
"""Get/create a shared bastd.actor.bomb.BombFactory object."""
|
||||||
activity = ba.getactivity()
|
activity = ba.getactivity()
|
||||||
@ -602,34 +601,28 @@ class Blast(ba.Actor):
|
|||||||
self.node.delete()
|
self.node.delete()
|
||||||
|
|
||||||
elif isinstance(msg, ExplodeHitMessage):
|
elif isinstance(msg, ExplodeHitMessage):
|
||||||
node = ba.get_collision_info('opposing_node')
|
node = ba.getcollision().opposing_node
|
||||||
if node:
|
assert self.node
|
||||||
assert self.node
|
nodepos = self.node.position
|
||||||
nodepos = self.node.position
|
mag = 2000.0
|
||||||
|
if self.blast_type == 'ice':
|
||||||
|
mag *= 0.5
|
||||||
|
elif self.blast_type == 'land_mine':
|
||||||
|
mag *= 2.5
|
||||||
|
elif self.blast_type == 'tnt':
|
||||||
|
mag *= 2.0
|
||||||
|
|
||||||
# new
|
node.handlemessage(
|
||||||
mag = 2000.0
|
ba.HitMessage(pos=nodepos,
|
||||||
if self.blast_type == 'ice':
|
velocity=(0, 0, 0),
|
||||||
mag *= 0.5
|
magnitude=mag,
|
||||||
elif self.blast_type == 'land_mine':
|
hit_type=self.hit_type,
|
||||||
mag *= 2.5
|
hit_subtype=self.hit_subtype,
|
||||||
elif self.blast_type == 'tnt':
|
radius=self.radius,
|
||||||
mag *= 2.0
|
source_player=ba.existing(self.source_player)))
|
||||||
|
if self.blast_type == 'ice':
|
||||||
node.handlemessage(
|
ba.playsound(get_factory().freeze_sound, 10, position=nodepos)
|
||||||
ba.HitMessage(pos=nodepos,
|
node.handlemessage(ba.FreezeMessage())
|
||||||
velocity=(0, 0, 0),
|
|
||||||
magnitude=mag,
|
|
||||||
hit_type=self.hit_type,
|
|
||||||
hit_subtype=self.hit_subtype,
|
|
||||||
radius=self.radius,
|
|
||||||
source_player=ba.existing(
|
|
||||||
self.source_player)))
|
|
||||||
if self.blast_type == 'ice':
|
|
||||||
ba.playsound(get_factory().freeze_sound,
|
|
||||||
10,
|
|
||||||
position=nodepos)
|
|
||||||
node.handlemessage(ba.FreezeMessage())
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
super().handlemessage(msg)
|
super().handlemessage(msg)
|
||||||
@ -850,14 +843,13 @@ class Bomb(ba.Actor):
|
|||||||
self.handlemessage(ba.DieMessage())
|
self.handlemessage(ba.DieMessage())
|
||||||
|
|
||||||
def _handle_impact(self) -> None:
|
def _handle_impact(self) -> None:
|
||||||
node = ba.get_collision_info('opposing_node')
|
node = ba.getcollision().opposing_node
|
||||||
# if we're an impact bomb and we came from this node, don't explode...
|
|
||||||
|
# If we're an impact bomb and we came from this node, don't explode...
|
||||||
# alternately if we're hitting another impact-bomb from the same
|
# alternately if we're hitting another impact-bomb from the same
|
||||||
# source, don't explode...
|
# source, don't explode...
|
||||||
try:
|
# try:
|
||||||
node_delegate = node.getdelegate()
|
node_delegate = node.getdelegate(object)
|
||||||
except Exception:
|
|
||||||
node_delegate = None
|
|
||||||
if node:
|
if node:
|
||||||
if (self.bomb_type == 'impact' and
|
if (self.bomb_type == 'impact' and
|
||||||
(node is self.owner or
|
(node is self.owner or
|
||||||
@ -883,7 +875,7 @@ class Bomb(ba.Actor):
|
|||||||
lambda: _safesetattr(self.node, 'stick_to_owner', True))
|
lambda: _safesetattr(self.node, 'stick_to_owner', True))
|
||||||
|
|
||||||
def _handle_splat(self) -> None:
|
def _handle_splat(self) -> None:
|
||||||
node = ba.get_collision_info('opposing_node')
|
node = ba.getcollision().opposing_node
|
||||||
if (node is not self.owner
|
if (node is not self.owner
|
||||||
and ba.time() - self._last_sticky_sound_time > 1.0):
|
and ba.time() - self._last_sticky_sound_time > 1.0):
|
||||||
self._last_sticky_sound_time = ba.time()
|
self._last_sticky_sound_time = ba.time()
|
||||||
|
|||||||
@ -105,19 +105,16 @@ class FlagFactory:
|
|||||||
|
|
||||||
self.flag_texture = ba.gettexture('flagColor')
|
self.flag_texture = ba.gettexture('flagColor')
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
# noinspection PyTypeHints
|
def get() -> FlagFactory:
|
||||||
def get_factory() -> FlagFactory:
|
"""Get/create a shared FlagFactory instance."""
|
||||||
"""Get/create a shared bastd.actor.flag.FlagFactory object."""
|
activity = ba.getactivity()
|
||||||
activity = ba.getactivity()
|
factory = getattr(activity, 'shared_flag_factory', None)
|
||||||
factory: FlagFactory
|
if factory is None:
|
||||||
try:
|
factory = FlagFactory()
|
||||||
# FIXME: Find elegant way to handle shared data like this.
|
setattr(activity, 'shared_flag_factory', factory)
|
||||||
factory = activity.shared_flag_factory # type: ignore
|
assert isinstance(factory, FlagFactory)
|
||||||
except Exception:
|
return factory
|
||||||
factory = activity.shared_flag_factory = FlagFactory() # type: ignore
|
|
||||||
assert isinstance(factory, FlagFactory)
|
|
||||||
return factory
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@ -201,7 +198,7 @@ class Flag(ba.Actor):
|
|||||||
|
|
||||||
self._initial_position: Optional[Sequence[float]] = None
|
self._initial_position: Optional[Sequence[float]] = None
|
||||||
self._has_moved = False
|
self._has_moved = False
|
||||||
factory = get_factory()
|
factory = FlagFactory.get()
|
||||||
|
|
||||||
if materials is None:
|
if materials is None:
|
||||||
materials = []
|
materials = []
|
||||||
|
|||||||
@ -305,11 +305,9 @@ class PowerupBox(ba.Actor):
|
|||||||
|
|
||||||
elif isinstance(msg, _TouchedMessage):
|
elif isinstance(msg, _TouchedMessage):
|
||||||
if not self._powersgiven:
|
if not self._powersgiven:
|
||||||
node = ba.get_collision_info('opposing_node')
|
node = ba.getcollision().opposing_node
|
||||||
if node:
|
node.handlemessage(
|
||||||
node.handlemessage(
|
ba.PowerupMessage(self.poweruptype, source_node=self.node))
|
||||||
ba.PowerupMessage(self.poweruptype,
|
|
||||||
source_node=self.node))
|
|
||||||
|
|
||||||
elif isinstance(msg, ba.DieMessage):
|
elif isinstance(msg, ba.DieMessage):
|
||||||
if self.node:
|
if self.node:
|
||||||
|
|||||||
@ -62,7 +62,6 @@ def get_factory() -> SpazFactory:
|
|||||||
activity = ba.getactivity()
|
activity = ba.getactivity()
|
||||||
factory = getattr(activity, 'shared_spaz_factory', None)
|
factory = getattr(activity, 'shared_spaz_factory', None)
|
||||||
if factory is None:
|
if factory is None:
|
||||||
# noinspection PyTypeHints
|
|
||||||
factory = activity.shared_spaz_factory = SpazFactory() # type: ignore
|
factory = activity.shared_spaz_factory = SpazFactory() # type: ignore
|
||||||
assert isinstance(factory, SpazFactory)
|
assert isinstance(factory, SpazFactory)
|
||||||
return factory
|
return factory
|
||||||
@ -1144,7 +1143,7 @@ class Spaz(ba.Actor):
|
|||||||
elif isinstance(msg, PunchHitMessage):
|
elif isinstance(msg, PunchHitMessage):
|
||||||
if not self.node:
|
if not self.node:
|
||||||
return None
|
return None
|
||||||
node = ba.get_collision_info('opposing_node')
|
node = ba.getcollision().opposing_node
|
||||||
|
|
||||||
# Only allow one hit per node per punch.
|
# Only allow one hit per node per punch.
|
||||||
if node and (node not in self._punched_nodes):
|
if node and (node not in self._punched_nodes):
|
||||||
@ -1203,10 +1202,11 @@ class Spaz(ba.Actor):
|
|||||||
if not self.node:
|
if not self.node:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
opposing_node, opposing_body = ba.get_collision_info(
|
try:
|
||||||
'opposing_node', 'opposing_body')
|
collision = ba.getcollision()
|
||||||
|
opposing_node = collision.opposing_node
|
||||||
if opposing_node is None or not opposing_node:
|
opposing_body = collision.opposing_body
|
||||||
|
except ba.NotFoundError:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# Don't allow picking up of invincible dudes.
|
# Don't allow picking up of invincible dudes.
|
||||||
|
|||||||
@ -62,7 +62,7 @@ class SpazBotPunchedMessage:
|
|||||||
self.damage = damage
|
self.damage = damage
|
||||||
|
|
||||||
|
|
||||||
class SpazBotDeathMessage:
|
class SpazBotDiedMessage:
|
||||||
"""A message saying a ba.SpazBot has died.
|
"""A message saying a ba.SpazBot has died.
|
||||||
|
|
||||||
category: Message Classes
|
category: Message Classes
|
||||||
@ -98,7 +98,7 @@ class SpazBot(Spaz):
|
|||||||
navigate obstacles and so should only be used
|
navigate obstacles and so should only be used
|
||||||
on wide-open maps.
|
on wide-open maps.
|
||||||
|
|
||||||
When a SpazBot is killed, it delivers a ba.SpazBotDeathMessage
|
When a SpazBot is killed, it delivers a ba.SpazBotDiedMessage
|
||||||
to the current activity.
|
to the current activity.
|
||||||
|
|
||||||
When a SpazBot is punched, it delivers a ba.SpazBotPunchedMessage
|
When a SpazBot is punched, it delivers a ba.SpazBotPunchedMessage
|
||||||
@ -569,7 +569,7 @@ class SpazBot(Spaz):
|
|||||||
killerplayer = None
|
killerplayer = None
|
||||||
if activity is not None:
|
if activity is not None:
|
||||||
activity.handlemessage(
|
activity.handlemessage(
|
||||||
SpazBotDeathMessage(self, killerplayer, msg.how))
|
SpazBotDiedMessage(self, killerplayer, msg.how))
|
||||||
super().handlemessage(msg) # Augment standard behavior.
|
super().handlemessage(msg) # Augment standard behavior.
|
||||||
|
|
||||||
# Keep track of the player who last hit us for point rewarding.
|
# Keep track of the player who last hit us for point rewarding.
|
||||||
@ -894,7 +894,7 @@ class ExplodeyBotShielded(ExplodeyBot):
|
|||||||
points_mult = 5
|
points_mult = 5
|
||||||
|
|
||||||
|
|
||||||
class BotSet:
|
class SpazBotSet:
|
||||||
"""A container/controller for one or more ba.SpazBots.
|
"""A container/controller for one or more ba.SpazBots.
|
||||||
|
|
||||||
category: Bot Classes
|
category: Bot Classes
|
||||||
@ -963,9 +963,7 @@ class BotSet:
|
|||||||
def _update(self) -> None:
|
def _update(self) -> None:
|
||||||
|
|
||||||
# Update one of our bot lists each time through.
|
# Update one of our bot lists each time through.
|
||||||
# First off, remove dead bots from the list. Note that we check
|
# First off, remove no-longer-existing bots from the list.
|
||||||
# exists() here via the bool operator instead of dead; we want to
|
|
||||||
# keep them around even if they're just a corpse.
|
|
||||||
try:
|
try:
|
||||||
bot_list = self._bot_lists[self._bot_update_list] = ([
|
bot_list = self._bot_lists[self._bot_update_list] = ([
|
||||||
b for b in self._bot_lists[self._bot_update_list] if b
|
b for b in self._bot_lists[self._bot_update_list] if b
|
||||||
@ -982,6 +980,9 @@ class BotSet:
|
|||||||
for player in ba.getactivity().players:
|
for player in ba.getactivity().players:
|
||||||
assert isinstance(player, ba.Player)
|
assert isinstance(player, ba.Player)
|
||||||
try:
|
try:
|
||||||
|
# TODO: could use abstracted player.position here so we
|
||||||
|
# don't have to assume their actor type, but we have no
|
||||||
|
# abstracted velocity as of yet.
|
||||||
if player.is_alive():
|
if player.is_alive():
|
||||||
assert isinstance(player.actor, Spaz)
|
assert isinstance(player.actor, Spaz)
|
||||||
assert player.actor.node
|
assert player.actor.node
|
||||||
|
|||||||
@ -179,16 +179,9 @@ class AssaultGame(ba.TeamGameActivity[Player, Team]):
|
|||||||
ba.timer(length, light.delete)
|
ba.timer(length, light.delete)
|
||||||
|
|
||||||
def _handle_base_collide(self, team: Team) -> None:
|
def _handle_base_collide(self, team: Team) -> None:
|
||||||
|
player = ba.getcollision().opposing_node.getdelegate(
|
||||||
# Attempt to pull a living ba.Player from what we hit.
|
PlayerSpaz, True).getplayer(Player)
|
||||||
cnode = ba.get_collision_info('opposing_node')
|
if not player or not player.is_alive():
|
||||||
assert isinstance(cnode, ba.Node)
|
|
||||||
actor = cnode.getdelegate()
|
|
||||||
if not isinstance(actor, PlayerSpaz):
|
|
||||||
return
|
|
||||||
|
|
||||||
player = actor.getplayer(Player)
|
|
||||||
if not player or not player.actor:
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# If its another team's player, they scored.
|
# If its another team's player, they scored.
|
||||||
|
|||||||
@ -28,15 +28,16 @@ from __future__ import annotations
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
import ba
|
import ba
|
||||||
from bastd.actor import flag as stdflag
|
|
||||||
from bastd.actor.playerspaz import PlayerSpaz
|
from bastd.actor.playerspaz import PlayerSpaz
|
||||||
from bastd.actor.scoreboard import Scoreboard
|
from bastd.actor.scoreboard import Scoreboard
|
||||||
|
from bastd.actor.flag import (FlagFactory, Flag, FlagPickedUpMessage,
|
||||||
|
FlagDroppedMessage, FlagDiedMessage)
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from typing import Any, Type, List, Dict, Sequence, Union, Optional
|
from typing import Any, Type, List, Dict, Sequence, Union, Optional
|
||||||
|
|
||||||
|
|
||||||
class CTFFlag(stdflag.Flag):
|
class CTFFlag(Flag):
|
||||||
"""Special flag type for CTF games."""
|
"""Special flag type for CTF games."""
|
||||||
|
|
||||||
activity: CaptureTheFlagGame
|
activity: CaptureTheFlagGame
|
||||||
@ -73,10 +74,7 @@ class CTFFlag(stdflag.Flag):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def from_node(cls, node: Optional[ba.Node]) -> Optional[CTFFlag]:
|
def from_node(cls, node: Optional[ba.Node]) -> Optional[CTFFlag]:
|
||||||
"""Attempt to get a CTFFlag from a flag node."""
|
"""Attempt to get a CTFFlag from a flag node."""
|
||||||
if not node:
|
return node.getdelegate(CTFFlag) if node else None
|
||||||
return None
|
|
||||||
delegate = node.getdelegate()
|
|
||||||
return delegate if isinstance(delegate, CTFFlag) else None
|
|
||||||
|
|
||||||
|
|
||||||
class Player(ba.Player['Team']):
|
class Player(ba.Player['Team']):
|
||||||
@ -246,8 +244,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]):
|
|||||||
|
|
||||||
# We wanna know when *any* flag enters/leaves our base.
|
# We wanna know when *any* flag enters/leaves our base.
|
||||||
base_region_mat.add_actions(
|
base_region_mat.add_actions(
|
||||||
conditions=('they_have_material',
|
conditions=('they_have_material', FlagFactory.get().flagmaterial),
|
||||||
stdflag.get_factory().flagmaterial),
|
|
||||||
actions=(('modify_part_collision', 'collide',
|
actions=(('modify_part_collision', 'collide',
|
||||||
True), ('modify_part_collision', 'physical', False),
|
True), ('modify_part_collision', 'physical', False),
|
||||||
('call', 'at_connect',
|
('call', 'at_connect',
|
||||||
@ -277,9 +274,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]):
|
|||||||
ba.playsound(self._swipsound, position=team.flag.node.position)
|
ba.playsound(self._swipsound, position=team.flag.node.position)
|
||||||
|
|
||||||
def _handle_flag_entered_base(self, team: Team) -> None:
|
def _handle_flag_entered_base(self, team: Team) -> None:
|
||||||
node = ba.get_collision_info('opposing_node')
|
flag = CTFFlag.from_node(ba.getcollision().opposing_node)
|
||||||
assert isinstance(node, (ba.Node, type(None)))
|
|
||||||
flag = CTFFlag.from_node(node)
|
|
||||||
if not flag:
|
if not flag:
|
||||||
print('Unable to get flag in _handle_flag_entered_base')
|
print('Unable to get flag in _handle_flag_entered_base')
|
||||||
return
|
return
|
||||||
@ -389,9 +384,12 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]):
|
|||||||
|
|
||||||
def _handle_flag_left_base(self, team: Team) -> None:
|
def _handle_flag_left_base(self, team: Team) -> None:
|
||||||
cur_time = ba.time()
|
cur_time = ba.time()
|
||||||
op_node = ba.get_collision_info('opposing_node')
|
try:
|
||||||
assert isinstance(op_node, (ba.Node, type(None)))
|
flag = CTFFlag.from_node(ba.getcollision().opposing_node)
|
||||||
flag = CTFFlag.from_node(op_node)
|
except ba.NodeNotFoundError:
|
||||||
|
# We still get this call even if the flag stopped touching us
|
||||||
|
# because it was deleted; that's ok.
|
||||||
|
flag = None
|
||||||
if not flag:
|
if not flag:
|
||||||
return
|
return
|
||||||
if flag.team is team:
|
if flag.team is team:
|
||||||
@ -445,19 +443,15 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]):
|
|||||||
"""Return a player if given a node that is part of one's actor."""
|
"""Return a player if given a node that is part of one's actor."""
|
||||||
if not node:
|
if not node:
|
||||||
return None
|
return None
|
||||||
delegate = node.getdelegate()
|
delegate = node.getdelegate(PlayerSpaz)
|
||||||
if not isinstance(delegate, PlayerSpaz):
|
return None if delegate is None else delegate.getplayer(Player)
|
||||||
return None
|
|
||||||
return delegate.getplayer(Player)
|
|
||||||
|
|
||||||
def _handle_hit_own_flag(self, team: Team, val: int) -> None:
|
def _handle_hit_own_flag(self, team: Team, val: int) -> None:
|
||||||
"""
|
"""
|
||||||
keep track of when each player is touching their
|
keep track of when each player is touching their
|
||||||
own flag so we can award points when returned
|
own flag so we can award points when returned
|
||||||
"""
|
"""
|
||||||
srcnode = ba.get_collision_info('source_node')
|
player = self._player_from_node(ba.getcollision().source_node)
|
||||||
assert isinstance(srcnode, (ba.Node, type(None)))
|
|
||||||
player = self._player_from_node(srcnode)
|
|
||||||
if player:
|
if player:
|
||||||
player.touching_own_flag += (1 if val else -1)
|
player.touching_own_flag += (1 if val else -1)
|
||||||
|
|
||||||
@ -470,10 +464,9 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]):
|
|||||||
# Use a node message to kill the flag instead of just killing
|
# Use a node message to kill the flag instead of just killing
|
||||||
# our team's. (avoids redundantly killing new flags if
|
# our team's. (avoids redundantly killing new flags if
|
||||||
# multiple body parts generate callbacks in one step).
|
# multiple body parts generate callbacks in one step).
|
||||||
node = ba.get_collision_info('opposing_node')
|
node = ba.getcollision().opposing_node
|
||||||
if node:
|
self._award_players_touching_own_flag(team)
|
||||||
self._award_players_touching_own_flag(team)
|
node.handlemessage(ba.DieMessage())
|
||||||
node.handlemessage(ba.DieMessage())
|
|
||||||
|
|
||||||
# Takes a non-zero amount of time to return.
|
# Takes a non-zero amount of time to return.
|
||||||
else:
|
else:
|
||||||
@ -547,16 +540,17 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]):
|
|||||||
# Augment standard behavior.
|
# Augment standard behavior.
|
||||||
super().handlemessage(msg)
|
super().handlemessage(msg)
|
||||||
self.respawn_player(msg.getplayer(Player))
|
self.respawn_player(msg.getplayer(Player))
|
||||||
elif isinstance(msg, stdflag.FlagDiedMessage):
|
elif isinstance(msg, FlagDiedMessage):
|
||||||
assert isinstance(msg.flag, CTFFlag)
|
assert isinstance(msg.flag, CTFFlag)
|
||||||
ba.timer(0.1, ba.Call(self._spawn_flag_for_team, msg.flag.team))
|
ba.timer(0.1, ba.Call(self._spawn_flag_for_team, msg.flag.team))
|
||||||
elif isinstance(msg, stdflag.FlagPickedUpMessage):
|
elif isinstance(msg, FlagPickedUpMessage):
|
||||||
# Store the last player to hold the flag for scoring purposes.
|
# Store the last player to hold the flag for scoring purposes.
|
||||||
assert isinstance(msg.flag, CTFFlag)
|
assert isinstance(msg.flag, CTFFlag)
|
||||||
msg.flag.last_player_to_hold = msg.node.getdelegate().getplayer()
|
msg.flag.last_player_to_hold = msg.node.getdelegate(
|
||||||
|
PlayerSpaz, True).getplayer(Player)
|
||||||
msg.flag.held_count += 1
|
msg.flag.held_count += 1
|
||||||
msg.flag.reset_return_times()
|
msg.flag.reset_return_times()
|
||||||
elif isinstance(msg, stdflag.FlagDroppedMessage):
|
elif isinstance(msg, FlagDroppedMessage):
|
||||||
# Store the last player to hold the flag for scoring purposes.
|
# Store the last player to hold the flag for scoring purposes.
|
||||||
assert isinstance(msg.flag, CTFFlag)
|
assert isinstance(msg.flag, CTFFlag)
|
||||||
msg.flag.held_count -= 1
|
msg.flag.held_count -= 1
|
||||||
|
|||||||
@ -177,11 +177,10 @@ class ChosenOneGame(ba.TeamGameActivity[Player, Team]):
|
|||||||
# If we have a chosen one, ignore these.
|
# If we have a chosen one, ignore these.
|
||||||
if self._get_chosen_one_player() is not None:
|
if self._get_chosen_one_player() is not None:
|
||||||
return
|
return
|
||||||
delegate = ba.get_collision_info('opposing_node').getdelegate()
|
player = ba.getcollision().opposing_node.getdelegate(
|
||||||
if isinstance(delegate, PlayerSpaz):
|
PlayerSpaz, True).getplayer(Player)
|
||||||
player = delegate.getplayer(Player)
|
if player is not None and player.is_alive():
|
||||||
if player is not None and player.is_alive():
|
self._set_chosen_one_player(player)
|
||||||
self._set_chosen_one_player(player)
|
|
||||||
|
|
||||||
def _flash_flag_spawn(self) -> None:
|
def _flash_flag_spawn(self) -> None:
|
||||||
light = ba.newnode('light',
|
light = ba.newnode('light',
|
||||||
|
|||||||
@ -31,6 +31,7 @@ from typing import TYPE_CHECKING
|
|||||||
import ba
|
import ba
|
||||||
from bastd.actor.flag import Flag
|
from bastd.actor.flag import Flag
|
||||||
from bastd.actor.scoreboard import Scoreboard
|
from bastd.actor.scoreboard import Scoreboard
|
||||||
|
from bastd.actor.playerspaz import PlayerSpaz
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from typing import Any, Optional, Type, List, Dict, Sequence, Union
|
from typing import Any, Optional, Type, List, Dict, Sequence, Union
|
||||||
@ -233,15 +234,12 @@ class ConquestGame(ba.TeamGameActivity[Player, Team]):
|
|||||||
ba.timer(length, light.delete)
|
ba.timer(length, light.delete)
|
||||||
|
|
||||||
def _handle_flag_player_collide(self) -> None:
|
def _handle_flag_player_collide(self) -> None:
|
||||||
flagnode, playernode = ba.get_collision_info('source_node',
|
collision = ba.getcollision()
|
||||||
'opposing_node')
|
flag = collision.source_node.getdelegate(ConquestFlag)
|
||||||
try:
|
player = collision.opposing_node.getdelegate(PlayerSpaz,
|
||||||
player = playernode.getdelegate().getplayer()
|
True).getplayer(Player)
|
||||||
flag = flagnode.getdelegate()
|
if not flag or not player:
|
||||||
except Exception:
|
return
|
||||||
return # Player may have left and his body hit the flag.
|
|
||||||
assert isinstance(player, Player)
|
|
||||||
assert isinstance(flag, ConquestFlag)
|
|
||||||
assert flag.light
|
assert flag.light
|
||||||
|
|
||||||
if flag.team is not player.team:
|
if flag.team is not player.team:
|
||||||
|
|||||||
@ -31,7 +31,7 @@ from typing import TYPE_CHECKING
|
|||||||
import ba
|
import ba
|
||||||
from bastd.actor.bomb import Bomb
|
from bastd.actor.bomb import Bomb
|
||||||
from bastd.actor.playerspaz import PlayerSpaz
|
from bastd.actor.playerspaz import PlayerSpaz
|
||||||
from bastd.actor.spazbot import BotSet, BouncyBot, SpazBotDeathMessage
|
from bastd.actor.spazbot import SpazBotSet, BouncyBot, SpazBotDiedMessage
|
||||||
from bastd.actor.onscreencountdown import OnScreenCountdown
|
from bastd.actor.onscreencountdown import OnScreenCountdown
|
||||||
from bastd.actor.scoreboard import Scoreboard
|
from bastd.actor.scoreboard import Scoreboard
|
||||||
from bastd.actor.respawnicon import RespawnIcon
|
from bastd.actor.respawnicon import RespawnIcon
|
||||||
@ -94,7 +94,7 @@ class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]):
|
|||||||
self._eggs: List[Egg] = []
|
self._eggs: List[Egg] = []
|
||||||
self._update_timer: Optional[ba.Timer] = None
|
self._update_timer: Optional[ba.Timer] = None
|
||||||
self._countdown: Optional[OnScreenCountdown] = None
|
self._countdown: Optional[OnScreenCountdown] = None
|
||||||
self._bots: Optional[BotSet] = None
|
self._bots: Optional[SpazBotSet] = None
|
||||||
|
|
||||||
# Base class overrides
|
# Base class overrides
|
||||||
self.default_music = ba.MusicType.FORWARD_MARCH
|
self.default_music = ba.MusicType.FORWARD_MARCH
|
||||||
@ -117,7 +117,7 @@ class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]):
|
|||||||
self._update_timer = ba.Timer(0.25, self._update, repeat=True)
|
self._update_timer = ba.Timer(0.25, self._update, repeat=True)
|
||||||
self._countdown = OnScreenCountdown(60, endcall=self.end_game)
|
self._countdown = OnScreenCountdown(60, endcall=self.end_game)
|
||||||
ba.timer(4.0, self._countdown.start)
|
ba.timer(4.0, self._countdown.start)
|
||||||
self._bots = BotSet()
|
self._bots = SpazBotSet()
|
||||||
|
|
||||||
# Spawn evil bunny in co-op only.
|
# Spawn evil bunny in co-op only.
|
||||||
if isinstance(self.session, ba.CoopSession) and self._pro_mode:
|
if isinstance(self.session, ba.CoopSession) and self._pro_mode:
|
||||||
@ -134,49 +134,44 @@ class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]):
|
|||||||
self._bots.spawn_bot(BouncyBot, pos=(6, 4, -7.8), spawn_time=10.0)
|
self._bots.spawn_bot(BouncyBot, pos=(6, 4, -7.8), spawn_time=10.0)
|
||||||
|
|
||||||
def _on_egg_player_collide(self) -> None:
|
def _on_egg_player_collide(self) -> None:
|
||||||
if not self.has_ended():
|
if self.has_ended():
|
||||||
egg_node, playernode = ba.get_collision_info(
|
return
|
||||||
'source_node', 'opposing_node')
|
collision = ba.getcollision()
|
||||||
if egg_node is not None and playernode is not None:
|
egg = collision.source_node.getdelegate(Egg)
|
||||||
egg = egg_node.getdelegate()
|
player = collision.opposing_node.getdelegate(PlayerSpaz,
|
||||||
assert isinstance(egg, Egg)
|
True).getplayer(Player)
|
||||||
spaz = playernode.getdelegate()
|
if player and egg:
|
||||||
assert isinstance(spaz, PlayerSpaz)
|
player.team.score += 1
|
||||||
player = spaz.getplayer(Player)
|
|
||||||
if player and egg:
|
|
||||||
player.team.score += 1
|
|
||||||
|
|
||||||
# Displays a +1 (and adds to individual player score in
|
# Displays a +1 (and adds to individual player score in
|
||||||
# teams mode).
|
# teams mode).
|
||||||
self.stats.player_scored(player, 1, screenmessage=False)
|
self.stats.player_scored(player, 1, screenmessage=False)
|
||||||
if self._max_eggs < 5:
|
if self._max_eggs < 5:
|
||||||
self._max_eggs += 1.0
|
self._max_eggs += 1.0
|
||||||
elif self._max_eggs < 10:
|
elif self._max_eggs < 10:
|
||||||
self._max_eggs += 0.5
|
self._max_eggs += 0.5
|
||||||
elif self._max_eggs < 30:
|
elif self._max_eggs < 30:
|
||||||
self._max_eggs += 0.3
|
self._max_eggs += 0.3
|
||||||
self._update_scoreboard()
|
self._update_scoreboard()
|
||||||
ba.playsound(self._collect_sound,
|
ba.playsound(self._collect_sound, 0.5, position=egg.node.position)
|
||||||
0.5,
|
|
||||||
position=egg.node.position)
|
|
||||||
|
|
||||||
# Create a flash.
|
# Create a flash.
|
||||||
light = ba.newnode('light',
|
light = ba.newnode('light',
|
||||||
attrs={
|
attrs={
|
||||||
'position': egg_node.position,
|
'position': egg.node.position,
|
||||||
'height_attenuated': False,
|
'height_attenuated': False,
|
||||||
'radius': 0.1,
|
'radius': 0.1,
|
||||||
'color': (1, 1, 0)
|
'color': (1, 1, 0)
|
||||||
})
|
})
|
||||||
ba.animate(light,
|
ba.animate(light,
|
||||||
'intensity', {
|
'intensity', {
|
||||||
0: 0,
|
0: 0,
|
||||||
0.1: 1.0,
|
0.1: 1.0,
|
||||||
0.2: 0
|
0.2: 0
|
||||||
},
|
},
|
||||||
loop=False)
|
loop=False)
|
||||||
ba.timer(0.200, light.delete)
|
ba.timer(0.200, light.delete)
|
||||||
egg.handlemessage(ba.DieMessage())
|
egg.handlemessage(ba.DieMessage())
|
||||||
|
|
||||||
def _update(self) -> None:
|
def _update(self) -> None:
|
||||||
# Misc. periodic updating.
|
# Misc. periodic updating.
|
||||||
@ -219,7 +214,7 @@ class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]):
|
|||||||
player.respawn_icon = RespawnIcon(player, respawn_time)
|
player.respawn_icon = RespawnIcon(player, respawn_time)
|
||||||
|
|
||||||
# Whenever our evil bunny dies, respawn him and spew some eggs.
|
# Whenever our evil bunny dies, respawn him and spew some eggs.
|
||||||
elif isinstance(msg, SpazBotDeathMessage):
|
elif isinstance(msg, SpazBotDiedMessage):
|
||||||
self._spawn_evil_bunny()
|
self._spawn_evil_bunny()
|
||||||
assert msg.badguy.node
|
assert msg.badguy.node
|
||||||
pos = msg.badguy.node.position
|
pos = msg.badguy.node.position
|
||||||
|
|||||||
@ -30,20 +30,26 @@ from typing import TYPE_CHECKING
|
|||||||
import math
|
import math
|
||||||
|
|
||||||
import ba
|
import ba
|
||||||
from bastd.actor import spazbot
|
|
||||||
from bastd.actor import flag as stdflag
|
|
||||||
from bastd.actor.bomb import TNTSpawner
|
from bastd.actor.bomb import TNTSpawner
|
||||||
from bastd.actor.playerspaz import PlayerSpaz
|
from bastd.actor.playerspaz import PlayerSpaz
|
||||||
from bastd.actor.scoreboard import Scoreboard
|
from bastd.actor.scoreboard import Scoreboard
|
||||||
from bastd.actor.respawnicon import RespawnIcon
|
from bastd.actor.respawnicon import RespawnIcon
|
||||||
from bastd.actor.powerupbox import PowerupBoxFactory, PowerupBox
|
from bastd.actor.powerupbox import PowerupBoxFactory, PowerupBox
|
||||||
|
from bastd.actor.flag import (FlagFactory, Flag, FlagPickedUpMessage,
|
||||||
|
FlagDroppedMessage, FlagDiedMessage)
|
||||||
|
from bastd.actor.spazbot import (SpazBotDiedMessage, SpazBotPunchedMessage,
|
||||||
|
SpazBotSet, BrawlerBotLite, BrawlerBot,
|
||||||
|
BomberBotLite, BomberBot, TriggerBot,
|
||||||
|
ChargerBot, TriggerBotPro, BrawlerBotPro,
|
||||||
|
StickyBot, ExplodeyBot)
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from typing import Any, List, Type, Dict, Sequence, Optional, Union
|
from typing import Any, List, Type, Dict, Sequence, Optional, Union
|
||||||
from bastd.actor.spaz import Spaz
|
from bastd.actor.spaz import Spaz
|
||||||
|
from bastd.actor.spazbot import SpazBot
|
||||||
|
|
||||||
|
|
||||||
class FootballFlag(stdflag.Flag):
|
class FootballFlag(Flag):
|
||||||
"""Custom flag class for football games."""
|
"""Custom flag class for football games."""
|
||||||
|
|
||||||
def __init__(self, position: Sequence[float]):
|
def __init__(self, position: Sequence[float]):
|
||||||
@ -129,8 +135,7 @@ class FootballTeamGame(ba.TeamGameActivity[Player, Team]):
|
|||||||
self._whistle_sound = ba.getsound('refWhistle')
|
self._whistle_sound = ba.getsound('refWhistle')
|
||||||
self._score_region_material = ba.Material()
|
self._score_region_material = ba.Material()
|
||||||
self._score_region_material.add_actions(
|
self._score_region_material.add_actions(
|
||||||
conditions=('they_have_material',
|
conditions=('they_have_material', FlagFactory.get().flagmaterial),
|
||||||
stdflag.get_factory().flagmaterial),
|
|
||||||
actions=(
|
actions=(
|
||||||
('modify_part_collision', 'collide', True),
|
('modify_part_collision', 'collide', True),
|
||||||
('modify_part_collision', 'physical', False),
|
('modify_part_collision', 'physical', False),
|
||||||
@ -204,7 +209,7 @@ class FootballTeamGame(ba.TeamGameActivity[Player, Team]):
|
|||||||
assert self._flag is not None
|
assert self._flag is not None
|
||||||
if self._flag.scored:
|
if self._flag.scored:
|
||||||
return
|
return
|
||||||
region = ba.get_collision_info('source_node')
|
region = ba.getcollision().source_node
|
||||||
i = None
|
i = None
|
||||||
for i in range(len(self._score_regions)):
|
for i in range(len(self._score_regions)):
|
||||||
if region == self._score_regions[i].node:
|
if region == self._score_regions[i].node:
|
||||||
@ -238,7 +243,7 @@ class FootballTeamGame(ba.TeamGameActivity[Player, Team]):
|
|||||||
ba.timer(1.0, self._kill_flag)
|
ba.timer(1.0, self._kill_flag)
|
||||||
light = ba.newnode('light',
|
light = ba.newnode('light',
|
||||||
attrs={
|
attrs={
|
||||||
'position': ba.get_collision_info('position'),
|
'position': ba.getcollision().position,
|
||||||
'height_attenuated': False,
|
'height_attenuated': False,
|
||||||
'color': (1, 0, 0)
|
'color': (1, 0, 0)
|
||||||
})
|
})
|
||||||
@ -260,18 +265,14 @@ class FootballTeamGame(ba.TeamGameActivity[Player, Team]):
|
|||||||
self._score_to_win)
|
self._score_to_win)
|
||||||
|
|
||||||
def handlemessage(self, msg: Any) -> Any:
|
def handlemessage(self, msg: Any) -> Any:
|
||||||
if isinstance(msg, stdflag.FlagPickedUpMessage):
|
if isinstance(msg, FlagPickedUpMessage):
|
||||||
assert isinstance(msg.flag, FootballFlag)
|
assert isinstance(msg.flag, FootballFlag)
|
||||||
try:
|
player = msg.node.getdelegate(PlayerSpaz, True).getplayer(Player)
|
||||||
player = msg.node.getdelegate().getplayer()
|
if player:
|
||||||
if player:
|
msg.flag.last_holding_player = player
|
||||||
msg.flag.last_holding_player = player
|
msg.flag.held_count += 1
|
||||||
msg.flag.held_count += 1
|
|
||||||
except Exception:
|
|
||||||
ba.print_exception('exception in Football FlagPickedUpMessage;'
|
|
||||||
" this shouldn't happen")
|
|
||||||
|
|
||||||
elif isinstance(msg, stdflag.FlagDroppedMessage):
|
elif isinstance(msg, FlagDroppedMessage):
|
||||||
assert isinstance(msg.flag, FootballFlag)
|
assert isinstance(msg.flag, FootballFlag)
|
||||||
msg.flag.held_count -= 1
|
msg.flag.held_count -= 1
|
||||||
|
|
||||||
@ -282,7 +283,7 @@ class FootballTeamGame(ba.TeamGameActivity[Player, Team]):
|
|||||||
self.respawn_player(msg.getplayer(Player))
|
self.respawn_player(msg.getplayer(Player))
|
||||||
|
|
||||||
# Respawn dead flags.
|
# Respawn dead flags.
|
||||||
elif isinstance(msg, stdflag.FlagDiedMessage):
|
elif isinstance(msg, FlagDiedMessage):
|
||||||
if not self.has_ended():
|
if not self.has_ended():
|
||||||
self._flag_respawn_timer = ba.Timer(3.0, self._spawn_flag)
|
self._flag_respawn_timer = ba.Timer(3.0, self._spawn_flag)
|
||||||
self._flag_respawn_light = ba.NodeActor(
|
self._flag_respawn_light = ba.NodeActor(
|
||||||
@ -368,8 +369,7 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
self._score_to_win = 21
|
self._score_to_win = 21
|
||||||
self._score_region_material = ba.Material()
|
self._score_region_material = ba.Material()
|
||||||
self._score_region_material.add_actions(
|
self._score_region_material.add_actions(
|
||||||
conditions=('they_have_material',
|
conditions=('they_have_material', FlagFactory.get().flagmaterial),
|
||||||
stdflag.get_factory().flagmaterial),
|
|
||||||
actions=(
|
actions=(
|
||||||
('modify_part_collision', 'collide', True),
|
('modify_part_collision', 'collide', True),
|
||||||
('modify_part_collision', 'physical', False),
|
('modify_part_collision', 'physical', False),
|
||||||
@ -384,15 +384,15 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
self._score_regions: List[ba.NodeActor] = []
|
self._score_regions: List[ba.NodeActor] = []
|
||||||
self._exclude_powerups: List[str] = []
|
self._exclude_powerups: List[str] = []
|
||||||
self._have_tnt = False
|
self._have_tnt = False
|
||||||
self._bot_types_initial: Optional[List[Type[spazbot.SpazBot]]] = None
|
self._bot_types_initial: Optional[List[Type[SpazBot]]] = None
|
||||||
self._bot_types_7: Optional[List[Type[spazbot.SpazBot]]] = None
|
self._bot_types_7: Optional[List[Type[SpazBot]]] = None
|
||||||
self._bot_types_14: Optional[List[Type[spazbot.SpazBot]]] = None
|
self._bot_types_14: Optional[List[Type[SpazBot]]] = None
|
||||||
self._bot_team: Optional[Team] = None
|
self._bot_team: Optional[Team] = None
|
||||||
self._starttime_ms: Optional[int] = None
|
self._starttime_ms: Optional[int] = None
|
||||||
self._time_text: Optional[ba.NodeActor] = None
|
self._time_text: Optional[ba.NodeActor] = None
|
||||||
self._time_text_input: Optional[ba.NodeActor] = None
|
self._time_text_input: Optional[ba.NodeActor] = None
|
||||||
self._tntspawner: Optional[TNTSpawner] = None
|
self._tntspawner: Optional[TNTSpawner] = None
|
||||||
self._bots = spazbot.BotSet()
|
self._bots = SpazBotSet()
|
||||||
self._bot_spawn_timer: Optional[ba.Timer] = None
|
self._bot_spawn_timer: Optional[ba.Timer] = None
|
||||||
self._powerup_drop_timer: Optional[ba.Timer] = None
|
self._powerup_drop_timer: Optional[ba.Timer] = None
|
||||||
self._scoring_team: Optional[Team] = None
|
self._scoring_team: Optional[Team] = None
|
||||||
@ -440,64 +440,56 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
controlsguide.ControlsGuide(delay=3.0, lifespan=10.0,
|
controlsguide.ControlsGuide(delay=3.0, lifespan=10.0,
|
||||||
bright=True).autoretain()
|
bright=True).autoretain()
|
||||||
assert self.initial_player_info is not None
|
assert self.initial_player_info is not None
|
||||||
abot: Type[spazbot.SpazBot]
|
abot: Type[SpazBot]
|
||||||
bbot: Type[spazbot.SpazBot]
|
bbot: Type[SpazBot]
|
||||||
cbot: Type[spazbot.SpazBot]
|
cbot: Type[SpazBot]
|
||||||
if self._preset in ['rookie', 'rookie_easy']:
|
if self._preset in ['rookie', 'rookie_easy']:
|
||||||
self._exclude_powerups = ['curse']
|
self._exclude_powerups = ['curse']
|
||||||
self._have_tnt = False
|
self._have_tnt = False
|
||||||
abot = (spazbot.BrawlerBotLite
|
abot = (BrawlerBotLite
|
||||||
if self._preset == 'rookie_easy' else spazbot.BrawlerBot)
|
if self._preset == 'rookie_easy' else BrawlerBot)
|
||||||
self._bot_types_initial = [abot] * len(self.initial_player_info)
|
self._bot_types_initial = [abot] * len(self.initial_player_info)
|
||||||
bbot = (spazbot.BomberBotLite
|
bbot = (BomberBotLite
|
||||||
if self._preset == 'rookie_easy' else spazbot.BomberBot)
|
if self._preset == 'rookie_easy' else BomberBot)
|
||||||
self._bot_types_7 = (
|
self._bot_types_7 = (
|
||||||
[bbot] * (1 if len(self.initial_player_info) < 3 else 2))
|
[bbot] * (1 if len(self.initial_player_info) < 3 else 2))
|
||||||
cbot = (spazbot.BomberBot
|
cbot = (BomberBot if self._preset == 'rookie_easy' else TriggerBot)
|
||||||
if self._preset == 'rookie_easy' else spazbot.TriggerBot)
|
|
||||||
self._bot_types_14 = (
|
self._bot_types_14 = (
|
||||||
[cbot] * (1 if len(self.initial_player_info) < 3 else 2))
|
[cbot] * (1 if len(self.initial_player_info) < 3 else 2))
|
||||||
elif self._preset == 'tournament':
|
elif self._preset == 'tournament':
|
||||||
self._exclude_powerups = []
|
self._exclude_powerups = []
|
||||||
self._have_tnt = True
|
self._have_tnt = True
|
||||||
self._bot_types_initial = (
|
self._bot_types_initial = (
|
||||||
[spazbot.BrawlerBot] *
|
[BrawlerBot] * (1 if len(self.initial_player_info) < 2 else 2))
|
||||||
(1 if len(self.initial_player_info) < 2 else 2))
|
|
||||||
self._bot_types_7 = (
|
self._bot_types_7 = (
|
||||||
[spazbot.TriggerBot] *
|
[TriggerBot] * (1 if len(self.initial_player_info) < 3 else 2))
|
||||||
(1 if len(self.initial_player_info) < 3 else 2))
|
|
||||||
self._bot_types_14 = (
|
self._bot_types_14 = (
|
||||||
[spazbot.ChargerBot] *
|
[ChargerBot] * (1 if len(self.initial_player_info) < 4 else 2))
|
||||||
(1 if len(self.initial_player_info) < 4 else 2))
|
|
||||||
elif self._preset in ['pro', 'pro_easy', 'tournament_pro']:
|
elif self._preset in ['pro', 'pro_easy', 'tournament_pro']:
|
||||||
self._exclude_powerups = ['curse']
|
self._exclude_powerups = ['curse']
|
||||||
self._have_tnt = True
|
self._have_tnt = True
|
||||||
self._bot_types_initial = [spazbot.ChargerBot] * len(
|
self._bot_types_initial = [ChargerBot] * len(
|
||||||
self.initial_player_info)
|
self.initial_player_info)
|
||||||
abot = (spazbot.BrawlerBot
|
abot = (BrawlerBot if self._preset == 'pro' else BrawlerBotLite)
|
||||||
if self._preset == 'pro' else spazbot.BrawlerBotLite)
|
typed_bot_list: List[Type[SpazBot]] = []
|
||||||
typed_bot_list: List[Type[spazbot.SpazBot]] = []
|
|
||||||
self._bot_types_7 = (
|
self._bot_types_7 = (
|
||||||
typed_bot_list + [abot] + [spazbot.BomberBot] *
|
typed_bot_list + [abot] + [BomberBot] *
|
||||||
(1 if len(self.initial_player_info) < 3 else 2))
|
(1 if len(self.initial_player_info) < 3 else 2))
|
||||||
bbot = (spazbot.TriggerBotPro
|
bbot = (TriggerBotPro if self._preset == 'pro' else TriggerBot)
|
||||||
if self._preset == 'pro' else spazbot.TriggerBot)
|
|
||||||
self._bot_types_14 = (
|
self._bot_types_14 = (
|
||||||
[bbot] * (1 if len(self.initial_player_info) < 3 else 2))
|
[bbot] * (1 if len(self.initial_player_info) < 3 else 2))
|
||||||
elif self._preset in ['uber', 'uber_easy']:
|
elif self._preset in ['uber', 'uber_easy']:
|
||||||
self._exclude_powerups = []
|
self._exclude_powerups = []
|
||||||
self._have_tnt = True
|
self._have_tnt = True
|
||||||
abot = (spazbot.BrawlerBotPro
|
abot = (BrawlerBotPro if self._preset == 'uber' else BrawlerBot)
|
||||||
if self._preset == 'uber' else spazbot.BrawlerBot)
|
bbot = (TriggerBotPro if self._preset == 'uber' else TriggerBot)
|
||||||
bbot = (spazbot.TriggerBotPro
|
typed_bot_list_2: List[Type[SpazBot]] = []
|
||||||
if self._preset == 'uber' else spazbot.TriggerBot)
|
self._bot_types_initial = (typed_bot_list_2 + [StickyBot] +
|
||||||
typed_bot_list_2: List[Type[spazbot.SpazBot]] = []
|
|
||||||
self._bot_types_initial = (typed_bot_list_2 + [spazbot.StickyBot] +
|
|
||||||
[abot] * len(self.initial_player_info))
|
[abot] * len(self.initial_player_info))
|
||||||
self._bot_types_7 = (
|
self._bot_types_7 = (
|
||||||
[bbot] * (1 if len(self.initial_player_info) < 3 else 2))
|
[bbot] * (1 if len(self.initial_player_info) < 3 else 2))
|
||||||
self._bot_types_14 = (
|
self._bot_types_14 = (
|
||||||
[spazbot.ExplodeyBot] *
|
[ExplodeyBot] *
|
||||||
(1 if len(self.initial_player_info) < 3 else 2))
|
(1 if len(self.initial_player_info) < 3 else 2))
|
||||||
else:
|
else:
|
||||||
raise Exception()
|
raise Exception()
|
||||||
@ -549,7 +541,7 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
if self._have_tnt:
|
if self._have_tnt:
|
||||||
self._tntspawner = TNTSpawner(position=(0, 1, -1))
|
self._tntspawner = TNTSpawner(position=(0, 1, -1))
|
||||||
|
|
||||||
self._bots = spazbot.BotSet()
|
self._bots = SpazBotSet()
|
||||||
self._bot_spawn_timer = ba.Timer(1.0, self._update_bots, repeat=True)
|
self._bot_spawn_timer = ba.Timer(1.0, self._update_bots, repeat=True)
|
||||||
|
|
||||||
for bottype in self._bot_types_initial:
|
for bottype in self._bot_types_initial:
|
||||||
@ -558,12 +550,12 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
def _on_got_scores_to_beat(self, scores: List[Dict[str, Any]]) -> None:
|
def _on_got_scores_to_beat(self, scores: List[Dict[str, Any]]) -> None:
|
||||||
self._show_standard_scores_to_beat_ui(scores)
|
self._show_standard_scores_to_beat_ui(scores)
|
||||||
|
|
||||||
def _on_bot_spawn(self, spaz: spazbot.SpazBot) -> None:
|
def _on_bot_spawn(self, spaz: SpazBot) -> None:
|
||||||
# We want to move to the left by default.
|
# We want to move to the left by default.
|
||||||
spaz.target_point_default = ba.Vec3(0, 0, 0)
|
spaz.target_point_default = ba.Vec3(0, 0, 0)
|
||||||
|
|
||||||
def _spawn_bot(self,
|
def _spawn_bot(self,
|
||||||
spaz_type: Type[spazbot.SpazBot],
|
spaz_type: Type[SpazBot],
|
||||||
immediate: bool = False) -> None:
|
immediate: bool = False) -> None:
|
||||||
assert self._bot_team is not None
|
assert self._bot_team is not None
|
||||||
pos = self.map.get_start_position(self._bot_team.id)
|
pos = self.map.get_start_position(self._bot_team.id)
|
||||||
@ -594,7 +586,7 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
return
|
return
|
||||||
|
|
||||||
flagpos = ba.Vec3(self._flag.node.position)
|
flagpos = ba.Vec3(self._flag.node.position)
|
||||||
closest_bot: Optional[spazbot.SpazBot] = None
|
closest_bot: Optional[SpazBot] = None
|
||||||
closest_dist = 0.0 # Always gets assigned first time through.
|
closest_dist = 0.0 # Always gets assigned first time through.
|
||||||
for bot in bots:
|
for bot in bots:
|
||||||
# If a bot is picked up, he should forget about the flag.
|
# If a bot is picked up, he should forget about the flag.
|
||||||
@ -662,7 +654,7 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
return
|
return
|
||||||
|
|
||||||
# See which score region it was.
|
# See which score region it was.
|
||||||
region = ba.get_collision_info('source_node')
|
region = ba.getcollision().source_node
|
||||||
i = None
|
i = None
|
||||||
for i in range(len(self._score_regions)):
|
for i in range(len(self._score_regions)):
|
||||||
if region == self._score_regions[i].node:
|
if region == self._score_regions[i].node:
|
||||||
@ -707,7 +699,7 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
self.update_scores()
|
self.update_scores()
|
||||||
light = ba.newnode('light',
|
light = ba.newnode('light',
|
||||||
attrs={
|
attrs={
|
||||||
'position': ba.get_collision_info('position'),
|
'position': ba.getcollision().position,
|
||||||
'height_attenuated': False,
|
'height_attenuated': False,
|
||||||
'color': (1, 0, 0)
|
'color': (1, 0, 0)
|
||||||
})
|
})
|
||||||
@ -821,12 +813,12 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
# Augment standard behavior.
|
# Augment standard behavior.
|
||||||
super().handlemessage(msg)
|
super().handlemessage(msg)
|
||||||
|
|
||||||
elif isinstance(msg, spazbot.SpazBotDeathMessage):
|
elif isinstance(msg, SpazBotDiedMessage):
|
||||||
|
|
||||||
# Every time a bad guy dies, spawn a new one.
|
# Every time a bad guy dies, spawn a new one.
|
||||||
ba.timer(3.0, ba.Call(self._spawn_bot, (type(msg.badguy))))
|
ba.timer(3.0, ba.Call(self._spawn_bot, (type(msg.badguy))))
|
||||||
|
|
||||||
elif isinstance(msg, spazbot.SpazBotPunchedMessage):
|
elif isinstance(msg, SpazBotPunchedMessage):
|
||||||
if self._preset in ['rookie', 'rookie_easy']:
|
if self._preset in ['rookie', 'rookie_easy']:
|
||||||
if msg.damage >= 500:
|
if msg.damage >= 500:
|
||||||
self._award_achievement('Super Punch')
|
self._award_achievement('Super Punch')
|
||||||
@ -835,7 +827,7 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
self._award_achievement('Super Mega Punch')
|
self._award_achievement('Super Mega Punch')
|
||||||
|
|
||||||
# Respawn dead flags.
|
# Respawn dead flags.
|
||||||
elif isinstance(msg, stdflag.FlagDiedMessage):
|
elif isinstance(msg, FlagDiedMessage):
|
||||||
assert isinstance(msg.flag, FootballFlag)
|
assert isinstance(msg.flag, FootballFlag)
|
||||||
msg.flag.respawn_timer = ba.Timer(3.0, self._spawn_flag)
|
msg.flag.respawn_timer = ba.Timer(3.0, self._spawn_flag)
|
||||||
self._flag_respawn_light = ba.NodeActor(
|
self._flag_respawn_light = ba.NodeActor(
|
||||||
|
|||||||
@ -28,6 +28,7 @@ from __future__ import annotations
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
import ba
|
import ba
|
||||||
|
from bastd.actor.playerspaz import PlayerSpaz
|
||||||
from bastd.actor.scoreboard import Scoreboard
|
from bastd.actor.scoreboard import Scoreboard
|
||||||
from bastd.actor.powerupbox import PowerupBoxFactory
|
from bastd.actor.powerupbox import PowerupBoxFactory
|
||||||
|
|
||||||
@ -243,15 +244,10 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]):
|
|||||||
self._update_scoreboard()
|
self._update_scoreboard()
|
||||||
|
|
||||||
def _handle_puck_player_collide(self) -> None:
|
def _handle_puck_player_collide(self) -> None:
|
||||||
try:
|
collision = ba.getcollision()
|
||||||
pucknode, playernode = ba.get_collision_info(
|
puck = collision.source_node.getdelegate(Puck)
|
||||||
'source_node', 'opposing_node')
|
player = collision.opposing_node.getdelegate(PlayerSpaz,
|
||||||
puck = pucknode.getdelegate()
|
True).getplayer(Player)
|
||||||
player = playernode.getdelegate().getplayer()
|
|
||||||
except Exception:
|
|
||||||
player = puck = None
|
|
||||||
assert isinstance(player, Player)
|
|
||||||
assert isinstance(puck, Puck)
|
|
||||||
if player and puck:
|
if player and puck:
|
||||||
puck.last_players_to_touch[player.team.id] = player
|
puck.last_players_to_touch[player.team.id] = player
|
||||||
|
|
||||||
@ -269,7 +265,7 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]):
|
|||||||
if self._puck.scored:
|
if self._puck.scored:
|
||||||
return
|
return
|
||||||
|
|
||||||
region = ba.get_collision_info('source_node')
|
region = ba.getcollision().source_node
|
||||||
index = 0
|
index = 0
|
||||||
for index in range(len(self._score_regions)):
|
for index in range(len(self._score_regions)):
|
||||||
if region == self._score_regions[index].node:
|
if region == self._score_regions[index].node:
|
||||||
@ -308,7 +304,7 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]):
|
|||||||
|
|
||||||
light = ba.newnode('light',
|
light = ba.newnode('light',
|
||||||
attrs={
|
attrs={
|
||||||
'position': ba.get_collision_info('position'),
|
'position': ba.getcollision().position,
|
||||||
'height_attenuated': False,
|
'height_attenuated': False,
|
||||||
'color': (1, 0, 0)
|
'color': (1, 0, 0)
|
||||||
})
|
})
|
||||||
|
|||||||
@ -247,10 +247,8 @@ class KingOfTheHillGame(ba.TeamGameActivity[Player, Team]):
|
|||||||
ba.playsound(self._swipsound)
|
ba.playsound(self._swipsound)
|
||||||
|
|
||||||
def _handle_player_flag_region_collide(self, colliding: bool) -> None:
|
def _handle_player_flag_region_collide(self, colliding: bool) -> None:
|
||||||
delegate = ba.get_collision_info('opposing_node').getdelegate()
|
player = ba.getcollision().opposing_node.getdelegate(
|
||||||
if not isinstance(delegate, PlayerSpaz):
|
PlayerSpaz, True).getplayer(Player)
|
||||||
return
|
|
||||||
player = delegate.getplayer(Player)
|
|
||||||
if not player:
|
if not player:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
@ -29,7 +29,7 @@ import random
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
import ba
|
import ba
|
||||||
from bastd.actor.spazbot import BotSet, ChargerBot, SpazBotDeathMessage
|
from bastd.actor.spazbot import SpazBotSet, ChargerBot, SpazBotDiedMessage
|
||||||
from bastd.actor.onscreentimer import OnScreenTimer
|
from bastd.actor.onscreentimer import OnScreenTimer
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
@ -76,7 +76,7 @@ class NinjaFightGame(ba.TeamGameActivity[Player, Team]):
|
|||||||
self._winsound = ba.getsound('score')
|
self._winsound = ba.getsound('score')
|
||||||
self._won = False
|
self._won = False
|
||||||
self._timer: Optional[OnScreenTimer] = None
|
self._timer: Optional[OnScreenTimer] = None
|
||||||
self._bots = BotSet()
|
self._bots = SpazBotSet()
|
||||||
|
|
||||||
# Called when our game is transitioning in but not ready to begin;
|
# Called when our game is transitioning in but not ready to begin;
|
||||||
# we can go ahead and start creating stuff, playing music, etc.
|
# we can go ahead and start creating stuff, playing music, etc.
|
||||||
@ -150,7 +150,7 @@ class NinjaFightGame(ba.TeamGameActivity[Player, Team]):
|
|||||||
self.respawn_player(msg.getplayer(Player))
|
self.respawn_player(msg.getplayer(Player))
|
||||||
|
|
||||||
# A spaz-bot has died.
|
# A spaz-bot has died.
|
||||||
elif isinstance(msg, SpazBotDeathMessage):
|
elif isinstance(msg, SpazBotDiedMessage):
|
||||||
# Unfortunately the bot-set will always tell us there are living
|
# Unfortunately the bot-set will always tell us there are living
|
||||||
# bots if we ask here (the currently-dying bot isn't officially
|
# bots if we ask here (the currently-dying bot isn't officially
|
||||||
# marked dead yet) ..so lets push a call into the event loop to
|
# marked dead yet) ..so lets push a call into the event loop to
|
||||||
|
|||||||
@ -39,7 +39,7 @@ from bastd.actor.scoreboard import Scoreboard
|
|||||||
from bastd.actor.controlsguide import ControlsGuide
|
from bastd.actor.controlsguide import ControlsGuide
|
||||||
from bastd.actor.powerupbox import PowerupBox, PowerupBoxFactory
|
from bastd.actor.powerupbox import PowerupBox, PowerupBoxFactory
|
||||||
from bastd.actor.spazbot import (
|
from bastd.actor.spazbot import (
|
||||||
SpazBotDeathMessage, BotSet, ChargerBot, StickyBot, BomberBot,
|
SpazBotDiedMessage, SpazBotSet, ChargerBot, StickyBot, BomberBot,
|
||||||
BomberBotLite, BrawlerBot, BrawlerBotLite, TriggerBot, BomberBotStaticLite,
|
BomberBotLite, BrawlerBot, BrawlerBotLite, TriggerBot, BomberBotStaticLite,
|
||||||
TriggerBotStatic, BomberBotProStatic, TriggerBotPro, ExplodeyBot,
|
TriggerBotStatic, BomberBotProStatic, TriggerBotPro, ExplodeyBot,
|
||||||
BrawlerBotProShielded, ChargerBotProShielded, BomberBotPro,
|
BrawlerBotProShielded, ChargerBotProShielded, BomberBotPro,
|
||||||
@ -189,7 +189,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
raise Exception('Unsupported map: ' + str(settings['map']))
|
raise Exception('Unsupported map: ' + str(settings['map']))
|
||||||
self._scoreboard: Optional[Scoreboard] = None
|
self._scoreboard: Optional[Scoreboard] = None
|
||||||
self._game_over = False
|
self._game_over = False
|
||||||
self._wave = 0
|
self._wavenum = 0
|
||||||
self._can_end_wave = True
|
self._can_end_wave = True
|
||||||
self._score = 0
|
self._score = 0
|
||||||
self._time_bonus = 0
|
self._time_bonus = 0
|
||||||
@ -200,7 +200,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
self._excluded_powerups: Optional[List[str]] = None
|
self._excluded_powerups: Optional[List[str]] = None
|
||||||
self._waves: List[Wave] = []
|
self._waves: List[Wave] = []
|
||||||
self._tntspawner: Optional[TNTSpawner] = None
|
self._tntspawner: Optional[TNTSpawner] = None
|
||||||
self._bots: Optional[BotSet] = None
|
self._bots: Optional[SpazBotSet] = None
|
||||||
self._powerup_drop_timer: Optional[ba.Timer] = None
|
self._powerup_drop_timer: Optional[ba.Timer] = None
|
||||||
self._time_bonus_timer: Optional[ba.Timer] = None
|
self._time_bonus_timer: Optional[ba.Timer] = None
|
||||||
self._time_bonus_text: Optional[ba.NodeActor] = None
|
self._time_bonus_text: Optional[ba.NodeActor] = None
|
||||||
@ -214,6 +214,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
def on_transition_in(self) -> None:
|
def on_transition_in(self) -> None:
|
||||||
super().on_transition_in()
|
super().on_transition_in()
|
||||||
session = ba.getsession()
|
session = ba.getsession()
|
||||||
|
|
||||||
# Show special landmine tip on rookie preset.
|
# Show special landmine tip on rookie preset.
|
||||||
if self._preset in {Preset.ROOKIE, Preset.ROOKIE_EASY}:
|
if self._preset in {Preset.ROOKIE, Preset.ROOKIE_EASY}:
|
||||||
# Show once per session only (then we revert to regular tips).
|
# Show once per session only (then we revert to regular tips).
|
||||||
@ -550,33 +551,28 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
|
|
||||||
self.setup_low_life_warning_sound()
|
self.setup_low_life_warning_sound()
|
||||||
self._update_scores()
|
self._update_scores()
|
||||||
self._bots = BotSet()
|
self._bots = SpazBotSet()
|
||||||
ba.timer(4.0, self._start_updating_waves)
|
ba.timer(4.0, self._start_updating_waves)
|
||||||
|
|
||||||
def _on_got_scores_to_beat(self, scores: List[Dict[str, Any]]) -> None:
|
def _on_got_scores_to_beat(self, scores: List[Dict[str, Any]]) -> None:
|
||||||
self._show_standard_scores_to_beat_ui(scores)
|
self._show_standard_scores_to_beat_ui(scores)
|
||||||
|
|
||||||
|
def _get_dist_grp_totals(self, grps: List[Any]) -> Tuple[int, int]:
|
||||||
|
totalpts = 0
|
||||||
|
totaldudes = 0
|
||||||
|
for grp in grps:
|
||||||
|
for grpentry in grp:
|
||||||
|
dudes = grpentry[1]
|
||||||
|
totalpts += grpentry[0] * dudes
|
||||||
|
totaldudes += dudes
|
||||||
|
return totalpts, totaldudes
|
||||||
|
|
||||||
def _get_distribution(self, target_points: int, min_dudes: int,
|
def _get_distribution(self, target_points: int, min_dudes: int,
|
||||||
max_dudes: int, group_count: int,
|
max_dudes: int, group_count: int,
|
||||||
max_level: int) -> List[List[Tuple[int, int]]]:
|
max_level: int) -> List[List[Tuple[int, int]]]:
|
||||||
""" calculate a distribution of bad guys given some params """
|
"""Calculate a distribution of bad guys given some params."""
|
||||||
# FIXME; This method wears the cone of shame
|
|
||||||
# pylint: disable=too-many-branches
|
|
||||||
# pylint: disable=too-many-statements
|
|
||||||
# pylint: disable=too-many-locals
|
|
||||||
# pylint: disable=too-many-nested-blocks
|
|
||||||
max_iterations = 10 + max_dudes * 2
|
max_iterations = 10 + max_dudes * 2
|
||||||
|
|
||||||
def _get_totals(grps: List[Any]) -> Tuple[int, int]:
|
|
||||||
totalpts = 0
|
|
||||||
totaldudes = 0
|
|
||||||
for grp in grps:
|
|
||||||
for grpentry in grp:
|
|
||||||
dudes = grpentry[1]
|
|
||||||
totalpts += grpentry[0] * dudes
|
|
||||||
totaldudes += dudes
|
|
||||||
return totalpts, totaldudes
|
|
||||||
|
|
||||||
groups: List[List[Tuple[int, int]]] = []
|
groups: List[List[Tuple[int, int]]] = []
|
||||||
for _g in range(group_count):
|
for _g in range(group_count):
|
||||||
groups.append([])
|
groups.append([])
|
||||||
@ -588,83 +584,29 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
if max_level > 3:
|
if max_level > 3:
|
||||||
types.append(4)
|
types.append(4)
|
||||||
for iteration in range(max_iterations):
|
for iteration in range(max_iterations):
|
||||||
|
diff = self._add_dist_entry_if_possible(groups, max_dudes,
|
||||||
|
target_points, types)
|
||||||
|
|
||||||
# See how much we're off our target by.
|
total_points, total_dudes = self._get_dist_grp_totals(groups)
|
||||||
total_points, total_dudes = _get_totals(groups)
|
|
||||||
diff = target_points - total_points
|
|
||||||
dudes_diff = max_dudes - total_dudes
|
|
||||||
|
|
||||||
# Add an entry if one will fit.
|
|
||||||
value = types[random.randrange(len(types))]
|
|
||||||
group = groups[random.randrange(len(groups))]
|
|
||||||
if not group:
|
|
||||||
max_count = random.randint(1, 6)
|
|
||||||
else:
|
|
||||||
max_count = 2 * random.randint(1, 3)
|
|
||||||
max_count = min(max_count, dudes_diff)
|
|
||||||
count = min(max_count, diff // value)
|
|
||||||
if count > 0:
|
|
||||||
group.append((value, count))
|
|
||||||
total_points += value * count
|
|
||||||
total_dudes += count
|
|
||||||
diff = target_points - total_points
|
|
||||||
|
|
||||||
total_points, total_dudes = _get_totals(groups)
|
|
||||||
full = (total_points >= target_points)
|
full = (total_points >= target_points)
|
||||||
|
|
||||||
if full:
|
if full:
|
||||||
# Every so often, delete a random entry just to
|
# Every so often, delete a random entry just to
|
||||||
# shake up our distribution.
|
# shake up our distribution.
|
||||||
if random.random() < 0.2 and iteration != max_iterations - 1:
|
if random.random() < 0.2 and iteration != max_iterations - 1:
|
||||||
entry_count = 0
|
self._delete_random_dist_entry(groups)
|
||||||
for group in groups:
|
|
||||||
for _ in group:
|
|
||||||
entry_count += 1
|
|
||||||
if entry_count > 1:
|
|
||||||
del_entry = random.randrange(entry_count)
|
|
||||||
entry_count = 0
|
|
||||||
for group in groups:
|
|
||||||
for entry in group:
|
|
||||||
if entry_count == del_entry:
|
|
||||||
group.remove(entry)
|
|
||||||
break
|
|
||||||
entry_count += 1
|
|
||||||
|
|
||||||
# If we don't have enough dudes, kill the group with
|
# If we don't have enough dudes, kill the group with
|
||||||
# the biggest point value.
|
# the biggest point value.
|
||||||
elif (total_dudes < min_dudes
|
elif (total_dudes < min_dudes
|
||||||
and iteration != max_iterations - 1):
|
and iteration != max_iterations - 1):
|
||||||
biggest_value = 9999
|
self._delete_biggest_dist_entry(groups)
|
||||||
biggest_entry = None
|
|
||||||
biggest_entry_group = None
|
|
||||||
for group in groups:
|
|
||||||
for entry in group:
|
|
||||||
if (entry[0] > biggest_value
|
|
||||||
or biggest_entry is None):
|
|
||||||
biggest_value = entry[0]
|
|
||||||
biggest_entry = entry
|
|
||||||
biggest_entry_group = group
|
|
||||||
if biggest_entry is not None:
|
|
||||||
assert biggest_entry_group is not None
|
|
||||||
biggest_entry_group.remove(biggest_entry)
|
|
||||||
|
|
||||||
# If we've got too many dudes, kill the group with the
|
# If we've got too many dudes, kill the group with the
|
||||||
# smallest point value.
|
# smallest point value.
|
||||||
elif (total_dudes > max_dudes
|
elif (total_dudes > max_dudes
|
||||||
and iteration != max_iterations - 1):
|
and iteration != max_iterations - 1):
|
||||||
smallest_value = 9999
|
self._delete_smallest_dist_entry(groups)
|
||||||
smallest_entry = None
|
|
||||||
smallest_entry_group = None
|
|
||||||
for group in groups:
|
|
||||||
for entry in group:
|
|
||||||
if (entry[0] < smallest_value
|
|
||||||
or smallest_entry is None):
|
|
||||||
smallest_value = entry[0]
|
|
||||||
smallest_entry = entry
|
|
||||||
smallest_entry_group = group
|
|
||||||
assert smallest_entry is not None
|
|
||||||
assert smallest_entry_group is not None
|
|
||||||
smallest_entry_group.remove(smallest_entry)
|
|
||||||
|
|
||||||
# Close enough.. we're done.
|
# Close enough.. we're done.
|
||||||
else:
|
else:
|
||||||
@ -673,6 +615,76 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
|
|
||||||
return groups
|
return groups
|
||||||
|
|
||||||
|
def _add_dist_entry_if_possible(self, groups: List[List[Tuple[int, int]]],
|
||||||
|
max_dudes: int, target_points: int,
|
||||||
|
types: List[int]) -> int:
|
||||||
|
# See how much we're off our target by.
|
||||||
|
total_points, total_dudes = self._get_dist_grp_totals(groups)
|
||||||
|
diff = target_points - total_points
|
||||||
|
dudes_diff = max_dudes - total_dudes
|
||||||
|
|
||||||
|
# Add an entry if one will fit.
|
||||||
|
value = types[random.randrange(len(types))]
|
||||||
|
group = groups[random.randrange(len(groups))]
|
||||||
|
if not group:
|
||||||
|
max_count = random.randint(1, 6)
|
||||||
|
else:
|
||||||
|
max_count = 2 * random.randint(1, 3)
|
||||||
|
max_count = min(max_count, dudes_diff)
|
||||||
|
count = min(max_count, diff // value)
|
||||||
|
if count > 0:
|
||||||
|
group.append((value, count))
|
||||||
|
total_points += value * count
|
||||||
|
total_dudes += count
|
||||||
|
diff = target_points - total_points
|
||||||
|
return diff
|
||||||
|
|
||||||
|
def _delete_smallest_dist_entry(
|
||||||
|
self, groups: List[List[Tuple[int, int]]]) -> None:
|
||||||
|
smallest_value = 9999
|
||||||
|
smallest_entry = None
|
||||||
|
smallest_entry_group = None
|
||||||
|
for group in groups:
|
||||||
|
for entry in group:
|
||||||
|
if entry[0] < smallest_value or smallest_entry is None:
|
||||||
|
smallest_value = entry[0]
|
||||||
|
smallest_entry = entry
|
||||||
|
smallest_entry_group = group
|
||||||
|
assert smallest_entry is not None
|
||||||
|
assert smallest_entry_group is not None
|
||||||
|
smallest_entry_group.remove(smallest_entry)
|
||||||
|
|
||||||
|
def _delete_biggest_dist_entry(
|
||||||
|
self, groups: List[List[Tuple[int, int]]]) -> None:
|
||||||
|
biggest_value = 9999
|
||||||
|
biggest_entry = None
|
||||||
|
biggest_entry_group = None
|
||||||
|
for group in groups:
|
||||||
|
for entry in group:
|
||||||
|
if entry[0] > biggest_value or biggest_entry is None:
|
||||||
|
biggest_value = entry[0]
|
||||||
|
biggest_entry = entry
|
||||||
|
biggest_entry_group = group
|
||||||
|
if biggest_entry is not None:
|
||||||
|
assert biggest_entry_group is not None
|
||||||
|
biggest_entry_group.remove(biggest_entry)
|
||||||
|
|
||||||
|
def _delete_random_dist_entry(self,
|
||||||
|
groups: List[List[Tuple[int, int]]]) -> None:
|
||||||
|
entry_count = 0
|
||||||
|
for group in groups:
|
||||||
|
for _ in group:
|
||||||
|
entry_count += 1
|
||||||
|
if entry_count > 1:
|
||||||
|
del_entry = random.randrange(entry_count)
|
||||||
|
entry_count = 0
|
||||||
|
for group in groups:
|
||||||
|
for entry in group:
|
||||||
|
if entry_count == del_entry:
|
||||||
|
group.remove(entry)
|
||||||
|
break
|
||||||
|
entry_count += 1
|
||||||
|
|
||||||
def spawn_player(self, player: Player) -> ba.Actor:
|
def spawn_player(self, player: Player) -> ba.Actor:
|
||||||
|
|
||||||
# We keep track of who got hurt each wave for score purposes.
|
# We keep track of who got hurt each wave for score purposes.
|
||||||
@ -734,7 +746,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
if outcome == 'defeat':
|
if outcome == 'defeat':
|
||||||
self.fade_to_red()
|
self.fade_to_red()
|
||||||
score: Optional[int]
|
score: Optional[int]
|
||||||
if self._wave >= 2:
|
if self._wavenum >= 2:
|
||||||
score = self._score
|
score = self._score
|
||||||
fail_message = None
|
fail_message = None
|
||||||
else:
|
else:
|
||||||
@ -777,7 +789,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
if self._preset in {Preset.ENDLESS, Preset.ENDLESS_TOURNAMENT}:
|
if self._preset in {Preset.ENDLESS, Preset.ENDLESS_TOURNAMENT}:
|
||||||
won = False
|
won = False
|
||||||
else:
|
else:
|
||||||
won = (self._wave == len(self._waves))
|
won = (self._wavenum == len(self._waves))
|
||||||
|
|
||||||
base_delay = 4.0 if won else 0.0
|
base_delay = 4.0 if won else 0.0
|
||||||
|
|
||||||
@ -789,7 +801,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
base_delay += 1.0
|
base_delay += 1.0
|
||||||
|
|
||||||
# Reward flawless bonus.
|
# Reward flawless bonus.
|
||||||
if self._wave > 0:
|
if self._wavenum > 0:
|
||||||
have_flawless = False
|
have_flawless = False
|
||||||
for player in self.players:
|
for player in self.players:
|
||||||
if player.is_alive() and not player.has_been_hurt:
|
if player.is_alive() and not player.has_been_hurt:
|
||||||
@ -806,9 +818,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
scale=1.0,
|
scale=1.0,
|
||||||
duration=4.0)
|
duration=4.0)
|
||||||
self.celebrate(20.0)
|
self.celebrate(20.0)
|
||||||
|
|
||||||
self._award_completion_achievements()
|
self._award_completion_achievements()
|
||||||
|
|
||||||
ba.timer(base_delay, ba.WeakCall(self._award_completion_bonus))
|
ba.timer(base_delay, ba.WeakCall(self._award_completion_bonus))
|
||||||
base_delay += 0.85
|
base_delay += 0.85
|
||||||
ba.playsound(self._winsound)
|
ba.playsound(self._winsound)
|
||||||
@ -822,10 +832,10 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
ba.timer(base_delay, ba.WeakCall(self.do_end, 'victory'))
|
ba.timer(base_delay, ba.WeakCall(self.do_end, 'victory'))
|
||||||
return
|
return
|
||||||
|
|
||||||
self._wave += 1
|
self._wavenum += 1
|
||||||
|
|
||||||
# Short celebration after waves.
|
# Short celebration after waves.
|
||||||
if self._wave > 1:
|
if self._wavenum > 1:
|
||||||
self.celebrate(0.5)
|
self.celebrate(0.5)
|
||||||
ba.timer(base_delay, ba.WeakCall(self._start_next_wave))
|
ba.timer(base_delay, ba.WeakCall(self._start_next_wave))
|
||||||
|
|
||||||
@ -903,17 +913,17 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
|
|
||||||
def _respawn_players_for_wave(self) -> None:
|
def _respawn_players_for_wave(self) -> None:
|
||||||
# Respawn applicable players.
|
# Respawn applicable players.
|
||||||
if self._wave > 1 and not self.is_waiting_for_continue():
|
if self._wavenum > 1 and not self.is_waiting_for_continue():
|
||||||
for player in self.players:
|
for player in self.players:
|
||||||
if (not player.is_alive()
|
if (not player.is_alive()
|
||||||
and player.respawn_wave == self._wave):
|
and player.respawn_wave == self._wavenum):
|
||||||
self.spawn_player(player)
|
self.spawn_player(player)
|
||||||
self._update_player_spawn_info()
|
self._update_player_spawn_info()
|
||||||
|
|
||||||
def _setup_wave_spawns(self, wave: Wave) -> None:
|
def _setup_wave_spawns(self, wave: Wave) -> None:
|
||||||
tval = 0.0
|
tval = 0.0
|
||||||
dtime = 0.2
|
dtime = 0.2
|
||||||
if self._wave == 1:
|
if self._wavenum == 1:
|
||||||
spawn_time = 3.973
|
spawn_time = 3.973
|
||||||
tval += 0.5
|
tval += 0.5
|
||||||
else:
|
else:
|
||||||
@ -970,7 +980,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
if self._preset in {Preset.ENDLESS, Preset.ENDLESS_TOURNAMENT}:
|
if self._preset in {Preset.ENDLESS, Preset.ENDLESS_TOURNAMENT}:
|
||||||
wave = self._generate_random_wave()
|
wave = self._generate_random_wave()
|
||||||
else:
|
else:
|
||||||
wave = self._waves[self._wave - 1]
|
wave = self._waves[self._wavenum - 1]
|
||||||
self._setup_wave_spawns(wave)
|
self._setup_wave_spawns(wave)
|
||||||
self._update_wave_ui_and_bonuses()
|
self._update_wave_ui_and_bonuses()
|
||||||
ba.timer(0.4, ba.Call(ba.playsound, self._new_wave_sound))
|
ba.timer(0.4, ba.Call(ba.playsound, self._new_wave_sound))
|
||||||
@ -980,7 +990,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
self.show_zoom_message(ba.Lstr(value='${A} ${B}',
|
self.show_zoom_message(ba.Lstr(value='${A} ${B}',
|
||||||
subs=[('${A}',
|
subs=[('${A}',
|
||||||
ba.Lstr(resource='waveText')),
|
ba.Lstr(resource='waveText')),
|
||||||
('${B}', str(self._wave))]),
|
('${B}', str(self._wavenum))]),
|
||||||
scale=1.0,
|
scale=1.0,
|
||||||
duration=1.0,
|
duration=1.0,
|
||||||
trail=True)
|
trail=True)
|
||||||
@ -1012,7 +1022,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
wttxt = ba.Lstr(
|
wttxt = ba.Lstr(
|
||||||
value='${A} ${B}',
|
value='${A} ${B}',
|
||||||
subs=[('${A}', ba.Lstr(resource='waveText')),
|
subs=[('${A}', ba.Lstr(resource='waveText')),
|
||||||
('${B}', str(self._wave) +
|
('${B}', str(self._wavenum) +
|
||||||
('' if self._preset
|
('' if self._preset
|
||||||
in [Preset.ENDLESS, Preset.ENDLESS_TOURNAMENT] else
|
in [Preset.ENDLESS, Preset.ENDLESS_TOURNAMENT] else
|
||||||
('/' + str(len(self._waves)))))])
|
('/' + str(len(self._waves)))))])
|
||||||
@ -1032,7 +1042,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
def _bot_levels_for_wave(self) -> List[List[Type[SpazBot]]]:
|
def _bot_levels_for_wave(self) -> List[List[Type[SpazBot]]]:
|
||||||
level = self._wave
|
level = self._wavenum
|
||||||
bot_types = [
|
bot_types = [
|
||||||
BomberBot, BrawlerBot, TriggerBot, ChargerBot, BomberBotPro,
|
BomberBot, BrawlerBot, TriggerBot, ChargerBot, BomberBotPro,
|
||||||
BrawlerBotPro, TriggerBotPro, BomberBotProShielded, ExplodeyBot,
|
BrawlerBotPro, TriggerBotPro, BomberBotProShielded, ExplodeyBot,
|
||||||
@ -1067,6 +1077,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
[b for b in bot_types if b.points_mult == 2],
|
[b for b in bot_types if b.points_mult == 2],
|
||||||
[b for b in bot_types if b.points_mult == 3],
|
[b for b in bot_types if b.points_mult == 3],
|
||||||
[b for b in bot_types if b.points_mult == 4]]
|
[b for b in bot_types if b.points_mult == 4]]
|
||||||
|
|
||||||
# Make sure all lists have something in them
|
# Make sure all lists have something in them
|
||||||
if not all(bot_levels):
|
if not all(bot_levels):
|
||||||
raise RuntimeError('Got empty bot level')
|
raise RuntimeError('Got empty bot level')
|
||||||
@ -1099,7 +1110,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
Spacing(40.0 if random.random() < 0.5 else 80.0))
|
Spacing(40.0 if random.random() < 0.5 else 80.0))
|
||||||
|
|
||||||
def _generate_random_wave(self) -> Wave:
|
def _generate_random_wave(self) -> Wave:
|
||||||
level = self._wave
|
level = self._wavenum
|
||||||
bot_levels = self._bot_levels_for_wave()
|
bot_levels = self._bot_levels_for_wave()
|
||||||
|
|
||||||
target_points = level * 3 - 2
|
target_points = level * 3 - 2
|
||||||
@ -1199,20 +1210,19 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
self._a_player_has_been_hurt = True
|
self._a_player_has_been_hurt = True
|
||||||
|
|
||||||
# Make note with the player when they can respawn:
|
# Make note with the player when they can respawn:
|
||||||
if self._wave < 10:
|
if self._wavenum < 10:
|
||||||
player.respawn_wave = max(2, self._wave + 1)
|
player.respawn_wave = max(2, self._wavenum + 1)
|
||||||
elif self._wave < 15:
|
elif self._wavenum < 15:
|
||||||
player.respawn_wave = max(2, self._wave + 2)
|
player.respawn_wave = max(2, self._wavenum + 2)
|
||||||
else:
|
else:
|
||||||
player.respawn_wave = max(2, self._wave + 3)
|
player.respawn_wave = max(2, self._wavenum + 3)
|
||||||
ba.timer(0.1, self._update_player_spawn_info)
|
ba.timer(0.1, self._update_player_spawn_info)
|
||||||
ba.timer(0.1, self._checkroundover)
|
ba.timer(0.1, self._checkroundover)
|
||||||
|
|
||||||
elif isinstance(msg, SpazBotDeathMessage):
|
elif isinstance(msg, SpazBotDiedMessage):
|
||||||
pts, importance = msg.badguy.get_death_points(msg.how)
|
pts, importance = msg.badguy.get_death_points(msg.how)
|
||||||
if msg.killerplayer is not None:
|
if msg.killerplayer is not None:
|
||||||
self._handle_kill_achievements(msg)
|
self._handle_kill_achievements(msg)
|
||||||
|
|
||||||
target: Optional[Sequence[float]]
|
target: Optional[Sequence[float]]
|
||||||
try:
|
try:
|
||||||
assert msg.badguy.node
|
assert msg.badguy.node
|
||||||
@ -1242,47 +1252,57 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
else:
|
else:
|
||||||
super().handlemessage(msg)
|
super().handlemessage(msg)
|
||||||
|
|
||||||
def _handle_kill_achievements(self, msg: SpazBotDeathMessage) -> None:
|
def _handle_kill_achievements(self, msg: SpazBotDiedMessage) -> None:
|
||||||
# pylint: disable=too-many-branches
|
|
||||||
# Toss-off-map achievement:
|
|
||||||
if self._preset in {Preset.TRAINING, Preset.TRAINING_EASY}:
|
if self._preset in {Preset.TRAINING, Preset.TRAINING_EASY}:
|
||||||
if msg.badguy.last_attacked_type == ('picked_up', 'default'):
|
self._handle_training_kill_achievements(msg)
|
||||||
self._throw_off_kills += 1
|
|
||||||
if self._throw_off_kills >= 3:
|
|
||||||
self._award_achievement('Off You Go Then')
|
|
||||||
|
|
||||||
# Land-mine achievement:
|
|
||||||
elif self._preset in {Preset.ROOKIE, Preset.ROOKIE_EASY}:
|
elif self._preset in {Preset.ROOKIE, Preset.ROOKIE_EASY}:
|
||||||
if msg.badguy.last_attacked_type == ('explosion', 'land_mine'):
|
self._handle_rookie_kill_achievements(msg)
|
||||||
self._land_mine_kills += 1
|
elif self._preset in {Preset.PRO, Preset.PRO_EASY}:
|
||||||
if self._land_mine_kills >= 3:
|
self._handle_pro_kill_achievements(msg)
|
||||||
self._award_achievement('Mine Games')
|
elif self._preset in {Preset.UBER, Preset.UBER_EASY}:
|
||||||
|
self._handle_uber_kill_achievements(msg)
|
||||||
|
|
||||||
|
def _handle_uber_kill_achievements(self, msg: SpazBotDiedMessage) -> None:
|
||||||
|
|
||||||
|
# Uber mine achievement:
|
||||||
|
if msg.badguy.last_attacked_type == ('explosion', 'land_mine'):
|
||||||
|
self._land_mine_kills += 1
|
||||||
|
if self._land_mine_kills >= 6:
|
||||||
|
self._award_achievement('Gold Miner')
|
||||||
|
|
||||||
|
# Uber tnt achievement:
|
||||||
|
if msg.badguy.last_attacked_type == ('explosion', 'tnt'):
|
||||||
|
self._tnt_kills += 1
|
||||||
|
if self._tnt_kills >= 6:
|
||||||
|
ba.timer(0.5, ba.WeakCall(self._award_achievement,
|
||||||
|
'TNT Terror'))
|
||||||
|
|
||||||
|
def _handle_pro_kill_achievements(self, msg: SpazBotDiedMessage) -> None:
|
||||||
|
|
||||||
# TNT achievement:
|
# TNT achievement:
|
||||||
elif self._preset in {Preset.PRO, Preset.PRO_EASY}:
|
if msg.badguy.last_attacked_type == ('explosion', 'tnt'):
|
||||||
if msg.badguy.last_attacked_type == ('explosion', 'tnt'):
|
self._tnt_kills += 1
|
||||||
self._tnt_kills += 1
|
if self._tnt_kills >= 3:
|
||||||
if self._tnt_kills >= 3:
|
ba.timer(
|
||||||
ba.timer(
|
0.5,
|
||||||
0.5,
|
ba.WeakCall(self._award_achievement,
|
||||||
ba.WeakCall(self._award_achievement,
|
'Boom Goes the Dynamite'))
|
||||||
'Boom Goes the Dynamite'))
|
|
||||||
|
|
||||||
elif self._preset in {Preset.UBER, Preset.UBER_EASY}:
|
def _handle_rookie_kill_achievements(self,
|
||||||
|
msg: SpazBotDiedMessage) -> None:
|
||||||
|
# Land-mine achievement:
|
||||||
|
if msg.badguy.last_attacked_type == ('explosion', 'land_mine'):
|
||||||
|
self._land_mine_kills += 1
|
||||||
|
if self._land_mine_kills >= 3:
|
||||||
|
self._award_achievement('Mine Games')
|
||||||
|
|
||||||
# Uber mine achievement:
|
def _handle_training_kill_achievements(self,
|
||||||
if msg.badguy.last_attacked_type == ('explosion', 'land_mine'):
|
msg: SpazBotDiedMessage) -> None:
|
||||||
self._land_mine_kills += 1
|
# Toss-off-map achievement:
|
||||||
if self._land_mine_kills >= 6:
|
if msg.badguy.last_attacked_type == ('picked_up', 'default'):
|
||||||
self._award_achievement('Gold Miner')
|
self._throw_off_kills += 1
|
||||||
|
if self._throw_off_kills >= 3:
|
||||||
# Uber tnt achievement:
|
self._award_achievement('Off You Go Then')
|
||||||
if msg.badguy.last_attacked_type == ('explosion', 'tnt'):
|
|
||||||
self._tnt_kills += 1
|
|
||||||
if self._tnt_kills >= 6:
|
|
||||||
ba.timer(
|
|
||||||
0.5, ba.WeakCall(self._award_achievement,
|
|
||||||
'TNT Terror'))
|
|
||||||
|
|
||||||
def _set_can_end_wave(self) -> None:
|
def _set_can_end_wave(self) -> None:
|
||||||
self._can_end_wave = True
|
self._can_end_wave = True
|
||||||
@ -1308,7 +1328,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
return
|
return
|
||||||
if not any(player.is_alive() for player in self.teams[0].players):
|
if not any(player.is_alive() for player in self.teams[0].players):
|
||||||
# Allow continuing after wave 1.
|
# Allow continuing after wave 1.
|
||||||
if self._wave > 1:
|
if self._wavenum > 1:
|
||||||
self.continue_or_end_game()
|
self.continue_or_end_game()
|
||||||
else:
|
else:
|
||||||
self.end_game()
|
self.end_game()
|
||||||
|
|||||||
@ -226,17 +226,13 @@ class RaceGame(ba.TeamGameActivity[Player, Team]):
|
|||||||
# pylint: disable=too-many-statements
|
# pylint: disable=too-many-statements
|
||||||
# pylint: disable=too-many-branches
|
# pylint: disable=too-many-branches
|
||||||
# pylint: disable=too-many-nested-blocks
|
# pylint: disable=too-many-nested-blocks
|
||||||
region_node, playernode = ba.get_collision_info(
|
collision = ba.getcollision()
|
||||||
'source_node', 'opposing_node')
|
region = collision.source_node.getdelegate(RaceRegion)
|
||||||
try:
|
playerspaz = collision.opposing_node.getdelegate(PlayerSpaz,
|
||||||
player = playernode.getdelegate().getplayer()
|
doraise=False)
|
||||||
except Exception:
|
player = playerspaz.getplayer(Player) if playerspaz else None
|
||||||
player = None
|
|
||||||
region = region_node.getdelegate()
|
|
||||||
if not player or not region:
|
if not player or not region:
|
||||||
return
|
return
|
||||||
assert isinstance(player, Player)
|
|
||||||
assert isinstance(region, RaceRegion)
|
|
||||||
|
|
||||||
last_region = player.last_region
|
last_region = player.last_region
|
||||||
this_region = region.index
|
this_region = region.index
|
||||||
|
|||||||
@ -29,11 +29,16 @@ import random
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
import ba
|
import ba
|
||||||
from bastd.actor import spazbot
|
from bastd.actor.popuptext import PopupText
|
||||||
from bastd.actor.bomb import TNTSpawner
|
from bastd.actor.bomb import TNTSpawner
|
||||||
from bastd.actor.scoreboard import Scoreboard
|
from bastd.actor.scoreboard import Scoreboard
|
||||||
from bastd.actor.respawnicon import RespawnIcon
|
from bastd.actor.respawnicon import RespawnIcon
|
||||||
from bastd.actor.powerupbox import PowerupBox, PowerupBoxFactory
|
from bastd.actor.powerupbox import PowerupBox, PowerupBoxFactory
|
||||||
|
from bastd.actor.spazbot import (
|
||||||
|
SpazBotSet, SpazBot, SpazBotDiedMessage, BomberBot, BrawlerBot, TriggerBot,
|
||||||
|
TriggerBotPro, BomberBotProShielded, TriggerBotProShielded, ChargerBot,
|
||||||
|
ChargerBotProShielded, StickyBot, ExplodeyBot, BrawlerBotProShielded,
|
||||||
|
BomberBotPro, BrawlerBotPro)
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from typing import Type, Any, List, Dict, Tuple, Sequence, Optional
|
from typing import Type, Any, List, Dict, Tuple, Sequence, Optional
|
||||||
@ -57,22 +62,23 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
'No, you can\'t get up on the ledge. You have to throw bombs.',
|
'No, you can\'t get up on the ledge. You have to throw bombs.',
|
||||||
'Whip back and forth to get more distance on your throws..'
|
'Whip back and forth to get more distance on your throws..'
|
||||||
]
|
]
|
||||||
|
default_music = ba.MusicType.MARCHING
|
||||||
|
|
||||||
# How fast our various bot types walk.
|
# How fast our various bot types walk.
|
||||||
_bot_speed_map: Dict[Type[spazbot.SpazBot], float] = {
|
_bot_speed_map: Dict[Type[SpazBot], float] = {
|
||||||
spazbot.BomberBot: 0.48,
|
BomberBot: 0.48,
|
||||||
spazbot.BomberBotPro: 0.48,
|
BomberBotPro: 0.48,
|
||||||
spazbot.BomberBotProShielded: 0.48,
|
BomberBotProShielded: 0.48,
|
||||||
spazbot.BrawlerBot: 0.57,
|
BrawlerBot: 0.57,
|
||||||
spazbot.BrawlerBotPro: 0.57,
|
BrawlerBotPro: 0.57,
|
||||||
spazbot.BrawlerBotProShielded: 0.57,
|
BrawlerBotProShielded: 0.57,
|
||||||
spazbot.TriggerBot: 0.73,
|
TriggerBot: 0.73,
|
||||||
spazbot.TriggerBotPro: 0.78,
|
TriggerBotPro: 0.78,
|
||||||
spazbot.TriggerBotProShielded: 0.78,
|
TriggerBotProShielded: 0.78,
|
||||||
spazbot.ChargerBot: 1.0,
|
ChargerBot: 1.0,
|
||||||
spazbot.ChargerBotProShielded: 1.0,
|
ChargerBotProShielded: 1.0,
|
||||||
spazbot.ExplodeyBot: 1.0,
|
ExplodeyBot: 1.0,
|
||||||
spazbot.StickyBot: 0.5
|
StickyBot: 0.5
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, settings: Dict[str, Any]):
|
def __init__(self, settings: Dict[str, Any]):
|
||||||
@ -108,7 +114,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
self._player_has_picked_up_powerup = False
|
self._player_has_picked_up_powerup = False
|
||||||
self._scoreboard: Optional[Scoreboard] = None
|
self._scoreboard: Optional[Scoreboard] = None
|
||||||
self._game_over = False
|
self._game_over = False
|
||||||
self._wave = 0
|
self._wavenum = 0
|
||||||
self._can_end_wave = True
|
self._can_end_wave = True
|
||||||
self._score = 0
|
self._score = 0
|
||||||
self._time_bonus = 0
|
self._time_bonus = 0
|
||||||
@ -118,7 +124,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
self._exclude_powerups: Optional[List[str]] = None
|
self._exclude_powerups: Optional[List[str]] = None
|
||||||
self._have_tnt: Optional[bool] = None
|
self._have_tnt: Optional[bool] = None
|
||||||
self._waves: Optional[List[Dict[str, Any]]] = None
|
self._waves: Optional[List[Dict[str, Any]]] = None
|
||||||
self._bots = spazbot.BotSet()
|
self._bots = SpazBotSet()
|
||||||
self._tntspawner: Optional[TNTSpawner] = None
|
self._tntspawner: Optional[TNTSpawner] = None
|
||||||
self._lives_bg: Optional[ba.NodeActor] = None
|
self._lives_bg: Optional[ba.NodeActor] = None
|
||||||
self._start_lives = 10
|
self._start_lives = 10
|
||||||
@ -133,7 +139,6 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
self._wave_update_timer: Optional[ba.Timer] = None
|
self._wave_update_timer: Optional[ba.Timer] = None
|
||||||
|
|
||||||
def on_transition_in(self) -> None:
|
def on_transition_in(self) -> None:
|
||||||
self.default_music = ba.MusicType.MARCHING
|
|
||||||
super().on_transition_in()
|
super().on_transition_in()
|
||||||
self._scoreboard = Scoreboard(label=ba.Lstr(resource='scoreText'),
|
self._scoreboard = Scoreboard(label=ba.Lstr(resource='scoreText'),
|
||||||
score_split=0.5)
|
score_split=0.5)
|
||||||
@ -157,110 +162,110 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
self._have_tnt = True
|
self._have_tnt = True
|
||||||
self._waves = [
|
self._waves = [
|
||||||
{'entries': [
|
{'entries': [
|
||||||
{'type': spazbot.BomberBot, 'path': 3 if hard else 2},
|
{'type': BomberBot, 'path': 3 if hard else 2},
|
||||||
{'type': spazbot.BomberBot, 'path': 2},
|
{'type': BomberBot, 'path': 2},
|
||||||
{'type': spazbot.BomberBot, 'path': 2} if hard else None,
|
{'type': BomberBot, 'path': 2} if hard else None,
|
||||||
{'type': spazbot.BomberBot, 'path': 2} if player_count > 1
|
{'type': BomberBot, 'path': 2} if player_count > 1
|
||||||
else None,
|
else None,
|
||||||
{'type': spazbot.BomberBot, 'path': 1} if hard else None,
|
{'type': BomberBot, 'path': 1} if hard else None,
|
||||||
{'type': spazbot.BomberBot, 'path': 1} if player_count > 2
|
{'type': BomberBot, 'path': 1} if player_count > 2
|
||||||
else None,
|
else None,
|
||||||
{'type': spazbot.BomberBot, 'path': 1} if player_count > 3
|
{'type': BomberBot, 'path': 1} if player_count > 3
|
||||||
else None,
|
else None,
|
||||||
]},
|
]},
|
||||||
{'entries': [
|
{'entries': [
|
||||||
{'type': spazbot.BomberBot, 'path': 1} if hard else None,
|
{'type': BomberBot, 'path': 1} if hard else None,
|
||||||
{'type': spazbot.BomberBot, 'path': 2} if hard else None,
|
{'type': BomberBot, 'path': 2} if hard else None,
|
||||||
{'type': spazbot.BomberBot, 'path': 2},
|
{'type': BomberBot, 'path': 2},
|
||||||
{'type': spazbot.BomberBot, 'path': 2},
|
{'type': BomberBot, 'path': 2},
|
||||||
{'type': spazbot.BomberBot, 'path': 2} if player_count > 3
|
{'type': BomberBot, 'path': 2} if player_count > 3
|
||||||
else None,
|
else None,
|
||||||
{'type': spazbot.BrawlerBot, 'path': 3},
|
{'type': BrawlerBot, 'path': 3},
|
||||||
{'type': spazbot.BrawlerBot, 'path': 3},
|
{'type': BrawlerBot, 'path': 3},
|
||||||
{'type': spazbot.BrawlerBot, 'path': 3} if hard else None,
|
{'type': BrawlerBot, 'path': 3} if hard else None,
|
||||||
{'type': spazbot.BrawlerBot, 'path': 3} if player_count > 1
|
{'type': BrawlerBot, 'path': 3} if player_count > 1
|
||||||
else None,
|
else None,
|
||||||
{'type': spazbot.BrawlerBot, 'path': 3} if player_count > 2
|
{'type': BrawlerBot, 'path': 3} if player_count > 2
|
||||||
else None,
|
else None,
|
||||||
]},
|
]},
|
||||||
{'entries': [
|
{'entries': [
|
||||||
{'type': spazbot.ChargerBot, 'path': 2} if hard else None,
|
{'type': ChargerBot, 'path': 2} if hard else None,
|
||||||
{'type': spazbot.ChargerBot, 'path': 2} if player_count > 2
|
{'type': ChargerBot, 'path': 2} if player_count > 2
|
||||||
else None,
|
else None,
|
||||||
{'type': spazbot.TriggerBot, 'path': 2},
|
{'type': TriggerBot, 'path': 2},
|
||||||
{'type': spazbot.TriggerBot, 'path': 2} if player_count > 1
|
{'type': TriggerBot, 'path': 2} if player_count > 1
|
||||||
else None,
|
else None,
|
||||||
{'type': 'spacing', 'duration': 3.0},
|
{'type': 'spacing', 'duration': 3.0},
|
||||||
{'type': spazbot.BomberBot, 'path': 2} if hard else None,
|
{'type': BomberBot, 'path': 2} if hard else None,
|
||||||
{'type': spazbot.BomberBot, 'path': 2} if hard else None,
|
{'type': BomberBot, 'path': 2} if hard else None,
|
||||||
{'type': spazbot.BomberBot, 'path': 2},
|
{'type': BomberBot, 'path': 2},
|
||||||
{'type': spazbot.BomberBot, 'path': 3} if hard else None,
|
{'type': BomberBot, 'path': 3} if hard else None,
|
||||||
{'type': spazbot.BomberBot, 'path': 3},
|
{'type': BomberBot, 'path': 3},
|
||||||
{'type': spazbot.BomberBot, 'path': 3},
|
{'type': BomberBot, 'path': 3},
|
||||||
{'type': spazbot.BomberBot, 'path': 3} if player_count > 3
|
{'type': BomberBot, 'path': 3} if player_count > 3
|
||||||
else None,
|
else None,
|
||||||
]},
|
]},
|
||||||
{'entries': [
|
{'entries': [
|
||||||
{'type': spazbot.TriggerBot, 'path': 1} if hard else None,
|
{'type': TriggerBot, 'path': 1} if hard else None,
|
||||||
{'type': 'spacing', 'duration': 1.0} if hard else None,
|
{'type': 'spacing', 'duration': 1.0} if hard else None,
|
||||||
{'type': spazbot.TriggerBot, 'path': 2},
|
{'type': TriggerBot, 'path': 2},
|
||||||
{'type': 'spacing', 'duration': 1.0},
|
{'type': 'spacing', 'duration': 1.0},
|
||||||
{'type': spazbot.TriggerBot, 'path': 3},
|
{'type': TriggerBot, 'path': 3},
|
||||||
{'type': 'spacing', 'duration': 1.0},
|
{'type': 'spacing', 'duration': 1.0},
|
||||||
{'type': spazbot.TriggerBot, 'path': 1} if hard else None,
|
{'type': TriggerBot, 'path': 1} if hard else None,
|
||||||
{'type': 'spacing', 'duration': 1.0} if hard else None,
|
{'type': 'spacing', 'duration': 1.0} if hard else None,
|
||||||
{'type': spazbot.TriggerBot, 'path': 2},
|
{'type': TriggerBot, 'path': 2},
|
||||||
{'type': 'spacing', 'duration': 1.0},
|
{'type': 'spacing', 'duration': 1.0},
|
||||||
{'type': spazbot.TriggerBot, 'path': 3},
|
{'type': TriggerBot, 'path': 3},
|
||||||
{'type': 'spacing', 'duration': 1.0},
|
{'type': 'spacing', 'duration': 1.0},
|
||||||
{'type': spazbot.TriggerBot, 'path': 1}
|
{'type': TriggerBot, 'path': 1}
|
||||||
if (player_count > 1 and hard) else None,
|
if (player_count > 1 and hard) else None,
|
||||||
{'type': 'spacing', 'duration': 1.0},
|
{'type': 'spacing', 'duration': 1.0},
|
||||||
{'type': spazbot.TriggerBot, 'path': 2} if player_count > 2
|
{'type': TriggerBot, 'path': 2} if player_count > 2
|
||||||
else None,
|
else None,
|
||||||
{'type': 'spacing', 'duration': 1.0},
|
{'type': 'spacing', 'duration': 1.0},
|
||||||
{'type': spazbot.TriggerBot, 'path': 3} if player_count > 3
|
{'type': TriggerBot, 'path': 3} if player_count > 3
|
||||||
else None,
|
else None,
|
||||||
{'type': 'spacing', 'duration': 1.0},
|
{'type': 'spacing', 'duration': 1.0},
|
||||||
]},
|
]},
|
||||||
{'entries': [
|
{'entries': [
|
||||||
{'type': spazbot.ChargerBotProShielded if hard
|
{'type': ChargerBotProShielded if hard
|
||||||
else spazbot.ChargerBot, 'path': 1},
|
else ChargerBot, 'path': 1},
|
||||||
{'type': spazbot.BrawlerBot, 'path': 2} if hard else None,
|
{'type': BrawlerBot, 'path': 2} if hard else None,
|
||||||
{'type': spazbot.BrawlerBot, 'path': 2},
|
{'type': BrawlerBot, 'path': 2},
|
||||||
{'type': spazbot.BrawlerBot, 'path': 2},
|
{'type': BrawlerBot, 'path': 2},
|
||||||
{'type': spazbot.BrawlerBot, 'path': 3} if hard else None,
|
{'type': BrawlerBot, 'path': 3} if hard else None,
|
||||||
{'type': spazbot.BrawlerBot, 'path': 3},
|
{'type': BrawlerBot, 'path': 3},
|
||||||
{'type': spazbot.BrawlerBot, 'path': 3},
|
{'type': BrawlerBot, 'path': 3},
|
||||||
{'type': spazbot.BrawlerBot, 'path': 3} if player_count > 1
|
{'type': BrawlerBot, 'path': 3} if player_count > 1
|
||||||
else None,
|
else None,
|
||||||
{'type': spazbot.BrawlerBot, 'path': 3} if player_count > 2
|
{'type': BrawlerBot, 'path': 3} if player_count > 2
|
||||||
else None,
|
else None,
|
||||||
{'type': spazbot.BrawlerBot, 'path': 3} if player_count > 3
|
{'type': BrawlerBot, 'path': 3} if player_count > 3
|
||||||
else None,
|
else None,
|
||||||
]},
|
]},
|
||||||
{'entries': [
|
{'entries': [
|
||||||
{'type': spazbot.BomberBotProShielded, 'path': 3},
|
{'type': BomberBotProShielded, 'path': 3},
|
||||||
{'type': 'spacing', 'duration': 1.5},
|
{'type': 'spacing', 'duration': 1.5},
|
||||||
{'type': spazbot.BomberBotProShielded, 'path': 2},
|
{'type': BomberBotProShielded, 'path': 2},
|
||||||
{'type': 'spacing', 'duration': 1.5},
|
{'type': 'spacing', 'duration': 1.5},
|
||||||
{'type': spazbot.BomberBotProShielded, 'path': 1} if hard
|
{'type': BomberBotProShielded, 'path': 1} if hard
|
||||||
else None,
|
else None,
|
||||||
{'type': 'spacing', 'duration': 1.0} if hard else None,
|
{'type': 'spacing', 'duration': 1.0} if hard else None,
|
||||||
{'type': spazbot.BomberBotProShielded, 'path': 3},
|
{'type': BomberBotProShielded, 'path': 3},
|
||||||
{'type': 'spacing', 'duration': 1.5},
|
{'type': 'spacing', 'duration': 1.5},
|
||||||
{'type': spazbot.BomberBotProShielded, 'path': 2},
|
{'type': BomberBotProShielded, 'path': 2},
|
||||||
{'type': 'spacing', 'duration': 1.5},
|
{'type': 'spacing', 'duration': 1.5},
|
||||||
{'type': spazbot.BomberBotProShielded, 'path': 1} if hard
|
{'type': BomberBotProShielded, 'path': 1} if hard
|
||||||
else None,
|
else None,
|
||||||
{'type': 'spacing', 'duration': 1.5} if hard else None,
|
{'type': 'spacing', 'duration': 1.5} if hard else None,
|
||||||
{'type': spazbot.BomberBotProShielded, 'path': 3}
|
{'type': BomberBotProShielded, 'path': 3}
|
||||||
if player_count > 1 else None,
|
if player_count > 1 else None,
|
||||||
{'type': 'spacing', 'duration': 1.5},
|
{'type': 'spacing', 'duration': 1.5},
|
||||||
{'type': spazbot.BomberBotProShielded, 'path': 2}
|
{'type': BomberBotProShielded, 'path': 2}
|
||||||
if player_count > 2 else None,
|
if player_count > 2 else None,
|
||||||
{'type': 'spacing', 'duration': 1.5},
|
{'type': 'spacing', 'duration': 1.5},
|
||||||
{'type': spazbot.BomberBotProShielded, 'path': 1}
|
{'type': BomberBotProShielded, 'path': 1}
|
||||||
if player_count > 3 else None,
|
if player_count > 3 else None,
|
||||||
]},
|
]},
|
||||||
] # yapf: disable
|
] # yapf: disable
|
||||||
@ -269,84 +274,84 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
self._have_tnt = True
|
self._have_tnt = True
|
||||||
self._waves = [
|
self._waves = [
|
||||||
{'entries': [
|
{'entries': [
|
||||||
{'type': spazbot.TriggerBot, 'path': 1} if hard else None,
|
{'type': TriggerBot, 'path': 1} if hard else None,
|
||||||
{'type': spazbot.TriggerBot, 'path': 2},
|
{'type': TriggerBot, 'path': 2},
|
||||||
{'type': spazbot.TriggerBot, 'path': 2},
|
{'type': TriggerBot, 'path': 2},
|
||||||
{'type': spazbot.TriggerBot, 'path': 3},
|
{'type': TriggerBot, 'path': 3},
|
||||||
{'type': spazbot.BrawlerBotPro if hard
|
{'type': BrawlerBotPro if hard
|
||||||
else spazbot.BrawlerBot, 'point': 'bottom_left'},
|
else BrawlerBot, 'point': 'bottom_left'},
|
||||||
{'type': spazbot.BrawlerBotPro, 'point': 'bottom_right'}
|
{'type': BrawlerBotPro, 'point': 'bottom_right'}
|
||||||
if player_count > 2 else None,
|
if player_count > 2 else None,
|
||||||
]},
|
]},
|
||||||
{'entries': [
|
{'entries': [
|
||||||
{'type': spazbot.ChargerBot, 'path': 2},
|
{'type': ChargerBot, 'path': 2},
|
||||||
{'type': spazbot.ChargerBot, 'path': 3},
|
{'type': ChargerBot, 'path': 3},
|
||||||
{'type': spazbot.ChargerBot, 'path': 1} if hard else None,
|
{'type': ChargerBot, 'path': 1} if hard else None,
|
||||||
{'type': spazbot.ChargerBot, 'path': 2},
|
{'type': ChargerBot, 'path': 2},
|
||||||
{'type': spazbot.ChargerBot, 'path': 3},
|
{'type': ChargerBot, 'path': 3},
|
||||||
{'type': spazbot.ChargerBot, 'path': 1} if player_count > 2
|
{'type': ChargerBot, 'path': 1} if player_count > 2
|
||||||
else None,
|
else None,
|
||||||
]},
|
]},
|
||||||
{'entries': [
|
{'entries': [
|
||||||
{'type': spazbot.BomberBotProShielded, 'path': 1} if hard
|
{'type': BomberBotProShielded, 'path': 1} if hard
|
||||||
else None,
|
else None,
|
||||||
{'type': spazbot.BomberBotProShielded, 'path': 2},
|
{'type': BomberBotProShielded, 'path': 2},
|
||||||
{'type': spazbot.BomberBotProShielded, 'path': 2},
|
{'type': BomberBotProShielded, 'path': 2},
|
||||||
{'type': spazbot.BomberBotProShielded, 'path': 3},
|
{'type': BomberBotProShielded, 'path': 3},
|
||||||
{'type': spazbot.BomberBotProShielded, 'path': 3},
|
{'type': BomberBotProShielded, 'path': 3},
|
||||||
{'type': spazbot.ChargerBot, 'point': 'bottom_right'},
|
{'type': ChargerBot, 'point': 'bottom_right'},
|
||||||
{'type': spazbot.ChargerBot, 'point': 'bottom_left'}
|
{'type': ChargerBot, 'point': 'bottom_left'}
|
||||||
if player_count > 2 else None,
|
if player_count > 2 else None,
|
||||||
]},
|
]},
|
||||||
{'entries': [
|
{'entries': [
|
||||||
{'type': spazbot.TriggerBotPro, 'path': 1}
|
{'type': TriggerBotPro, 'path': 1}
|
||||||
if hard else None,
|
if hard else None,
|
||||||
{'type': spazbot.TriggerBotPro, 'path': 1 if hard else 2},
|
{'type': TriggerBotPro, 'path': 1 if hard else 2},
|
||||||
{'type': spazbot.TriggerBotPro, 'path': 1 if hard else 2},
|
{'type': TriggerBotPro, 'path': 1 if hard else 2},
|
||||||
{'type': spazbot.TriggerBotPro, 'path': 1 if hard else 2},
|
{'type': TriggerBotPro, 'path': 1 if hard else 2},
|
||||||
{'type': spazbot.TriggerBotPro, 'path': 1 if hard else 2},
|
{'type': TriggerBotPro, 'path': 1 if hard else 2},
|
||||||
{'type': spazbot.TriggerBotPro, 'path': 1 if hard else 2},
|
{'type': TriggerBotPro, 'path': 1 if hard else 2},
|
||||||
{'type': spazbot.TriggerBotPro, 'path': 1 if hard else 2}
|
{'type': TriggerBotPro, 'path': 1 if hard else 2}
|
||||||
if player_count > 1 else None,
|
if player_count > 1 else None,
|
||||||
{'type': spazbot.TriggerBotPro, 'path': 1 if hard else 2}
|
{'type': TriggerBotPro, 'path': 1 if hard else 2}
|
||||||
if player_count > 3 else None,
|
if player_count > 3 else None,
|
||||||
]},
|
]},
|
||||||
{'entries': [
|
{'entries': [
|
||||||
{'type': spazbot.TriggerBotProShielded if hard
|
{'type': TriggerBotProShielded if hard
|
||||||
else spazbot.TriggerBotPro, 'point': 'bottom_left'},
|
else TriggerBotPro, 'point': 'bottom_left'},
|
||||||
{'type': spazbot.TriggerBotProShielded,
|
{'type': TriggerBotProShielded,
|
||||||
'point': 'bottom_right'}
|
'point': 'bottom_right'}
|
||||||
if hard else None,
|
if hard else None,
|
||||||
{'type': spazbot.TriggerBotProShielded,
|
{'type': TriggerBotProShielded,
|
||||||
'point': 'bottom_right'}
|
'point': 'bottom_right'}
|
||||||
if player_count > 2 else None,
|
if player_count > 2 else None,
|
||||||
{'type': spazbot.BomberBot, 'path': 3},
|
{'type': BomberBot, 'path': 3},
|
||||||
{'type': spazbot.BomberBot, 'path': 3},
|
{'type': BomberBot, 'path': 3},
|
||||||
{'type': 'spacing', 'duration': 5.0},
|
{'type': 'spacing', 'duration': 5.0},
|
||||||
{'type': spazbot.BrawlerBot, 'path': 2},
|
{'type': BrawlerBot, 'path': 2},
|
||||||
{'type': spazbot.BrawlerBot, 'path': 2},
|
{'type': BrawlerBot, 'path': 2},
|
||||||
{'type': 'spacing', 'duration': 5.0},
|
{'type': 'spacing', 'duration': 5.0},
|
||||||
{'type': spazbot.TriggerBot, 'path': 1} if hard else None,
|
{'type': TriggerBot, 'path': 1} if hard else None,
|
||||||
{'type': spazbot.TriggerBot, 'path': 1} if hard else None,
|
{'type': TriggerBot, 'path': 1} if hard else None,
|
||||||
]},
|
]},
|
||||||
{'entries': [
|
{'entries': [
|
||||||
{'type': spazbot.BomberBotProShielded, 'path': 2},
|
{'type': BomberBotProShielded, 'path': 2},
|
||||||
{'type': spazbot.BomberBotProShielded, 'path': 2} if hard
|
{'type': BomberBotProShielded, 'path': 2} if hard
|
||||||
else None,
|
else None,
|
||||||
{'type': spazbot.StickyBot, 'point': 'bottom_right'},
|
{'type': StickyBot, 'point': 'bottom_right'},
|
||||||
{'type': spazbot.BomberBotProShielded, 'path': 2},
|
{'type': BomberBotProShielded, 'path': 2},
|
||||||
{'type': spazbot.BomberBotProShielded, 'path': 2},
|
{'type': BomberBotProShielded, 'path': 2},
|
||||||
{'type': spazbot.StickyBot, 'point': 'bottom_right'}
|
{'type': StickyBot, 'point': 'bottom_right'}
|
||||||
if player_count > 2 else None,
|
if player_count > 2 else None,
|
||||||
{'type': spazbot.BomberBotProShielded, 'path': 2},
|
{'type': BomberBotProShielded, 'path': 2},
|
||||||
{'type': spazbot.ExplodeyBot, 'point': 'bottom_left'},
|
{'type': ExplodeyBot, 'point': 'bottom_left'},
|
||||||
{'type': spazbot.BomberBotProShielded, 'path': 2},
|
{'type': BomberBotProShielded, 'path': 2},
|
||||||
{'type': spazbot.BomberBotProShielded, 'path': 2}
|
{'type': BomberBotProShielded, 'path': 2}
|
||||||
if player_count > 1 else None,
|
if player_count > 1 else None,
|
||||||
{'type': 'spacing', 'duration': 5.0},
|
{'type': 'spacing', 'duration': 5.0},
|
||||||
{'type': spazbot.StickyBot, 'point': 'bottom_left'},
|
{'type': StickyBot, 'point': 'bottom_left'},
|
||||||
{'type': 'spacing', 'duration': 2.0},
|
{'type': 'spacing', 'duration': 2.0},
|
||||||
{'type': spazbot.ExplodeyBot, 'point': 'bottom_right'},
|
{'type': ExplodeyBot, 'point': 'bottom_right'},
|
||||||
]},
|
]},
|
||||||
] # yapf: disable
|
] # yapf: disable
|
||||||
elif self._preset in ['endless', 'endless_tournament']:
|
elif self._preset in ['endless', 'endless_tournament']:
|
||||||
@ -401,9 +406,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
ba.timer(2.0, self._start_updating_waves)
|
ba.timer(2.0, self._start_updating_waves)
|
||||||
|
|
||||||
def _handle_reached_end(self) -> None:
|
def _handle_reached_end(self) -> None:
|
||||||
oppnode = ba.get_collision_info('opposing_node')
|
spaz = ba.getcollision().opposing_node.getdelegate(SpazBot, True)
|
||||||
spaz = oppnode.getdelegate()
|
|
||||||
|
|
||||||
if not spaz.is_alive():
|
if not spaz.is_alive():
|
||||||
return # Ignore bodies flying in.
|
return # Ignore bodies flying in.
|
||||||
|
|
||||||
@ -495,7 +498,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
def _drop_powerups(self,
|
def _drop_powerups(self,
|
||||||
standard_points: bool = False,
|
standard_points: bool = False,
|
||||||
force_first: str = None) -> None:
|
force_first: str = None) -> None:
|
||||||
""" Generic powerup drop """
|
"""Generic powerup drop."""
|
||||||
|
|
||||||
# If its been a minute since our last wave finished emerging, stop
|
# If its been a minute since our last wave finished emerging, stop
|
||||||
# giving out land-mine powerups. (prevents players from waiting
|
# giving out land-mine powerups. (prevents players from waiting
|
||||||
@ -528,14 +531,6 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
extra_excludes)).autoretain()
|
extra_excludes)).autoretain()
|
||||||
|
|
||||||
def end_game(self) -> None:
|
def end_game(self) -> None:
|
||||||
|
|
||||||
# FIXME: If we don't start our bots moving again we get stuck. This
|
|
||||||
# is because the bot-set never prunes itself while movement is off
|
|
||||||
# and on_expire() never gets called for some bots because
|
|
||||||
# _prune_dead_objects() saw them as dead and pulled them off the
|
|
||||||
# weak-ref lists. this is an architectural issue; can hopefully fix
|
|
||||||
# this by having _actor_weak_refs not look at exists().
|
|
||||||
self._bots.start_moving()
|
|
||||||
ba.pushcall(ba.Call(self.do_end, 'defeat'))
|
ba.pushcall(ba.Call(self.do_end, 'defeat'))
|
||||||
ba.setmusic(None)
|
ba.setmusic(None)
|
||||||
ba.playsound(self._player_death_sound)
|
ba.playsound(self._player_death_sound)
|
||||||
@ -550,7 +545,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
delay = 0
|
delay = 0
|
||||||
|
|
||||||
score: Optional[int]
|
score: Optional[int]
|
||||||
if self._wave >= 2:
|
if self._wavenum >= 2:
|
||||||
score = self._score
|
score = self._score
|
||||||
fail_message = None
|
fail_message = None
|
||||||
else:
|
else:
|
||||||
@ -583,7 +578,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
won = False
|
won = False
|
||||||
else:
|
else:
|
||||||
assert self._waves is not None
|
assert self._waves is not None
|
||||||
won = (self._wave == len(self._waves))
|
won = (self._wavenum == len(self._waves))
|
||||||
|
|
||||||
# Reward time bonus.
|
# Reward time bonus.
|
||||||
base_delay = 4.0 if won else 0
|
base_delay = 4.0 if won else 0
|
||||||
@ -594,7 +589,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
base_delay += 1.0
|
base_delay += 1.0
|
||||||
|
|
||||||
# Reward flawless bonus.
|
# Reward flawless bonus.
|
||||||
if self._wave > 0 and self._flawless:
|
if self._wavenum > 0 and self._flawless:
|
||||||
ba.timer(base_delay, self._award_flawless_bonus)
|
ba.timer(base_delay, self._award_flawless_bonus)
|
||||||
base_delay += 1.0
|
base_delay += 1.0
|
||||||
|
|
||||||
@ -636,69 +631,60 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
ba.timer(base_delay, ba.Call(self.do_end, 'victory'))
|
ba.timer(base_delay, ba.Call(self.do_end, 'victory'))
|
||||||
return
|
return
|
||||||
|
|
||||||
self._wave += 1
|
self._wavenum += 1
|
||||||
|
|
||||||
# Short celebration after waves.
|
# Short celebration after waves.
|
||||||
if self._wave > 1:
|
if self._wavenum > 1:
|
||||||
self.celebrate(0.5)
|
self.celebrate(0.5)
|
||||||
|
|
||||||
ba.timer(base_delay, self._start_next_wave)
|
ba.timer(base_delay, self._start_next_wave)
|
||||||
|
|
||||||
def _award_completion_bonus(self) -> None:
|
def _award_completion_bonus(self) -> None:
|
||||||
from bastd.actor import popuptext
|
|
||||||
bonus = 200
|
bonus = 200
|
||||||
ba.playsound(self._cashregistersound)
|
ba.playsound(self._cashregistersound)
|
||||||
popuptext.PopupText(ba.Lstr(
|
PopupText(ba.Lstr(value='+${A} ${B}',
|
||||||
value='+${A} ${B}',
|
subs=[('${A}', str(bonus)),
|
||||||
subs=[('${A}', str(bonus)),
|
('${B}',
|
||||||
('${B}', ba.Lstr(resource='completionBonusText'))]),
|
ba.Lstr(resource='completionBonusText'))]),
|
||||||
color=(0.7, 0.7, 1.0, 1),
|
color=(0.7, 0.7, 1.0, 1),
|
||||||
scale=1.6,
|
scale=1.6,
|
||||||
position=(0, 1.5, -1)).autoretain()
|
position=(0, 1.5, -1)).autoretain()
|
||||||
self._score += bonus
|
self._score += bonus
|
||||||
self._update_scores()
|
self._update_scores()
|
||||||
|
|
||||||
def _award_lives_bonus(self) -> None:
|
def _award_lives_bonus(self) -> None:
|
||||||
from bastd.actor import popuptext
|
|
||||||
bonus = self._lives * 30
|
bonus = self._lives * 30
|
||||||
ba.playsound(self._cashregistersound)
|
ba.playsound(self._cashregistersound)
|
||||||
popuptext.PopupText(ba.Lstr(value='+${A} ${B}',
|
PopupText(ba.Lstr(value='+${A} ${B}',
|
||||||
subs=[('${A}', str(bonus)),
|
subs=[('${A}', str(bonus)),
|
||||||
('${B}',
|
('${B}', ba.Lstr(resource='livesBonusText'))]),
|
||||||
ba.Lstr(resource='livesBonusText'))
|
color=(0.7, 1.0, 0.3, 1),
|
||||||
]),
|
scale=1.3,
|
||||||
color=(0.7, 1.0, 0.3, 1),
|
position=(0, 1, -1)).autoretain()
|
||||||
scale=1.3,
|
|
||||||
position=(0, 1, -1)).autoretain()
|
|
||||||
self._score += bonus
|
self._score += bonus
|
||||||
self._update_scores()
|
self._update_scores()
|
||||||
|
|
||||||
def _award_time_bonus(self, bonus: int) -> None:
|
def _award_time_bonus(self, bonus: int) -> None:
|
||||||
from bastd.actor import popuptext
|
|
||||||
ba.playsound(self._cashregistersound)
|
ba.playsound(self._cashregistersound)
|
||||||
popuptext.PopupText(ba.Lstr(value='+${A} ${B}',
|
PopupText(ba.Lstr(value='+${A} ${B}',
|
||||||
subs=[('${A}', str(bonus)),
|
subs=[('${A}', str(bonus)),
|
||||||
('${B}',
|
('${B}', ba.Lstr(resource='timeBonusText'))]),
|
||||||
ba.Lstr(resource='timeBonusText'))
|
color=(1, 1, 0.5, 1),
|
||||||
]),
|
scale=1.0,
|
||||||
color=(1, 1, 0.5, 1),
|
position=(0, 3, -1)).autoretain()
|
||||||
scale=1.0,
|
|
||||||
position=(0, 3, -1)).autoretain()
|
|
||||||
|
|
||||||
self._score += self._time_bonus
|
self._score += self._time_bonus
|
||||||
self._update_scores()
|
self._update_scores()
|
||||||
|
|
||||||
def _award_flawless_bonus(self) -> None:
|
def _award_flawless_bonus(self) -> None:
|
||||||
from bastd.actor import popuptext
|
|
||||||
ba.playsound(self._cashregistersound)
|
ba.playsound(self._cashregistersound)
|
||||||
popuptext.PopupText(ba.Lstr(value='+${A} ${B}',
|
PopupText(ba.Lstr(value='+${A} ${B}',
|
||||||
subs=[('${A}', str(self._flawless_bonus)),
|
subs=[('${A}', str(self._flawless_bonus)),
|
||||||
('${B}',
|
('${B}', ba.Lstr(resource='perfectWaveText'))
|
||||||
ba.Lstr(resource='perfectWaveText'))
|
]),
|
||||||
]),
|
color=(1, 1, 0.2, 1),
|
||||||
color=(1, 1, 0.2, 1),
|
scale=1.2,
|
||||||
scale=1.2,
|
position=(0, 2, -1)).autoretain()
|
||||||
position=(0, 2, -1)).autoretain()
|
|
||||||
|
|
||||||
assert self._flawless_bonus is not None
|
assert self._flawless_bonus is not None
|
||||||
self._score += self._flawless_bonus
|
self._score += self._flawless_bonus
|
||||||
@ -717,7 +703,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
self.show_zoom_message(ba.Lstr(value='${A} ${B}',
|
self.show_zoom_message(ba.Lstr(value='${A} ${B}',
|
||||||
subs=[('${A}',
|
subs=[('${A}',
|
||||||
ba.Lstr(resource='waveText')),
|
ba.Lstr(resource='waveText')),
|
||||||
('${B}', str(self._wave))]),
|
('${B}', str(self._wavenum))]),
|
||||||
scale=1.0,
|
scale=1.0,
|
||||||
duration=1.0,
|
duration=1.0,
|
||||||
trail=True)
|
trail=True)
|
||||||
@ -728,52 +714,49 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
bot_types: List[Optional[Dict[str, Any]]] = []
|
bot_types: List[Optional[Dict[str, Any]]] = []
|
||||||
|
|
||||||
if self._preset in ['endless', 'endless_tournament']:
|
if self._preset in ['endless', 'endless_tournament']:
|
||||||
level = self._wave
|
level = self._wavenum
|
||||||
target_points = (level + 1) * 8.0
|
target_points = (level + 1) * 8.0
|
||||||
group_count = random.randint(1, 3)
|
group_count = random.randint(1, 3)
|
||||||
entries = []
|
entries = []
|
||||||
spaz_types: List[Tuple[Type[spazbot.SpazBot], float]] = []
|
spaz_types: List[Tuple[Type[SpazBot], float]] = []
|
||||||
if level < 6:
|
if level < 6:
|
||||||
spaz_types += [(spazbot.BomberBot, 5.0)]
|
spaz_types += [(BomberBot, 5.0)]
|
||||||
if level < 10:
|
if level < 10:
|
||||||
spaz_types += [(spazbot.BrawlerBot, 5.0)]
|
spaz_types += [(BrawlerBot, 5.0)]
|
||||||
if level < 15:
|
if level < 15:
|
||||||
spaz_types += [(spazbot.TriggerBot, 6.0)]
|
spaz_types += [(TriggerBot, 6.0)]
|
||||||
if level > 5:
|
if level > 5:
|
||||||
spaz_types += [(spazbot.TriggerBotPro, 7.5)
|
spaz_types += [(TriggerBotPro, 7.5)] * (1 + (level - 5) // 7)
|
||||||
] * (1 + (level - 5) // 7)
|
|
||||||
if level > 2:
|
if level > 2:
|
||||||
spaz_types += [(spazbot.BomberBotProShielded, 8.0)
|
spaz_types += [(BomberBotProShielded, 8.0)
|
||||||
] * (1 + (level - 2) // 6)
|
] * (1 + (level - 2) // 6)
|
||||||
if level > 6:
|
if level > 6:
|
||||||
spaz_types += [(spazbot.TriggerBotProShielded, 12.0)
|
spaz_types += [(TriggerBotProShielded, 12.0)
|
||||||
] * (1 + (level - 6) // 5)
|
] * (1 + (level - 6) // 5)
|
||||||
if level > 1:
|
if level > 1:
|
||||||
spaz_types += ([(spazbot.ChargerBot, 10.0)] *
|
spaz_types += ([(ChargerBot, 10.0)] * (1 + (level - 1) // 4))
|
||||||
(1 + (level - 1) // 4))
|
|
||||||
if level > 7:
|
if level > 7:
|
||||||
spaz_types += [(spazbot.ChargerBotProShielded, 15.0)
|
spaz_types += [(ChargerBotProShielded, 15.0)
|
||||||
] * (1 + (level - 7) // 3)
|
] * (1 + (level - 7) // 3)
|
||||||
|
|
||||||
# Bot type, their effect on target points.
|
# Bot type, their effect on target points.
|
||||||
defender_types: List[Tuple[Type[spazbot.SpazBot], float]] = [
|
defender_types: List[Tuple[Type[SpazBot], float]] = [
|
||||||
(spazbot.BomberBot, 0.9),
|
(BomberBot, 0.9),
|
||||||
(spazbot.BrawlerBot, 0.9),
|
(BrawlerBot, 0.9),
|
||||||
(spazbot.TriggerBot, 0.85),
|
(TriggerBot, 0.85),
|
||||||
]
|
]
|
||||||
if level > 2:
|
if level > 2:
|
||||||
defender_types += [(spazbot.ChargerBot, 0.75)]
|
defender_types += [(ChargerBot, 0.75)]
|
||||||
if level > 4:
|
if level > 4:
|
||||||
defender_types += ([(spazbot.StickyBot, 0.7)] *
|
defender_types += ([(StickyBot, 0.7)] * (1 + (level - 5) // 6))
|
||||||
(1 + (level - 5) // 6))
|
|
||||||
if level > 6:
|
if level > 6:
|
||||||
defender_types += ([(spazbot.ExplodeyBot, 0.7)] *
|
defender_types += ([(ExplodeyBot, 0.7)] * (1 +
|
||||||
(1 + (level - 5) // 5))
|
(level - 5) // 5))
|
||||||
if level > 8:
|
if level > 8:
|
||||||
defender_types += ([(spazbot.BrawlerBotProShielded, 0.65)] *
|
defender_types += ([(BrawlerBotProShielded, 0.65)] *
|
||||||
(1 + (level - 5) // 4))
|
(1 + (level - 5) // 4))
|
||||||
if level > 10:
|
if level > 10:
|
||||||
defender_types += ([(spazbot.TriggerBotProShielded, 0.6)] *
|
defender_types += ([(TriggerBotProShielded, 0.6)] *
|
||||||
(1 + (level - 6) // 3))
|
(1 + (level - 6) // 3))
|
||||||
|
|
||||||
for group in range(group_count):
|
for group in range(group_count):
|
||||||
@ -821,8 +804,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
elif path == 6:
|
elif path == 6:
|
||||||
this_target_point_s *= 0.7
|
this_target_point_s *= 0.7
|
||||||
|
|
||||||
def _add_defender(defender_type: Tuple[Type[spazbot.SpazBot],
|
def _add_defender(defender_type: Tuple[Type[SpazBot], float],
|
||||||
float],
|
|
||||||
pnt: str) -> Tuple[float, Dict[str, Any]]:
|
pnt: str) -> Tuple[float, Dict[str, Any]]:
|
||||||
# FIXME: should look into this warning
|
# FIXME: should look into this warning
|
||||||
# pylint: disable=cell-var-from-loop
|
# pylint: disable=cell-var-from-loop
|
||||||
@ -884,7 +866,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
|
|
||||||
else:
|
else:
|
||||||
assert self._waves is not None
|
assert self._waves is not None
|
||||||
wave = self._waves[self._wave - 1]
|
wave = self._waves[self._wavenum - 1]
|
||||||
|
|
||||||
bot_types += wave['entries']
|
bot_types += wave['entries']
|
||||||
self._time_bonus_mult = 1.0
|
self._time_bonus_mult = 1.0
|
||||||
@ -965,15 +947,13 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
# dropping land-mines powerups at some point (otherwise a crafty
|
# dropping land-mines powerups at some point (otherwise a crafty
|
||||||
# player could fill the whole map with them)
|
# player could fill the whole map with them)
|
||||||
self._last_wave_end_time = ba.time() + t_sec
|
self._last_wave_end_time = ba.time() + t_sec
|
||||||
assert self._waves is not None
|
totalwaves = str(len(self._waves)) if self._waves is not None else '??'
|
||||||
txtval = ba.Lstr(
|
txtval = ba.Lstr(
|
||||||
value='${A} ${B}',
|
value='${A} ${B}',
|
||||||
subs=[
|
subs=[('${A}', ba.Lstr(resource='waveText')),
|
||||||
('${A}', ba.Lstr(resource='waveText')),
|
('${B}', str(self._wavenum) +
|
||||||
('${B}', str(self._wave) +
|
('' if self._preset in ['endless', 'endless_tournament']
|
||||||
('' if self._preset in ['endless', 'endless_tournament'] else
|
else f'/{totalwaves}'))])
|
||||||
('/' + str(len(self._waves)))))
|
|
||||||
])
|
|
||||||
self._wave_text = ba.NodeActor(
|
self._wave_text = ba.NodeActor(
|
||||||
ba.newnode('text',
|
ba.newnode('text',
|
||||||
attrs={
|
attrs={
|
||||||
@ -989,16 +969,16 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
'text': txtval
|
'text': txtval
|
||||||
}))
|
}))
|
||||||
|
|
||||||
# noinspection PyTypeHints
|
def _on_bot_spawn(self, path: int, spaz: SpazBot) -> None:
|
||||||
def _on_bot_spawn(self, path: int, spaz: spazbot.SpazBot) -> None:
|
|
||||||
# Add our custom update callback and set some info for this bot.
|
# Add our custom update callback and set some info for this bot.
|
||||||
spaz_type = type(spaz)
|
spaz_type = type(spaz)
|
||||||
assert spaz is not None
|
assert spaz is not None
|
||||||
spaz.update_callback = self._update_bot
|
spaz.update_callback = self._update_bot
|
||||||
|
|
||||||
# FIXME: Do this in a type-safe way.
|
# Tack some custom attrs onto the spaz.
|
||||||
spaz.r_walk_row = path # type: ignore
|
setattr(spaz, 'r_walk_row', path)
|
||||||
spaz.r_walk_speed = self._get_bot_speed(spaz_type) # type: ignore
|
setattr(spaz, 'r_walk_speed', self._get_bot_speed(spaz_type))
|
||||||
|
|
||||||
def add_bot_at_point(self,
|
def add_bot_at_point(self,
|
||||||
point: str,
|
point: str,
|
||||||
@ -1047,7 +1027,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
assert self._scoreboard is not None
|
assert self._scoreboard is not None
|
||||||
self._scoreboard.set_team_value(self.teams[0], score, max_score=None)
|
self._scoreboard.set_team_value(self.teams[0], score, max_score=None)
|
||||||
|
|
||||||
def _update_bot(self, bot: spazbot.SpazBot) -> bool:
|
def _update_bot(self, bot: SpazBot) -> bool:
|
||||||
# Yup; that's a lot of return statements right there.
|
# Yup; that's a lot of return statements right there.
|
||||||
# pylint: disable=too-many-return-statements
|
# pylint: disable=too-many-return-statements
|
||||||
|
|
||||||
@ -1057,8 +1037,8 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
assert bot.node
|
assert bot.node
|
||||||
|
|
||||||
# FIXME: Do this in a type safe way.
|
# FIXME: Do this in a type safe way.
|
||||||
r_walk_speed: float = bot.r_walk_speed # type: ignore
|
r_walk_speed: float = getattr(bot, 'r_walk_speed')
|
||||||
r_walk_row: int = bot.r_walk_row # type: ignore
|
r_walk_row: int = getattr(bot, 'r_walk_row')
|
||||||
|
|
||||||
speed = r_walk_speed
|
speed = r_walk_speed
|
||||||
pos = bot.node.position
|
pos = bot.node.position
|
||||||
@ -1109,6 +1089,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
if ((ba.is_point_in_box(pos, boxes['b8'])
|
if ((ba.is_point_in_box(pos, boxes['b8'])
|
||||||
and not ba.is_point_in_box(pos, boxes['b9']))
|
and not ba.is_point_in_box(pos, boxes['b9']))
|
||||||
or pos == (0.0, 0.0, 0.0)):
|
or pos == (0.0, 0.0, 0.0)):
|
||||||
|
|
||||||
# Default to walking right if we're still in the walking area.
|
# Default to walking right if we're still in the walking area.
|
||||||
bot.node.move_left_right = speed
|
bot.node.move_left_right = speed
|
||||||
bot.node.move_up_down = 0
|
bot.node.move_up_down = 0
|
||||||
@ -1136,7 +1117,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
respawn_time, ba.Call(self.spawn_player_if_exists, player))
|
respawn_time, ba.Call(self.spawn_player_if_exists, player))
|
||||||
player.gamedata['respawn_icon'] = RespawnIcon(player, respawn_time)
|
player.gamedata['respawn_icon'] = RespawnIcon(player, respawn_time)
|
||||||
|
|
||||||
elif isinstance(msg, spazbot.SpazBotDeathMessage):
|
elif isinstance(msg, SpazBotDiedMessage):
|
||||||
if msg.how is ba.DeathType.REACHED_GOAL:
|
if msg.how is ba.DeathType.REACHED_GOAL:
|
||||||
return
|
return
|
||||||
pts, importance = msg.badguy.get_death_points(msg.how)
|
pts, importance = msg.badguy.get_death_points(msg.how)
|
||||||
@ -1161,7 +1142,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
self._dingsoundhigh,
|
self._dingsoundhigh,
|
||||||
volume=0.6)
|
volume=0.6)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
print('EXC in Runaround on SpazBotDeathMessage:', exc)
|
print('EXC in Runaround on SpazBotDiedMessage:', exc)
|
||||||
|
|
||||||
# Normally we pull scores from the score-set, but if there's no
|
# Normally we pull scores from the score-set, but if there's no
|
||||||
# player lets be explicit.
|
# player lets be explicit.
|
||||||
@ -1172,7 +1153,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
else:
|
else:
|
||||||
super().handlemessage(msg)
|
super().handlemessage(msg)
|
||||||
|
|
||||||
def _get_bot_speed(self, bot_type: Type[spazbot.SpazBot]) -> float:
|
def _get_bot_speed(self, bot_type: Type[SpazBot]) -> float:
|
||||||
speed = self._bot_speed_map.get(bot_type)
|
speed = self._bot_speed_map.get(bot_type)
|
||||||
if speed is None:
|
if speed is None:
|
||||||
raise TypeError('Invalid bot type to _get_bot_speed(): ' +
|
raise TypeError('Invalid bot type to _get_bot_speed(): ' +
|
||||||
|
|||||||
@ -26,14 +26,20 @@ import random
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
import ba
|
import ba
|
||||||
from bastd.actor import spazbot
|
|
||||||
from bastd.actor.playerspaz import PlayerSpaz
|
from bastd.actor.playerspaz import PlayerSpaz
|
||||||
from bastd.actor.bomb import TNTSpawner
|
from bastd.actor.bomb import TNTSpawner
|
||||||
from bastd.actor.scoreboard import Scoreboard
|
from bastd.actor.scoreboard import Scoreboard
|
||||||
from bastd.actor.powerupbox import PowerupBoxFactory, PowerupBox
|
from bastd.actor.powerupbox import PowerupBoxFactory, PowerupBox
|
||||||
|
from bastd.actor.spazbot import (SpazBotSet, SpazBotDiedMessage, BomberBot,
|
||||||
|
BomberBotPro, BomberBotProShielded,
|
||||||
|
BrawlerBot, BrawlerBotPro,
|
||||||
|
BrawlerBotProShielded, TriggerBot,
|
||||||
|
TriggerBotPro, TriggerBotProShielded,
|
||||||
|
ChargerBot, StickyBot, ExplodeyBot)
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from typing import Any, Dict, Type, List, Optional, Sequence
|
from typing import Any, Dict, Type, List, Optional, Sequence
|
||||||
|
from bastd.actor.spazbot import SpazBot
|
||||||
|
|
||||||
|
|
||||||
class Player(ba.Player['Team']):
|
class Player(ba.Player['Team']):
|
||||||
@ -76,7 +82,7 @@ class TheLastStandGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
self._excludepowerups: List[str] = []
|
self._excludepowerups: List[str] = []
|
||||||
self._scoreboard: Optional[Scoreboard] = None
|
self._scoreboard: Optional[Scoreboard] = None
|
||||||
self._score = 0
|
self._score = 0
|
||||||
self._bots = spazbot.BotSet()
|
self._bots = SpazBotSet()
|
||||||
self._dingsound = ba.getsound('dingSmall')
|
self._dingsound = ba.getsound('dingSmall')
|
||||||
self._dingsoundhigh = ba.getsound('dingSmallHigh')
|
self._dingsoundhigh = ba.getsound('dingSmallHigh')
|
||||||
self._tntspawner: Optional[TNTSpawner] = None
|
self._tntspawner: Optional[TNTSpawner] = None
|
||||||
@ -86,18 +92,18 @@ class TheLastStandGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
|
|
||||||
# For each bot type: [spawn-rate, increase, d_increase]
|
# For each bot type: [spawn-rate, increase, d_increase]
|
||||||
self._bot_spawn_types = {
|
self._bot_spawn_types = {
|
||||||
spazbot.BomberBot: [1.00, 0.00, 0.000],
|
BomberBot: [1.00, 0.00, 0.000],
|
||||||
spazbot.BomberBotPro: [0.00, 0.05, 0.001],
|
BomberBotPro: [0.00, 0.05, 0.001],
|
||||||
spazbot.BomberBotProShielded: [0.00, 0.02, 0.002],
|
BomberBotProShielded: [0.00, 0.02, 0.002],
|
||||||
spazbot.BrawlerBot: [1.00, 0.00, 0.000],
|
BrawlerBot: [1.00, 0.00, 0.000],
|
||||||
spazbot.BrawlerBotPro: [0.00, 0.05, 0.001],
|
BrawlerBotPro: [0.00, 0.05, 0.001],
|
||||||
spazbot.BrawlerBotProShielded: [0.00, 0.02, 0.002],
|
BrawlerBotProShielded: [0.00, 0.02, 0.002],
|
||||||
spazbot.TriggerBot: [0.30, 0.00, 0.000],
|
TriggerBot: [0.30, 0.00, 0.000],
|
||||||
spazbot.TriggerBotPro: [0.00, 0.05, 0.001],
|
TriggerBotPro: [0.00, 0.05, 0.001],
|
||||||
spazbot.TriggerBotProShielded: [0.00, 0.02, 0.002],
|
TriggerBotProShielded: [0.00, 0.02, 0.002],
|
||||||
spazbot.ChargerBot: [0.30, 0.05, 0.000],
|
ChargerBot: [0.30, 0.05, 0.000],
|
||||||
spazbot.StickyBot: [0.10, 0.03, 0.001],
|
StickyBot: [0.10, 0.03, 0.001],
|
||||||
spazbot.ExplodeyBot: [0.05, 0.02, 0.002]
|
ExplodeyBot: [0.05, 0.02, 0.002]
|
||||||
} # yapf: disable
|
} # yapf: disable
|
||||||
|
|
||||||
def on_transition_in(self) -> None:
|
def on_transition_in(self) -> None:
|
||||||
@ -206,9 +212,7 @@ class TheLastStandGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
for i in range(3):
|
for i in range(3):
|
||||||
for playerpt in playerpts:
|
for playerpt in playerpts:
|
||||||
dists[i] += abs(playerpt[0] - botspawnpts[i][0])
|
dists[i] += abs(playerpt[0] - botspawnpts[i][0])
|
||||||
|
dists[i] += random.random() * 5.0 # Minor random variation.
|
||||||
# Little random variation.
|
|
||||||
dists[i] += random.random() * 5.0
|
|
||||||
if dists[0] > dists[1] and dists[0] > dists[2]:
|
if dists[0] > dists[1] and dists[0] > dists[2]:
|
||||||
spawnpt = botspawnpts[0]
|
spawnpt = botspawnpts[0]
|
||||||
elif dists[1] > dists[2]:
|
elif dists[1] > dists[2]:
|
||||||
@ -227,7 +231,7 @@ class TheLastStandGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
|
|
||||||
# Now go back through and see where this value falls.
|
# Now go back through and see where this value falls.
|
||||||
total = 0
|
total = 0
|
||||||
bottype: Optional[Type[spazbot.SpazBot]] = None
|
bottype: Optional[Type[SpazBot]] = None
|
||||||
for spawntype in self._bot_spawn_types.items():
|
for spawntype in self._bot_spawn_types.items():
|
||||||
total += spawntype[1][0]
|
total += spawntype[1][0]
|
||||||
if randval <= total:
|
if randval <= total:
|
||||||
@ -244,8 +248,9 @@ class TheLastStandGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
spawntype[1][1] += spawntype[1][2] # incr spawn rate incr rate
|
spawntype[1][1] += spawntype[1][2] # incr spawn rate incr rate
|
||||||
|
|
||||||
def _update_scores(self) -> None:
|
def _update_scores(self) -> None:
|
||||||
# Do achievements in default preset only.
|
|
||||||
score = self._score
|
score = self._score
|
||||||
|
|
||||||
|
# Achievements apply to the default preset only.
|
||||||
if self._preset == 'default':
|
if self._preset == 'default':
|
||||||
if score >= 250:
|
if score >= 250:
|
||||||
self._award_achievement('Last Stand Master')
|
self._award_achievement('Last Stand Master')
|
||||||
@ -266,28 +271,21 @@ class TheLastStandGame(ba.CoopGameActivity[Player, Team]):
|
|||||||
self._score += msg.score
|
self._score += msg.score
|
||||||
self._update_scores()
|
self._update_scores()
|
||||||
|
|
||||||
elif isinstance(msg, spazbot.SpazBotDeathMessage):
|
elif isinstance(msg, SpazBotDiedMessage):
|
||||||
pts, importance = msg.badguy.get_death_points(msg.how)
|
pts, importance = msg.badguy.get_death_points(msg.how)
|
||||||
target: Optional[Sequence[float]]
|
target: Optional[Sequence[float]]
|
||||||
if msg.killerplayer:
|
if msg.killerplayer:
|
||||||
try:
|
assert msg.badguy.node
|
||||||
assert msg.badguy.node
|
target = msg.badguy.node.position
|
||||||
target = msg.badguy.node.position
|
self.stats.player_scored(msg.killerplayer,
|
||||||
except Exception:
|
pts,
|
||||||
ba.print_exception()
|
target=target,
|
||||||
target = None
|
kill=True,
|
||||||
try:
|
screenmessage=False,
|
||||||
self.stats.player_scored(msg.killerplayer,
|
importance=importance)
|
||||||
pts,
|
ba.playsound(self._dingsound
|
||||||
target=target,
|
if importance == 1 else self._dingsoundhigh,
|
||||||
kill=True,
|
volume=0.6)
|
||||||
screenmessage=False,
|
|
||||||
importance=importance)
|
|
||||||
ba.playsound(self._dingsound
|
|
||||||
if importance == 1 else self._dingsoundhigh,
|
|
||||||
volume=0.6)
|
|
||||||
except Exception as exc:
|
|
||||||
print('EXC on last-stand SpazBotDeathMessage', exc)
|
|
||||||
|
|
||||||
# Normally we pull scores from the score-set, but if there's no
|
# Normally we pull scores from the score-set, but if there's no
|
||||||
# player lets be explicit.
|
# player lets be explicit.
|
||||||
|
|||||||
@ -906,8 +906,8 @@ def _preload4() -> None:
|
|||||||
ba.getmodel(mname)
|
ba.getmodel(mname)
|
||||||
for sname in ['metalHit', 'metalSkid', 'refWhistle', 'achievement']:
|
for sname in ['metalHit', 'metalSkid', 'refWhistle', 'achievement']:
|
||||||
ba.getsound(sname)
|
ba.getsound(sname)
|
||||||
from bastd.actor.flag import get_factory
|
from bastd.actor.flag import FlagFactory
|
||||||
get_factory()
|
FlagFactory.get()
|
||||||
|
|
||||||
|
|
||||||
class MainMenuSession(ba.Session):
|
class MainMenuSession(ba.Session):
|
||||||
|
|||||||
@ -464,7 +464,6 @@ def handle_party_invite(name: str, invite_id: str) -> None:
|
|||||||
# FIXME: Ugly.
|
# FIXME: Ugly.
|
||||||
# Let's store the invite-id away on the confirm window so we know if
|
# Let's store the invite-id away on the confirm window so we know if
|
||||||
# we need to kill it later.
|
# we need to kill it later.
|
||||||
# noinspection PyTypeHints
|
|
||||||
conf.party_invite_id = invite_id # type: ignore
|
conf.party_invite_id = invite_id # type: ignore
|
||||||
|
|
||||||
# store a weak-ref so we can get at this later
|
# store a weak-ref so we can get at this later
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
<!-- THIS FILE IS AUTO GENERATED; DO NOT EDIT BY HAND -->
|
<!-- THIS FILE IS AUTO GENERATED; DO NOT EDIT BY HAND -->
|
||||||
<h4><em>last updated on 2020-05-24 for Ballistica version 1.5.0 build 20026</em></h4>
|
<h4><em>last updated on 2020-05-25 for Ballistica version 1.5.0 build 20027</em></h4>
|
||||||
<p>This page documents the Python classes and functions in the 'ba' module,
|
<p>This page documents the Python classes and functions in the 'ba' module,
|
||||||
which are the ones most relevant to modding in Ballistica. If you come across something you feel should be included here or could be better explained, please <a href="mailto:support@froemling.net">let me know</a>. Happy modding!</p>
|
which are the ones most relevant to modding in Ballistica. If you come across something you feel should be included here or could be better explained, please <a href="mailto:support@froemling.net">let me know</a>. Happy modding!</p>
|
||||||
<hr>
|
<hr>
|
||||||
@ -51,7 +51,6 @@
|
|||||||
<li><a href="#function_ba_camerashake">ba.camerashake()</a></li>
|
<li><a href="#function_ba_camerashake">ba.camerashake()</a></li>
|
||||||
<li><a href="#function_ba_emitfx">ba.emitfx()</a></li>
|
<li><a href="#function_ba_emitfx">ba.emitfx()</a></li>
|
||||||
<li><a href="#function_ba_existing">ba.existing()</a></li>
|
<li><a href="#function_ba_existing">ba.existing()</a></li>
|
||||||
<li><a href="#function_ba_get_collision_info">ba.get_collision_info()</a></li>
|
|
||||||
<li><a href="#function_ba_getactivity">ba.getactivity()</a></li>
|
<li><a href="#function_ba_getactivity">ba.getactivity()</a></li>
|
||||||
<li><a href="#function_ba_getnodes">ba.getnodes()</a></li>
|
<li><a href="#function_ba_getnodes">ba.getnodes()</a></li>
|
||||||
<li><a href="#function_ba_getsession">ba.getsession()</a></li>
|
<li><a href="#function_ba_getsession">ba.getsession()</a></li>
|
||||||
@ -200,6 +199,14 @@
|
|||||||
<li><a href="#class_ba_WidgetNotFoundError">ba.WidgetNotFoundError</a></li>
|
<li><a href="#class_ba_WidgetNotFoundError">ba.WidgetNotFoundError</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</ul>
|
</ul>
|
||||||
|
<h4><a name="class_category_Misc_Classes">Misc Classes</a></h4>
|
||||||
|
<ul>
|
||||||
|
<li><a href="#class_ba_Collision">ba.Collision</a></li>
|
||||||
|
</ul>
|
||||||
|
<h4><a name="function_category_Misc_Functions">Misc Functions</a></h4>
|
||||||
|
<ul>
|
||||||
|
<li><a href="#function_ba_getcollision">ba.getcollision()</a></li>
|
||||||
|
</ul>
|
||||||
<h4><a name="class_category_Protocols">Protocols</a></h4>
|
<h4><a name="class_category_Protocols">Protocols</a></h4>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="#class_ba_Existable">ba.Existable</a></li>
|
<li><a href="#class_ba_Existable">ba.Existable</a></li>
|
||||||
@ -1368,6 +1375,44 @@ mycall()</pre>
|
|||||||
|
|
||||||
<p>Use <a href="#function_ba_getcollidemodel">ba.getcollidemodel</a>() to instantiate one.</p>
|
<p>Use <a href="#function_ba_getcollidemodel">ba.getcollidemodel</a>() to instantiate one.</p>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<h2><strong><a name="class_ba_Collision">ba.Collision</a></strong></h3>
|
||||||
|
<p><em><top level class></em>
|
||||||
|
</p>
|
||||||
|
<p>A class providing info about occurring collisions.</p>
|
||||||
|
|
||||||
|
<h3>Attributes:</h3>
|
||||||
|
<h5><a href="#attr_ba_Collision__opposing_body">opposing_body</a>, <a href="#attr_ba_Collision__opposing_node">opposing_node</a>, <a href="#attr_ba_Collision__position">position</a>, <a href="#attr_ba_Collision__source_node">source_node</a></h5>
|
||||||
|
<dl>
|
||||||
|
<dt><h4><a name="attr_ba_Collision__opposing_body">opposing_body</a></h4></dt><dd>
|
||||||
|
<p><span>int</span></p>
|
||||||
|
<p>The body index on the opposing node in the current collision.</p>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
<dt><h4><a name="attr_ba_Collision__opposing_node">opposing_node</a></h4></dt><dd>
|
||||||
|
<p><span><a href="#class_ba_Node">ba.Node</a></span></p>
|
||||||
|
<p>The node the current callback material node is hitting.</p>
|
||||||
|
|
||||||
|
<p> Throws a <a href="#class_ba_NodeNotFoundError">ba.NodeNotFoundError</a> if the node does not exist.
|
||||||
|
This can be expected in some cases such as in 'disconnect'
|
||||||
|
callbacks triggered by deleting a currently-colliding node.</p>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
<dt><h4><a name="attr_ba_Collision__position">position</a></h4></dt><dd>
|
||||||
|
<p><span><a href="#class_ba_Vec3">ba.Vec3</a></span></p>
|
||||||
|
<p>The position of the current collision.</p>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
<dt><h4><a name="attr_ba_Collision__source_node">source_node</a></h4></dt><dd>
|
||||||
|
<p><span><a href="#class_ba_Node">ba.Node</a></span></p>
|
||||||
|
<p>The node containing the material triggering the current callback.</p>
|
||||||
|
|
||||||
|
<p> Throws a <a href="#class_ba_NodeNotFoundError">ba.NodeNotFoundError</a> if the node does not exist, though
|
||||||
|
the node should always exist (at least at the start of the collision
|
||||||
|
callback).</p>
|
||||||
|
|
||||||
|
</dd>
|
||||||
|
</dl>
|
||||||
<hr>
|
<hr>
|
||||||
<h2><strong><a name="class_ba_Context">ba.Context</a></strong></h3>
|
<h2><strong><a name="class_ba_Context">ba.Context</a></strong></h3>
|
||||||
<p><em><top level class></em>
|
<p><em><top level class></em>
|
||||||
@ -3547,10 +3592,13 @@ the right thing both for Node objects and values of None.</p>
|
|||||||
|
|
||||||
</dd>
|
</dd>
|
||||||
<dt><h4><a name="method_ba_Node__getdelegate">getdelegate()</a></dt></h4><dd>
|
<dt><h4><a name="method_ba_Node__getdelegate">getdelegate()</a></dt></h4><dd>
|
||||||
<p><span>getdelegate() -> Any</span></p>
|
<p><span>getdelegate(type: Type, doraise: bool = False) -> <varies></span></p>
|
||||||
|
|
||||||
<p>Returns the node's current delegate, which is the Python object
|
<p>Return the node's current delegate object if it matches a certain type.</p>
|
||||||
designated to handle the Node's messages.</p>
|
|
||||||
|
<p>If the node has no delegate or it is not an instance of the passed
|
||||||
|
type, then None will be returned. If 'doraise' is True, then an
|
||||||
|
Exception will be raised instead in such cases.</p>
|
||||||
|
|
||||||
</dd>
|
</dd>
|
||||||
<dt><h4><a name="method_ba_Node__getnodetype">getnodetype()</a></dt></h4><dd>
|
<dt><h4><a name="method_ba_Node__getnodetype">getnodetype()</a></dt></h4><dd>
|
||||||
@ -5732,18 +5780,6 @@ method) and will convert it to a None value if it does not exist.
|
|||||||
For more info, see notes on 'existables' here:
|
For more info, see notes on 'existables' here:
|
||||||
https://ballistica.net/wiki/Coding-Style-Guide</p>
|
https://ballistica.net/wiki/Coding-Style-Guide</p>
|
||||||
|
|
||||||
<hr>
|
|
||||||
<h2><strong><a name="function_ba_get_collision_info">ba.get_collision_info()</a></strong></h3>
|
|
||||||
<p><span>get_collision_info(*args: Any) -> Any</span></p>
|
|
||||||
|
|
||||||
<p>Return collision related values</p>
|
|
||||||
|
|
||||||
<p>Category: <a href="#function_category_Gameplay_Functions">Gameplay Functions</a></p>
|
|
||||||
|
|
||||||
<p>Returns a single collision value or tuple of values such as location,
|
|
||||||
depth, nodes involved, etc. Only call this in the handler of a
|
|
||||||
collision-triggered callback or message</p>
|
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
<h2><strong><a name="function_ba_get_valid_languages">ba.get_valid_languages()</a></strong></h3>
|
<h2><strong><a name="function_ba_get_valid_languages">ba.get_valid_languages()</a></strong></h3>
|
||||||
<p><span>get_valid_languages() -> List[str]</span></p>
|
<p><span>get_valid_languages() -> List[str]</span></p>
|
||||||
@ -5785,6 +5821,12 @@ to be loaded. To avoid hitches, instantiate your media objects in
|
|||||||
advance of when you will be using them, allowing time for them to load
|
advance of when you will be using them, allowing time for them to load
|
||||||
in the background if necessary.</p>
|
in the background if necessary.</p>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<h2><strong><a name="function_ba_getcollision">ba.getcollision()</a></strong></h3>
|
||||||
|
<p><span>getcollision() -> Collision</span></p>
|
||||||
|
|
||||||
|
<p>Return the in-progress collision.</p>
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
<h2><strong><a name="function_ba_getmaps">ba.getmaps()</a></strong></h3>
|
<h2><strong><a name="function_ba_getmaps">ba.getmaps()</a></strong></h3>
|
||||||
<p><span>getmaps(playtype: str) -> List[str]</span></p>
|
<p><span>getmaps(playtype: str) -> List[str]</span></p>
|
||||||
|
|||||||
@ -149,7 +149,6 @@ def test_validate() -> None:
|
|||||||
dataclass_validate(tclass)
|
dataclass_validate(tclass)
|
||||||
|
|
||||||
# No longer valid.
|
# No longer valid.
|
||||||
# noinspection PyTypeHints
|
|
||||||
tclass.ival = None # type: ignore
|
tclass.ival = None # type: ignore
|
||||||
with pytest.raises(TypeError):
|
with pytest.raises(TypeError):
|
||||||
dataclass_validate(tclass)
|
dataclass_validate(tclass)
|
||||||
|
|||||||
@ -80,7 +80,6 @@ class EntityTest(entity.Entity):
|
|||||||
fval2 = entity.Field('f2', entity.Float3Value())
|
fval2 = entity.Field('f2', entity.Float3Value())
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyTypeHints
|
|
||||||
def test_entity_values() -> None:
|
def test_entity_values() -> None:
|
||||||
"""Test various entity assigns for value and type correctness."""
|
"""Test various entity assigns for value and type correctness."""
|
||||||
ent = EntityTest()
|
ent = EntityTest()
|
||||||
@ -134,7 +133,6 @@ def test_entity_values() -> None:
|
|||||||
assert dict(ent.str_int_dict.items()) == {'foo': 123}
|
assert dict(ent.str_int_dict.items()) == {'foo': 123}
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyTypeHints
|
|
||||||
def test_entity_values_2() -> None:
|
def test_entity_values_2() -> None:
|
||||||
"""Test various entity assigns for value and type correctness."""
|
"""Test various entity assigns for value and type correctness."""
|
||||||
|
|
||||||
@ -191,7 +189,6 @@ def test_entity_values_2() -> None:
|
|||||||
assert static_type_equals(ent.grp.compoundlist[0].subval, bool)
|
assert static_type_equals(ent.grp.compoundlist[0].subval, bool)
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyTypeHints
|
|
||||||
def test_field_copies() -> None:
|
def test_field_copies() -> None:
|
||||||
"""Test copying various values between fields."""
|
"""Test copying various values between fields."""
|
||||||
ent1 = EntityTest()
|
ent1 = EntityTest()
|
||||||
|
|||||||
@ -121,7 +121,6 @@ class EntityMixin:
|
|||||||
self.d_data = target.d_data
|
self.d_data = target.d_data
|
||||||
|
|
||||||
# Make sure target blows up if someone tries to use it.
|
# Make sure target blows up if someone tries to use it.
|
||||||
# noinspection PyTypeHints
|
|
||||||
target.d_data = None # type: ignore
|
target.d_data = None # type: ignore
|
||||||
|
|
||||||
def pruned_data(self) -> Dict[str, Any]:
|
def pruned_data(self) -> Dict[str, Any]:
|
||||||
|
|||||||
@ -99,7 +99,7 @@ class DispatchMethodWrapper(Generic[TARG, TRET]):
|
|||||||
registry: Dict[Any, Callable]
|
registry: Dict[Any, Callable]
|
||||||
|
|
||||||
|
|
||||||
# noinspection PyTypeHints, PyProtectedMember
|
# noinspection PyProtectedMember
|
||||||
def dispatchmethod(
|
def dispatchmethod(
|
||||||
func: Callable[[Any, TARG],
|
func: Callable[[Any, TARG],
|
||||||
TRET]) -> DispatchMethodWrapper[TARG, TRET]:
|
TRET]) -> DispatchMethodWrapper[TARG, TRET]:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user