forked from BlenderDumbass/DanisRace
1084 lines
33 KiB
Python
1084 lines
33 KiB
Python
|
# This will controll characters.
|
||
|
|
||
|
import os
|
||
|
import bge
|
||
|
from Scripts import Opt
|
||
|
import math
|
||
|
import json
|
||
|
import time
|
||
|
import mathutils
|
||
|
import random
|
||
|
|
||
|
|
||
|
from Scripts import Reuse
|
||
|
from Scripts.Common import *
|
||
|
from Scripts import Vehicle
|
||
|
from Scripts import Multiplayer_Shared
|
||
|
|
||
|
controls = {
|
||
|
|
||
|
"forward" :keycodes["W"],
|
||
|
"backward":keycodes["S"],
|
||
|
"left" :keycodes["A"],
|
||
|
"right" :keycodes["D"],
|
||
|
"jump" :keycodes["LCtrl"],
|
||
|
"getcar" :keycodes["E"],
|
||
|
"swimdown":keycodes["LShift"],
|
||
|
}
|
||
|
|
||
|
if "chr_controls" not in bge.logic.globalDict:
|
||
|
bge.logic.globalDict["chr_controls"] = controls
|
||
|
controls = bge.logic.globalDict["chr_controls"]
|
||
|
|
||
|
# Loading animation data.
|
||
|
def LoadAnimations():
|
||
|
|
||
|
# Loading Json animation data files.
|
||
|
|
||
|
folder = bge.logic.expandPath("//animdata/chr/")
|
||
|
|
||
|
if "character-anim-data" not in bge.logic.globalDict:
|
||
|
animations = {}
|
||
|
|
||
|
for f in os.listdir(folder):
|
||
|
if f.endswith(".json"):
|
||
|
print("Reading", f, "...")
|
||
|
with open(folder+f) as fl:
|
||
|
data = json.load(fl)
|
||
|
|
||
|
name = f.replace(".json", "")
|
||
|
|
||
|
animations[name] = data
|
||
|
bge.logic.globalDict["character-anim-data"] = animations
|
||
|
|
||
|
return bge.logic.globalDict["character-anim-data"]
|
||
|
|
||
|
animations = LoadAnimations()
|
||
|
|
||
|
def DaniUpdate():
|
||
|
|
||
|
# This function is specifically meant for Dani.
|
||
|
# Since he is the main character. But if you
|
||
|
# want to modify the game, so somebody else is
|
||
|
# the main character. Use this function on that
|
||
|
# character.
|
||
|
|
||
|
cont = bge.logic.getCurrentController()
|
||
|
scene = bge.logic.getCurrentScene()
|
||
|
dani = cont.owner
|
||
|
|
||
|
keys = bge.logic.globalDict.get("keys", [])
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
if not dani["driving"]:
|
||
|
|
||
|
# Jump animation logic
|
||
|
onground = OnGround(dani)
|
||
|
if dani.get("not-onground", 0) > 20 and onground and "Water" not in str(onground):
|
||
|
dani["landing"] = 13
|
||
|
|
||
|
if onground:
|
||
|
dani["not-onground"] = 0
|
||
|
else:
|
||
|
try: dani["not-onground"] += 1
|
||
|
except: pass
|
||
|
|
||
|
if not onground or dani.get("grab"):
|
||
|
GrabEdge(dani)
|
||
|
|
||
|
dani["onground"] = onground
|
||
|
|
||
|
if dani.get("landing"):
|
||
|
ApplyAnimation(dani, "Land")
|
||
|
WalkForward(dani)
|
||
|
|
||
|
device = bge.logic.globalDict["SoundDevice"]
|
||
|
sound = bge.logic.globalDict["sounds"]["dani_land"]
|
||
|
if not sound["play"] or not sound["play"].status:
|
||
|
sound["play"] = device.play(sound["sound"])
|
||
|
|
||
|
StopWalkSound(dani)
|
||
|
|
||
|
dani["landing"] -= 1
|
||
|
elif not onground and not dani.get("underwater"):
|
||
|
if not dani.get("grab"):
|
||
|
ApplyAnimation(dani, "Fly")
|
||
|
else:
|
||
|
ApplyAnimation(dani, "Hang")
|
||
|
StopWalkSound(dani)
|
||
|
|
||
|
|
||
|
# Moving back and forth
|
||
|
if controls["forward"] in keys:
|
||
|
WalkForward(dani)
|
||
|
elif controls["backward"] in keys:
|
||
|
WalkBackward(dani)
|
||
|
|
||
|
# Moving left to right
|
||
|
if controls["left"] in keys:
|
||
|
WalkLeft(dani)
|
||
|
elif controls["right"] in keys:
|
||
|
WalkRight(dani)
|
||
|
|
||
|
# Jumping
|
||
|
if controls["jump"] in keys:
|
||
|
Jump(dani)
|
||
|
else: dani["jumping"] = False
|
||
|
|
||
|
# Swiming down
|
||
|
if controls["swimdown"] in keys:
|
||
|
GoDown(dani)
|
||
|
|
||
|
if not dani.get("swimming_down"):
|
||
|
WaterBoyancy(dani)
|
||
|
|
||
|
|
||
|
# Standing still animation
|
||
|
if not keys and not dani["walkingtowardcar"]:
|
||
|
ApplyAnimation(dani, "Stand")
|
||
|
StopWalkSound(dani)
|
||
|
#AutoStand(dani)
|
||
|
|
||
|
# If getting car
|
||
|
if controls["getcar"] in keys:
|
||
|
getIntoCar(dani)
|
||
|
|
||
|
elif dani["walkingtowardcar"]:
|
||
|
walkTowardCar(dani)
|
||
|
|
||
|
if any(controls[x] in keys for x in ["forward", "backward", "left", "right"]):
|
||
|
getOutCar(dani)
|
||
|
|
||
|
else:
|
||
|
|
||
|
ApplyAnimation(dani, "Drive")
|
||
|
|
||
|
# If getting out of car
|
||
|
if controls["getcar"] in keys:
|
||
|
getOutCar(dani)
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
# Executing camera changes
|
||
|
ExecuteChangeCameraTarget()
|
||
|
CameraRuleOfThirds(dani)
|
||
|
|
||
|
# Reverting swimming
|
||
|
dani["swimming_down"] = False
|
||
|
|
||
|
def OnGround(character):
|
||
|
|
||
|
# Returns whether the car
|
||
|
# in on the ground or not.
|
||
|
|
||
|
# Getting the relative position of the ground
|
||
|
down = Vehicle.RelativePoint(character, [0,0,-0.6])
|
||
|
center = Vehicle.RelativePoint(character, [0,0, 0.6])
|
||
|
|
||
|
# See if there is grown under the car
|
||
|
ray = character.rayCast(down, center, poly=True)
|
||
|
|
||
|
# If nothing is sensed, we return None
|
||
|
if not ray[1]:
|
||
|
return None
|
||
|
|
||
|
# Else we return the material of the object underneith
|
||
|
# Useful to see on what kind of ground the car is.
|
||
|
else:
|
||
|
try: return ray[3].material
|
||
|
# If there is no material data it will game the name
|
||
|
# of the object
|
||
|
except: return ray[0].name
|
||
|
|
||
|
def WalkForward(character):
|
||
|
|
||
|
toFPS = Opt.ToFPS()
|
||
|
character.applyMovement([0,-0.05*toFPS,0], True)
|
||
|
|
||
|
# Facing correctly
|
||
|
rig = getRig(character)
|
||
|
rot = rig.localOrientation.to_euler()
|
||
|
target = 0
|
||
|
rot[2] = rot[2] + (( target - rot[2] ) / 5 )
|
||
|
rig.localOrientation = rot
|
||
|
|
||
|
if not character.get("underwater"):
|
||
|
ApplyAnimation(character, "Walk")
|
||
|
else:
|
||
|
ApplyAnimation(character, "Swim")
|
||
|
|
||
|
WalkSound(character)
|
||
|
|
||
|
def WalkBackward(character):
|
||
|
|
||
|
toFPS = Opt.ToFPS()
|
||
|
character.applyMovement([0,0.05*toFPS,0], True)
|
||
|
|
||
|
# Facing correctly
|
||
|
rig = getRig(character)
|
||
|
rot = rig.localOrientation.to_euler()
|
||
|
target = math.pi
|
||
|
if rot[2] < 0: target -= math.pi*2
|
||
|
rot[2] = rot[2] + (( target - rot[2] ) / 5 )
|
||
|
rig.localOrientation = rot
|
||
|
|
||
|
if not character.get("underwater"):
|
||
|
ApplyAnimation(character, "Walk")
|
||
|
else:
|
||
|
ApplyAnimation(character, "Swim")
|
||
|
|
||
|
WalkSound(character)
|
||
|
|
||
|
def WalkLeft(character):
|
||
|
|
||
|
toFPS = Opt.ToFPS()
|
||
|
character.applyMovement([0.05*toFPS,0,0], True)
|
||
|
|
||
|
# Facing correctly
|
||
|
if not character.get("grab"):
|
||
|
rig = getRig(character)
|
||
|
rot = rig.localOrientation.to_euler()
|
||
|
target = math.pi/2
|
||
|
if rot[2] < -(math.pi/2): rot[2] += math.pi*2
|
||
|
rot[2] = rot[2] + (( target - rot[2] ) / 5 )
|
||
|
rig.localOrientation = rot
|
||
|
|
||
|
|
||
|
|
||
|
if not character.get("underwater"):
|
||
|
ApplyAnimation(character, "Walk")
|
||
|
else:
|
||
|
ApplyAnimation(character, "Swim")
|
||
|
|
||
|
WalkSound(character)
|
||
|
|
||
|
def WalkRight(character):
|
||
|
|
||
|
toFPS = Opt.ToFPS()
|
||
|
character.applyMovement([-0.05*toFPS,0,0], True)
|
||
|
|
||
|
# Facing correctly
|
||
|
if not character.get("grab"):
|
||
|
rig = getRig(character)
|
||
|
rot = rig.localOrientation.to_euler()
|
||
|
target = -(math.pi/2)
|
||
|
if rot[2] > math.pi/2: rot[2] -= math.pi*2
|
||
|
rot[2] = rot[2] + (( target - rot[2] ) / 5 )
|
||
|
rig.localOrientation = rot
|
||
|
|
||
|
if not character.get("underwater"):
|
||
|
ApplyAnimation(character, "Walk")
|
||
|
else:
|
||
|
ApplyAnimation(character, "Swim")
|
||
|
|
||
|
WalkSound(character)
|
||
|
|
||
|
def Jump(character):
|
||
|
|
||
|
toFPS = Opt.ToFPS()
|
||
|
character.applyMovement([0, 0, 0.07*toFPS], False)
|
||
|
|
||
|
character["jumping"] = True
|
||
|
|
||
|
if "Dani" in character.name:
|
||
|
|
||
|
device = bge.logic.globalDict["SoundDevice"]
|
||
|
sound = bge.logic.globalDict["sounds"]["dani_jump"]
|
||
|
|
||
|
if OnGround(character) and ( not sound["play"] or not sound["play"].status ) :
|
||
|
|
||
|
sound["play"] = device.play(sound["sound"])
|
||
|
|
||
|
def GoDown(character):
|
||
|
|
||
|
toFPS = Opt.ToFPS()
|
||
|
character.applyMovement([0, 0, -0.1*toFPS], False)
|
||
|
character["swimming_down"] = False
|
||
|
|
||
|
def WaterBoyancy(character):
|
||
|
|
||
|
# Creating water boyancy underwater
|
||
|
|
||
|
toFPS = Opt.ToFPS()
|
||
|
scene = bge.logic.getCurrentScene()
|
||
|
|
||
|
|
||
|
if character["underwater"] and character.position[2] < -10.5 and not character["driving"]:
|
||
|
|
||
|
#character.worldLinearVelocity.z /= 10
|
||
|
#if round(character.worldLinearVelocity.z, 1) == 0.0:
|
||
|
character.worldLinearVelocity.z = 0.5
|
||
|
|
||
|
#character.applyForce([0,0,character.mass*9.8*-min(0, character.worldLinearVelocity[2])]) #*min(1.1, (character.position[2]+9.5)*-10)
|
||
|
scene.objects["DanisRig"]["underwater"] = True
|
||
|
elif character.position[2] > -9.5:
|
||
|
character["underwater"] = False
|
||
|
scene.objects["DanisRig"]["underwater"] = False
|
||
|
|
||
|
def getIntoCar(character, car=None, passanger=False):
|
||
|
|
||
|
# This function will run when any character wants to get into
|
||
|
# any car
|
||
|
|
||
|
# If character already in a car or walking to another car
|
||
|
# we give this up.
|
||
|
if character.get("driving") or character.get("walkingtowardcar") or character.get("last_change",0) > time.time()-1:
|
||
|
return
|
||
|
|
||
|
|
||
|
if not car:
|
||
|
# If a car is not specified we are going to choose the
|
||
|
# closest car within 10 meters away from Dani.
|
||
|
|
||
|
closest = 10
|
||
|
car = None
|
||
|
|
||
|
for trycar in bge.logic.globalDict["allcars"]:
|
||
|
distance = trycar.getDistanceTo(character)
|
||
|
if distance < closest:
|
||
|
car = trycar
|
||
|
closest = distance
|
||
|
if not car:
|
||
|
|
||
|
# There is no car within this distance we give up
|
||
|
return
|
||
|
|
||
|
# Then we want to choose the closest car target.
|
||
|
|
||
|
dani_stand_target = car.children["Dani_Stand_Target"]
|
||
|
try: other_stand_target = car.children["Other_Stand_Target"]
|
||
|
except: other_stand_target = dani_stand_target
|
||
|
|
||
|
# Now we want to activate the movement.
|
||
|
|
||
|
character["walkingtowardcar"] = car
|
||
|
if not passanger:
|
||
|
character["walkingtowardcartarget"] = dani_stand_target
|
||
|
else:
|
||
|
character["walkingtowardcartarget"] = other_stand_target
|
||
|
character["becomepassanger"] = passanger
|
||
|
|
||
|
# Readjust the camera
|
||
|
|
||
|
# if character.name == "Dani_Box":
|
||
|
# car.children["CarCamTarget"].orientation = [0.2,0,0]
|
||
|
# zoom = car["specs"].get("cameraZoom", 3)
|
||
|
# ChangeCameraTarget(car.children["CarCamTarget"], 100, [zoom,zoom,zoom])
|
||
|
pass
|
||
|
|
||
|
def walkToward(character, point):
|
||
|
|
||
|
# Function used when character needs to walk somewhere
|
||
|
|
||
|
walkVector = character.getVectTo(point)
|
||
|
|
||
|
# We want the character to walk only to the strongest
|
||
|
# vector. So he will not end up flapping arround all
|
||
|
# the time.
|
||
|
|
||
|
fro = character.position.copy()
|
||
|
fro.z += 1
|
||
|
|
||
|
ray = Vehicle.BeautyRayCast(character, "walk",
|
||
|
point,
|
||
|
fro)
|
||
|
if ray[0] and ray[0].position != point and ray[0] != point and ray[0].visible:
|
||
|
|
||
|
obstacleVector = character.getVectTo(ray[1])
|
||
|
|
||
|
# Instead of trying to walk toward the target we will instead walk
|
||
|
# around the obstacle
|
||
|
|
||
|
WalkForward(character)
|
||
|
if obstacleVector[2][0] > 0:
|
||
|
character.alignAxisToVect(obstacleVector[1], 0, 0.5)
|
||
|
else:
|
||
|
character.alignAxisToVect(-obstacleVector[1], 0, 0.5)
|
||
|
character.alignAxisToVect( (0,0,1), 2, 1.0 )
|
||
|
|
||
|
|
||
|
return walkVector
|
||
|
|
||
|
else:
|
||
|
walkVectorIs = walkVector[2]
|
||
|
|
||
|
if walkVectorIs[1] < 0:
|
||
|
WalkForward(character)
|
||
|
elif walkVectorIs[1] > 0:
|
||
|
WalkBackward(character)
|
||
|
|
||
|
if walkVectorIs[0] > 0:
|
||
|
character.applyRotation([0,0,walkVectorIs[0]/5], False)
|
||
|
#WalkLeft(character)
|
||
|
elif walkVectorIs[0] < 0:
|
||
|
#WalkRight(character)
|
||
|
character.applyRotation([0,0,walkVectorIs[0]/5], False)
|
||
|
|
||
|
if walkVectorIs[2] > 0.1:
|
||
|
Jump(character)
|
||
|
elif walkVectorIs[2] < -0.1:
|
||
|
GoDown(character)
|
||
|
|
||
|
|
||
|
return walkVector
|
||
|
|
||
|
def ChangeCameraTarget(targetobject, delay, scaling=None, callable=None, rotate=True):
|
||
|
|
||
|
# This function changes dani's camera target
|
||
|
# useful for when getting into cars and the
|
||
|
# mounting point of the camera is changed.
|
||
|
# And because I can, it is also delayed.
|
||
|
|
||
|
scene = bge.logic.getCurrentScene()
|
||
|
|
||
|
bge.logic.globalDict["CameraTargetChange"] = {"delay":delay,
|
||
|
"remaining":delay,
|
||
|
"target":targetobject,
|
||
|
"targetscale":scaling,
|
||
|
"callable":callable,
|
||
|
"rotate":rotate}
|
||
|
|
||
|
cam_parent = scene.objects["DaniCam_Parent"]
|
||
|
cam_parent.removeParent()
|
||
|
|
||
|
cam_parent["startingPosition"] = cam_parent.position.copy()
|
||
|
cam_parent["startingOrientation"] = mathutils.Vector(cam_parent.orientation.to_euler())
|
||
|
|
||
|
# This fixes the spins that are more than 360 degrees
|
||
|
targetRotation = mathutils.Vector(targetobject.orientation.to_euler())
|
||
|
for i in range(3):
|
||
|
d = targetRotation[i] - cam_parent["startingOrientation"][i]
|
||
|
if d > math.pi:
|
||
|
cam_parent["startingOrientation"][i] += 2 * math.pi
|
||
|
elif d < -math.pi:
|
||
|
cam_parent["startingOrientation"][i] -= 2 * math.pi
|
||
|
|
||
|
cam_parent["startingScaling"] = cam_parent.scaling.copy()
|
||
|
|
||
|
def CameraRuleOfThirds(dani):
|
||
|
|
||
|
# This function implements the rule of thirds.
|
||
|
# The rule of thirds is a technique to compose
|
||
|
# pretty images. Where the main subject in the
|
||
|
# frame is positioned on in the center of the
|
||
|
# frame, but rather slightly to the side.
|
||
|
# Imagine dividing the frame in 3. And putting
|
||
|
# your subject on one of those division lines.
|
||
|
# This is rule of thirds.
|
||
|
|
||
|
# One more think to keep in mind. We want more empty
|
||
|
# frame toward the direction where the main character
|
||
|
# is looking.
|
||
|
|
||
|
scene = bge.logic.getCurrentScene()
|
||
|
cam = scene.objects["DaniCam"]
|
||
|
|
||
|
# We do that only for the walking.
|
||
|
if not dani["driving"]:
|
||
|
|
||
|
# We want to get the z rotation of Dani's rig
|
||
|
# which is determening where he is looking.
|
||
|
# We are going to use local space orientation
|
||
|
# since it is in relation to the parent, which
|
||
|
# rotates in sinc with the camera.
|
||
|
|
||
|
daniZrot = getRig(dani).localOrientation.to_euler()[2]
|
||
|
|
||
|
# Finding the multiplication fraction of the effect
|
||
|
# When dani points in the same direction as the camera
|
||
|
# we want the effect to be 0. The same as if we look
|
||
|
# directly at him from the front. But looking at him
|
||
|
# from the side should give 100% effect.
|
||
|
|
||
|
frac = math.cos(daniZrot * 2) - 1
|
||
|
|
||
|
# Limiting the effect to be between 0 and 1
|
||
|
frac = min(0, max(-1, frac))
|
||
|
|
||
|
# Multiplying the effectiveness of the effect
|
||
|
frac = frac ** 0.6
|
||
|
if type(frac) == complex: frac = float(frac.real)
|
||
|
|
||
|
|
||
|
# Flipping the effect when he looks right, versus left.
|
||
|
if daniZrot > 0: frac *= -1
|
||
|
|
||
|
# Applying the math to the camera
|
||
|
cam.localOrientation = [math.pi/2, # X - Move camera up, so it is not looking at the floor
|
||
|
-frac/3, # Y - Add a dutch angle since it's cool and cool is cool
|
||
|
math.pi+frac] # Z - Add the rule of thirds.
|
||
|
|
||
|
else:
|
||
|
# Applying the math to the camera
|
||
|
cam.localOrientation = [math.pi/2, # X - Move camera up, so it is not looking at the floor
|
||
|
0,
|
||
|
math.pi]
|
||
|
|
||
|
def ExecuteChangeCameraTarget():
|
||
|
|
||
|
# This function will execute the actual camera movement itself.
|
||
|
|
||
|
|
||
|
scene = bge.logic.getCurrentScene()
|
||
|
|
||
|
if "CameraTargetChange" not in bge.logic.globalDict:
|
||
|
return
|
||
|
|
||
|
cam_parent = scene.objects["DaniCam_Parent"]
|
||
|
|
||
|
|
||
|
targetObject = bge.logic.globalDict["CameraTargetChange"]["target"]
|
||
|
delayFull = bge.logic.globalDict["CameraTargetChange"]["delay"]
|
||
|
delayRemaining = bge.logic.globalDict["CameraTargetChange"]["remaining"]
|
||
|
ToRotate = bge.logic.globalDict["CameraTargetChange"]["rotate"]
|
||
|
|
||
|
|
||
|
# Counting down frames of the delay
|
||
|
bge.logic.globalDict["CameraTargetChange"]["remaining"] -= 1
|
||
|
|
||
|
# Getting a fraction of how much from that other target the character walked
|
||
|
try:
|
||
|
camFactor = ( delayRemaining / delayFull ) ** 2
|
||
|
except:
|
||
|
camFactor = 1
|
||
|
camFactor = camFactor * -1 + 1
|
||
|
camFactor = min(1, max(0, camFactor))
|
||
|
|
||
|
|
||
|
# Applying camera location and rotation based on this factor
|
||
|
|
||
|
targetObject.orientation = [0.2,0,0]
|
||
|
|
||
|
target_position = targetObject.position
|
||
|
target_orientation = mathutils.Vector(targetObject.orientation.to_euler())
|
||
|
|
||
|
|
||
|
if bge.logic.globalDict["CameraTargetChange"]["targetscale"]:
|
||
|
target_scale = mathutils.Vector(bge.logic.globalDict["CameraTargetChange"]["targetscale"])
|
||
|
|
||
|
if delayRemaining <= 0:
|
||
|
|
||
|
|
||
|
if ToRotate:
|
||
|
cam_parent.orientation = target_orientation
|
||
|
else:
|
||
|
vect = cam_parent.getVectTo(target_position)
|
||
|
vect[1].z = min(-0.1, vect[1].z)
|
||
|
cam_parent.alignAxisToVect(-vect[1], 1, 0.1)
|
||
|
|
||
|
|
||
|
cam_parent.position = target_position
|
||
|
|
||
|
if bge.logic.globalDict["CameraTargetChange"]["targetscale"]:
|
||
|
cam_parent.scaling = target_scale
|
||
|
cam_parent.setParent(targetObject, 0, 0)
|
||
|
|
||
|
if bge.logic.globalDict["CameraTargetChange"]["callable"]:
|
||
|
bge.logic.globalDict["CameraTargetChange"]["callable"]()
|
||
|
|
||
|
del bge.logic.globalDict["CameraTargetChange"]
|
||
|
|
||
|
return
|
||
|
|
||
|
cam_parent.position = ( cam_parent["startingPosition"] + ( target_position - cam_parent["startingPosition"] ) * camFactor )
|
||
|
if ToRotate:
|
||
|
cam_parent.orientation = ( cam_parent["startingOrientation"] + ( target_orientation - cam_parent["startingOrientation"] ) * camFactor )
|
||
|
if bge.logic.globalDict["CameraTargetChange"]["targetscale"]:
|
||
|
cam_parent.scaling = ( cam_parent["startingScaling"] + ( target_scale - cam_parent["startingScaling"] ) * camFactor )
|
||
|
|
||
|
def walkTowardCar(character):
|
||
|
|
||
|
# This function is running while the character is getting into car
|
||
|
|
||
|
settings = bge.logic.globalDict["settings"]
|
||
|
|
||
|
walkVector = walkToward(character, character["walkingtowardcartarget"])
|
||
|
|
||
|
scene = bge.logic.getCurrentScene()
|
||
|
car = character["walkingtowardcar"]
|
||
|
finaltarget = car.children["Dani_Stand_Target"]
|
||
|
passanger = character["becomepassanger"]
|
||
|
|
||
|
if passanger:
|
||
|
try: finaltarget = car.children["Other_Stand_Target"]
|
||
|
except: pass
|
||
|
|
||
|
# Change to final target
|
||
|
|
||
|
if walkVector[0] < 1 and character["walkingtowardcartarget"] != finaltarget:
|
||
|
character["walkingtowardcartarget"] = finaltarget
|
||
|
|
||
|
# Change to sitting inside of the car
|
||
|
|
||
|
elif walkVector[0] < 1 and character["walkingtowardcartarget"] == finaltarget:
|
||
|
|
||
|
StopWalkSound(character)
|
||
|
character["walkingtowardcar"] = False
|
||
|
if character.name == "Dani_Box":
|
||
|
car["active"] = True
|
||
|
|
||
|
character["driving"] = car
|
||
|
|
||
|
if not passanger:
|
||
|
car["driver"] = character
|
||
|
else:
|
||
|
if "passangers" not in car:
|
||
|
car["passangers"] = []
|
||
|
car["passangers"].append(character)
|
||
|
|
||
|
car["npc"] = ""
|
||
|
car["enemy"] = ""
|
||
|
car["shake"] = 0.0
|
||
|
|
||
|
rig = getRig(character)
|
||
|
rig["driving"] = True
|
||
|
target = car.children["Dani_Sit_Target"]
|
||
|
|
||
|
if passanger:
|
||
|
try: target = car.children["Other_Sit_Target"]
|
||
|
except: pass
|
||
|
|
||
|
rig.removeParent()
|
||
|
pos = target.worldPosition
|
||
|
rig.position = [pos[0],pos[1],pos[2]]
|
||
|
pos = target.worldOrientation
|
||
|
rig.orientation = [pos[0],pos[1],pos[2]]
|
||
|
rig.setParent(target, False, False)
|
||
|
|
||
|
character.suspendPhysics(True)
|
||
|
character.setParent(car, False, False)
|
||
|
|
||
|
|
||
|
#car_rig = car.children[car.get("rig","RIG")]
|
||
|
#car_rig.playAction(car.get("rigaction", "NeonspeedsterRIGAction"), 10,20)
|
||
|
|
||
|
if character.name == "Dani_Box":
|
||
|
scene.objects["Gage"].visible = True
|
||
|
scene.objects["Gage_Arrow"].visible = True
|
||
|
scene.objects["Gage_Health"].visible = True
|
||
|
scene.objects["Gage_Nitro"].visible = True
|
||
|
scene.objects["Gage_Tachometer"].visible = True
|
||
|
scene.objects["Gage_Gear"].visible = True
|
||
|
scene.objects["Gage_Redline"].visible = True
|
||
|
if settings.get("veh_mouse"):
|
||
|
|
||
|
if settings.get("veh_mouse_guides"):
|
||
|
scene.objects["Mouse_Turn_UI_Piece"].visible = True
|
||
|
scene.objects["Mouse_Turn_UI"].visible = True
|
||
|
scene.objects["Mouse_Accelation_UI_Piece"].visible = True
|
||
|
scene.objects["Mouse_Accelation_UI"].visible = True
|
||
|
|
||
|
if settings.get("veh_mouse_cursor"):
|
||
|
bge.render.showMouse(True)
|
||
|
|
||
|
|
||
|
Vehicle.RemoveNetId(car)
|
||
|
|
||
|
print(consoleForm(character), "in car:", consoleForm(car))
|
||
|
|
||
|
|
||
|
|
||
|
# Sound device for sounds.
|
||
|
device = bge.logic.globalDict["SoundDevice"]
|
||
|
|
||
|
sound = bge.logic.globalDict["sounds"]["door"]
|
||
|
sound["play"] = device.play(sound["sound"])
|
||
|
sound["play"].location = car.worldPosition
|
||
|
sound["play"].velocity = car.getLinearVelocity()
|
||
|
sound["play"].relative = False
|
||
|
sound["play"].distance_maximum = 200
|
||
|
sound["play"].distance_reference = 1
|
||
|
sound["play"].attenuation = 1
|
||
|
sound["play"].volume = 1.5
|
||
|
|
||
|
|
||
|
# Readjust the camera
|
||
|
|
||
|
if character.name == "Dani_Box":
|
||
|
car.children["CarCamTarget"].orientation = [0.2,0,0]
|
||
|
zoom = car["specs"].get("cameraZoom", 3)
|
||
|
ChangeCameraTarget(car.children["CarCamTarget"], 20, [zoom,zoom,zoom])
|
||
|
|
||
|
def getOutCar(character):
|
||
|
|
||
|
# Fucntion to get out of car
|
||
|
|
||
|
scene = bge.logic.getCurrentScene()
|
||
|
|
||
|
# If character is not in the car
|
||
|
if character["walkingtowardcar"]:
|
||
|
car = character["walkingtowardcar"]
|
||
|
soundDo = False
|
||
|
elif character["driving"]:
|
||
|
car = character["driving"]
|
||
|
soundDo = True
|
||
|
else:
|
||
|
return
|
||
|
|
||
|
rig = getRig(character)
|
||
|
|
||
|
if character.name == "Dani_Box":
|
||
|
car["active"] = False
|
||
|
|
||
|
# Unfucking the camera
|
||
|
cam = bge.logic.getCurrentScene().active_camera
|
||
|
cam.shift_x = 0
|
||
|
cam.shift_y = 0
|
||
|
cam.lens = 20
|
||
|
|
||
|
if character == car.get("driver"):
|
||
|
car["driver"] = None
|
||
|
if character in car.get("passangers",[]):
|
||
|
car["passangers"].remove(character)
|
||
|
|
||
|
rig["driving"] = False
|
||
|
|
||
|
character["last_change"] = int(time.time())
|
||
|
|
||
|
character.restorePhysics()
|
||
|
character.removeParent()
|
||
|
character.localLinearVelocity = [0,0,0]
|
||
|
if -car.localLinearVelocity[1] > 10 and not character["walkingtowardcar"]:
|
||
|
character["landing"] = 13
|
||
|
|
||
|
pos = car.worldOrientation.to_euler()
|
||
|
character.orientation = [0,0,float(pos[2])]
|
||
|
|
||
|
if not character.get("walkingtowardcar"):
|
||
|
character.position[2] += 1.5
|
||
|
|
||
|
character["driving"] = False
|
||
|
|
||
|
|
||
|
rig.removeParent()
|
||
|
pos = character.worldPosition
|
||
|
rig.position = [pos[0],pos[1],pos[2]]
|
||
|
pos = character.worldOrientation
|
||
|
rig.orientation = [pos[0],pos[1],pos[2]]
|
||
|
rig.setParent(character, False, False)
|
||
|
|
||
|
# Readjust camera
|
||
|
if character.name == "Dani_Box":
|
||
|
character.children["Dani_cam_Target"].orientation = [0,0,0]
|
||
|
ChangeCameraTarget(character.children["Dani_cam_Target"], 20, [1,1,1])
|
||
|
|
||
|
# if soundDo:
|
||
|
# rig = car.children["RIG"]
|
||
|
# rig.playAction(car.get("rigaction", "NeonspeedsterRIGAction"), 10,20)
|
||
|
|
||
|
scene.objects["Gage"].visible = False
|
||
|
scene.objects["Gage_Arrow"].visible = False
|
||
|
scene.objects["Gage_Health"].visible = False
|
||
|
scene.objects["Gage_Nitro"].visible = False
|
||
|
scene.objects["Gage_Tachometer"].visible = False
|
||
|
scene.objects["Gage_Gear"].visible = False
|
||
|
scene.objects["Gage_Redline"].visible = False
|
||
|
scene.objects["Mouse_Turn_UI_Piece"].visible = False
|
||
|
scene.objects["Mouse_Turn_UI"].visible = False
|
||
|
scene.objects["Mouse_Accelation_UI_Piece"].visible = False
|
||
|
scene.objects["Mouse_Accelation_UI"].visible = False
|
||
|
|
||
|
bge.render.showMouse(False)
|
||
|
|
||
|
|
||
|
if not character.get("walkingtowardcar"):
|
||
|
device = bge.logic.globalDict["SoundDevice"]
|
||
|
sound = bge.logic.globalDict["sounds"]["door"]
|
||
|
sound["play"] = device.play(sound["sound"])
|
||
|
sound["play"].location = car.worldPosition
|
||
|
sound["play"].velocity = car.getLinearVelocity()
|
||
|
sound["play"].relative = False
|
||
|
sound["play"].distance_maximum = 200
|
||
|
sound["play"].distance_reference = 1
|
||
|
sound["play"].attenuation = 1
|
||
|
sound["play"].volume = 1.5
|
||
|
|
||
|
character["walkingtowardcar"] = False
|
||
|
|
||
|
print(consoleForm(character), "got out of:", consoleForm(car))
|
||
|
|
||
|
def getRig(character):
|
||
|
|
||
|
scene = bge.logic.getCurrentScene()
|
||
|
|
||
|
if type(character.get("rig", "")) == str and character.get("rig", ""):
|
||
|
rig = scene.objects[character.get("rig", "")]
|
||
|
elif character.get("rig"):
|
||
|
rig = character.get("rig")
|
||
|
|
||
|
return rig
|
||
|
|
||
|
def ApplyAnimation(character, animation, keep=False, **kwargs):
|
||
|
|
||
|
# Optimization
|
||
|
cam = bge.logic.getCurrentScene().active_camera
|
||
|
if character in Reuse.reuse.get(character.name, [])\
|
||
|
or cam.getDistanceTo(character) > 150:
|
||
|
return
|
||
|
|
||
|
# Exctracting data request
|
||
|
rig = getRig(character)
|
||
|
action = rig.get("Action")
|
||
|
startframe = animation[0]
|
||
|
endframe = animation[1]
|
||
|
|
||
|
# Failsafe
|
||
|
if not action:
|
||
|
return
|
||
|
|
||
|
# If we are reading animation from the database
|
||
|
if type(animation) == str and animation in animations.get(character.name, {}):
|
||
|
|
||
|
data = animations[character.name][animation]
|
||
|
action = data.get("Action", action)
|
||
|
keep = data.get("Keep", keep)
|
||
|
startframe = data["Frames"][0]
|
||
|
endframe = data["Frames"][1]
|
||
|
kwargs = data.get("kwargs", kwargs)
|
||
|
|
||
|
# Sometimes we might want to keep the animation at it's
|
||
|
# last frame when it ends.
|
||
|
if keep and rig.getActionFrame(kwargs.get("layer", 0)) == endframe:
|
||
|
startframe = endframe
|
||
|
|
||
|
|
||
|
# Executing the animation
|
||
|
rig.playAction(action, startframe, endframe, **kwargs)
|
||
|
|
||
|
# To activate the stand animation we want to know if anything is playing
|
||
|
if kwargs.get("layer", 0) == 0:
|
||
|
|
||
|
# Recording the animation
|
||
|
rig["animation"] = animation
|
||
|
|
||
|
def AutoStand(character):
|
||
|
|
||
|
# This function will automatically play the stand animation if
|
||
|
# nothing else is playing.
|
||
|
|
||
|
|
||
|
rig = getRig(character)
|
||
|
|
||
|
if not rig.get("animation"):
|
||
|
ApplyAnimation(character, "Stand")
|
||
|
|
||
|
else:
|
||
|
|
||
|
animation = rig.get("animation")
|
||
|
|
||
|
startframe = animation[0]
|
||
|
endframe = animation[1]
|
||
|
|
||
|
# If we are reading animation from the database
|
||
|
if type(animation) == str and animation in animations.get(character.name, {}):
|
||
|
|
||
|
data = animations[character.name][animation]
|
||
|
keep = data.get("Keep", None)
|
||
|
startframe = data["Frames"][0]
|
||
|
endframe = data["Frames"][1]
|
||
|
kwargs = data.get("kwargs", {})
|
||
|
|
||
|
if rig.getActionFrame(0) == endframe:
|
||
|
rig["animation"] = None
|
||
|
|
||
|
def GrabEdge(character):
|
||
|
|
||
|
rig = getRig(character)
|
||
|
|
||
|
chest = Vehicle.RelativePoint(rig, [0,0,0.7])
|
||
|
fromchest = Vehicle.RelativePoint(rig, [0,-1,0.7])
|
||
|
|
||
|
chestray = Vehicle.BeautyRayCast(character, "chest", fromchest, chest)
|
||
|
|
||
|
face = Vehicle.RelativePoint(rig, [0,0,1.5])
|
||
|
fromface = Vehicle.RelativePoint(rig, [0,-1,1.5])
|
||
|
|
||
|
faceray = Vehicle.BeautyRayCast(character, "face", fromface, face)
|
||
|
|
||
|
try: facedist = math.dist(face, faceray[1])
|
||
|
except: facedist = 1
|
||
|
try: chestdist = math.dist(chest, chestray[1])
|
||
|
except: chestdist = 1
|
||
|
|
||
|
if chestdist < facedist:
|
||
|
|
||
|
|
||
|
if not character.get("jumping"):
|
||
|
|
||
|
dist = chestdist+0.01
|
||
|
toedge = Vehicle.RelativePoint(rig, [0,-dist,1.0])
|
||
|
fromedge = Vehicle.RelativePoint(rig, [0,-dist,1.5])
|
||
|
edgeray = Vehicle.BeautyRayCast(character, "edge", toedge, fromedge)
|
||
|
if edgeray[1]:
|
||
|
character["grab"] = float(edgeray[1].z-1.2)
|
||
|
else:
|
||
|
character["grab"] = float(character.position.z)
|
||
|
character.position.z = character["grab"]
|
||
|
character.worldLinearVelocity = [0,0,0]
|
||
|
|
||
|
|
||
|
|
||
|
else:
|
||
|
|
||
|
character["grab"] = character.position.z
|
||
|
|
||
|
|
||
|
# Ratate character to face the point.
|
||
|
vect = character.getVectTo(chestray[2])
|
||
|
character.alignAxisToVect(chestray[2], 1, 1)
|
||
|
character.alignAxisToVect((0,0,1), 2, 1)
|
||
|
|
||
|
vect = rig.getVectTo(chestray[2])
|
||
|
rig.alignAxisToVect(chestray[2], 1, 1)
|
||
|
rig.alignAxisToVect((0,0,1), 2, 1)
|
||
|
|
||
|
character.applyMovement((0,-0.01,0), True)
|
||
|
|
||
|
|
||
|
else:
|
||
|
character["grab"] = None
|
||
|
|
||
|
|
||
|
|
||
|
### SOUND STUFF ####
|
||
|
|
||
|
def WalkSound(character):
|
||
|
|
||
|
if "Dani" in character.name and character.get("onground") and not character.get("landing"):
|
||
|
device = bge.logic.globalDict["SoundDevice"]
|
||
|
sound = bge.logic.globalDict["sounds"]["dani_walk"]
|
||
|
if not sound["play"] or not sound["play"].status:
|
||
|
sound["play"] = device.play(sound["sound"])
|
||
|
def StopWalkSound(character):
|
||
|
|
||
|
try: bge.logic.globalDict["sounds"]["dani_walk"]["play"].stop()
|
||
|
except: pass
|
||
|
|
||
|
|
||
|
##### STORY RELATED FUNCTIONS ####
|
||
|
|
||
|
def StoryCharacter(character):
|
||
|
|
||
|
# It may run from an actuator, so we want to make sure we get the object
|
||
|
# and not the actuator.
|
||
|
scene, character = Vehicle.GetSceneAndCar(character)
|
||
|
|
||
|
|
||
|
if character.get("walkingtowardcar"):
|
||
|
walkTowardCar(character)
|
||
|
|
||
|
|
||
|
if not character.get("driving"):
|
||
|
|
||
|
AutoStand(character)
|
||
|
|
||
|
else:
|
||
|
|
||
|
ApplyAnimation(character, "Drive")
|
||
|
|
||
|
ReactionsToDaniDriving(character)
|
||
|
|
||
|
def ReactionsToDaniDriving(character):
|
||
|
|
||
|
# This function will make characters react to dani's driving
|
||
|
# when they are sitting in the same car.
|
||
|
|
||
|
scene = bge.logic.getCurrentScene()
|
||
|
dani = scene.objects["Dani_Box"]
|
||
|
|
||
|
# First we need to make sure that the character is in the
|
||
|
# car as dani.
|
||
|
|
||
|
if not character.get("driving") == dani.get("driving") or not character.get("driving"):
|
||
|
return
|
||
|
|
||
|
# Then we want to get data about what if going on with the car.
|
||
|
|
||
|
car = character.get("driving")
|
||
|
crash = car.get("crash", 0.0)
|
||
|
near = car.get("near", 0.0)
|
||
|
speed = -car.localLinearVelocity[1]
|
||
|
|
||
|
car["crash"] = 0.0
|
||
|
car["near"] = 0.0
|
||
|
|
||
|
react = None
|
||
|
|
||
|
if crash > 0.1:
|
||
|
react = "crash"
|
||
|
|
||
|
if speed > 50:
|
||
|
react = "speed"
|
||
|
|
||
|
if near >= 0.4:
|
||
|
react = "near"
|
||
|
|
||
|
|
||
|
|
||
|
device = bge.logic.globalDict["SoundDevice"]
|
||
|
|
||
|
try:
|
||
|
voices = bge.logic.globalDict[character.name+"Voices"]
|
||
|
except:
|
||
|
return
|
||
|
|
||
|
if ( not character.get("saying") or not character.get("saying").status ) and react:
|
||
|
sound = random.choice(voices[react])
|
||
|
while character.get("lastsaid") == sound:
|
||
|
sound = random.choice(voices[react])
|
||
|
character["lastsaid"] = sound
|
||
|
sound["play"] = device.play(sound["sound"])
|
||
|
character["saying"] = sound["play"]
|
||
|
|
||
|
sound["play"].volume = 2
|
||
|
|
||
|
|
||
|
ApplyAnimation(character, "Talk")
|
||
|
|
||
|
|
||
|
##### NETWORK RELATE FUNCTIONS ####
|
||
|
|
||
|
def Encode(character):
|
||
|
|
||
|
data = {
|
||
|
"ID" :id(character),
|
||
|
"type" :"chr",
|
||
|
"name" :character.name,
|
||
|
"netId" :character.get("netId"),
|
||
|
"position" :list(character.position),
|
||
|
"orientation" :list(character.orientation.to_euler())
|
||
|
}
|
||
|
|
||
|
character["netId"] = data["netId"]
|
||
|
|
||
|
netObjects = bge.logic.globalDict["netObjects"]
|
||
|
if data["ID"] not in netObjects["pythonId"]:
|
||
|
netObjects["pythonId"][data["ID"]] = character
|
||
|
|
||
|
return data
|
||
|
|
||
|
def Decode(data, network=False):
|
||
|
|
||
|
# Decoding character data
|
||
|
|
||
|
netObjects = bge.logic.globalDict["netObjects"]
|
||
|
|
||
|
if data.get("netId") not in netObjects["netId"]:
|
||
|
|
||
|
# Making the character
|
||
|
try:
|
||
|
character = Reuse.Create(data.get("name"))
|
||
|
except:
|
||
|
character = Reuse.Create("MoriaBox")
|
||
|
|
||
|
netObjects["netId"][data.get("netId")] = character
|
||
|
|
||
|
character = netObjects["netId"][data.get("netId")]
|
||
|
character["netId"] = data.get("netId")
|
||
|
|
||
|
character.position = data.get("position", (0,0,0))
|
||
|
character.orientation = data.get("orientation", (0,0,0))
|