618 lines
19 KiB
Python
618 lines
19 KiB
Python
import bge
|
|
import bpy
|
|
import json
|
|
import os
|
|
import aud
|
|
import time
|
|
import datetime
|
|
import threading
|
|
import random
|
|
import numpy
|
|
import math
|
|
import mathutils
|
|
|
|
from Scripts import Reuse
|
|
from Scripts import Destruction
|
|
from Scripts import Opt
|
|
from Scripts.Common import *
|
|
|
|
|
|
from Scripts import Map
|
|
from Scripts import UI
|
|
from Scripts import Script
|
|
from Scripts import Vehicle
|
|
from Scripts import Settings
|
|
from Scripts import Tools
|
|
from Scripts import Money
|
|
from Scripts import Garage
|
|
from Scripts import Racing
|
|
from Scripts import Mouse
|
|
from Scripts import Music
|
|
from Scripts import Hints
|
|
from Scripts import Cinema
|
|
from Scripts import GameTime
|
|
from Scripts import Doors
|
|
from Scripts import Elevators
|
|
from Scripts import Input
|
|
|
|
from Scripts import Character
|
|
from Scripts import Multiplayer_Client
|
|
|
|
|
|
def main():
|
|
|
|
# Resolution for optimization
|
|
spawnAtDistance = 250
|
|
maxCars = 6
|
|
bge.logic.globalDict["spawnAtDistance"] = spawnAtDistance
|
|
bge.logic.globalDict["maxCars"] = maxCars
|
|
|
|
# Often referenced objects
|
|
scene = bge.logic.getCurrentScene()
|
|
cont = bge.logic.getCurrentController()
|
|
dani = scene.objects["Dani_Box"]
|
|
cam = scene.active_camera
|
|
|
|
# Inputs
|
|
Input.UpdateKeys()
|
|
Input.UpdateMouse()
|
|
keys = bge.logic.globalDict["keys"]
|
|
Mouse.DeactivateToggler()
|
|
Input.UnpressSimulatedPresses()
|
|
|
|
firsteverupdatetime = False
|
|
|
|
if UI.StartLoadingScreen(): return # Loading screen
|
|
UI.UpdateFPSCounter()
|
|
|
|
Opt.ExecuteScheduled()
|
|
|
|
# Calculating the camera surround position.
|
|
camSurroundCars = Opt.Surround(cam.position, spawnAtDistance, cam.orientation.to_euler())
|
|
|
|
# Getting if Dani is in Cinema.
|
|
inCinema = Cinema.InCinema()
|
|
|
|
# Destroy those needing destroying
|
|
Reuse.SelfDestructDo()
|
|
|
|
# Initialization
|
|
if not Opt.chunks:
|
|
Init()
|
|
|
|
# Delaying Danis physics for a few frames after Init()
|
|
# so that the physics of the house could load in properly.
|
|
|
|
if bge.logic.globalDict["restore-physics-timer"]:
|
|
bge.logic.globalDict["restore-physics-timer"] -= 2
|
|
Mouse.CenterCursor()
|
|
return
|
|
elif bge.logic.globalDict["restore-physics"]:
|
|
bge.logic.globalDict["restore-physics"] = False
|
|
dani.restorePhysics()
|
|
Mouse.CenterCursor()
|
|
|
|
UI.RemoveLoadingScreen()
|
|
|
|
# Getting settings
|
|
settings = bge.logic.globalDict["settings"]
|
|
|
|
# Updating chunks
|
|
Opt.ScheduleTask("Scene Chunk Updates", 0.85, Opt.UpdateScene,
|
|
cam, spawnAtDistance, cam.orientation.to_euler())
|
|
|
|
# Running the story of the game
|
|
Script.Run(scene, dani)
|
|
|
|
# Multiplayer scene updates
|
|
if settings.get("multiplayer"):
|
|
Multiplayer_Client.SecondaryLoop()
|
|
|
|
|
|
# SPAWNING CARS
|
|
if not settings.get("multiplayer"):
|
|
Opt.ScheduleTask("Car Updates", 0.80, Vehicle.SpawnLogic,
|
|
camSurroundCars)
|
|
Vehicle.UnspawnLogic()
|
|
|
|
# Logic reducing hints rendered on the screens.
|
|
Hints.UnshowLogic()
|
|
|
|
# Updating elevators
|
|
Elevators.MainLoop()
|
|
|
|
# Updating doors
|
|
Doors.MainLoop()
|
|
|
|
# WHEEL UP DOWN
|
|
|
|
cam_parent = scene.objects["DaniCam_Parent"]
|
|
|
|
wheelup = cont.sensors["wheel_up"]
|
|
wheeldown = cont.sensors["wheel_down"]
|
|
if wheelup.status:
|
|
cam_parent.scaling /= 1.1
|
|
elif wheeldown.status and cam_parent.scaling[0] < 20:
|
|
cam_parent.scaling *= 1.1
|
|
|
|
# CHEAT CODES
|
|
Input.CheatCodes()
|
|
|
|
|
|
# RACES
|
|
Racing.MainLoop(spawnAtDistance)
|
|
|
|
|
|
|
|
# Messages
|
|
|
|
if "done-prints" not in bge.logic.globalDict:
|
|
bge.logic.globalDict["done-prints"] = []
|
|
|
|
if bge.logic.globalDict.get("print") and bge.logic.globalDict.get("last_print") != bge.logic.globalDict["print"]:
|
|
|
|
print()
|
|
for line in bge.logic.globalDict["print"].split("\n"):
|
|
print(" "+clr["bold"]+clr["tdyl"]+line+clr["norm"])
|
|
|
|
print()
|
|
|
|
#scene.objects["Messages"]["Text"] = str(bge.logic.globalDict.get("print"))
|
|
scene.objects["Messages"].blenderObject.data.body = str(bge.logic.globalDict.get("print"))
|
|
scene.objects["Messages"].stopAction()
|
|
scene.objects["Messages"].playAction("MessagesAction", 0, 100)
|
|
|
|
bge.logic.globalDict["print-change-size"] = True
|
|
|
|
|
|
|
|
bge.logic.globalDict["last_print"] = bge.logic.globalDict["print"]
|
|
|
|
|
|
if bge.logic.globalDict["print"] not in bge.logic.globalDict["done-prints"]:
|
|
bge.logic.globalDict["done-prints"].append(bge.logic.globalDict["print"])
|
|
|
|
bge.logic.globalDict["print"] = ""
|
|
|
|
elif bge.logic.globalDict.get("print-change-size"):
|
|
|
|
# Changing the size of the element under the text
|
|
# This is done in a different frame, because we need
|
|
# to let it update the depsgraph with the text dimensions.
|
|
|
|
camscale = scene.objects["DaniCam_Parent"].scaling[0]
|
|
|
|
textSize = scene.objects["Messages"].blenderObject.dimensions
|
|
thingSize = scene.objects["Message_Background"].blenderObject.dimensions
|
|
thingScale = scene.objects["Message_Background"].worldScale
|
|
|
|
textSize = mathutils.Vector((
|
|
textSize.x + ( 0.04 * camscale ),
|
|
textSize.y + ( 0.02 * camscale ),
|
|
textSize.z
|
|
))
|
|
|
|
thingSize = mathutils.Vector((
|
|
thingSize.x / thingScale.x,
|
|
thingSize.y / thingScale.y,
|
|
thingSize.z / thingScale.z
|
|
))
|
|
|
|
|
|
thingScale = mathutils.Vector((
|
|
textSize.x / thingSize.x,
|
|
textSize.y / thingSize.y,
|
|
1.0 # It doesn't matter, and making it 0 collapes the object
|
|
))
|
|
|
|
scene.objects["Message_Background"].worldScale = thingScale
|
|
point = Vehicle.RelativePoint(scene.objects["Messages"],
|
|
(-0.007 * camscale,
|
|
(-0.010 * camscale) + (textSize.y / 2),
|
|
-0.001))
|
|
scene.objects["Message_Background"].worldPosition = point
|
|
|
|
bge.logic.globalDict["print-change-size"] = False
|
|
|
|
|
|
# SOUND
|
|
|
|
#print(dir(aud))
|
|
|
|
if "SoundDevice" not in bge.logic.globalDict:
|
|
bge.logic.globalDict["SoundDevice"] = aud.Device()
|
|
bge.logic.globalDict["SoundDevice"].distance_model = aud.DISTANCE_MODEL_INVERSE_CLAMPED
|
|
bge.logic.globalDict["sounds"] = {}
|
|
|
|
bge.logic.globalDict["sounds"]["active"] = {"sound":aud.Sound(bge.logic.expandPath("//sfx/active.ogg")),
|
|
"play":None}
|
|
|
|
# Angry pursuit sounds
|
|
|
|
bge.logic.globalDict["sounds_angry_start"] = []
|
|
|
|
for i in range(8):
|
|
i += 1
|
|
i = str(i)
|
|
if len(i) < 2:
|
|
i = "0"+i
|
|
i = "//sfx/voices/angry_pursuit/start_"+i+".ogg"
|
|
bge.logic.globalDict["sounds"][i] = {"sound":aud.Sound(bge.logic.expandPath(i)),
|
|
"play":None}
|
|
bge.logic.globalDict["sounds_angry_start"].append(i)
|
|
|
|
|
|
bge.logic.globalDict["sounds_angry_hit"] = []
|
|
|
|
for i in range(5):
|
|
i += 1
|
|
i = str(i)
|
|
if len(i) < 2:
|
|
i = "0"+i
|
|
i = "//sfx/voices/angry_pursuit/hit_"+i+".ogg"
|
|
bge.logic.globalDict["sounds"][i] = {"sound":aud.Sound(bge.logic.expandPath(i)),
|
|
"play":None}
|
|
bge.logic.globalDict["sounds_angry_hit"].append(i)
|
|
|
|
# Dani voices
|
|
|
|
bge.logic.globalDict["sounds"]["dani_yelling"] = {"sound":aud.Sound(bge.logic.expandPath("//sfx/voices/dani/yelling.ogg")),
|
|
"play":None}
|
|
bge.logic.globalDict["sounds"]["dani_entering"] = {"sound":aud.Sound(bge.logic.expandPath("//sfx/voices/dani/entering.ogg")),
|
|
"play":None}
|
|
bge.logic.globalDict["sounds"]["dani_ohno"] = {"sound":aud.Sound(bge.logic.expandPath("//sfx/voices/dani/ohno.ogg")),
|
|
"play":None}
|
|
bge.logic.globalDict["sounds"]["dani_ohnoindeed"] = {"sound":aud.Sound(bge.logic.expandPath("//sfx/voices/dani/ohnoindeed.ogg")),
|
|
"play":None}
|
|
bge.logic.globalDict["sounds"]["dani_wearesinking"] = {"sound":aud.Sound(bge.logic.expandPath("//sfx/voices/dani/wearesinking.ogg")),
|
|
"play":None}
|
|
bge.logic.globalDict["sounds"]["dani_ohgod"] = {"sound":aud.Sound(bge.logic.expandPath("//sfx/voices/dani/ohgod.ogg")),
|
|
"play":None}
|
|
|
|
bge.logic.globalDict["sounds"]["dani_jump"] = {"sound":aud.Sound(bge.logic.expandPath("//sfx/voices/dani/jump.ogg")),
|
|
"play":None}
|
|
|
|
bge.logic.globalDict["sounds"]["dani_land"] = {"sound":aud.Sound(bge.logic.expandPath("//sfx/voices/dani/land.ogg")),
|
|
"play":None}
|
|
bge.logic.globalDict["sounds"]["dani_walk"] = {"sound":aud.Sound(bge.logic.expandPath("//sfx/voices/dani/walk.ogg")),
|
|
"play":None}
|
|
|
|
# Jack voices
|
|
bge.logic.globalDict["JackBoxVoices"] = {"crash":[],
|
|
"near" :[],
|
|
"speed":[]}
|
|
|
|
|
|
|
|
JV = bge.logic.globalDict["JackBoxVoices"]
|
|
JF = bge.logic.expandPath("//sfx/voices/jack/")
|
|
for t in ["crash", "near", "speed"]:
|
|
for f in os.listdir(JF):
|
|
if f.startswith(t) and f.endswith(".ogg"):
|
|
name = f.replace(".ogg", "")
|
|
bge.logic.globalDict["sounds"]["jack_"+name] = {"sound":aud.Sound(JF+f),
|
|
"play":None}
|
|
JV[t].append(bge.logic.globalDict["sounds"]["jack_"+name])
|
|
|
|
|
|
# Car Sounds
|
|
|
|
bge.logic.globalDict["sounds"]["door"] = {"sound":aud.Sound(bge.logic.expandPath("//sfx/door.ogg")),
|
|
"play":None}
|
|
bge.logic.globalDict["sounds"]["tire_pop"] = {"sound":aud.Sound(bge.logic.expandPath("//sfx/tire_pop.ogg")),
|
|
"play":None}
|
|
|
|
# Race sounds
|
|
|
|
bge.logic.globalDict["sounds"]["checkpoint"] = {"sound":aud.Sound(bge.logic.expandPath("//sfx/checkpoint.ogg")),
|
|
"play":None}
|
|
|
|
|
|
device = bge.logic.globalDict["SoundDevice"]
|
|
device.listener_location = scene.active_camera.worldPosition
|
|
device.listener_orientation = scene.active_camera.worldOrientation.to_quaternion()
|
|
device.listener_velocity = scene.active_camera.getLinearVelocity()
|
|
|
|
for i in bge.logic.globalDict["sound-ambiances"]:
|
|
s = i["ambiance-sound"]
|
|
#s = "//sfx/ambiance/forest.ogg"
|
|
if s not in bge.logic.globalDict["sounds"]:
|
|
bge.logic.globalDict["sounds"][s] = {"sound":aud.Sound(bge.logic.expandPath(s)),
|
|
"play":None}
|
|
|
|
sound = bge.logic.globalDict["sounds"][s]
|
|
|
|
if not sound["play"] or not sound["play"].status:
|
|
sound["play"] = device.play(sound["sound"])
|
|
|
|
scale = i.scaling[0]
|
|
distance = i.getDistanceTo(dani)
|
|
|
|
if inCinema:
|
|
sound["inCinema"] = sound.get("inCinema", 1) * 0.95
|
|
elif sound.get("inCinema", 1) < 1:
|
|
if sound["inCinema"] < 0.1:
|
|
sound["inCinema"] = 0.1
|
|
sound["inCinema"] = sound.get("inCinema", 1) * 1.05
|
|
sound["play"].volume = max(0, min(1, (1-(distance / scale ))*5))*i.get("volume", 1) * sound.get("inCinema", 1)
|
|
|
|
# Music subsystem
|
|
if settings.get("music"):
|
|
Music.Loop()
|
|
else:
|
|
Music.CoolDown()
|
|
Music.ShakyCam()
|
|
|
|
|
|
# LODs of buildings
|
|
Opt.BuildingsLOD()
|
|
|
|
############ Camera UI ###########
|
|
|
|
Map.UpdateMapUI()
|
|
|
|
#Map.Show([0,0,0], icon="Map_Circle")
|
|
|
|
############ GARAGE ##########
|
|
|
|
# The idea is that all cars inside of the garage will
|
|
# stay in the garage.
|
|
|
|
garage = scene.objects["GarageColider"]
|
|
garageDistance = 70
|
|
|
|
if dani.getDistanceTo(garage) > garageDistance:
|
|
Garage.Encode()
|
|
elif dani.getDistanceTo(garage) < garageDistance - 10:
|
|
Garage.Decode()
|
|
|
|
# Crates
|
|
# There are crates in the house, in the garage. They are rigid body objects.
|
|
# the problem is that when you go far enough away, the ground beneath them
|
|
# stops being solid, so we need to deactiave their physics.
|
|
|
|
crates = bge.logic.globalDict["garage-crates"]
|
|
for crate in crates:
|
|
if dani.getDistanceTo(crate) > 100:
|
|
crate.suspendPhysics()
|
|
elif dani.getDistanceTo(crate) < 90:
|
|
crate.restorePhysics()
|
|
|
|
# Tools
|
|
Tools.MainLoop()
|
|
Garage.Computer()
|
|
|
|
|
|
################ DAY NIGHT CYCLE ################
|
|
|
|
GameTime.UpdateClock()
|
|
if firsteverupdatetime or Opt.GoodFPS("clock-scene-updates"):
|
|
GameTime.UpdateScene()
|
|
|
|
timecontroller = scene.objects["TimeController"]
|
|
|
|
# Background racetrack / city backdrop calcualtion
|
|
|
|
city_at = 137
|
|
racetrack_at = 630
|
|
now_at = float(cam.worldPosition.y)
|
|
|
|
if now_at > racetrack_at: crFactor = 1.0
|
|
elif now_at < city_at: crFactor = 0.0
|
|
else:
|
|
crFactor = (now_at - city_at) / ( racetrack_at - city_at )
|
|
timecontroller.position.y = ( crFactor * 100 ) - 100
|
|
|
|
|
|
# Moving the background up and down depending on the position of
|
|
# the camera.
|
|
|
|
max_z = 39
|
|
min_z = -12
|
|
now_z = float(cam.worldPosition.z)
|
|
move_z = 14
|
|
|
|
if now_z > max_z: mzFactor = 0.0
|
|
elif now_z < min_z: mzFactor = 1.0
|
|
else:
|
|
mzFactor = 1- ((now_z - min_z) / ( max_z - min_z ))
|
|
timecontroller.position.z = ( mzFactor * move_z )
|
|
|
|
|
|
|
|
# Now to position the racetrack properly we want to rotate it
|
|
|
|
p1 = [7.39, -805.686]
|
|
p2 = [30 , 95.5932]
|
|
cur_x = float(cam.worldPosition.x)
|
|
rotFactor = (cur_x - p1[1]) / (p2[1] - p1[1]) * ( p2[0] - p1[0] ) + p1[0]
|
|
rotationcontroller = scene.objects["Racetrack_rotaion"]
|
|
rotationcontroller.position.x = rotFactor
|
|
|
|
# Now the same object at Z will control the level of the volumetric
|
|
# Water effect. ( Important when below water level, but not in the
|
|
# water ).
|
|
|
|
waterleveler = scene.objects["WaterLevel"]
|
|
|
|
if dani.position.y < 0:
|
|
waterleveler.position.z = -1000
|
|
else:
|
|
waterleveler.position.z = 0
|
|
|
|
|
|
# Police related stuff
|
|
|
|
# Updating cops rate
|
|
chasing = Vehicle.IsChased(dani.get("driving"))
|
|
if chasing:
|
|
# 5 chasing cars and you are having 100% police spawning.
|
|
a = len(chasing)
|
|
p = max(0.1, min(1.0, a / 5.5 + 0.1))
|
|
bge.logic.globalDict["policeSpawnFactor"] = p
|
|
else:
|
|
bge.logic.globalDict["policeSpawnFactor"] = 0.2
|
|
|
|
# hiding UI
|
|
# for i in cam.childrenRecursive:
|
|
# if i.visible:
|
|
# i.visible = False
|
|
|
|
def Init():
|
|
|
|
spawnAtDistance = bge.logic.globalDict["spawnAtDistance"]
|
|
maxCars = bge.logic.globalDict["spawnAtDistance"]
|
|
|
|
# Often referenced objects
|
|
scene = bge.logic.getCurrentScene()
|
|
cont = bge.logic.getCurrentController()
|
|
dani = scene.objects["Dani_Box"]
|
|
cam = scene.active_camera
|
|
|
|
dani.suspendPhysics()
|
|
Mouse.CenterCursor()
|
|
|
|
# Making settings executed
|
|
Settings.Execute()
|
|
settings = Settings.load_settings()
|
|
bge.logic.globalDict["settings"] = settings
|
|
|
|
Settings.LoadGame()
|
|
|
|
Script.StatusText(" ")
|
|
|
|
GameTime.InitiateClock()
|
|
|
|
firsteverupdatetime = True
|
|
|
|
# Stuff
|
|
|
|
bge.logic.globalDict["netObjects"] = {
|
|
"pythonId":{},
|
|
"netId":{}
|
|
}
|
|
|
|
bge.logic.globalDict["elevators"] = {}
|
|
bge.logic.globalDict["sound-ambiances"] = []
|
|
bge.logic.globalDict["doors"] = {}
|
|
|
|
bge.logic.globalDict["garage-crates"] = []
|
|
|
|
# Cars related
|
|
|
|
bge.logic.globalDict["spawns"] = {}
|
|
bge.logic.globalDict["allcars"] = []
|
|
bge.logic.globalDict["cars"] = []
|
|
bge.logic.globalDict["policeCars"] = []
|
|
bge.logic.globalDict["policeSpawnFactor"] = 0.1
|
|
bge.logic.globalDict["spawnedCarModels"] = []
|
|
|
|
# Cheat code modes
|
|
|
|
bge.logic.globalDict["pursuit-cheat"] = False
|
|
bge.logic.globalDict["derby-cheat"] = False
|
|
bge.logic.globalDict["gravity"] = True
|
|
|
|
# Navigation for NPCs
|
|
bge.logic.globalDict["Navigation"] = {"road" :[],
|
|
"parking":[]}
|
|
|
|
Navigation = bge.logic.globalDict["Navigation"]
|
|
|
|
for navtag in bpy.data.collections["Navigation"].objects:
|
|
|
|
tagdata = {"position":navtag.location,
|
|
"orientation":navtag.rotation_euler,
|
|
"radius":navtag.scale[0],
|
|
"connected":[]}
|
|
|
|
if navtag.get("parking"):
|
|
Navigation["parking"].append(tagdata)
|
|
else:
|
|
Navigation["road"].append(tagdata)
|
|
|
|
|
|
|
|
# Races
|
|
Racing.Precalculate()
|
|
|
|
# Characters
|
|
|
|
Reuse.Delete(scene.objects["PapsBox"])
|
|
#Reuse.Delete(scene.objects["MoriaBox"])
|
|
Reuse.Delete(scene.objects["JackBox"])
|
|
|
|
# Objects
|
|
|
|
for object in scene.objects:
|
|
|
|
if "spawn" in object:
|
|
Vehicle.RegisterSpawnPoint(object)
|
|
|
|
if str(object.name).startswith("Crate"):
|
|
crates = bge.logic.globalDict["garage-crates"]
|
|
crates.append(object)
|
|
|
|
if "LightSpawn" in object:
|
|
Opt.RegisterObjects(object, spawnAtDistance, "LightSpawn")
|
|
|
|
elif type(object.blenderObject.data) == bpy.types.AreaLight:
|
|
Opt.RegisterObjects(object, spawnAtDistance, "AreaLamp")
|
|
|
|
elif "Tree" in object.name:
|
|
Opt.RegisterObjects(object, spawnAtDistance, "Tree")
|
|
|
|
elif "Palm" in object.name:
|
|
Opt.RegisterObjects(object, spawnAtDistance, "Palm")
|
|
|
|
elif "Elevator" in object:
|
|
Elevators.RegisterElevator(object)
|
|
|
|
elif "Door" in object:
|
|
Doors.RegisterDoor(object)
|
|
|
|
elif "ambiance-sound" in object:
|
|
bge.logic.globalDict["sound-ambiances"].append(object)
|
|
|
|
|
|
# Precalculating objects for smoothness
|
|
Opt.Precalculate()
|
|
|
|
# Setting Exit Function
|
|
scene.onRemove.append(OnExit)
|
|
|
|
# Dani's Delay for proper loading.
|
|
bge.logic.globalDict["restore-physics-timer"] = 100
|
|
bge.logic.globalDict["restore-physics"] = True
|
|
|
|
# Running multiplayer daemon
|
|
if settings.get("multiplayer"):
|
|
multiplayer = threading.Thread(target=Multiplayer_Client.MainLoop)
|
|
multiplayer.setDaemon(True)
|
|
multiplayer.start()
|
|
|
|
def OnExit():
|
|
|
|
# Function running on the exit.
|
|
|
|
preData = bge.logic.globalDict["preData"]
|
|
|
|
print("\nScene Spawn Totals:\n")
|
|
for obj in Reuse.amounts:
|
|
|
|
precached = preData.get(obj, 0)
|
|
cached = Reuse.amounts[obj]
|
|
|
|
d = cached - precached
|
|
if d > 0:
|
|
dc = clr["tdrd"]
|
|
d = "+"+str(d)
|
|
elif d <= 0:
|
|
dc = clr["tdgr"]
|
|
|
|
print(" "+clr["bold"]+obj+clr["norm"]+" Exited with"+clr["bold"], cached, clr["norm"]+", Started with"+clr["bold"], precached, clr["norm"]+", Difference"+dc, d , clr["norm"] )
|
|
|
|
|
|
print()
|
|
Settings.SaveGame()
|
|
print()
|