test/A-Soccer(5).py

1186 lines
49 KiB
Python
Raw Permalink Normal View History

2025-11-23 17:03:48 +00:00
# ba_meta require api 9
# can u see the mouse 😱🐀 take car of your self
# خلي بالك من الفار يمكن ياكل صباعك 😱🐀الرجاء الحظر منه
from __future__ import annotations
import math
import inspect
import babase
import random
import bauiv1 as bui
import bascenev1 as bs
from os import listdir
from bascenev1lib import maps
from typing import TYPE_CHECKING
from bascenev1lib.actor import playerspaz
from bascenev1lib.actor.bomb import Bomb
from bascenev1lib.gameutils import SharedObjects
from bascenev1lib.actor.playerspaz import PlayerSpaz
from bascenev1lib.actor.scoreboard import Scoreboard
from bascenev1 import get_foreground_host_activity as ga
if TYPE_CHECKING:
from typing import Any, Sequence, Dict, Type, List, Optional, Union
""" Feel Free To Edit, it's All Yours <3 """
""" Discord: marwan_magdi """
textures_dir = listdir("ba_data/textures")
meshes_dir = listdir("ba_data/meshes")
textures = [i.split('.')[0] for i in textures_dir]
meshes = [i.split('.')[0] for i in meshes_dir]
NormalPlayerSpaz = playerspaz.PlayerSpaz # storing the original spaz
class NewPlayerSpaz(playerspaz.PlayerSpaz): # tweaked spaz class
def __init__(self, player: bascenev1.Player, color: Sequence[float] = (1.0, 1.0, 1.0), highlight: Sequence[float] = (0.5, 0.5, 0.5), character: str = 'Spaz', powerups_expire: bool = True, start_invincible: bool = False):
super().__init__(player=player,color=color,highlight=highlight,character=character, powerups_expire=powerups_expire)
self.equip_boxing_gloves() # our pretty Ggoves
def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, bs.HitMessage): # if spaz is hitted
self.node.handlemessage('flash') # emit a flash
pass # no more.
else:
return super().handlemessage(msg)
class BallDiedMessage:
def __init__(self, ball: Ball):
self.ball = ball
class Ball(bs.Actor):
def __init__(self, position: Sequence[float] = (0.0, 0.0, 0.0), is_area_of_interest: bool = True):
super().__init__()
activity = self.getactivity()
assert activity is not None
assert isinstance(activity, SoccerGame)
self.scale = 1
self.mesh_scale = self.scale*0.25
self.gravity = 1.2
shared = SharedObjects.get()
ball_material = [shared.footing_material]
ball_material = [shared.object_material, activity.ball_material]
self.all_players_hitted: List[Player] = []
self.all_players_touched: Dict[int, Player] = {}
self.spawn_pos = (position[0], position[1]+0.6, position[2])
self.node = bs.newnode('prop',delegate=self,attrs={
'mesh': activity.ball_model,
'color_texture': activity.ball_tex,
'body': 'sphere',
'body_scale': self.scale, # the real colliding size
'mesh_scale': self.mesh_scale, # the outside appearance
'reflection': 'soft',
'reflection_scale': [0],
'shadow_size': 3,
'is_area_of_interest': is_area_of_interest,
'position': self.spawn_pos,
'materials': ball_material,
'gravity_scale': 0
})
bs.animate(self.node, 'mesh_scale', {0:0, 0.01:self.mesh_scale})
def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, bs.DieMessage):
assert self.node
self.node.delete()
activity = self._activity()
if activity and not msg.immediate:
activity.handlemessage(BallDiedMessage(self))
elif isinstance(msg, bs.OutOfBoundsMessage):
activity = self._activity()
if activity.gk_mode:
activity.handle_ball_wall_collide()
assert self.node
self.node.position = self.spawn_pos
elif isinstance(msg, bs.HitMessage):
assert self.node
assert msg.force_direction is not None
s_player = msg.get_source_player(Player)
x = 1 # power multiplier
if s_player is not None:
activity = self._activity()
if activity:
if s_player in activity.players:
self.all_players_touched[s_player.team.id] = s_player
self.all_players_hitted.append(s_player)
if activity.assistant_mode:
if activity.activated:
activity.left_right = 0
activity.up_down = 0
x = 1.2
else:
activity.left_right = 1
activity.up_down = 1
activity.assistant_setup()
self.node.handlemessage('impulse',
msg.pos[0], msg.pos[1], msg.pos[2],
msg.velocity[0]*x, msg.velocity[1]*x, msg.velocity[2]*x,
msg.magnitude*x,
msg.velocity_magnitude*x, 0, 0,
msg.force_direction[0], msg.force_direction[1],msg.force_direction[2]
)
else:
super().handlemessage(msg)
class Wall(bs.Actor):
def __init__(self, position: Tuple[float, float, float]=(0,0,0), scale: Tuple[int, int, int]=(10,10,10)):
super().__init__()
activity = self.getactivity()
self.node = bs.newnode('region',attrs={
'position': position,
'scale': scale,
'type': 'box',
'materials': [activity.wall_material]
})
class Dot(bs.Actor):
def __init__(self, position: Tuple[float, float, float]=(0,0,0), size: List[int]=[0.3], color: Tuple[float, float, float]=(1,0,0)):
super().__init__()
activity = bs.getactivity()
self.node = bs.newnode('locator', attrs={
'shape':'circle',
'color': color,
'opacity':1,
'position': position,
'size': size,
'drawShadow': False
})
class Text(bs.Actor):
def __init__(self, text: Str='' , scale: Float=1.0, position: Tuple(Float, Float, Float)=(0,0,0), color: Tuple(Float, Float, Float)=(1,0,0), shadow: float=1.0, h_align=None, v_attach=None, in_world=True):
super().__init__()
activity = bs.getactivity()
self.node = bs.newnode('text', attrs={
'text': text,
'color': color,
'opacity':1,
'position': position,
'scale': scale,
'in_world': in_world,
'shadow': shadow
})
if h_align is not None:
self.node.h_align = h_align
if v_attach is not None:
self.node.v_attach = v_attach
def delete(self) -> None:
self.node.delete()
class Player(bs.Player['Team']):
pass
class Team(bs.Team[Player]):
def __init__(self) -> None:
self.score = 0
# ba_meta export bascenev1.GameActivity
class SoccerGame(bs.TeamGameActivity[Player, Team]):
creator = "\ue043Empoli FC\ue043"
name = 'Empoli FC'
description = f"Showup Your Soccer Skills\nin a Very Customizable Soccer Game \ue047.\n\n{creator}"
gk_easy, gk_medium, gk_hard = 300, 350, 380
available_settings = [
bs.IntSetting('Target Score',
min_value=1,
default=10,
increment=1
),
bs.IntChoiceSetting('Weather', choices=[
#random
('Random 🎲', -1),
('Clear ☀️', 0),
# Rain
('Light Rain 🌦️', 1),
('Medium Rain 🌧️', 2),
('Heavy Rain ⛈️', 3),
# Snow
('Light Snow ❄️', 4),
('Medium Snow 🌨️', 5),
('Blizzard 🌪️', 6),
# Storm
('Storm ⚡', 7),
('Thunderstorm ⛈️', 8),
('Mega Storm 🌩️', 9),
], default=0),
bs.IntChoiceSetting('Game Time',choices=[
('None', 0),
('1 Minute', 60),
('2 Minutes', 120),
('5 Minutes', 300),
('10 Minutes', 600),
('20 Minutes', 1200)
],
default=300
),
bs.FloatChoiceSetting('Respawn Times',choices=[
('Shorter', 0.1),
('Short', 0.5),
('Normal', 1.0),
('Long', 2.0),
('Longer', 4.0)
],
default=0.1
),
bs.IntChoiceSetting('GK Practice Mode',choices=[
('Disabled', 0),
('Beginner', gk_easy),
('Amatuer', gk_medium),
('Intermediate', gk_hard),
],
default=0
),
bs.IntChoiceSetting('Ball Texture',choices=[
('Blue Stripes', 1),
('Orange Stripes', 2),
('Yellow Stripes', 3),
('Volley Ball', 4),
('Empoli Ball', 5),
],
default=1
),
bs.BoolSetting('Epic SlowMotion', True),
bs.BoolSetting('Map Limits (Invisible Walls)', True),
bs.BoolSetting('Map Posters', True),
bs.BoolSetting('Night Mode', True),
bs.BoolSetting('Invincible Players', True),
bs.BoolSetting('Icy Ground', False),
bs.BoolSetting('Enable Pickup', False),
bs.BoolSetting('Assisted Ball', False)]
allow_pausing = False
default_music = bs.MusicType.HOCKEY
@classmethod
def supports_session_type(cls, sessiontype: Type[bs.Session]) -> bool:
return issubclass(sessiontype, bs.DualTeamSession)
@classmethod
def get_supported_maps(cls, sessiontype: Type[bs.Session]) -> List[str]:
return ['Soccer Stadium']
def __init__(self, settings: dict):
super().__init__(settings)
shared = SharedObjects.get()
# Game Modes
self.gk_mode = int(settings['GK Practice Mode'])
self.gk_level = {0:None, self.gk_easy:'Easy ★', self.gk_medium:'Medium ★★', self.gk_hard:'Hard ★★★'}[self.gk_mode]
self.assistant_mode = bool(settings['Assisted Ball'])
#حفظ الإعدادات
self.weather_mode = int(settings['Weather'])
if self.weather_mode == -1: # يعني Random
self.weather_mode = random.randint(0, 9)
# Game Settings
self.map_posters = bool(settings['Map Posters'])
self.limited_map = bool(settings['Map Limits (Invisible Walls)'])
self.invincible_mode = bool(settings['Invincible Players'])
self.enable_pickup = bool(settings['Enable Pickup'])
self.icy_ground = bool(settings['Icy Ground'])
self.slow_motion = bool(settings['Epic SlowMotion'])
self.night_mode = bool(settings['Night Mode'])
self.score_to_win = int(settings['Target Score'])
self.time_limit = float(settings['Game Time'])
self.cheer_sound = bui.getsound('cheer')
self.chant_sound = bui.getsound('crowdChant')
self.foghorn_sound = bui.getsound('foghorn')
self.swipsound = bui.getsound('swip')
self.whistle_sound = bui.getsound('refWhistle')
self.ball_textures = {
1 : bs.gettexture('ouyaUButton'),
2 : bs.gettexture('ouyaIcon'),
3 : bs.gettexture('ouyaYButton'),
4 : bs.gettexture('gameCircleIcon'),
5 : bs.gettexture('helloxd'),
}
self.ball_tex = self.ball_textures[int(settings['Ball Texture'])]
self.ball_model = bs.getmesh('shield')
self.ball_sound = bs.getsound('metalHit')
self.emojis = ["\ue043","\ue04f",'\ue046','\ue048'] # for scoring suspense
self.expressions = ['SUUIIII!','CALMA CALMA','BOOOM!','GOOOOAAL!']
# Materials And Regions
self.ball_material = bs.Material()
self.ball_material.add_actions(
actions=(('modify_part_collision','friction', 1.1)))
self.ball_material.add_actions(
conditions=('they_have_material',shared.pickup_material),
actions=('modify_part_collision','collide', True))
self.ball_material.add_actions(
conditions=(('we_are_younger_than', 100),'and',('they_have_material', shared.object_material)),
actions=('modify_node_collision', 'collide', True))
self.ball_material.add_actions(
conditions=('they_have_material',shared.footing_material),
actions=('impact_sound',self.ball_sound, 0.2, 5))
self.ball_material.add_actions(
conditions=('they_have_material', shared.player_material),
actions=(('call', 'at_connect', self.handle_ball_player_collide)))
self.score_region_material = bs.Material()
self.score_region_material.add_actions(
conditions=('they_have_material', self.ball_material),
actions=(('modify_part_collision', 'collide',True),
('call', 'at_connect', self.handle_score_gk_mode if self.gk_mode else self.handle_score)))
self.wall_material = bs.Material()
self.wall_material.add_actions(
conditions=('they_have_material', self.ball_material),
actions=(('modify_part_collision', 'collide',True),
('call', 'at_connect', self.handle_ball_wall_collide)))
self.item_material = bs.Material()
self.item_material.add_actions(
actions=(
('modify_part_collision', 'collide', True),
('modify_part_collision', 'physical', True)))
self.score_regions: Optional[List[bs.NodeActor]] = []
self.ball_spawn_pos: Optional[Sequence[float]] = None
self.ball: Optional[Ball] = None
# Extras & Abbreviations
self.red_dot_y = 9/1000 # Red Dot Height From Ground
self.rainbow_animate = {0:(1,0,0), 0.5:(1,1,0), 1:(0,1,0), 1.5:(0,1,1), 2:(0,0,1), 2.5:(1,0,1), 3:(1,0,0)}
self.bsd = 3.5 # Ball Spawn Delay
##########################################
self.celebrater = 2 #وقت مخصص للاحتفال
self.delete_text = 2 # مسح النص الاحتفالي
##########################################
self.ctt = 0.03 # Scorer Text Transition Time
self.att = self.ctt # Assister Text Transition Time (as the scorer)
self.glt = 0.1 # Scorer Glow Transition Time
self.gtt = self.ctt # "GOALLL!" Text Transition Time (as the scorer also)
self.sgt = 0.2 # Scorer Glow Transition Time
self.gd = "Welcome To XERO Football Club" # Game Beginning Description
self.hdag = 'Score a Goal To Win' # Heading Description (a goal)
self.hd = f"Score {self.score_to_win} Goals." # Heading Description (several goals)
self.gmgd = f"Save Your Goal « LEVEL : {self.gk_level} »" # GK Mode Game Beginning Description
self.gmhd = f"Goal Keaper Mode « LEVEL : {self.gk_level} »"# GK Mode Heading Description
self.gmbsd = 0.5 # GK Mode Ball Spawn Delay
self.activated = False # For Assistant Mode (A.M)
self.left_right, self.up_down = 1, 1 # For A.M
if self.gk_mode:
self.tips = [bs.GameTip(
'Shoot The Ball Towards Purple Lines So You Score.',
icon=bs.gettexture('storeCharacter'),
sound=bs.getsound('ding')
)]
else:
self.scoreboard = Scoreboard()
def on_begin(self) -> None:
super().on_begin()
shared = SharedObjects.get()
# ⛔ حل قوي: إزالة متكررة للأضواء
def aggressive_light_removal():
try:
lights_removed = 0
for node in bs.getnodes():
try:
# طرق متعددة للكشف عن الأضواء
if hasattr(node, 'getNodeType'):
node_type = node.getNodeType()
if node_type == 'light':
node.delete()
lights_removed += 1
continue
# إذا كانت العقدة لها خصائص الضوء
if hasattr(node, 'intensity') and hasattr(node, 'color'):
# إذا كانت في منطقة المنتصف، أزلها
if hasattr(node, 'position'):
pos = node.position
if (-15 < pos[0] < 15) and (pos[1] > 0) and (-15 < pos[2] < 15):
node.delete()
lights_removed += 1
except:
continue
if lights_removed > 0:
print(f"تم إزالة {lights_removed} ضوء في هذه الجولة")
# استمر في المراقبة كل ثانية
bs.timer(1.0, aggressive_light_removal)
except Exception as e:
print(f"خطأ في إزالة الأضواء: {e}")
bs.timer(1.0, aggressive_light_removal)
# بدء عملية الإزالة
bs.timer(0.5, aggressive_light_removal)
self.team1 = self.teams[0]
self.team2 = self.teams[1]
goal1 = Wall(self.map.defs.boxes['goal1'][0:3], self.map.defs.boxes['goal1'][6:9])
goal2 = Wall(self.map.defs.boxes['goal2'][0:3], self.map.defs.boxes['goal2'][6:9])
goal1.node.materials = [self.score_region_material]
goal2.node.materials = [self.score_region_material]
self.score_regions.append(bs.NodeActor(goal1.node))
self.score_regions.append(bs.NodeActor(goal2.node))
# Small Credits For Me...
self.credits = Text(f"{self.creator}",0.8,(0,0),(0,0,0),0,'center','bottom',False)
bs.animate_array(self.credits.node, 'color', 3, self.rainbow_animate, loop=True)
self.chant_sound.play()
self.map_highlights()
self.setup_standard_time_limit(self.time_limit)
self.ball_spawn_pos = self.map.get_flag_position(None)
if self.gk_mode:
self.gk_setup()
else:
self.update_scoreboard()
self.spawn_ball()
# في on_begin: شغّل السحابة أول مرة بعد 20 ثانية (بلا repeat)
bs.Timer(20.0, bs.Call(self.spawn_cloud), repeat=True)
# تابع: spawn_cloud مع إصلاحات
def spawn_cloud(self):
x = random.uniform(-8, 8)
z = random.uniform(-5, 5)
# سحابة خفيفة (جزيئات 'ice' تعطي لون أبيض ضبابي)
bs.emitfx(
position=(x, 10, z),
count=15,
scale=2.0,
spread=1.0,
chunk_type='ice'
)
# ضوء باهت يدي إحساس ضبابي
# try:
# cloud_light = bs.newnode('light', attrs={
# 'position': (x, 9, z),
# 'color': (0.8, 0.8, 0.85),
# 'radius': 6.0,
# 'intensity': 0.3,
# 'height_attenuated': False
# })
# # نحذف الضوء بعد مدة قصيرة
# bs.timer(2.0, cloud_light.delete)
# except Exception:
# pass
# جدولة الاستدعاء التالي بعشوائية (آمن)
next_delay = random.uniform(15.0, 30.0)
bs.timer(next_delay, self.spawn_cloud)
def apply_weather(self):
gnode = bs.getactivity().globalsnode
if self.weather_mode == 0: # clear
gnode.tint = (1, 1, 1)
bs.broadcastmessage("☀️ Clear Weather")
# ===== RAIN =====
elif self.weather_mode == 1: # light rain
self.start_rain(intensity=10, scale=0.5, speed=0.4)
elif self.weather_mode == 2: # medium rain
self.start_rain(intensity=20, scale=0.7, speed=0.3)
elif self.weather_mode == 3: # heavy rain
self.start_rain(intensity=40, scale=1.0, speed=0.2)
# ===== SNOW =====
elif self.weather_mode == 4: # light snow
self.start_snow(intensity=10, scale=0.6, speed=0.4)
elif self.weather_mode == 5: # medium snow
self.start_snow(intensity=20, scale=0.8, speed=0.3)
elif self.weather_mode == 6: # blizzard
self.start_snow(intensity=50, scale=1.2, speed=0.2)
# ===== STORM =====
elif self.weather_mode == 7: # storm
self.start_storm(light_freq=3, flash_intensity=2.0)
elif self.weather_mode == 8: # thunderstorm
self.start_storm(light_freq=2, flash_intensity=3.0)
elif self.weather_mode == 9: # mega storm
self.start_storm(light_freq=1, flash_intensity=5.0)
def start_rain(self, intensity, scale, speed):
def rain_effect():
for i in range(intensity):
x = random.uniform(-10, 10)
z = random.uniform(-6, 6)
bs.emitfx(position=(x, 10, z),
count=10,
scale=scale,
spread=1.0,
chunk_type='sweat')
for t in range(60):
bs.timer(speed * t, rain_effect)
def start_snow(self, intensity, scale, speed):
def snow_effect():
for i in range(intensity):
x = random.uniform(-10, 10)
z = random.uniform(-6, 6)
bs.emitfx(position=(x, 10, z),
count=15,
scale=scale,
spread=1.5,
chunk_type='ice')
for t in range(60):
bs.timer(speed * t, snow_effect)
def start_storm(self, light_freq, flash_intensity):
gnode = bs.getactivity().globalsnode
gnode.tint = (0.2, 0.2, 0.3)
def storm_light():
flash = bs.newnode('light', attrs={
'position': (0, 5, 0),
'color': (1, 1, 1),
'intensity': flash_intensity,
'radius': 6.0
})
bs.timer(0.3, flash.delete)
# نخليها تتكرر باستمرار
def loop_lightning():
storm_light()
bs.timer(light_freq, loop_lightning) # تتكرر كل شوية
loop_lightning()
def on_transition_in(self) -> None:
super().on_transition_in()
activity = bs.getactivity()
gnode = bs.getactivity().globalsnode
if self.night_mode:
gnode.tint = (0.82, 0.82, 0.82)
# gnode.tint = (0.72, 0.62, 0.72)
if self.icy_ground:
activity.map.is_hockey = True
else:
activity.map.is_hockey = False
def spawn_player(self, player: Player) -> None:
if self.invincible_mode:
playerspaz.PlayerSpaz = NewPlayerSpaz
else:
playerspaz.PlayerSpaz = NormalPlayerSpaz
spaz = self.spawn_player_spaz(player)
if self.enable_pickup:
spaz.connect_controls_to_player(enable_pickup=True)
else:
spaz.connect_controls_to_player(enable_pickup=False)
#player.assigninput(babase.InputType.JUMP_PRESS, lambda: self.backflip_player(player))
return spaz
def handle_ball_player_collide(self) -> None:
collision = bs.getcollision()
try:
ball = collision.sourcenode.getdelegate(Ball, True)
player = collision.opposingnode.getdelegate(PlayerSpaz, True).getplayer(Player, True)
ball.all_players_touched[player.team.id] = player
except:
return
def handle_ball_wall_collide(self) -> None:
collision = bs.getcollision()
if not self.gk_mode:
return
self.gk_saves_num_txt.node.text = str(int(self.gk_saves_num_txt.node.text)+1)
self.update_score_gk_mode()
self.kill_ball()
bs.timer(self.gmbsd, self.gk_setup)
def handle_score(self) -> None:
assert self.score_regions is not None
assert self.ball is not None
gnode = bs.getactivity().globalsnode
region = bs.getcollision().sourcenode
index = 0
scorer_celebration_txt = random.choice(self.expressions) + ' ' + random.choice(self.emojis)
for index in range(len(self.score_regions)):
if region == self.score_regions[index].node:
break
scoring_team = None
for team in self.teams:
if team.id == index:
team.score += 1
scoring_team = team
team_color = team.color
for player in scoring_team.players:
if player.actor:
player.actor.handlemessage(bs.CelebrateMessage(self.celebrater))
#self.backflip_player(player)
#player.actor.node.handlemessage("celebrate_l", 1000) #Waving The Left Hand
#player.actor.node.handlemessage("celebrate_r", 1000) #Waving The Right Hand
if (scoring_team.id in self.ball.all_players_touched and self.ball.all_players_touched[scoring_team.id]):
self.scorer = self.ball.all_players_touched[scoring_team.id]
self.stats.player_scored(self.scorer,100,color=team_color)
glow_color = (10, 10, 10)
prev_color = self.scorer.actor.node.color
bs.animate_array(self.scorer.actor.node, 'color', 3, {0:prev_color,self.sgt: glow_color,self.delete_text-self.sgt: glow_color,self.delete_text: prev_color})
try:
self.assister = self.ball.all_players_hitted[-2]
if self.scorer != self.assister and self.assister in scoring_team.players:
pos = self.assister.actor.node.position
self.stats.player_scored(self.assister, 70, color=team_color)
bs.broadcastmessage(f"Goal Scorer : {self.scorer.getname()}", color=(0,1,0))
bs.broadcastmessage(f"Assister : {self.assister.getname()}", color=(1,0.1,1))
self.assister_txt = Text( '💪🏻',0.01,(pos[0], pos[1]+1.25, pos[2]),shadow=2)
bs.animate(self.assister_txt.node, 'scale', {0:0, self.att:0.02, self.delete_text-self.att:0.02, self.delete_text:0})
self.follow_assister()
bs.timer(self.delete_text, self.assister_txt.delete)
else:
bs.broadcastmessage(f"Goal Scorer : {self.scorer.getname()}", color=(0,1,0))
except:
bs.broadcastmessage(f"Goal Scorer : {self.scorer.getname()}", color=(0,1,0))
pos = self.scorer.actor.node.position
self.scorer_txt = Text(scorer_celebration_txt, 0.01, (pos[0], pos[1]+1.25, pos[2]), team_color,2)
bs.animate(self.scorer_txt.node, 'scale', {0:0, self.ctt:0.02, self.delete_text-self.ctt:0.02, self.delete_text:0})
self.follow_scorer()
bs.timer(self.delete_text, self.scorer_txt.delete)
goal_txt = Text('GOOOALLL!!',0.05, (-3.2, 0, -4), team_color,1.5)
# Big Bang
pos = bs.getcollision().position
explosion = bs.newnode('explosion',attrs={
'position': pos,
'color': team_color,
'radius':4
})
try:
self.spawn_goal_fire(pos, color=team_color, radius=4.0, flames=16, duration=2.5)
except Exception:
pass
bs.animate(goal_txt.node, 'scale', {0:0, self.gtt:0.05, self.delete_text-self.gtt:0.05, self.delete_text:0})
bs.timer(self.delete_text, goal_txt.delete)
bs.animate_array(gnode, 'tint', 3, {0:gnode.tint, 0.07:(0,0,0) , 0.3:gnode.tint}) # darker tint for A glance
bs.cameraflash(duration=1 if int(self.delete_text) < 1 else int(self.delete_text))
self.foghorn_sound.play()
self.cheer_sound.play()
if scoring_team is not None:
try:
if scoring_team is self.teams[0]:
goal_pos = self.map.defs.boxes['goal2'][0:3]
else:
goal_pos = self.map.defs.boxes['goal1'][0:3]
gnode.camera_target = (goal_pos[0], goal_pos[1] + 2.0, goal_pos[2])
gnode.camera_mode = "manual"
def reset_camera():
gnode.camera_mode = "follow"
try:
center = self.map.get_flag_position(None)
gnode.camera_target = (center[0], center[1] + 1.0, center[2])
except Exception:
pass
bs.timer(2.0, reset_camera)
except Exception:
pass
self.update_scoreboard()
self.kill_ball()
if scoring_team.score >= self.score_to_win:
self.end_game()
print(f"{scoring_team.name} Score:", scoring_team.score)
""" You Can Enable it When Scoring by Uncommenting The Line (443) """
""" or When You Press Jump by Uncommenting The Line (384) """
def backflip_player(self, player) -> None: # some suspens when score also when jump, like a backflip lol!
pp = player.actor.node.position
pv = player.actor.node.velocity
pr = player.actor.node.run
player.actor.node.handlemessage('impulse',pp[0],pp[1]-3,pp[2],pv[0],pv[1],pv[2],50*pr,10*pr,0,0,pv[0],pv[1],pv[2])
player.actor.node.handlemessage('impulse',pp[0],pp[1]-4,pp[2],pv[0],pv[1],pv[2],50*pr,20*pr,0,0,pv[0],pv[1],pv[2])
player.actor.node.handlemessage('impulse',pp[0],pp[1]-5,pp[2],0,10,0,50,20,0,0,0,10,0)
bs.emitfx(chunk_type='sweat',position=pp,count=12,scale=3.0,spread=0.6)
bs.emitfx(chunk_type='sweat',position=pp,velocity=(pv[0]*5,pv[1]*2,pv[2]), count=random.randrange(12,20), scale=2.4, spread=0.40)
bs.emitfx(chunk_type='spark',position=pp,count=12,scale=1.0,spread=0.4)
def follow_scorer(self) -> None:
if not self.scorer_txt.node:
return
pos = self.scorer.actor.node.position
self.scorer_txt.node.position = (pos[0], pos[1] + 1.5, pos[2])
bs.timer(0, self.follow_scorer)
def follow_assister(self) -> None:
if not self.assister_txt.node:
return
pos = self.assister.actor.node.position
self.assister_txt.node.position = (pos[0], pos[1] + 1.5, pos[2])
bs.timer(0, self.follow_assister)
def follow_label(self, player, label: Text) -> None:
"""Updates label position to stay above player. Stops when player or label gone."""
try:
# if label node removed -> stop
if not getattr(label, 'node', None):
return
# if player or his actor gone -> delete label and stop
if not getattr(player, 'actor', None) or not getattr(player.actor, 'node', None):
try:
label.delete()
except:
pass
return
pos = player.actor.node.position
label.node.position = (pos[0], pos[1] + 1.5, pos[2])
bs.timer(0, lambda: self.follow_label(player, label))
except Exception:
try:
label.delete()
except Exception:
pass
#######################################################################################################
def spawn_goal_fire(self, position , color=(1.0, 0.45 ,0.0), radius=3.0, flames=12, duration=2.0):
"""Spawn a ring of small explosison, sparks and flickering lights around 'position'."""
nodes_to_cleanup = []
def cleanup():
for n in nodes_to_cleanup:
try:
n.delete()
except Exception:
pass
#create flame in a circle
for i in range(flames):
ang = 2 * math.pi * i / flames
fx_pos = (position[0] + math.cos(ang) * radius,
position[1] + 0.6,
position[2] + math.sin(ang) * radius)
try:
expl = bs.newnode('explosion', attrs={
'position': fx_pos,
'color': color,
'radius': 0.9
})
nodes_to_cleanup.append(expl)
except Exception:
pass
try:
bs.emitfx(chunk_type='spark', position=fx_pos, count=12, scale=3.1, spread=0.6)
except Exception:
pass
try:
light = bs.newnode('light', attrs={
'position': fx_pos,
'color': color,
'intensity': 1.2,
'radius': 0.6,
'height_attenuated': False
})
nodes_to_cleanup.append(light)
bs.animate(light, 'intensity', {0: 1.4, duration * 0.4: 0.6, duration * 0.85: 1.0})
except Exception:
pass
bs.timer(duration, cleanup)
self._goal_fire_cleanup_timer=bs.Timer(int(duration * 1000), bs.Call(cleanup))
#######################################################################################################
def follow_ball(self) -> None:
ball = self.ball
if ball is None:
return
pos = ball.node.position
self.red_dot.node.position = (pos[0], self.red_dot_y, pos[2])
if ball.node.gravity_scale == 0: # if gravity is zero
if str(pos[0])[:5] != str(ball.spawn_pos[0])[:5]: # if The ball moved from it's spawn position a bit
ball.node.gravity_scale = ball.gravity # restore the gravity to normal.
bs.timer(0, self.follow_ball)
def map_highlights(self) -> None:
if self.gk_mode:
gk_saves_txt = Text('Saves',0.03,(0.35, 2, -6),(0, 1, 0),1.5)
gk_goals_txt = Text('Goals',0.03,(-2.2, 2, -6),(1, 0, 0),1.5)
gk_total_txt = Text('Total',0.03,(3.9, 2, -6),(0.3, 1, 1),1.5)
self.gk_saves_num_txt = Text('0',0.03,(1.1,1,-6),(0,1,0),1.5)
self.gk_goals_num_txt = Text('0',0.03,(-1.5,1,-6),(1,0,0),1.5)
self.gk_total_num_txt = Text('0.0%',0.03,(4, 1, -6),(1, 0, 0.1),1.5)
front_wall = Wall((0, 5, -3), (50, 36, 0.5))
near_wall = Wall((0, 5, 3), (50, 36, 0.5))
mid_map_wall = Wall((-1, 5, 0), (0.5, 36, 20))
dots_color = (1, 0, 1)
y, z, x_start, x_end = 0.009, 2.45, -0.45, 8
diameter = 0.1
dots_len1 = int((-x_start+x_end)/diameter)
dots_len2 = int(z/diameter)
for i in range(0, dots_len1+1):
Dot((x_start+i/(1/diameter), y, -z), [diameter], dots_color)
Dot((x_start+i/(1/diameter), y, z), [diameter], dots_color)
for i in range(0, dots_len2+1):
Dot((x_start, y, z-i/(1/diameter)), [diameter], dots_color)
Dot((x_start, y, -z+i/(1/diameter)), [diameter], dots_color)
elif self.map_posters:
team1_txt = Text(self.team1.name,0.03,(-5.25, 2, -6),self.team1.color,1.5)
team2_txt = Text(self.team2.name,0.03,(1.3, 2, -6),self.team2.color,1.5)
self.team1_score_txt = Text(str(self.team1.score),0.035,(-1.1, 1, -6),self.team1.color,1.5)
self.team2_score_txt = Text(str(self.team2.score),0.035,(0.5, 1, -6),self.team2.color,1.5)
versis_txt = Text('VS',0.03,(-0.5, 2, -6),(1,1,1,0.7),1.5)
colon_txt = Text(':',0.03,(-0.15, 1, -6),(1,1,1,0.7),1.5)
if self.limited_map:
x, y, z, v = 8.25, 0, 7, 20
wall_scale = (0.5, 36, 10)
right_goal_R = Wall((x, y, -z), wall_scale)
right_goal_L = Wall((x, y, z), wall_scale)
right_goal_T = Wall((x, y+v, z-z), wall_scale)
left_goal_R = Wall((-x, y, z), wall_scale)
left_goal_L = Wall((-x, y, -z), wall_scale)
left_goal_T = Wall((-x, y+v, z-z), wall_scale)
# Map Edges Light Spots
pos1, pos2, pos3, pos4 = (-11.05, 0.3, -5.3), (11.9, 0.3, -4.04), (10.99, 0.3, 5.08), (-12, 0.3, 3.78)
up_wall = [(pos1[0]+i, pos1[1], pos1[2]) if i < 22 else (pos1[0]+i-0.2, pos1[1], pos1[2]+0.1) for i in range(0, 23, 2)]
right_wall = [(pos2[0], pos2[1], pos2[2]+i) for i in range(0, 9, 2)]
down_wall = [(pos3[0]-i, pos3[1], pos3[2]) for i in range(0, 23, 2)]
left_wall = [(pos4[0], pos4[1], pos4[2]-i) for i in range(0, 9, 2)]
light_positions = [i for i in up_wall+right_wall+down_wall+left_wall]
# for light_pos in light_positions:
# light = bs.newnode('light', attrs={
# 'position': light_pos,
# 'color': (0, 0.8, 1),
# 'intensity': 1.1,
# 'radius': 0.16,
# 'height_attenuated': True
# })
def on_team_join(self, team: Team) -> None:
pass
def get_instance_description(self) -> Union[str, Sequence]:
if self.gk_mode:
return self.gmgd
if self.score_to_win == 1:
return self.gd
return self.gd
def get_instance_description_short(self) -> Union[str, Sequence]:
if self.gk_mode:
return self.gmhd
if self.score_to_win == 1:
return self.hdag
return self.hd
#############################################################################################
def end_game(self) -> None:
"""Create WIN/LOSE/DRAW labels above players, keep them visible for self.delete_text,
then actually call self.end(results)."""
results = bs.GameResults()
for team in self.teams:
results.set_team_score(team, team.score)
# توقعات النتيجة
winner = None
loser = None
if len(self.teams) >= 2:
t1, t2 = self.teams[0], self.teams[1]
if t1.score > t2.score:
winner, loser = t1, t2
elif t2.score > t1.score:
winner, loser = t2, t1
else:
winner = None # draw
else:
winner = None
if winner is None:
# لو تعادل
for team in self.teams:
for player in team.players:
if getattr(player, 'actor', None) and getattr(player.actor, 'node', None):
pos = player.actor.node.position
lbl = Text('DRAW', 0.02, (pos[0], pos[1] + 1.5, pos[2]), (1, 1, 0), 2)
try:
bs.animate(lbl.node, 'scale', {0:0, 0.05:0.02, self.delete_text - 0.05:0.02, self.delete_text:0})
except Exception:
pass
bs.timer(0, lambda p=player, l=lbl: self.follow_label(p, l))
bs.timer(self.delete_text, lbl.delete)
else:
# الكسبان و الخسران
for player in winner.players:
if getattr(player, 'actor', None) and getattr(player.actor, 'node', None):
pos = player.actor.node.position
lbl = Text('Winner', 0.02, (pos[0], pos[1] + 1.5, pos[2]), (0, 1, 0), 2)
try:
bs.animate(lbl.node, 'scale', {0:0, 0.05:0.02, self.delete_text - 0.05:0.02, self.delete_text:0})
except Exception:
pass
bs.timer(0, lambda p=player, l=lbl: self.follow_label(p, l))
bs.timer(self.delete_text, lbl.delete)
for player in loser.players:
if getattr(player, 'actor', None) and getattr(player.actor, 'node', None):
pos = player.actor.node.position
lbl = Text('Loser', 0.02, (pos[0], pos[1] + 1.5, pos[2]), (1, 0, 0), 2)
try:
bs.animate(lbl.node, 'scale', {0:0, 0.05:0.02, self.delete_text - 0.05:0.02, self.delete_text:0})
except Exception:
pass
bs.timer(0, lambda p=player, l=lbl: self.follow_label(p, l))
bs.timer(self.delete_text, lbl.delete)
if winner is not None:
# نص في النص
win_label = bs.newnode('text',
attrs={
'text': "\ue043Game Over\ue043",
'scale': 0.5,
'position': (0,250, 0),
'color': (0, 1, 0),
'h_align': 'center',
'v_attach': 'center'
})
bs.animate(win_label, 'scale', {0:0, 0.1:2.5, 4.5:2.5, 5:0})
bs.timer(5.0, win_label.delete)
# تلج كثييير ينزل
def snow_effect():
for i in range(50):
x = random.uniform(-10, 10)
z = random.uniform(-6, 6)
bs.emitfx(
position=(x, 10, z),
count=20,
scale=0.8,
spread=1.5,
chunk_type='ice'
)
for t in range(25):
bs.timer(0.2 * t, snow_effect)
# 🎆 ألعاب نارية بألوان مختلفة
def fireworks_effect():
for i in range(6):
x = random.uniform(-8, 8)
z = random.uniform(-5, 5)
color = (random.random(), random.random(), random.random())
bs.emitfx(
position=(x, 1, z),
count=30,
scale=1.5,
spread=2.0,
chunk_type='spark'
)
bs.newnode('explosion', attrs={
'position': (x, 1, z),
'color': color,
'radius': 1.2
})
for t in range(20):
bs.timer(0.3 * t, fireworks_effect)
# انهاء الللعبه
end_delay = max(0.05, float(self.delete_text) + 0.05)
bs.timer(end_delay, lambda: self.end(results=results))
#############################################################################################
def update_scoreboard(self) -> None:
if self.map_posters:
try:
self.team1 = self.teams[0]
self.team1_score_txt.node.text = str(self.team1.score)
self.team2 = self.teams[1]
self.team2_score_txt.node.text = str(self.team2.score)
except:
pass
win_score = self.score_to_win
for team in self.teams:
self.scoreboard.set_team_value(team, team.score, win_score)
def create_red_dot(self) -> None:
self.red_dot = Dot((0, self.red_dot_y, 0), [0.2])
def kill_ball(self) -> None:
self.red_dot.node.delete()
self.ball = None
def spawn_ball(self) -> None:
if self.gk_mode:
try:
if not self.red_dot.node:
self.create_red_dot()
except:
self.create_red_dot()
self.ball = Ball(position=(0, 0, 0), is_area_of_interest=False)
self.follow_ball()
return
self.swipsound.play()
self.whistle_sound.play()
assert self.ball_spawn_pos is not None
self.ball = Ball(position=self.ball_spawn_pos,is_area_of_interest=True)
self.create_red_dot()
self.follow_ball()
def handlemessage(self, msg: Any) -> Any:
if isinstance(msg, bs.PlayerDiedMessage):
super().handlemessage(msg)
self.respawn_player(msg.getplayer(Player))
elif isinstance(msg, BallDiedMessage):
if self.gk_mode:
return
if not self.has_ended():
bs.timer(self.bsd, self.spawn_ball)
else:
super().handlemessage(msg)
"""———————————Assistant MODE (START)——————————— """
""" Ball is Attached to You!, it's Not That Cool But i Was Just Bored so i Made it """
def assistant_setup(self) -> None:
if self.gk_mode:
return
ball = self.ball
if not ball:
return
last_player = ball.all_players_hitted[0]
pos = last_player.actor.node.position
if not self.left_right or not self.up_down:
self.activated = False
return
self.left_right = last_player.actor.node.move_left_right/1.75
self.up_down = last_player.actor.node.move_up_down/1.75
if not self.left_right or not self.up_down:
self.activated = False
return
pos = (pos[0]+self.left_right, pos[1]+0.8, pos[2]-self.up_down)
ball.node.position = pos
self.activated = True
bs.timer(0, self.assistant_setup)
"""———————————Assistant MODE (END)——————————— """
"""———————————GK MODE (START)——————————— """
def gk_setup(self) -> None:
if self.ball:
self.kill_ball()
self.spawn_ball()
magnitude = random.randint(self.gk_mode, self.gk_mode+10)
velocity_magnitude = self.gk_mode/6
force_x = 15
force_y = 3
force_z = random.uniform(-2.7, 2.7)
self.ball.node.handlemessage('impulse',
0,0,0,3,3,3,
magnitude,
velocity_magnitude,
0,0,
force_x, force_y, force_z)
def update_score_gk_mode(self) -> None:
goals = int(self.gk_goals_num_txt.node.text)
saves = int(self.gk_saves_num_txt.node.text)
total = goals+saves
percentage = saves/total
new_txt = str(percentage*100)[:4]+'%' # just hate he 10 nums length number
self.gk_total_num_txt.node.text = new_txt
self.gk_total_num_txt.node.color = (1-percentage, percentage, 0.2) # makin it goes to green when a good percent, red otherwise.
def handle_score_gk_mode(self) -> None:
self.kill_ball()
self.gk_goals_num_txt.node.text = str(int(self.gk_goals_num_txt.node.text)+1)
self.update_score_gk_mode()
explosion_color = (random.random(), random.random(), random.random())
explosion_radius = {self.gk_easy: 2, self.gk_medium: 3, self.gk_hard: 4}[self.gk_mode] # specific radius of explosion for the difficulty of game mode
pos = bs.getcollision().position
explosion = bs.newnode('explosion',attrs={
'position': pos,
'color': explosion_color,
'radius': explosion_radius
})
bs.timer(self.gmbsd, self.gk_setup)
"""———————————GK MODE (END)——————————— """
class SoccerMap(maps.HockeyStadium):
name = 'Soccer Stadium'
@classmethod
def get_preview_texture_name(cls) -> str:
return 'hockeyStadiumPreview'
@classmethod
def is_flat_ground(cls) -> bool:
return True
@classmethod
def on_preload(cls) -> Any:
data: dict[int, Any] = {'meshes': (
bs.getmesh('hockeyStadiumOuter'),
bs.getmesh('hockeyStadiumInner'),
bs.getmesh('hockeyStadiumStands')
),
'vr_fill_mesh': bs.getmesh('footballStadiumVRFill'),
'collision_mesh': bs.getcollisionmesh('hockeyStadiumCollide'), # posts & walls that collides
'tex': bs.gettexture('hock'), # floor & foreground texture
'stands_tex': bs.gettexture('atoot'), # walls & background texture
}
material = bs.Material()
data['ice_material'] = material
return data
def __init__(self) -> None:
super().__init__()
shared = SharedObjects.get()
gnode = bs.getactivity().globalsnode
self.use_fixed_vr_overlay = False
self.node.materials = [shared.footing_material]
self.floor.color = (0.05, 0.97, 0.05)
gnode.floor_reflection = True
gnode.floor_reflection = 2.5
self._disable_stadium_lights()
try:
for node in bs.getnodes():
try:
if hasattr(node, 'getNodeType') and node.getNodeType() == 'light':
node.delete()
except:
pass
gnode.tint = (0.95, 0.95, 0.95)
gnode.ambient_color = (10.3, 10.3, 10.3)
gnode.vignette_inner = (0.85, 0.85, 0.85)
gnode.vignette_outer = (2, 2, 2)
gnode.shadow_range = 1.2
except:
pass
def _disable_stadium_lights(self):
"""تعطيل جميع أضواء الملعب المدمجة"""
def remove_lights():
try:
for node in bs.getnodes():
try:
if not hasattr(node, 'getNodeType'):
continue
node_type = node.getNodeType()
if node_type == 'light':
node.delete()
except Exception as e:
continue
gnode = bs.getactivity().globalsnode
gnode.ambient_color = (0.4, 0.4, 0.4)
except Exception as e:
print(f"خطأ في تعطيل الأضواء: {e}")
# ba_meta export babase.Plugin
class ImportSoccerMap(babase.Plugin):
def on_app_running(self) -> None:
bs._map.register_map(SoccerMap)
""" Big Thanks To...ahhg Honestly Only Me Worked on it """
"""Killer"""