DanisRace/Scripts/Character_Controll.py~
Victorious Children Studios db92590087 Version 08-08-24
2024-08-27 15:34:26 +03:00

1264 lines
39 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"]:
if not dani.get("underwater"):
ApplyAnimation(dani, "Stand")
else:
ApplyAnimation(dani, "SwimIdle")
StopWalkSound(dani)
#AutoStand(dani)
# If getting car
if controls["getcar"] in keys and not dani.get("getcartimer"):
getIntoCar(dani)
dani["getcartimer"] = 10
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 and not dani.get("getcartimer"):
getOutCar(dani)
dani["getcartimer"] = 10
if dani.get("getcartimer"): dani["getcartimer"] -= 1
collidewithwater = dani.collide(scene.objects["Water"])
if collidewithwater[1]: # Checking for collision points, first
# boolean gives false positives. Bug?
dani["underwater"] = True
# Executing camera changes
ExecuteChangeCameraTarget()
CameraRuleOfThirds(dani)
# Reverting swimming
dani["swimming_down"] = False
dani["jumping"] = False
if dani.get("jump-timer"): dani["jump-timer"] -= 1
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):
character.applyMovement([0,-0.02,0], True)
character.localLinearVelocity.y = -5
# 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):
character.applyMovement([0,0.02,0], True)
character.localLinearVelocity.y = 5
# 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):
character.applyMovement([0.02,0,0], True)
character.localLinearVelocity.x = 5
# 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):
character.applyMovement([-0.02,0,0], True)
character.localLinearVelocity.x = -5
# 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):
#if not OnGround(character) and not character.get("grab")\
# and not character.get("underwater"):
# return
character["jumping"] = True
if ( character.localLinearVelocity.z > 0.5 \
or character.localLinearVelocity.z < -0.5 )\
and not character.get("grab")\
and not character.get("underwater")\
and not character.get("underwater"):
return
if character.get("jump-timer") and not character.get("grab")\
and not character.get("underwater"):
return
character["jump-timer"] = 20
#character.applyMovement([0, 0, 0.1], False)
character.localLinearVelocity.z = 6
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.get("underwater") and character.position[2] < -10.5 and not character.get("driving"):
#character.worldLinearVelocity.z /= 10
#if round(character.worldLinearVelocity.z, 1) == 0.0:
if not character.get("jumping"):
character.worldLinearVelocity.z = 0.5
character.worldLinearVelocity.x *= 0.9
character.worldLinearVelocity.y *= 0.9
#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, immediately=False, closest=10, avoidblown=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.
car = None
for trycar in bge.logic.globalDict["allcars"]:
distance = trycar.getDistanceTo(character)
if avoidblown and trycar.get("blown"):
continue
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
if immediately:
walkTowardCar(character, immediately=True)
# 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, avoidObstacles=True):
# Function used when character needs to walk somewhere
if type(point) == bge.types.KX_GameObject:
point = point.position.copy()
rig = getRig(character)
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
if avoidObstacles:
ray = Vehicle.BeautyRayCast(character, "walk",
point,
fro)
else:
ray = [None]
if ray[0] and ray[0].position != point and ray[0] != point and ray[0].visible:
distance = math.dist(ray[1], fro)
if distance < 5:
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 )
if obstacleVector[2][0] < 0:
rto = ray[2]
else:
rto = -ray[2]
character.alignAxisToVect(rto, 0, 0.1)
character.alignAxisToVect((0,0,1), 2, 1)
rig.alignAxisToVect(rto, 0, 0.1)
rig.alignAxisToVect((0,0,1), 2, 1)
WalkForward(character)
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, immediately=False):
# 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
if immediately or walkVector[0] < 1 and character["walkingtowardcartarget"] == finaltarget:
# 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])
car["npc"] = ""
car["enemy"] = ""
car["shake"] = 0.0
character.position = finaltarget.position
StopWalkSound(character)
character["walkingtowardcar"] = False
if character.name == "Dani_Box":
car["active"] = True
character["driving"] = car
if not passanger:
if car.get("driver"):
driver = car["driver"]
getOutCar(driver)
driver["getbacktocar"] = car
driver["getbacktimer"] = 60
car["driver"] = character
else:
if "passangers" not in car:
car["passangers"] = []
car["passangers"].append(character)
rig = getRig(character)
rig["driving"] = True
target = car.children["Dani_Sit_Target"]
if passanger:
try: target = car.children["Other_Sit_Target"]
except: pass
character.suspendPhysics(True)
character.worldPosition = target.worldPosition
character.worldOrientation = target.worldOrientation
rig.worldOrientation = character.worldOrientation
character.setParent(car, False, False)
character["carTarget"] = finaltarget
#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
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
if not character.get("walkingtowardcar"):
pos = car.worldOrientation.to_euler()
character.orientation = [0,0,float(pos[2])]
target = character.get("carTarget", car.children["Dani_Stand_Target"])
character.worldPosition = target.worldPosition
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", ""):
rigname = character.get("rig", "")
# if str(character) == "MoriaBox":
# print()
# print("character:", character)
# print("rigname:", rigname)
# print("Game Children")
# for i in character.childrenRecursive:
# print("child:", i)
# print("Blender Children")
# for i in character.blenderObject.children_recursive:
# print("child:", i)
rig = character.children[rigname]
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)
elif type(animation) == str:
startframe = 0
endframe = 0
# 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
# Rotate 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
### NPC STUFF ###
def GetBackCar(character):
# First waiting in bevilderment
if character.get("getbacktimer"):
character["getbacktimer"] -= 1
return
if not character.get("driving"):
character["walkingtowardcar"] = None
getIntoCar(character, closest=100, avoidblown=True)
else:
if character["driving"] == character["getbacktocar"]:
character["driving"]["npc"] = "npc"
else:
character["driving"]["npc"] = "pursuit"
character["driving"]["target"] = character["getbacktocar"]
character["getbacktocar"] = None
def WhenBlewUpCar(character):
car = character["carblewup"]
# Turning off this function if the
# character got spawned.
if character.get("driving"):
if not character.get("target") or character.get("target") == character.get("driving"):
character["driving"]["npc"] = "npc"
else:
character["driving"]["npc"] = "pursuit"
character["driving"]["target"] = character.get("target")
character["target"] = None
character["carblewup"] = False
return
# Getting to any car
getIntoCar(character, closest=1000, avoidblown=True)
def NPCcar(character):
car = character["NPCcar"]
# Finishing the operation
if character.get("driving"):
if character["driving"] == car:
car["npc"] = "npc"
character["NPCcar"] = False
return
# If somebody is the targeted car
if car.get("driver"):
character["getbacktocar"] = car
character["NPCcar"] = False
return
if not car.get("blown"):
getIntoCar(character, car)
else:
getIntoCar(character, closest=100, avoidblown=True)
### 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 Update(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)
if character.get("getbacktocar"):
GetBackCar(character)
if character.get("carblewup"):
WhenBlewUpCar(character)
if character.get("NPCcar"):
NPCcar(character)
collidewithwater = character.collide(scene.objects["Water"])
if collidewithwater[1]: # Checking for collision points, first
# boolean gives false positives. Bug?
character["underwater"] = True
if not character.get("swimming_down"):
WaterBoyancy(character)
character["swimming_down"] = False
character["jumping"] = False
if character.get("jump-timer"): character["jump-timer"] -= 1
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))