Bombsquad-Ballistica-Modded.../dist/ba_root/mods/spazmod/effects.py

419 lines
19 KiB
Python
Raw Normal View History

# -*- coding: utf-8 -*-
# Released under the MIT License. See LICENSE for details.
#
"""Functionality related to player-controlled Spazzes."""
from __future__ import annotations
2023-02-19 13:24:59 +05:30
from ba._generated.enums import TimeType
from typing import TYPE_CHECKING, TypeVar, overload
from bastd.actor.spaz import *
from bastd.gameutils import SharedObjects
from typing import Any, Sequence, Optional, Dict, List, Union, Callable, Tuple, Set, Type, Literal
from bastd.actor import playerspaz
from bastd.actor.playerspaz import *
from bastd.actor.spazfactory import SpazFactory
from bastd.actor.popuptext import PopupText
2023-02-19 13:24:59 +05:30
from bastd.actor import spaz, spazappearance
from bastd.actor import bomb as stdbomb
from bastd.actor.powerupbox import PowerupBoxFactory
2023-02-19 13:24:59 +05:30
import ba
import _ba
import bastd
import weakref
import random
import math
import time
import base64
import os
import json
import setting
2022-09-25 16:35:32 +05:30
import ba.internal
from playersData import pdata
from stats import mystats
PlayerType = TypeVar('PlayerType', bound=ba.Player)
TeamType = TypeVar('TeamType', bound=ba.Team)
tt = ba.TimeType.SIM
tf = ba.TimeFormat.MILLISECONDS
2023-02-19 13:24:59 +05:30
multicolor = {0: ((0+random.random()*3.0), (0+random.random()*3.0), (0+random.random()*3.0)),
250: ((0+random.random()*3.0), (0+random.random()*3.0), (0+random.random()*3.0)),
500: ((0+random.random()*3.0), (0+random.random()*3.0), (0+random.random()*3.0)),
750: ((0+random.random()*3.0), (0+random.random()*3.0), (0+random.random()*3.0)),
1000: ((0+random.random()*3.0), (0+random.random()*3.0), (0+random.random()*3.0)),
1250: ((0+random.random()*3.0), (0+random.random()*3.0), (0+random.random()*3.0)),
1500: ((0+random.random()*3.0), (0+random.random()*3.0), (0+random.random()*3.0)),
1750: ((0+random.random()*3.0), (0+random.random()*3.0), (0+random.random()*3.0)),
2000: ((0+random.random()*3.0), (0+random.random()*3.0), (0+random.random()*3.0)),
2250: ((0+random.random()*3.0), (0+random.random()*3.0), (0+random.random()*3.0)),
2500: ((0+random.random()*3.0), (0+random.random()*3.0), (0+random.random()*3.0))}
2022-02-15 09:03:44 +05:30
class SurroundBallFactory(object):
def __init__(self):
self.bonesTex = ba.gettexture("powerupCurse")
self.bonesModel = ba.getmodel("bonesHead")
self.bearTex = ba.gettexture("bearColor")
self.bearModel = ba.getmodel("bearHead")
self.aliTex = ba.gettexture("aliColor")
self.aliModel = ba.getmodel("aliHead")
self.b9000Tex = ba.gettexture("cyborgColor")
self.b9000Model = ba.getmodel("cyborgHead")
self.frostyTex = ba.gettexture("frostyColor")
self.frostyModel = ba.getmodel("frostyHead")
self.cubeTex = ba.gettexture("crossOutMask")
self.cubeModel = ba.getmodel("powerup")
try:
self.mikuModel = ba.getmodel("operaSingerHead")
self.mikuTex = ba.gettexture("operaSingerColor")
2023-02-19 13:24:59 +05:30
except:
ba.print_exception()
self.ballMaterial = ba.Material()
self.impactSound = ba.getsound("impactMedium")
2023-02-19 13:24:59 +05:30
self.ballMaterial.add_actions(
actions=("modify_node_collision", "collide", False))
class SurroundBall(ba.Actor):
def __init__(self, spaz, shape="bones"):
ba.Actor.__init__(self)
self.spazRef = weakref.ref(spaz)
factory = self.getFactory()
s_model, s_texture = {
"bones": (factory.bonesModel, factory.bonesTex),
"bear": (factory.bearModel, factory.bearTex),
"ali": (factory.aliModel, factory.aliTex),
"b9000": (factory.b9000Model, factory.b9000Tex),
"miku": (factory.mikuModel, factory.mikuTex),
"frosty": (factory.frostyModel, factory.frostyTex),
"RedCube": (factory.cubeModel, factory.cubeTex)
}.get(shape, (factory.bonesModel, factory.bonesTex))
2023-02-19 13:24:59 +05:30
self.node = ba.newnode("prop", attrs={"model": s_model, "body": "sphere", "color_texture": s_texture, "reflection": "soft", "model_scale": 0.5, "body_scale": 0.1, "density": 0.1, "reflection_scale": [
0.15], "shadow_size": 0.6, "position": spaz.node.position, "velocity": (0, 0, 0), "materials": [SharedObjects.get().object_material, factory.ballMaterial]}, delegate=self)
self.surroundTimer = None
self.surroundRadius = 1.0
self.angleDelta = math.pi / 12.0
self.curAngle = random.random() * math.pi * 2.0
self.curHeight = 0.0
self.curHeightDir = 1
self.heightDelta = 0.2
self.heightMax = 1.0
self.heightMin = 0.1
self.initTimer(spaz.node.position)
def getTargetPosition(self, spazPos):
p = spazPos
2023-02-19 13:24:59 +05:30
pt = (p[0] + self.surroundRadius * math.cos(self.curAngle), p[1] +
self.curHeight, p[2] + self.surroundRadius * math.sin(self.curAngle))
self.curAngle += self.angleDelta
self.curHeight += self.heightDelta * self.curHeightDir
2023-02-19 13:24:59 +05:30
if (self.curHeight > self.heightMax) or (self.curHeight < self.heightMin):
self.curHeightDir = -self.curHeightDir
return pt
def initTimer(self, p):
self.node.position = self.getTargetPosition(p)
2023-02-19 13:24:59 +05:30
self.surroundTimer = ba.Timer(
30, self.circleMove, repeat=True, timetype=tt, timeformat=tf)
def circleMove(self):
spaz = self.spazRef()
if spaz is None or not spaz.is_alive() or not spaz.node.exists():
self.handlemessage(ba.DieMessage())
return
p = spaz.node.position
pt = self.getTargetPosition(p)
pn = self.node.position
d = [pt[0] - pn[0], pt[1] - pn[1], pt[2] - pn[2]]
speed = self.getMaxSpeedByDir(d)
self.node.velocity = speed
@staticmethod
def getMaxSpeedByDir(direction):
k = 7.0 / max((abs(x) for x in direction))
return tuple(x * k for x in direction)
def handlemessage(self, m):
ba.Actor.handlemessage(self, m)
if isinstance(m, ba.DieMessage):
2023-02-19 13:24:59 +05:30
if self.surroundTimer is not None:
self.surroundTimer = None
self.node.delete()
elif isinstance(m, ba.OutOfBoundsMessage):
self.handlemessage(ba.DieMessage())
def getFactory(cls):
activity = ba.getactivity()
2023-02-19 13:24:59 +05:30
if activity is None:
raise Exception("no current activity")
try:
return activity._sharedSurroundBallFactory
except Exception:
f = activity._sharedSurroundBallFactory = SurroundBallFactory()
return f
2023-02-19 13:24:59 +05:30
class Effect(ba.Actor):
def __init__(self, spaz, player):
ba.Actor.__init__(self)
_settings = setting.get_settings_data()
custom_tag = pdata.get_custom()['customtag']
custom_effects = pdata.get_custom()['customeffects']
self.source_player = player
self.spazRef = weakref.ref(spaz)
self.spazNormalColor = spaz.node.color
self.Decorations = []
self.Enhancements = []
self._powerScale = 1.0
self._armorScale = 1.0
self._lifeDrainScale = None
self._damageBounceScale = None
self._remoteMagicDamge = False
self._MulitPunch = None
self._AntiFreeze = 1.0
self.fallWings = 0
self.checkDeadTimer = None
self._hasDead = False
self.light = None
node_id = self.source_player.node.playerID
cl_str = None
clID = None
2022-09-25 16:35:32 +05:30
for c in ba.internal.get_foreground_host_session().sessionplayers:
if (c.activityplayer) and (c.activityplayer.node.playerID == node_id):
profiles = c.inputdevice.get_player_profiles()
clID = c.inputdevice.client_id
2022-06-09 01:42:09 +05:30
cl_str = c.get_v1_account_id()
try:
if cl_str in custom_effects:
effect = custom_effects[cl_str]
if effect == 'ice':
2021-05-31 16:59:13 +05:30
self.emitIce()
2023-02-19 13:24:59 +05:30
self.snowTimer = ba.Timer(
0.5, self.emitIce, repeat=True, timetype=TimeType.SIM)
2021-05-31 16:59:13 +05:30
return
elif effect == 'sweat':
2023-02-19 13:24:59 +05:30
self.smokeTimer = ba.Timer(
0.6, self.emitSmoke, repeat=True, timetype=TimeType.SIM)
2021-05-31 16:59:13 +05:30
return
elif effect == 'scorch':
2023-02-19 13:24:59 +05:30
self.scorchTimer = ba.Timer(
500, self.update_Scorch, repeat=True, timetype=tt, timeformat=tf)
2021-05-31 16:59:13 +05:30
return
elif effect == 'glow':
self.addLightColor((1, 0.6, 0.4))
2023-02-19 13:24:59 +05:30
self.checkDeadTimer = ba.Timer(
150, self.checkPlayerifDead, repeat=True, timetype=tt, timeformat=tf)
2021-05-31 16:59:13 +05:30
return
elif effect == 'distortion':
2023-02-19 13:24:59 +05:30
self.DistortionTimer = ba.Timer(
1000, self.emitDistortion, repeat=True, timetype=tt, timeformat=tf)
2021-05-31 16:59:13 +05:30
return
elif effect == 'slime':
2023-02-19 13:24:59 +05:30
self.slimeTimer = ba.Timer(
250, self.emitSlime, repeat=True, timetype=tt, timeformat=tf)
2021-05-31 16:59:13 +05:30
return
elif effect == 'metal':
2023-02-19 13:24:59 +05:30
self.metalTimer = ba.Timer(
500, self.emitMetal, repeat=True, timetype=tt, timeformat=tf)
2021-05-31 16:59:13 +05:30
return
elif effect == 'surrounder':
self.surround = SurroundBall(spaz, shape="bones")
2021-05-31 16:59:13 +05:30
return
elif effect == 'spark':
2023-02-19 13:24:59 +05:30
self.sparkTimer = ba.Timer(
100, self.emitSpark, repeat=True, timetype=tt, timeformat=tf)
2021-05-31 16:59:13 +05:30
return
except:
pass
if _settings['enablestats']:
pats = mystats.get_all_stats()
2021-05-31 16:59:13 +05:30
if cl_str in pats and _settings['enableTop5effects']:
rank = pats[cl_str]["rank"]
if rank < 6:
if rank == 1:
2023-02-19 13:24:59 +05:30
# self.neroLightTimer = ba.Timer(500, ba.WeakCall(self.neonLightSwitch,("shine" in self.Decorations),("extra_Highlight" in self.Decorations),("extra_NameColor" in self.Decorations)),repeat = True, timetype=tt, timeformat=tf)
self.surround = SurroundBall(spaz, shape="bones")
elif rank == 2:
2023-02-19 13:24:59 +05:30
self.smokeTimer = ba.Timer(
40, self.emitSmoke, repeat=True, timetype=tt, timeformat=tf)
elif rank == 3:
2023-02-19 13:24:59 +05:30
self.addLightColor((1, 0.6, 0.4))
self.scorchTimer = ba.Timer(
500, self.update_Scorch, repeat=True, timetype=tt, timeformat=tf)
elif rank == 4:
2023-02-19 13:24:59 +05:30
self.metalTimer = ba.Timer(
500, self.emitMetal, repeat=True, timetype=tt, timeformat=tf)
else:
2023-02-19 13:24:59 +05:30
self.addLightColor((1, 0.6, 0.4))
self.checkDeadTimer = ba.Timer(
150, self.checkPlayerifDead, repeat=True, timetype=tt, timeformat=tf)
if "smoke" and "spark" and "snowDrops" and "slimeDrops" and "metalDrops" and "Distortion" and "neroLight" and "scorch" and "HealTimer" and "KamikazeCheck" not in self.Decorations:
2023-02-19 13:24:59 +05:30
# self.checkDeadTimer = ba.Timer(150, ba.WeakCall(self.checkPlayerifDead), repeat=True, timetype=tt, timeformat=tf)
if self.source_player.is_alive() and self.source_player.actor.node.exists():
2023-02-19 13:24:59 +05:30
# print("OK")
self.source_player.actor.node.addDeathAction(
ba.Call(self.handlemessage, ba.DieMessage()))
def add_multicolor_effect(self):
2023-02-19 13:24:59 +05:30
if spaz.node:
ba.animate_array(spaz.node, 'color', 3, multicolor,
True, timetype=tt, timeformat=tf)
def checkPlayerifDead(self):
spaz = self.spazRef()
if spaz is None or not spaz.is_alive() or not spaz.node.exists():
self.checkDeadTimer = None
self.handlemessage(ba.DieMessage())
return
def update_Scorch(self):
spaz = self.spazRef()
if spaz is not None and spaz.is_alive() and spaz.node.exists():
2023-02-19 13:24:59 +05:30
color = (random.random(), random.random(), random.random())
if not hasattr(self, "scorchNode") or self.scorchNode == None:
self.scorchNode = None
2023-02-19 13:24:59 +05:30
self.scorchNode = ba.newnode("scorch", attrs={"position": (
spaz.node.position), "size": 1.17, "big": True})
spaz.node.connectattr("position", self.scorchNode, "position")
ba.animate_array(self.scorchNode, "color", 3, {
0: self.scorchNode.color, 500: color}, timetype=tt, timeformat=tf)
else:
self.scorchTimer = None
2023-02-19 13:24:59 +05:30
if hasattr(self, "scorchNode"):
self.scorchNode.delete()
self.handlemessage(ba.DieMessage())
2023-02-19 13:24:59 +05:30
def neonLightSwitch(self, shine, Highlight, NameColor):
spaz = self.spazRef()
if spaz is not None and spaz.is_alive() and spaz.node.exists():
2023-02-19 13:24:59 +05:30
color = (random.random(), random.random(), random.random())
if NameColor:
ba.animate_array(spaz.node, "nameColor", 3, {
0: spaz.node.nameColor, 500: ba.safecolor(color)}, timetype=tt, timeformat=tf)
if shine:
color = tuple([min(10., 10 * x) for x in color])
ba.animate_array(spaz.node, "color", 3, {
0: spaz.node.color, 500: color}, timetype=tt, timeformat=tf)
if Highlight:
2023-02-19 13:24:59 +05:30
# print spaz.node.highlight
color = (random.random(), random.random(), random.random())
if shine:
color = tuple([min(10., 10 * x) for x in color])
ba.animate_array(spaz.node, "highlight", 3, {
0: spaz.node.highlight, 500: color}, timetype=tt, timeformat=tf)
else:
self.neroLightTimer = None
self.handlemessage(ba.DieMessage())
def addLightColor(self, color):
2023-02-19 13:24:59 +05:30
self.light = ba.newnode(
"light", attrs={"color": color, "height_attenuated": False, "radius": 0.4})
self.spazRef().node.connectattr("position", self.light, "position")
2023-02-19 13:24:59 +05:30
ba.animate(self.light, "intensity", {
0: 0.1, 250: 0.3, 500: 0.1}, loop=True, timetype=tt, timeformat=tf)
def emitDistortion(self):
spaz = self.spazRef()
if spaz is None or not spaz.is_alive() or not spaz.node.exists():
self.handlemessage(ba.DieMessage())
return
2023-02-19 13:24:59 +05:30
ba.emitfx(position=spaz.node.position,
emit_type="distortion", spread=1.0)
ba.emitfx(position=spaz.node.position, velocity=spaz.node.velocity,
count=random.randint(1, 5), emit_type="tendrils", tendril_type="smoke")
def emitSpark(self):
spaz = self.spazRef()
if spaz is None or not spaz.is_alive() or not spaz.node.exists():
self.handlemessage(ba.DieMessage())
return
2023-02-19 13:24:59 +05:30
ba.emitfx(position=spaz.node.position, velocity=spaz.node.velocity,
count=random.randint(1, 10), scale=2, spread=0.2, chunk_type="spark")
def emitIce(self):
spaz = self.spazRef()
if spaz is None or not spaz.is_alive() or not spaz.node.exists():
self.handlemessage(ba.DieMessage())
return
2023-02-19 13:24:59 +05:30
ba.emitfx(position=spaz.node.position, velocity=spaz.node.velocity,
count=random.randint(2, 8), scale=0.4, spread=0.2, chunk_type="ice")
def emitSmoke(self):
spaz = self.spazRef()
if spaz is None or not spaz.is_alive() or not spaz.node.exists():
self.handlemessage(ba.DieMessage())
return
2023-02-19 13:24:59 +05:30
ba.emitfx(position=spaz.node.position, velocity=spaz.node.velocity,
count=random.randint(1, 10), scale=2, spread=0.2, chunk_type="sweat")
def emitSlime(self):
spaz = self.spazRef()
if spaz is None or not spaz.is_alive() or not spaz.node.exists():
self.handlemessage(ba.DieMessage())
return
2023-02-19 13:24:59 +05:30
ba.emitfx(position=spaz.node.position, velocity=spaz.node.velocity,
count=random.randint(1, 10), scale=0.4, spread=0.2, chunk_type="slime")
def emitMetal(self):
spaz = self.spazRef()
if spaz is None or not spaz.is_alive() or not spaz.node.exists():
self.handlemessage(ba.DieMessage())
return
2023-02-19 13:24:59 +05:30
ba.emitfx(position=spaz.node.position, velocity=spaz.node.velocity,
count=random.randint(2, 8), scale=0.4, spread=0.2, chunk_type="metal")
def handlemessage(self, m):
2023-02-19 13:24:59 +05:30
# self._handlemessageSanityCheck()
if isinstance(m, ba.OutOfBoundsMessage):
self.handlemessage(ba.DieMessage())
elif isinstance(m, ba.DieMessage):
2023-02-19 13:24:59 +05:30
if hasattr(self, "light") and self.light is not None:
self.light.delete()
if hasattr(self, "smokeTimer"):
self.smokeTimer = None
if hasattr(self, "surround"):
self.surround = None
if hasattr(self, "sparkTimer"):
self.sparkTimer = None
if hasattr(self, "snowTimer"):
self.snowTimer = None
if hasattr(self, "metalTimer"):
self.metalTimer = None
if hasattr(self, "DistortionTimer"):
self.DistortionTimer = None
if hasattr(self, "slimeTimer"):
self.slimeTimer = None
if hasattr(self, "KamikazeCheck"):
self.KamikazeCheck = None
if hasattr(self, "neroLightTimer"):
self.neroLightTimer = None
if hasattr(self, "checkDeadTimer"):
self.checkDeadTimer = None
if hasattr(self, "HealTimer"):
self.HealTimer = None
if hasattr(self, "scorchTimer"):
self.scorchTimer = None
if hasattr(self, "scorchNode"):
self.scorchNode = None
if not self._hasDead:
spaz = self.spazRef()
2023-02-19 13:24:59 +05:30
# print str(spaz) + "Spaz"
if spaz is not None and spaz.is_alive() and spaz.node.exists():
spaz.node.color = self.spazNormalColor
killer = spaz.last_player_attacked_by if spaz is not None else None
try:
2023-02-19 13:24:59 +05:30
if killer in (None, ba.Player(None)) or killer.actor is None or not killer.actor.exists() or killer.actor.hitPoints <= 0:
killer = None
except:
killer = None
2023-02-19 13:24:59 +05:30
# if hasattr(self,"hasDead") and not self.hasDead:
self._hasDead = True
ba.Actor.handlemessage(self, m)