DanisRace/Scripts/Script.py
Victorious Children Studios 594e088a83 07-07-24
2024-07-13 16:15:50 +03:00

819 lines
27 KiB
Python

# This file contains all of the scripted events of the game's story.
# And some logic to go with it.
import bge
import aud
from Scripts import Reuse
from Scripts import Character_Controll
from Scripts import Vehicle
from Scripts import Map
from Scripts import Main_update
from Scripts import Garage
from Scripts.Common import *
Story = {"currentEvent":"01_Bring_Neonspeedster_To_Racetrack","passed":[]}
Speakers = {}
def Run(scene, dani):
# This function runs the script
if Story["currentEvent"] in Story:
Story[Story["currentEvent"]](scene, dani)
# This needed incase some character started speaking
RemoveSpeakerAnimation()
def RingPhone():
# This function rings the phone.
bge.logic.globalDict["print"] = "Press P to answer the phone.\nPress H to hang up."
device = bge.logic.globalDict["SoundDevice"]
s = "//sfx/music/ringtone.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]
sound["play"] = device.play(sound["sound"])
sound["play"].volume = 0.5
return sound["play"]
def AnsweredPhone():
# This function answers phone if player presses P
sound = Story["ringing"]
# Answer Phone
if keycodes["P"] in bge.logic.globalDict["keys"]:
sound.stop()
return True
# Hang Up
elif keycodes["H"] in bge.logic.globalDict["keys"]:
sound.stop()
return False
# Do nothing
else:
return False
def PlayDialogue(number, character=None):
# This function plays dialogue from the specific scene.
device = bge.logic.globalDict["SoundDevice"]
s = "//sfx/voices/scenes/"+Story["currentEvent"]+"/"+number+".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]
sound["play"] = device.play(sound["sound"])
sound["play"].volume = 2
if character:
sound["play"].location = character.worldPosition
sound["play"].velocity = character.getLinearVelocity()
sound["play"].relative = False
sound["play"].distance_maximum = 200
sound["play"].distance_reference = 1
sound["play"].attenuation = 0
sound["play"].volume = 2
# Setting speaking animation
character["speaking"] = True
# Removing the speaking animation
# when the sound file is finished
Speakers[character.name] = {"sound":sound, "character":character}
return sound["play"]
def RemoveSpeakerAnimation():
# This function removes speaker animations
# for when characters speak.
for charactername in Speakers:
speaker = Speakers[charactername]
character = speaker["character"]
sound = speaker["sound"]
if not sound["play"].status:
character["speaking"] = False
def emote(dani, data, sound):
# This function will set off face animations
# based on the data and sound timing.
for emotion in data:
start, end = emotion[0]
emotion = emotion[1]
if start < sound.position < end:
Character_Controll.ApplyAnimation(dani, emotion)
def StatusText(text, bold=[]):
# This function prints a status text that is visible all
# the time.
scene = bge.logic.getCurrentScene()
st = scene.objects["Game_Status_Text"]
if "status-text" not in bge.logic.globalDict:
bge.logic.globalDict["status-text"] = ""
if text != bge.logic.globalDict["status-text"]:
# Updating text
# I'm doing this and not `st["Text"] = text` because
# I want it it update the blender object data now.
# Since next part will be to boldify the text.
st.blenderObject.data.body = text
# Storing the text value, so it will not update on every frame.
bge.logic.globalDict["status-text"] = text
bge.logic.globalDict["status-bold"] = ""
if "status-bold" not in bge.logic.globalDict:
bge.logic.globalDict["status-bold"] = ""
if bold != bge.logic.globalDict["status-bold"]:
bge.logic.globalDict["status-bold"] = bold
# Boldifying the text
for n, i in enumerate(st.blenderObject.data.body_format):
if n in bold:
i.use_bold = True
i.material_index = 0
else:
i.use_bold = False
i.material_index = 1
def StatusUpdate(stages, stage):
t = ""
bold = []
for n, s in enumerate(stages):
if n == stage:
bold = range(len(t), len(t)+len(s)+5+3)
t = t + "-> "
if stage > n:
t = t + s + " <+>\n"
else:
t = t + s + " < >\n"
try:StatusText(t, bold)
except Exception as e: print("error", e)
##############################################################################
# Mission : Deliver Neonspeedster to Racetrack.
# Challenge: Not to break the car.
def scene(scene, dani):
# First we will make the phone called to Dani.
# He needs to pick it up to start the mission itself.
# The phone call should only ring when Dani is close to the house
# since we don't want the player to be near the Racetrack and
# see that Paps isn't there yet. We will spawn him there later.
stages = [
"Find Neonspeedster",
"Deliver it to Paps"
]
house = scene.objects["TheHouse"]
pointer = scene.objects["PointingArrow"]
targetLocation = [-62.82, 967.5, 4.738]
# Showing on the map
if not dani.get("race"):
Map.Show(house, icon="Map_Circle", color=[1,0.8,0])
if dani.getDistanceTo(house) < 200 and not dani.get("race"):
# If at least 20 seconds have been passed from the start of the game.
if bge.logic.getRealTime() > Story.get("lastring", 20):
Story["ringing"] = RingPhone()
Story["lastring"] = bge.logic.getRealTime() + 100
# If the phone is still ringing we can answer it
if "ringing" in Story and Story["ringing"].status and AnsweredPhone():
del Story["ringing"]
Story["dialogue01"] = PlayDialogue("brief")
dani["race"] = Story["currentEvent"]
# Animation of dani holding the phone
if "dialogue01" in Story:
Character_Controll.ApplyAnimation(dani, "AnswerPhone")
# Emoting to the phone conversation
emotion_data = [
[[ 3.1 , 3.6 ], "Talk" ],
[[ 8.6 , 8.9 ], "Laugh"],
[[ 18.1 , 19.0 ], "Talk" ]
]
emote(dani, emotion_data, Story["dialogue01"])
# When we finished listening to it activate the event
if "dialogue01" in Story and not Story["dialogue01"].status:
del Story["dialogue01"]
bge.logic.globalDict["print"] = "Find the Neonspeedster.\nIt should be in the garage."
Story["stage0"] = True
StatusUpdate(stages, 0)
# Animation of putting away the phone
Character_Controll.ApplyAnimation(dani, "PutPhoneAway")
# We we will a neonspeedste at a specific point in the garage for this to work
# relying on the spawn system is stupid, since it might decide that we will not
# get a NeonSpeedster
NeonSpeedsterPosition = [-754.61, -1043.9, 409.32]
NeonSpeedsterOrientation = [0, 0, -1.79]
TruckPosition = [-44.62, 960.8, 4.738]
if "stage1" not in Story and not "NeonSpeedster" in Story and dani.getDistanceTo(NeonSpeedsterPosition) < 50:
f = False
for c in Garage.Inside():
if c.name == "NeonSpeedsterBox":
Story["NeonSpeedster"] = c
f = True
if not f:
# We need properly declare the car, otherwise it will break things
Story["NeonSpeedster"] = Vehicle.Spawn("NeonSpeedsterBox",
NeonSpeedsterPosition,
NeonSpeedsterOrientation)
# Showing all neonspeedsters on the map
if "stage0" in Story and str(dani.get("drving")) != "NeonSpeedsterBox":
for car in bge.logic.globalDict["allcars"]:
if car.name == "NeonSpeedsterBox":
Map.Show(car, color=Vehicle.GetColor(car))
# As soon as dani found the Neonspeedster, we activate the second stage
if "stage0" in Story and dani["driving"] and dani["driving"].name == "NeonSpeedsterBox":
del Story["stage0"]
try: del Story["NeonSpeedster"]
except: pass
bge.logic.globalDict["print"] = "Drive the Neonspeedster to the Racetrack.\nNot a single scratch!"
pointer.visible = True
# Making a cylinder where the mission ends
Story["stage1"] = Reuse.Create("Starter.Cylinder")
Story["stage1"].position = targetLocation
Story["stage1"].scaling = [8,8,1]
StatusUpdate(stages, 1)
# Spawning Paps To make sure he is there to recieve
# the car
Reuse.Delete(scene.objects["PapsBox"])
Story["Paps"] = Reuse.Create("PapsBox")
Story["Paps"].position = [-54.875, 972.66, 4.7383]
# He spawns in an area where the physics arent enabled for
# the ground yet.
Story["Paps"].suspendDynamics(True)
Story["Paps"]["deactivated"] = True
# Same thing but for Moria
Story["Moria"] = Reuse.Create("MoriaBox")
Story["Moria"].position = [-56.875, 972.66, 4.7383]
Story["Moria"].suspendDynamics(True)
# And Jack
Story["Jack"] = Reuse.Create("JackBox")
Story["Jack"].position = [-52.875, 972.66, 4.7383]
Story["Jack"].suspendDynamics(True)
# Fixing Pap's dynamics and making paps go at Dani
if "Paps" in Story and Story["Paps"].getDistanceTo(dani) < 500:
if Story["Paps"]["deactivated"]:
Story["Paps"].restoreDynamics()
Story["Moria"].restoreDynamics()
Story["Jack"].restoreDynamics()
Story["Paps"]["deactivated"] = False
# Draw a pointer to the racetrack
if "stage1" in Story:
# Showing the racetrack on the map
Map.Show(targetLocation, icon="Map_Circle", color=[1,0.8,0])
# Point the pointer to the racetrack
tocheck = pointer.getVectTo(targetLocation)
pointer.alignAxisToVect(tocheck[1], 1, 0.1)
pointer.alignAxisToVect( (0,0,1), 2, 1.0 )
# Spawning the truck that paps was talking about near paps
if "Truck" not in Story and dani.getDistanceTo(TruckPosition) < 200:
Story["Truck"] = Vehicle.Spawn("TruckBox",
TruckPosition,
[0,0,0])
# Deciding on the mission
if dani["driving"] and dani["driving"].name == "NeonSpeedsterBox" and dani["driving"].getDistanceTo(targetLocation) < 8:
StatusUpdate(stages, 2)
#Character_Controll.ApplyAnimation(Story["Paps"], "Stand")
Reuse.Delete(Story["stage1"])
del Story["stage1"]
if dani["driving"]["health"] >= 0.99:
bge.logic.globalDict["print"] = "Excellent Job!"
Story["dialogue02"] = PlayDialogue("win", Story["Paps"])
Story["verdict"] = "won"
Story["Neonspeedster"] = dani["driving"]
else:
bge.logic.globalDict["print"] = "You Failed! There was a scratch!"
Story["dialogue02"] = PlayDialogue("lose", Story["Paps"])
Story["verdict"] = "lost"
# While the paps is telling you that you won
if "dialogue02" in Story:
emotion_data = [
[[ 1.15 , 8 ], "Talk" ]
]
emote(Story["Paps"], emotion_data, Story["dialogue02"])
if 50 > Story["Paps"].getDistanceTo(dani) > 4:
Character_Controll.walkToward(Story["Paps"], dani)
if 50 > Story["Moria"].getDistanceTo(dani) > 4:
Character_Controll.walkToward(Story["Moria"], dani)
if 50 > Story["Jack"].getDistanceTo(dani) > 4:
Character_Controll.walkToward(Story["Jack"], dani)
# When the dialog ende# d.
if not Story["dialogue02"].status:
# Going for the next story
if Story["verdict"] == "won":
Story["passed"].append(Story["currentEvent"])
Story["currentEvent"] = "02_Bring_Truck_To_House"
Story["timer"] = 100
#else:
# try: del Story["Truck"]
# except: pass
# Ending the event
del Story["dialogue02"]
pointer.visible = False
dani["race"] = ""
StatusText("")
Story["01_Bring_Neonspeedster_To_Racetrack"] = scene
##############################################################################
def scene(scene, dani):
house = scene.objects["TheHouse"]
pointer = scene.objects["PointingArrow"]
# Moria goes to the racetrack and does some racing by herself.
if "Moria" in Story:
# Moria goes to the car
if not dani.get("driving") and not Story["Moria"].get("driving"):
Character_Controll.getIntoCar(Story["Moria"], Story["Neonspeedster"])
if Story["Moria"].get("driving"):
racepos = [-61.7856, 1028, 0]
# Moria drive the car to the race
if Story["Moria"]["driving"].getDistanceTo(racepos) > 2 and "Moria-Practicing" not in Story:
Story["Moria"]["driving"]["npc"] = "story"
Story["Moria"]["driving"]["target"] = racepos
Vehicle.TargetedNPC(Story["Moria"]["driving"])
# Moria racing the race
elif "Moria-Practicing" not in Story:
Story["Moria"]["driving"]["race"] = "RacetrackRace"
Story["Moria"]["driving"]["npc"] = "racer"
Story["Moria"]["driving"]["racing"] = True
Story["Moria-Practicing"] = True
# Optmization Deleting both Moria and the car she drives
# if Dani is far enough away.
if dani.getDistanceTo(Story["Moria"]) > 500:
if Story["Moria"].get("driving"):
Story["Moria"]["driving"]["racing"] = False
Reuse.Delete(Story["Moria"]["driving"])
Character_Controll.getOutCar(Story["Moria"])
Reuse.Delete(Story["Moria"])
del Story["Moria"]
# Paps
if "Paps" in Story:
# Optimization
if not "dialogue1" in Story and not "dialogue2" in Story:
if dani.getDistanceTo(Story["Paps"]) > 500:
Reuse.Delete(Story["Paps"])
del Story["Paps"]
# Jack
if "Jack" in Story:
# Optimization
if dani.getDistanceTo(Story["Jack"]) > 500 and Story.get("stage", 0) < 5:
Reuse.Delete(Story["Jack"])
if Story["Jack"].get("driving"):
Character_Controll.getOutCar(Story["Jack"])
del Story["Jack"]
dani["race"] = ""
try: del Story["stage"]
except: pass
pointer.visible = False
# Truck
if "Truck" in Story:
# Optimization
if dani.getDistanceTo(Story["Truck"]) > 500 and Story.get("stage", 0) < 5:
Reuse.Delete(Story["Truck"])
del Story["Truck"]
dani["race"] = ""
try:
del Story["stage"]
bge.logic.globalDict["print"] = "Mission Failed! You've abandoned it."
except: pass
pointer.visible = False
racetrack = [-62.82, 967.5, 4.738]
# Showing on the map
if not dani.get("race"):
Map.Show(racetrack, icon="Map_Circle", color=[1,0.8,0])
# If dani is close to the racetrack and everything has been despawned
# spawned it back in if dani comes.
if dani.getDistanceTo(racetrack) < 450 and "stage" not in Story and not dani.get("race"):
# Restoring truck, Paps and Jack
if "Truck" not in Story:
TruckPosition = [-44.62, 960.8, 4.738]
Story["Truck"] = Vehicle.Spawn("TruckBox",
TruckPosition,
[0,0,0])
if not Story["Truck"].get("cargo"):
# There is a car in the truck actually
DarkShadowLocation = [-44.62, 960.8, 10]
Story["DarkShadow"] = Vehicle.Spawn("DarkShadowBox",
DarkShadowLocation,
[0,0,0],
color="pallete")
Vehicle.PackCargo(Story["Truck"], Story["DarkShadow"])
if "Paps" not in Story:
Story["Paps"] = Reuse.Create("PapsBox")
Story["Paps"].position = [-54.875, 972.66, 4.7383]
try:
Reuse.Delete(Story["Jack"])
del Story["Jack"]
except:pass
try:
Reuse.Delete(Story["Truck"])
del Story["Truck"]
except:pass
if "Jack" not in Story:
Story["Jack"] = Reuse.Create("JackBox")
Story["Jack"].position = [-52.875, 972.66, 4.7383]
# Paps coming to Dani
if 100 > Story["Paps"].getDistanceTo(dani) > 4:
Character_Controll.walkToward(Story["Paps"], dani)
# Not restoring Moria.
if Story.get("timer", 100): Story["timer"] = Story.get("timer", 100) - 1
else:
# Paps is telling Jack to go inside the truck.
if dani.getDistanceTo(Story["Paps"]) < 50 and "dialogue1" not in Story:
Story["dialogue1"] = PlayDialogue("d1", Story["Paps"])
# Paps emoting
if "dialogue1" in Story:
emotion_data = [
[[ 0.18 , 0.7 ], "Talk" ],
[[ 1.52 , 2.5 ], "Talk" ]
]
emote(Story["Paps"], emotion_data, Story["dialogue1"])
# When he finished talking Jack goes to the truck.
if "dialogue1" in Story and not Story["dialogue1"].status:
if Story["Jack"].get("driving") != Story["Truck"]:
Character_Controll.getIntoCar(Story["Jack"], Story["Truck"], passanger=True)
else:
Story["stage"] = 1
del Story["dialogue1"]
# Paps telling you how he wants you to hummiliate jack
if Story.get("stage") == 1:
# Paps coming to Dani
if "Paps" in Story:
if 100 > Story["Paps"].getDistanceTo(dani) > 4:
Character_Controll.walkToward(Story["Paps"], dani)
if "dialogue2" not in Story:
Story["dialogue2"] = PlayDialogue("brief", Story["Paps"])
# Paps emoting
if "dialogue2" in Story:
emotion_data = [
[[ 0.0 , 0.8 ], "Talk" ],
[[ 2.6 , 3.5 ], "Talk" ],
[[ 4.7 , 12.7 ], "Talk" ],
[[ 14.1 , 15.4 ], "Talk" ],
[[ 17.3 , 20.303 ], "Talk" ],
[[ 21.37 , 27 ], "Talk" ],
[[ 28.5 , 34.6 ], "Talk" ],
[[ 36.6 , 37.6 ], "Talk" ],
[[ 38.3 , 40.0 ], "Talk" ],
]
emote(Story["Paps"], emotion_data, Story["dialogue2"])
if "dialogue2" in Story and not Story["dialogue2"].status:
Story["stage"] = 2
del Story["dialogue2"]
bge.logic.globalDict["print"] = "Get the truck home!"
# Now you are faced with the choice to either get the truck or
# continue doing some stupid stuff.
if Story.get("stage") == 2:
# Mapping the truck on the map
Map.Show(Story["Truck"], color=[0,0,1])
# If you sit in the truck the mission begins.
if dani.get("driving") == Story["Truck"]:
dani["race"] = Story["currentEvent"]
Story["stage"] = 3
Story["timer"] = 500
pointer.visible = True
if Story.get("stage") == 3:
# Mapping the house
Map.Show(house, icon="Map_Circle", color=[1,0.8,0])
# Point to the house
tocheck = pointer.getVectTo(house)
pointer.alignAxisToVect(tocheck[1], 1, 0.1)
pointer.alignAxisToVect( (0,0,1), 2, 1.0 )
# If Truck blows up you loose
if Story["Truck"].get("blown"):
bge.logic.globalDict["print"] = "Mission failed! You broke the truck."
dani["race"] = ""
del Story["stage"]
try:
Reuse.Delete(Story["Paps"])
del Story["Paps"]
except:pass
pointer.visible = False
if "dialogue3" in Story:
Story["dialogue3"].stop()
if "dialogue4" in Story:
Story["dialogue4"].stop()
# Jack telling his side of the story.
if Story["timer"]: Story["timer"] -= 1
else:
if "dialogue3" not in Story and ( not Story["Jack"].get("saying") or not Story["Jack"]["saying"].status ):
Story["dialogue3"] = PlayDialogue("d2")
Story["Jack"]["saying"] = Story["dialogue3"]
# Jack emoting
if "dialogue3" in Story:
emotion_data = [
[[ 4.2 , 4.7 ], "Talk" ],
[[ 10 , 10.5 ], "Laugh" ],
]
emote(dani, emotion_data, Story["dialogue3"])
emotion_data = [
[[ 0.1 , 0.8 ], "Talk" ],
[[ 1.2 , 3.7 ], "Talk" ],
[[ 6.5 , 7.1 ], "Talk" ],
[[ 8.3 , 10.1 ], "Talk" ],
[[ 11.3 , 14.8 ], "Talk" ],
[[ 15.4 , 17.3 ], "Talk" ],
[[ 18.6 , 22.1 ], "Talk" ],
[[ 23.5 , 25.1 ], "Talk" ],
[[ 26.3 , 30.2 ], "Talk" ],
[[ 30.9 , 31.8 ], "Talk" ],
[[ 32.5 , 33.7 ], "Talk" ],
[[ 34.6 , 38.5 ], "Talk" ],
[[ 39.6 , 41.6 ], "Talk" ],
]
emote(Story["Jack"], emotion_data, Story["dialogue3"])
# If Jack told his story and we are close enough to the house
if "dialogue3" in Story and not Story["dialogue3"].status:
# Jack tells changes the mission
if Story["Truck"].getDistanceTo(house) < 450:
if "dialogue4" not in Story and ( not Story["Jack"].get("saying") or not Story["Jack"]["saying"].status ):
Story["dialogue4"] = PlayDialogue("twist")
Story["Jack"]["saying"] = Story["dialogue4"]
# Jack emoting
if "dialogue4" in Story:
emotion_data = [
[[ 3.4 , 3.7 ], "Talk" ],
[[ 9.8 , 10.2 ], "Talk" ],
]
emote(dani, emotion_data, Story["dialogue4"])
emotion_data = [
[[ 0.1 , 0.5 ], "Talk" ],
[[ 1.1 , 1.8 ], "Talk" ],
[[ 2.2 , 3.0 ], "Talk" ],
[[ 4.3 , 5.0 ], "Talk" ],
[[ 5.5 , 7.9 ], "Talk" ],
[[ 8.4 , 9.6 ], "Talk" ],
]
emote(Story["Jack"], emotion_data, Story["dialogue4"])
if "dialogue4" in Story and not Story["dialogue4"].status:
del Story["dialogue3"]
del Story["dialogue4"]
Story["stage"] = 4
# Unlocking the race in the middle of this
Story["start_race"] = True
if Story.get("stage") == 4:
racepos = [-254.4, -508.1, 189.2]
# No need to show the race on the map, since it
# will temporarily unlocked and that will make
# the standard system show it on the map.
# Point to the race
tocheck = pointer.getVectTo(racepos)
pointer.alignAxisToVect(tocheck[1], 1, 0.1)
pointer.alignAxisToVect( (0,0,1), 2, 1.0 )
# If Truck blows up you loose
if Story["Truck"].get("blown"):
bge.logic.globalDict["print"] = "Mission failed! You broke the truck."
dani["race"] = ""
del Story["stage"]
try:
Reuse.Delete(Story["Paps"])
del Story["Paps"]
except:pass
pointer.visible = False
if Story["Truck"].getDistanceTo(racepos) < 70:
bge.logic.globalDict["print"] = "Press D to unload the car."
if not Story["DarkShadow"].get("isCargo"):
Story["stage"] = 5
Character_Controll.getOutCar(Story["Jack"])
pointer.visible = False
# Jack goes into the car that you've brought.
if Story.get("stage") == 5:
if Story["Jack"].get("driving") != Story["DarkShadow"]:
Character_Controll.getIntoCar(Story["Jack"], Story["DarkShadow"], passanger=True)
# else:
# Story["stage"] = 6
Story["02_Bring_Truck_To_House"] = scene
# Mission: Deliver the Truck with Jack to the house.
# Twist : Jack will want you to turn away from the challenge. To end up
# on a race not so far away from the house.
##############################################################################
# Mission: Race not so far away from the house.
# Twist : Paps notices you race, since he and moria are back from her training.
# He is mad because you drove like an idiot and broke the car.
##############################################################################
# Mission : The Mansion Race.
# Challenge: Not to break the car.
##############################################################################
# Mission : One of the drivers from the last race invites you to race
# like an idiot ( Pito's Statue Race ).