Version 08-08-24

This commit is contained in:
Victorious Children Studios 2024-08-27 15:34:26 +03:00
parent 6cb5deb94f
commit db92590087
204 changed files with 15350 additions and 419 deletions

4
LICENSE~ Normal file
View file

@ -0,0 +1,4 @@
Because the game is done in UPBGE which is a fork of Blender it is all together
technically GPLv3-or-later.
This package though, at this point in time is CC-BY-SA.

View file

@ -1,27 +0,0 @@
# Dani's Race
![](https://forg.madiator.cloud/BlenderDumbass/DanisRace/raw/branch/main/SettingUI/banner.jpg)
A Free / Libre Open World Game.
## What is Dani's Race?
![](https://blenderdumbass.codeberg.page/DanisRace/images/racing.jpg)
Dani's Race is an open world game which is aiming to merge the vibes of [GTA clones](https://en.wikipedia.org/wiki/Grand_Theft_Auto_clone) and racing games into one experience. While also remaining [Free / Libre Software](https://www.gnu.org/philosophy/free-sw.html).
## What License is it on?
Dani's Race as a whole is under GPL version 3 or later. For details look at the LICENSE file.
## Links!
[Website](https://blenderdumbass.codeberg.page/DanisRace/)
[Matrix Room](https://matrix.to/#/#danisrace:tchncs.de)
[PeerTube](https://peer.madiator.cloud/w/p/8JuSEJss8umVybr2Jj2ipT)
[Trisquel Forum](https://trisquel.info/en/forum/danis-race-free-software-game-continuing-morias-race-movie)
[Developer Mastodon](https://mastodon.online/@blenderdumbass)

45
SOUNDLICENSES~ Normal file
View file

@ -0,0 +1,45 @@
MADEULOOK_Soundfont - CC-BY - https://musical-artifacts.com/artifacts/2385
Ambience, Night Wildlife, A.wav - CC-BY by InspectorJ (www.jshaw.co.uk) of Freesound.org https://freesound.org/people/InspectorJ/sounds/352514/
Leather Bow Stretch - CC-BY by EminYILDIRIM from Freesound .org https://freesound.org/people/EminYILDIRIM/sounds/536085/
Eurofighter Typhoon Flyby 004 Close Proximity - CC-BY by TimoSchmied https://freesound.org/people/TimoSchmied/sounds/640498/
jet engine start, CRJ 900 - CC-BY by alex36917 https://freesound.org/people/alex36917/sounds/582249/
Jet Engine 1 - CC-BY by InSintesi https://freesound.org/people/InSintesi/sounds/346034/
motor_drill01 - CC-BY by Taira Komori https://freesound.org/people/Taira%20Komori/sounds/212397/
ELECTRIC_MOTOR - CC-BY by jacobsteel https://freesound.org/people/jacobsteel/sounds/336665/
Dental_chair_servo_switch - CC-BY by beerbelly38 https://freesound.org/people/beerbelly38/sounds/160432/
steps_sneakers - CC-BY by neohylanmay https://freesound.org/people/neohylanmay/sounds/333201/
Pipe_Drag_01 - CC-BY by dheming https://freesound.org/people/dheming/sounds/177782/
robot step short medium-heavy - CC-BY by keemocore https://freesound.org/people/keemocore/sounds/148309/
Swoosh_EminYILDIRIM CC-BY by EminYILDIRIM https://freesound.org/people/EminYILDIRIM/sounds/555057/
bunch_of_swooshes CC-BY by berglindsi https://freesound.org/people/berglindsi/sounds/402977/
Horn Honk CC-BY by mkoenig https://freesound.org/people/mkoenig/sounds/81173/
underwater_ambience CC-BY by akemov https://freesound.org/people/akemov/sounds/255597/
Water_Swirl_Small_3 CC-BY by InspectorJ https://freesound.org/people/InspectorJ/sounds/398723/
aprox-5000 CC-BY by lonemonk https://freesound.org/people/lonemonk/sounds/100840/
unfa's-swoosh CC-0 by unfa https://freesound.org/people/unfa/sounds/584188/
tire_puncture CC-BY by WaveAdventurer
https://freesound.org/people/WaveAdventurer/sounds/702718/
Big Explosion CC-BY by Lamoot
https://opengameart.org/content/big-explosion

View file

@ -104,3 +104,75 @@ Speeding up on a race:
Slow down! Listen to me! Dani!
__________________________________
The car is broken.
Jack: Ah... Okay. Em. Let me think. I know. We need to hurry up home and fix this car before Paps comes back with Moria and sees it. You drive the truck, incase he does see us. Oh... God...
Jack goes into the truck. As soon as you are in.
Jack: Pick up the car.
Message: Press D to pick the car back up.
If the car is not in the truck and the truck is not extended:
Jack: No, no, you need to pick up the car.
The mission is now to actually get back home and fix the car in the garage.
As soon as you are at the garage.
Jack: Get the car out here, hurry up.
As soon as the car itself is in the garage ( and not on the truck ):
Jack comes to the Power Wrench.
Jack: Take this Power Wrench, we need to fix the car before Paps gets home. I will look if we have all the parts.
Jack comes to the computer. If some parts are missing from the car, Jack buys them from his pocket.
Jack: Okay, it seems we have everything we need.
Message: Fix the car.
As soon as all the body work is done:
Jack: Okay now, lift the car, we need to tidy it from below.
As soon as you lift the car on the lift...
The door of the garage opens up and Paps comes in, with Moria driving the
Neonspeedster.
Paps: What the hell is going on here?
Jack: Oh god!
Paps: Oh god?
Jack: Eh... Nothing, I was just showing him the wrench and stuff.
Paps: And what's with that car up there?
Jack: Nothing.
Paps: You were racing?
Jack: Eh...
Paps ( to Dani ): He was racing? On that car?
Dani: Yes?
Jack: Wait a second. I wasn't racing.
Paps: You were racing!
Jack: No it was him!
Paps: Dani?
Jack: Yes?
Dani: Oh no...
Paps: He drives better than that. It was you!
Dani laughs.
Paps: Hm... He was racing?
Jack: Yes... Well... It was my idea.
Dani: Oh no indeed.
Paps: Dani? You were racing?
Dani: Noooo....
Paps: Dani? ... Dani?
Dani: Don't Kill me.
Paps: Hm... Well that's disapointing. How am I supposed to live with that you, my son, broke a car in a race? Go sleep. I don't care what time it is. Go to your room and think about things. I will think about what to do with you.
Objective. Go to the room.
As soon as you are in the room. The scene ends.

106
ScriptSnippits.txt~ Normal file
View file

@ -0,0 +1,106 @@
[01_Bring_Neonspeedster_To_Racetrack]
Dani wakes up in the room. Nobody is home. Telephone rings after 10 seconds.
Dani: Yes?
Paps Voice: Dani, I can't believe that I'm telling this. Jack just brought
the truck over without the car. Moria has to start practicing. And there is no
car. Dani. Bring here the Neonspeedster. It should be in the garage. You have
3 minutes. Not a single scratch. You hear me! Not a single scratch.
Message: Bring Neonspeedster to Paps onto the Racetrack.
A directional arrow appears and it points to Neonspeedster in the garage. As
soon as the player takes the car. The arrow will point at the racetrack. There
by the entrance, stands a Blue Truck. Paps, Jack and Moria are next to it.
If the car has less then 100% health:
Paps: I told you not a single scratch, Dani. What do you think should we
do with a broken car?
Message: Assignment Failed.
If the car is fully healthy:
Paps: Excellent! One, day, if you prove yourself, I'll let you drive on the
racetrack, Dani. Now get out.
If Dani gets out:
Message: Assignment Passed.
Moria takes the car and goes onto the racetrack on it.
Game goes to next assignment.
______________________________________________________________________
Dani delivered the car to the racetrack and got out of the car. Moria took the car without talking much and drove it to the racetrack. Paps was left with Dani and Jack alone.
Paps: Jack.
Jack: Yes.
Paps: Go wait in the truck!
Jack goes into the truck. Sitting on the passenger's seat.
Paps: Dani. This is unbelievable. Well, okay... Jack didn't break the truck. But the fact that he came here without Neonspeedster is frankly insane to say the least. I know what we can do.
Dani: Yes?
Paps: You will drive the truck home with him as a passenger. He is supposed to be a professional race driver, but your 11 yr old sister already drives better than him! And now you, will drive him instead of him driving you. Well this is something. That will teach him a lesson.
Dani laughs a bit.
Paps: Dani. Go get the truck back home. Keep Jack inside.
Dani: Okay.
Message: Bring the truck back home.
As soon as you sit into the truck and start going.
Jack: Let me guess... He is trying to punish me by making you drive the truck? Hm... He doesn't know me. It's not punishing. It's amazing! Also he probably told you that I didn't bring a car here. Well he is lying. I brought a car. It's in the truck right now. It's just not a Neonspeedster. And Moria apparently only likes Neonspeedsters. He is not punishing me for that, you know. He is punishing me for crashing on a tower spin. On a tower spin of all places! Who will not crash there? Even Moria barely made it through. Hell Tali Shtern crashed that day on the Tower Spin. And he is still punishing me for this.
As the truck is getting close to the house.
Jack: Wait, wait. Let's not go home. Wanna race?
Dani: Yes.
Jack: Let's go this way. There is a race coming up and we have a spare race car with us. Hell I'll let you race.
Dani: Okay!
Message: Drive the truck to the race.
The previous assignment is aborted and now they are driving to a race beside a huge building. There are a few cars already waiting and ready to race.
As soon as you get there:
Jack: Press here to unload the car.
Message: Press D to unload the car.
This is needed for later, when people could change their keybindings.
As soon as Dani is in the car, a circle appears into which you can drive.
Message: Press R to start the race.
The race starts. The race is very messy and with a lot of off-road-ing and breaking through stuff. A part of it goes through the place where Dani lives.
_____________________________________
Jack's Reactions to Dani's Driving.
Hitting cars:
Dani, your will break the car!
Dani, the car will break, dani!
We are, wrecking the car!
Paps will be pissed!
Dani, what are you doing man!
"Oh God!":
Dani, can you please concentrate, please!
You almost killed us, dani!
Ooooaaahhh!
Speeding up on a race:
Triple caution!!!
Dani! Double caution!!! Triple caution!!!
Concentrate, Dani, Please!
Concentrate!
You are going too fast!
We will miss the turn!
Slow down! Listen to me! Dani!

View file

@ -69,9 +69,7 @@ def DaniUpdate():
keys = bge.logic.globalDict.get("keys", [])
if not dani["driving"]:
# Jump animation logic
@ -137,13 +135,17 @@ def DaniUpdate():
# Standing still animation
if not keys and not dani["walkingtowardcar"]:
ApplyAnimation(dani, "Stand")
if not dani.get("underwater"):
ApplyAnimation(dani, "Stand")
else:
ApplyAnimation(dani, "SwimIdle")
StopWalkSound(dani)
#AutoStand(dani)
# If getting car
if controls["getcar"] in keys:
if controls["getcar"] in keys and not dani.get("getcartimer"):
getIntoCar(dani)
dani["getcartimer"] = 10
elif dani["walkingtowardcar"]:
walkTowardCar(dani)
@ -156,11 +158,16 @@ def DaniUpdate():
ApplyAnimation(dani, "Drive")
# If getting out of car
if controls["getcar"] in keys:
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()
@ -168,6 +175,8 @@ def DaniUpdate():
# Reverting swimming
dani["swimming_down"] = False
dani["jumping"] = False
if dani.get("jump-timer"): dani["jump-timer"] -= 1
def OnGround(character):
@ -195,8 +204,8 @@ def OnGround(character):
def WalkForward(character):
toFPS = Opt.ToFPS()
character.applyMovement([0,-0.05*toFPS,0], True)
character.applyMovement([0,-0.02,0], True)
character.localLinearVelocity.y = -5
# Facing correctly
rig = getRig(character)
@ -214,9 +223,8 @@ def WalkForward(character):
def WalkBackward(character):
toFPS = Opt.ToFPS()
character.applyMovement([0,0.05*toFPS,0], True)
character.applyMovement([0,0.02,0], True)
character.localLinearVelocity.y = 5
# Facing correctly
rig = getRig(character)
rot = rig.localOrientation.to_euler()
@ -234,8 +242,8 @@ def WalkBackward(character):
def WalkLeft(character):
toFPS = Opt.ToFPS()
character.applyMovement([0.05*toFPS,0,0], True)
character.applyMovement([0.02,0,0], True)
character.localLinearVelocity.x = 5
# Facing correctly
if not character.get("grab"):
@ -257,8 +265,9 @@ def WalkLeft(character):
def WalkRight(character):
toFPS = Opt.ToFPS()
character.applyMovement([-0.05*toFPS,0,0], True)
character.applyMovement([-0.02,0,0], True)
character.localLinearVelocity.x = -5
# Facing correctly
if not character.get("grab"):
@ -278,11 +287,28 @@ def WalkRight(character):
def Jump(character):
toFPS = Opt.ToFPS()
character.applyMovement([0, 0, 0.07*toFPS], False)
#if not OnGround(character) and not character.get("grab")\
# and not character.get("underwater"):
# return
character["jumping"] = True
if ( character.localLinearVelocity.z > 0.1 \
or character.localLinearVelocity.z < -0.1 )\
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"]
@ -291,7 +317,7 @@ def Jump(character):
if OnGround(character) and ( not sound["play"] or not sound["play"].status ) :
sound["play"] = device.play(sound["sound"])
def GoDown(character):
toFPS = Opt.ToFPS()
@ -306,26 +332,30 @@ def WaterBoyancy(character):
scene = bge.logic.getCurrentScene()
if character["underwater"] and character.position[2] < -10.5 and not character["driving"]:
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:
character.worldLinearVelocity.z = 0.5
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
#scene.objects["DanisRig"]["underwater"] = True
elif character.position[2] > -9.5:
character["underwater"] = False
scene.objects["DanisRig"]["underwater"] = False
#scene.objects["DanisRig"]["underwater"] = False
def getIntoCar(character, car=None, passanger=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:
if character.get("driving") or character.get("walkingtowardcar"):# or character.get("last_change",0) > time.time()-1:
return
@ -333,11 +363,14 @@ def getIntoCar(character, car=None, passanger=False):
# 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 avoidblown and trycar.get("blown"):
continue
if distance < closest:
car = trycar
closest = distance
@ -360,6 +393,9 @@ def getIntoCar(character, car=None, passanger=False):
else:
character["walkingtowardcartarget"] = other_stand_target
character["becomepassanger"] = passanger
if immediately:
walkTowardCar(character, immediately=True)
# Readjust the camera
@ -369,10 +405,15 @@ def getIntoCar(character, car=None, passanger=False):
# ChangeCameraTarget(car.children["CarCamTarget"], 100, [zoom,zoom,zoom])
pass
def walkToward(character, point):
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
@ -381,29 +422,50 @@ def walkToward(character, point):
fro = character.position.copy()
fro.z += 1
ray = Vehicle.BeautyRayCast(character, "walk",
point,
fro)
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:
obstacleVector = character.getVectTo(ray[1])
distance = math.dist(ray[1], fro)
if distance < 5:
# 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]
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)
@ -589,7 +651,7 @@ def ExecuteChangeCameraTarget():
if bge.logic.globalDict["CameraTargetChange"]["targetscale"]:
cam_parent.scaling = ( cam_parent["startingScaling"] + ( target_scale - cam_parent["startingScaling"] ) * camFactor )
def walkTowardCar(character):
def walkTowardCar(character, immediately=False):
# This function is running while the character is getting into car
@ -613,7 +675,20 @@ def walkTowardCar(character):
# Change to sitting inside of the car
elif walkVector[0] < 1 and character["walkingtowardcartarget"] == finaltarget:
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
@ -622,16 +697,26 @@ def walkTowardCar(character):
character["driving"] = car
if not passanger:
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)
car["npc"] = ""
car["enemy"] = ""
car["shake"] = 0.0
rig = getRig(character)
rig["driving"] = True
@ -640,17 +725,16 @@ def walkTowardCar(character):
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.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)
@ -693,15 +777,7 @@ def walkTowardCar(character):
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
@ -709,10 +785,10 @@ def getOutCar(character):
scene = bge.logic.getCurrentScene()
# If character is not in the car
if character["walkingtowardcar"]:
if character.get("walkingtowardcar"):
car = character["walkingtowardcar"]
soundDo = False
elif character["driving"]:
elif character.get("driving"):
car = character["driving"]
soundDo = True
else:
@ -743,22 +819,23 @@ def getOutCar(character):
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"):
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)
# 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":
@ -805,7 +882,21 @@ def getRig(character):
scene = bge.logic.getCurrentScene()
if type(character.get("rig", "")) == str and character.get("rig", ""):
rig = scene.objects[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")
@ -838,7 +929,11 @@ def ApplyAnimation(character, animation, keep=False, **kwargs):
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:
@ -926,12 +1021,12 @@ def GrabEdge(character):
character["grab"] = character.position.z
# Ratate character to face the point.
vect = character.getVectTo(chestray[2])
# 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])
#vect = rig.getVectTo(chestray[2])
rig.alignAxisToVect(chestray[2], 1, 1)
rig.alignAxisToVect((0,0,1), 2, 1)
@ -941,8 +1036,75 @@ def GrabEdge(character):
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):
@ -960,27 +1122,45 @@ def StopWalkSound(character):
##### STORY RELATED FUNCTIONS ####
def StoryCharacter(character):
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)
walkTowardCar(character)
if not character.get("driving"):
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

File diff suppressed because it is too large Load diff

183
Scripts/Cinema.py~ Normal file
View file

@ -0,0 +1,183 @@
# This script will make the cinema work.
import bge
import aud
scene = bge.logic.getCurrentScene()
cont = bge.logic.getCurrentController()
obj = cont.owner
inCinema = scene.objects["CinemaColider"]["InCinema"]
def cTprint(t):
cText = scene.objects["CinemaText"]
if cText["Text"] != t:
cText["Text"] = t
print(t)
black = scene.objects["CinemaScreen.Black"]
# Play the movie
if obj.get("Movie"):
cTprint("")
if not obj.get("Video"):
movieTexture = bge.texture.VideoFFmpeg(obj.get("Movie"))
print(dir(movieTexture))
texture = bge.texture.Texture(obj, 0, 0)
texture.source = movieTexture
texture.source.play()
texture.refresh(False)
width, height = movieTexture.size
obj.scaling[1] = obj.scaling[1] / height * 1080
device = aud.Device()
sound = aud.Sound(obj.get("Movie"))
obj["Sound"] = device.play(sound)
obj["Video"] = texture
obj["Time"] = bge.logic.getRealTime()
obj["StartTime"] = bge.logic.getRealTime()
obj["soundref"] = 100
black.visible = False
elif inCinema:
if obj.get("iTimer", 0):
obj["iTimer"] = obj.get("iTimer", 1) -1
# Move the audio forward
if 87 in bge.logic.globalDict["keys"] and not obj.get("iTimer", 0):
obj["AudOffset"] = obj.get("AudOffset", 0) + 0.25
obj["iTimer"] = 10
elif 85 in bge.logic.globalDict["keys"] and not obj.get("iTimer", 0):
obj["AudOffset"] = obj.get("AudOffset", 0) - 0.25
obj["iTimer"] = 10
if bge.logic.getRealTime() - obj["Time"] > (1/30):
obj["Video"].source.refresh()#obj["Sound"].position)
obj["Video"].refresh(False)
obj["Time"] = bge.logic.getRealTime()
#print(obj["Video"].source.framerate)
#print("Video Refreshed at:", obj["Time"], obj["Sound"].position)
if not obj["soundref"]:
try:
obj["Sound"].position = bge.logic.getRealTime()-obj["StartTime"]+obj.get("AudOffset", 0)
except:
obj["Movie"] = None
obj["Video"] = None
black.visible = True
obj.scaling[1] = 1
obj["cTfolder"] = obj["cTfolder"][:obj["cTfolder"].rfind("/")]
obj["cTfolder"] = obj["cTfolder"][:obj["cTfolder"].rfind("/")] + "/"
obj["soundref"] = 100
else:
obj["soundref"] -= 1
else:
obj["Sound"].stop()
obj["Video"].source.stop()
obj["Movie"] = None
obj["Video"] = None
obj.scaling[1] = 1
black.visible = True
obj["cTfolder"] = obj["cTfolder"][:obj["cTfolder"].rfind("/")]
obj["cTfolder"] = obj["cTfolder"][:obj["cTfolder"].rfind("/")] + "/"
# FILE MANAGER ( I know I'm crazy )
elif inCinema:
import os
obj["cTfolder"] = obj.get("cTfolder", "/")
obj["cTselect"] = obj.get("cTselect", 0)
# Files and folders
formats = [".mp4", ".ogg", ".ogv", ".avi"]
try:
listdir = []
for i in os.listdir(obj["cTfolder"]):
for format in formats:
if not os.path.isfile(obj["cTfolder"]+i) or i.endswith(format):
listdir.append(i)
break
listdir = list(sorted(listdir))
except:
listdir = []
obj["Movie"] = obj["cTfolder"][:-1]
if not listdir:
obj["cTfolder"] = obj["cTfolder"][:obj["cTfolder"].rfind("/")]
obj["cTfolder"] = obj["cTfolder"][:obj["cTfolder"].rfind("/")] + "/"
if obj.get("iTimer", 0):
obj["iTimer"] = obj.get("iTimer", 1) -1
# Up and down
if 72 in bge.logic.globalDict["keys"] and not obj.get("iTimer", 0):
obj["cTselect"] = ( obj["cTselect"] -1 ) % len(listdir)
obj["iTimer"] = 10
bge.logic.globalDict["SoundDevice"].play(bge.logic.globalDict["sounds"]["checkpoint"]["sound"]) # Play a Ding
elif 70 in bge.logic.globalDict["keys"] and not obj.get("iTimer", 0):
obj["cTselect"] = ( obj["cTselect"] +1 ) % len(listdir)
obj["iTimer"] = 10
bge.logic.globalDict["SoundDevice"].play(bge.logic.globalDict["sounds"]["checkpoint"]["sound"]) # Play a Ding
elif 7 in bge.logic.globalDict["keys"] and not obj.get("iTimer", 0):
obj["cTfolder"] = obj["cTfolder"] + listdir[obj["cTselect"]] + "/"
obj["cTselect"] = 0
obj["iTimer"] = 10
bge.logic.globalDict["SoundDevice"].play(bge.logic.globalDict["sounds"]["checkpoint"]["sound"]) # Play a Ding
elif 59 in bge.logic.globalDict["keys"] and not obj.get("iTimer", 0):
obj["cTfolder"] = obj["cTfolder"][:obj["cTfolder"].rfind("/")]
obj["cTfolder"] = obj["cTfolder"][:obj["cTfolder"].rfind("/")] + "/"
obj["cTselect"] = 0
obj["iTimer"] = 10
bge.logic.globalDict["SoundDevice"].play(bge.logic.globalDict["sounds"]["checkpoint"]["sound"]) # Play a Ding
# Drawing
t = "[ "+obj["cTfolder"]+" ]\n\n"
for n, f in enumerate(listdir[max(0,obj["cTselect"]-5):max(0,obj["cTselect"]-5)+10]):
if listdir[obj["cTselect"]] == f:
t = t + " [ "
else:
t = t + " "
t = t+f
if listdir[obj["cTselect"]] == f:
t = t + " ] "
else:
t = t + " "
t = t + "\n"
cTprint(t)

156
Scripts/Common.py~ Normal file
View file

@ -0,0 +1,156 @@
import random
# Common things needed for various things
# Colors are used to make the
clr = {
"norm":"\033[00m", # Reset to normal
"bold":"\033[01m", # Bold Text
"ital":"\033[03m", # Italic Text
"undr":"\033[04m", # Underlined
"blnk":"\033[05m", # Blinking
# Text
"tdbl":"\033[30m", # Dark Black
"tdrd":"\033[31m", # Dark Red
"tdgr":"\033[32m", # Dark Green
"tdyl":"\033[33m", # Dark Yellow
"tdbu":"\033[34m", # Dark Blue
"tdma":"\033[35m", # Dark Magenta
"tdcy":"\033[36m", # Dark Cyan
"tdwh":"\033[37m", # Dark White
"tbbl":"\033[90m", # Bright Black
"tbrd":"\033[91m", # Bright Red
"tbgr":"\033[92m", # Bright Green
"tbyl":"\033[93m", # Bright Yellow
"tbbu":"\033[94m", # Bright Blue
"tbma":"\033[95m", # Bright Magenta
"tbcy":"\033[96m", # Bright Cyan
"tbwh":"\033[97m", # Bright White
# Background
"bdbl":"\033[40m", # Dark Black
"bdrd":"\033[41m", # Dark Red
"bdgr":"\033[42m", # Dark Green
"bdyl":"\033[43m", # Dark Yellow
"bdbu":"\033[44m", # Dark Blue
"bdma":"\033[45m", # Dark Magenta
"bdcy":"\033[46m", # Dark Cyan
"bdwh":"\033[47m", # Dark White
"bbbl":"\033[100m", # Bright Black
"bbrd":"\033[101m", # Bright Red
"bbgr":"\033[102m", # Bright Green
"bbyl":"\033[103m", # Bright Yellow
"bbbu":"\033[104m", # Bright Blue
"bbma":"\033[105m", # Bright Magenta
"bbcy":"\033[106m", # Bright Cyan
"bbwh":"\033[108m" # Bright White
}
keycodes = {
"A":23,
"B":24,
"C":25,
"D":26,
"E":27,
"F":28,
"G":29,
"H":30,
"I":31,
"J":32,
"K":33,
"L":34,
"M":35,
"N":36,
"O":37,
"P":38,
"Q":39,
"R":40,
"S":41,
"T":42,
"U":43,
"V":44,
"W":45,
"X":46,
"Y":47,
"Z":48,
"0":13,
"1":14,
"2":15,
"3":16,
"4":17,
"5":18,
"6":19,
"7":20,
"8":21,
"9":22,
"F1" :88,
"F2" :89,
"F3" :90,
"F4" :91,
"F5" :92,
"F6" :93,
"F7" :94,
"F8" :95,
"F9" :96,
"F10":97,
"F11":98,
"F12":99,
"LShift" :55,
"RShift" :54,
"LCtrl" :50,
"RCtrl" :53,
"LAlt" :51,
"RAlt" :52,
"Tab" :57,
"Space" :8,
"Enter" :7,
"BackSpace" :59,
"Delete" :60,
"Home" :110,
"End" :109,
"PageUp" :111,
"PageDown" :112,
"UpArrow" :72,
"DownArrow" :70,
"RightArrow":71,
"LeftArrow" :69
}
mousecodes = {
"RMB" : 118,
"MMB" : 117,
"LMB" : 116
}
IDColors = {}
def consoleForm(obj):
# Function that prints a pretty object info about
ID = hex(id(obj))[2:].upper()
NAME = str(obj)
# Coloring
if ID not in IDColors:
r = random.random()
g = random.random()
b = random.random()
ct = clr["tdbl"]
if (r + g + b )/3 < 0.5:
ct = clr["tbwh"]
c = "\033[48;2;"+str(int(r*256))+";"+str(int(g*256))+";"+str(int(b*256))+"m"+ct
IDColors[ID] = c
c = IDColors[ID]
return clr["bold"] + c + " " + ID + " " + NAME + " " + clr["norm"]

View file

@ -86,7 +86,7 @@ def particles(object, # Particle object
# Adding the velocity
particle.actuators["Motion"].dLoc += mathutils.Vector(velocity)
def Smoke(point, strength=0.5):
def Smoke(point, strength=0.5, size=1.0):
# Not do the effect if not in view
if cam.getDistanceTo(point) > 100 or not cam.pointInsideFrustum(point) == cam.INSIDE:
@ -97,8 +97,19 @@ def Smoke(point, strength=0.5):
# Performance kill switch
def do(point):
smokeParticle = Reuse.Create("Smoke", random.randint(30, 60))
smokeParticle.position = point
#smokeParticle = Reuse.Create("Smoke", random.randint(30, 60))
#smokeParticle.scaling = [size, size, size]
#smokeParticle.position = point
# Adding some sparks to the fire
particles("SmokeBurst", point,
despawn = 10,
amount = random.randint(0, 3),
max = 50,
spread = 0.5,
normal = 0.01,
velocity = [0,0,0.1],
scale=random.uniform(0.2,1.0))
if Opt.GoodFPS("Smoke", strength):
do(point)

683
Scripts/Destruction.py~ Normal file
View file

@ -0,0 +1,683 @@
# This is full of destruction stuff
import bge
import aud
import random
import numpy
import math
import mathutils
import types
from Scripts import Reuse
from Scripts import Opt
from Scripts import Multiplayer_Shared
from Scripts.Common import *
scene = bge.logic.getCurrentScene()
cam = scene.active_camera
if "Destruction" not in bge.logic.globalDict:
bge.logic.globalDict["Destruction"] = {}
database = bge.logic.globalDict["Destruction"]
# Particle system
def particles(object, # Particle object
point, # Point where to spawn them
despawn, # Time ( in frames before disappearing )
amount=5, # Amount of them to spawn
max=50, # Max amount of them in the scene
spread=0, # Spread of particles on start
normal=0.05, # Spread of particles over time
velocity=[0,0,0], # Velocity of particles
scale = 1 # Scale of the particle object
):
# Performance kill switch
if not Opt.GoodFPS("particles", 0.5):
return
# Not do the effect if not in view
if cam.getDistanceTo(point) > 100 or not cam.pointInsideFrustum(point) == cam.INSIDE:
return
# We will need a place to register particles
if "particles-registry" not in bge.logic.globalDict:
bge.logic.globalDict["particles-registry"] = {}
registry = bge.logic.globalDict["particles-registry"]
# Making sure that registry contains particle type
if object not in registry:
registry[object] = []
for i in range(amount):
# If we reached max, we abort
inscene = len( registry[object] )
inreuse = len( Reuse.reuse.get(object, []) )
spawned = inscene - inreuse
if spawned > max:
return
# Making particle
particle = Reuse.Create(object, despawn)
particle.scaling = [scale, scale, scale]
# Recording into registry
if particle not in registry[object]:
registry[object].append(particle)
# Puting it into position ( adding the spread )
particle.position = point + mathutils.Vector([random.uniform(-spread, spread),
random.uniform(-spread, spread),
random.uniform(-spread, spread)])
# The next part will require an actuator
# Introducting random spread over time
particle.actuators["Motion"].dLoc = mathutils.Vector([random.uniform(-normal, normal),
random.uniform(-normal, normal),
random.uniform(-normal, normal)])
# Adding the velocity
particle.actuators["Motion"].dLoc += mathutils.Vector(velocity)
def Smoke(point, strength=0.5):
# Not do the effect if not in view
if cam.getDistanceTo(point) > 100 or not cam.pointInsideFrustum(point) == cam.INSIDE:
return
if numpy.random.choice([True, False], p=[strength, 1-strength]):
# Performance kill switch
def do(point):
smokeParticle = Reuse.Create("Smoke", random.randint(30, 60))
smokeParticle.position = point
if Opt.GoodFPS("Smoke", strength):
do(point)
def Dust(point, strength=0.5):
# Not do the effect if not in view
if cam.getDistanceTo(point) > 100 or not cam.pointInsideFrustum(point) == cam.INSIDE:
return
if numpy.random.choice([True, False], p=[strength, 1-strength]):
# Performance kill switch
def do(point):
smokeParticle = Reuse.Create("Dust", random.randint(30, 60))
smokeParticle.position = point
if Opt.GoodFPS("Dust", 0.85):
do(point)
else:
pass
def FireElementTextureLogic(obj):
if type(obj) == bge.types.SCA_PythonController:
obj = obj.owner
vect = obj.getVectTo(cam)
obj.alignAxisToVect((0,0,1), 2, 1)
obj.alignAxisToVect(vect[1], 1, 1)
obj.blenderObject["fire"] -= 0.1
try: v = obj.parent.worldLinearVelocity.copy()
except:
try: v = obj.parent.parent.worldLinearVelocity.copy()
except:return
v = -v + mathutils.Vector((0,0,30))
obj.alignAxisToVect(v, 2, 1)
def AttatchFireBall(point, attachment=None, size=1, duration=0):
# This function will attach a fireball to a point.
# Making the FireBall
FireBall = Reuse.Create("FireBall", duration)
# Attatching the Fireball
FireBall.position = point.copy()
FireBall.scaling = [size, size, size]
if attachment:
FireBall.setParent(attachment, True)
# Attatching a light to it.
if not duration:
if "Light" not in FireBall:
light = Reuse.Create("FireLamp")
light.position = FireBall.position
light.setParent(FireBall)
FireBall["Light"] = light
light = FireBall["Light"]
light.blenderObject.data.use_shadow = False
# In case the fireball is farther than 50 meters
# from the camera, we execute this ones.
FireElementTextureLogic(FireBall)
# Storring it and returning
#ID = Multiplayer_Shared.RandomString()
#database[ID] = FireBall
#FireBall["ID"] = ID
return FireBall
def DeleteFireBall(FireBall):
# To save space we gonna do that.
if "Light" in FireBall:
light = FireBall["Light"]
light.removeParent()
Reuse.Delete(light)
Reuse.Delete(FireBall)
FireBall.removeParent()
def FireBurst(point, size):
# This will make a short burst of fire.
FireBurst = Reuse.Create("FireBurst", 10)
FireBurst.position = point.copy()
FireBurst.scaling = [size, size, size]
FireBurst.blenderObject["fire"] = 1
def SpreadOnGround(object, point, size, spread, amount, duration=0, randomDuration=True):
# This works similarly to particles, but
# instead puts the objects onto the ground.
for i in range(amount):
if randomDuration:
d = random.uniform( duration / 2 , duration )
else: d = duration
obj = Reuse.Create(object, d)
obj.position = mathutils.Vector(point) + mathutils.Vector([random.uniform(-spread, spread),
random.uniform(-spread, spread),
random.uniform(-spread, spread)])
obj.scaling = [size, size, size]
# Puttin the object on the flor
obj.position.z += spread + 1
topos = obj.position.copy()
topos.z -= 200
ray = obj.rayCast(topos)
if ray[1]: obj.position = ray[1]
def Fire(point, strength=0.5):
# Not do the effect if not in view
if cam.getDistanceTo(point) > 100 or not cam.pointInsideFrustum(point) == cam.INSIDE:
return
if numpy.random.choice([True, False], p=[strength, 1-strength]):
# Performance kill switch
def do(point):
#fireParticle = Reuse.Create("Fire", random.randint(30, 60))
#fireParticle.position = point
#FireBurst(point, 0.5)
# Adding some sparks to the fire
particles("FireBurst", point,
despawn = 10,
amount = random.randint(0, 3),
max = 50,
spread = 0.5,
normal = 0.01,
velocity = [0,0,0.1],
scale=random.uniform(0.2,1.0))
if Opt.GoodFPS("Fire", strength):
do(point)
def WaterSplash(point, strength=0.5, rot=0, force=1):
if numpy.random.choice([True, False], p=[strength, 1-strength]):
waterSplash = Reuse.Create("WaterSplashCar", random.randint(10, 20))
waterSplash.position = point
waterSplash.orientation = [0,0,rot]
waterSplash.scaling = [
random.uniform(0.6, 1.4),
random.uniform(0.6, 1.4),
random.uniform(0.6*force, 1.4*force)
]
# Sound
device = bge.logic.globalDict["SoundDevice"]
s = "//sfx/splash.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"].location = point
sound["play"].relative = False
sound["play"].distance_maximum = 100
sound["play"].distance_reference = 1
sound["play"].attenuation = 1
sound["play"].pitch = random.uniform(0.6, 1.4)
sound["play"].volume = 5 * min(2, force)
def Explosion(point, visible=True, size=3, mass=10, effectcars=True):
# Shockwave
# Shockwave will be done using math applied to every object within
# a certain size to the explosion.
dani = scene.objects["Dani_Box"]
if dani.get("driving"):
dani["driving"]["shake"] = mass * 10 / dani.getDistanceTo(point)
for object in scene.objects:
# Getting distance to the object
distance = object.getDistanceTo(point)
# Skipping every object outside of the size of the explosion
if distance > size:
continue
# Calculating forces on the object ( father away less forces ).
force = ( 1 - distance / size ) * mass * object.mass
# Calculating direction of the force
vector = object.getVectTo(point)[1] * -force
# Applying force
try:
object.applyImpulse(point, vector)
# If it is a car we can apply damage to it, by sending it a fake
# impulse of collision.
# But first we need to make sure to have the data for this
# operation
Apoint = types.SimpleNamespace()
Apoint.worldPoint = mathutils.Vector(point)
Apoint.appliedImpulse = force * 10
points = [Apoint]
# Then we send it over
for callback in object.collisionCallbacks:
callback(None, point, None, points)
except:
pass
# Then we also have objects that use this very module to be
# destructable. The all have a collision actuator listening
# to a collision with a property "explosion" to execute their
# function.
if "spawned_by" in object:
for controller in object.controllers:
# This is a bit hacky, but it works.
try:
if "Destruction" in controller.script:
exec(controller.script.replace("Scripts.Destruction.", "")+"(controller)")
except: pass
# And also we want to unsuspend it's physics.
object.restoreDynamics()
# Fire particles
if visible:
# particles("Fire", point,
# despawn = random.randint(int(size/2), int(size)),
# amount = random.randint(int(size/2), int(size)),
# max = 200,
# spread = 0,
# normal = 0.2,
# velocity = [0,0,0.01],
# scale = 2)
FireBurst(point, size/2)
particles("Sparkle", point,
despawn = random.randint(0, 100),
amount = random.randint(10, 50),
max = 100,
spread = size/2,
normal = 0.5,
velocity = [0,0,0.01])
Smoke(point, 1)
#AttatchFireBall(point,
# size = 0.5,
# duration = 200)
SpreadOnGround("FireBall",
point,
0.5,
size/2,
10,
500)
# Sound
device = bge.logic.globalDict["SoundDevice"]
s = "//sfx/boom.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"].location = point
sound["play"].relative = False
sound["play"].distance_maximum = 100
sound["play"].distance_reference = 1
sound["play"].attenuation = 1
sound["play"].pitch = random.uniform(0.6, 1.4)
sound["play"].volume = 20
def DeclareBroken(cont):
#cont = bge.logic.getCurrentController()
scene = bge.logic.getCurrentScene()
part = cont.owner
part["spawned_by"]["broken"] = True
def WoodGate_level0(cont):
#cont = bge.logic.getCurrentController()
scene = bge.logic.getCurrentScene()
part = cont.owner
part["spawned_by"]["broken"] = True
colision = cont.sensors["Collision"]
car = colision.hitObject
def do(cont, car, scene, part):
# Optimization trick
if len(Reuse.reuse.get("GatePart.Level0", [])) >= 4:
# Spawning madness
for i in range(4):
chunk = Reuse.Create("GatePart.Level0", 10, selfDestructInactive=True)
Reuse.SelfDestruct(chunk, 500)
chunk.mass = 0
chunk.position = part.position
chunk.orientation = part.orientation
chunk.applyMovement( [ 0, i*1.24-2.45, 0 ] , True)
if car:
cv = car.getLinearVelocity()
chunk.setLinearVelocity( cv / 2)
# Sound
device = bge.logic.globalDict["SoundDevice"]
s = "//sfx/wood.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"].location = chunk.position
sound["play"].velocity = chunk.getLinearVelocity()
sound["play"].relative = False
sound["play"].distance_maximum = 100
sound["play"].distance_reference = 1
sound["play"].attenuation = 1
sound["play"].pitch = random.uniform(0.6, 1.4)
sound["play"].volume = 5
# Deleting the wooden gate
Reuse.Delete(part)
if Opt.GoodFPS("WoodGate_level0", 0.8) or (car and car.get("active")):
do(cont, car, scene, part)
else:
Opt.ScheduleTask("WoodGate_level0 ["+str(id(part))+"]", 0.8, do,
cont, car, scene, part)
def WoodGate_level1(cont):
# Performance kill switch
if not Opt.GoodFPS("WoodGate_level1", 0.7):
return
#cont = bge.logic.getCurrentController()
scene = bge.logic.getCurrentScene()
part = cont.owner
# Optimization trick
if len(Reuse.reuse.get("GatePart.Level1", [])) >= 4:
# Spawning madness
chunks = []
for i in range(4):
chunk = Reuse.Create("GatePart.Level1", 10, selfDestructInactive=True)
Reuse.SelfDestruct(chunk, 100)
chunk.mass = 0
chunk.position = part.position
chunk.orientation = part.orientation
chunks.append(chunk)
chunks[0].applyMovement( [ 0, 0, 0.75 ] , True)
chunks[0].applyRotation( [ math.pi/2, 0, 0 ] , True)
chunks[1].applyMovement( [ 0, -0.75, 0 ] , True)
chunks[2].applyMovement( [ 0.1, 0, 0 ] , True)
chunks[2].applyRotation( [ math.pi/4, 0, 0 ] , True)
chunks[3].applyRotation( [ -( math.pi/4 ), 0, 0, ] , True)
# Deleting the wooden part
Reuse.Delete(part)
def LightStand(cont):
#cont = bge.logic.getCurrentController()
scene = bge.logic.getCurrentScene()
part = cont.owner
colision = cont.sensors["Collision"]
car = colision.hitObject
def do(cont, car, scene, part):
part["spawned_by"]["broken"] = True
head = None
tail = None
if Reuse.reuse.get("LightStand.Borked.Head"):
# Head ( top part )
head = Reuse.Create("LightStand.Borked.Head", 300, selfDestructInactive=True)
Reuse.SelfDestruct(head, 600)
head.position = part.position
head.orientation = part.orientation
if Reuse.reuse.get("LightStand.Borked.Tail"):
# Tail ( or leg )
tail = Reuse.Create("LightStand.Borked.Tail", 300, selfDestructInactive=True)
Reuse.SelfDestruct(tail, 600)
tail.position = part.position
tail.orientation = part.orientation
tail.applyMovement( [ 0, 0, -1.3 ] , True)
tail.localAngularVelocity = [random.uniform(-1,1),random.uniform(-1,1),random.uniform(-1,1)]
if car:
cv = car.getLinearVelocity()
if head: head.setLinearVelocity( cv )
if tail: tail.setLinearVelocity( cv )
# Deleting the light stand
Reuse.Delete(part)
if head:
# Sound
device = bge.logic.globalDict["SoundDevice"]
s = "//sfx/hit.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"].location = head.position
sound["play"].velocity = head.getLinearVelocity()
sound["play"].relative = False
sound["play"].distance_maximum = 100
sound["play"].distance_reference = 1
sound["play"].attenuation = 1
sound["play"].pitch = random.uniform(0.6, 1.4)
sound["play"].volume = 5
if Opt.GoodFPS("LightStand", 0.9) or (car and car.get("active")):
do(cont, car, scene, part)
else:
Opt.ScheduleTask("LightStand ["+str(id(part))+"]", 0.8, do,
cont, car, scene, part)
def HouseShelf(cont):
# Performance kill switch
if not Opt.GoodFPS("HouseShelf", 0.5):
return
#cont = bge.logic.getCurrentController()
scene = bge.logic.getCurrentScene()
part = cont.owner
part["spawned_by"]["broken"] = True
# -753 -940 412
despawn = 200
# Shelfs
for i in range(5):
shelf = Reuse.Create("Shelf", despawn)
shelf.position = part.position
shelf.orientation = part.orientation
shelf.applyMovement([0.09,0,(0.3*i)-0.65], True)
# Legs
leg = Reuse.Create("Shelf_Leg1", despawn)
leg.position = part.position
leg.orientation = part.orientation
leg.applyMovement([1.3,0,0], True)
leg = Reuse.Create("Shelf_Leg2", despawn)
leg.position = part.position
leg.orientation = part.orientation
leg.applyMovement([-1.1,0,0], True)
# Lego bricks
brick = Reuse.Create("LegoBrick", despawn)
brick.position = part.position
brick.orientation = part.orientation
brick.applyMovement([0.3,0,0.31], True)
brick.applyRotation([0,0,-(math.pi/4)], True)
brick = Reuse.Create("LegoBrick", despawn)
brick.position = part.position
brick.orientation = part.orientation
brick.applyMovement([-0.2,0,0], True)
brick.applyRotation([0,0,-(math.pi/4)], True)
# Toy Boxes
box = Reuse.Create("Toy_Box", despawn)
box.position = part.position
box.orientation = part.orientation
box.applyMovement([-0.6,0,0], True)
box = Reuse.Create("Toy_Box", despawn)
box.position = part.position
box.orientation = part.orientation
box.applyMovement([0.3,0,0.7], True)
box = Reuse.Create("Toy_Box", despawn)
box.position = part.position
box.orientation = part.orientation
box.applyMovement([0.3,0,-0.7], True)
# Deleting the light stand
Reuse.Delete(part)
# Sound
device = bge.logic.globalDict["SoundDevice"]
s = "//sfx/wood.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"].location = box.position
sound["play"].velocity = box.getLinearVelocity()
sound["play"].relative = False
sound["play"].distance_maximum = 100
sound["play"].distance_reference = 1
sound["play"].attenuation = 1
sound["play"].pitch = random.uniform(0.6, 1.4)
sound["play"].volume = 5

3
Scripts/Garage.py~ Normal file
View file

@ -0,0 +1,3 @@
# GPLv3-or-later
# (C) J.Y.Amihud ( blenderdumbass )

View file

@ -24,6 +24,8 @@ 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 Character_Controll
@ -149,7 +151,12 @@ def main():
onTarget = []
for n, axis in enumerate(["X", "Y", "Z"]):
axislist = ["X", "Y", "Z"]
for axis in axislist:
n = ["X", "Y", "Z"].index(axis)
targetRot = door[openClose+"Rot"+axis]
targetLoc = door[openClose+"Loc"+axis]
@ -168,6 +175,7 @@ def main():
door["door"].orientation = dRot
if not onLocTraget:
door["door"].position[n] += (targetLoc - door["door"].position[n])/15
@ -175,6 +183,7 @@ def main():
else:
door["door"].position[n] = targetLoc
onTarget.append( onRotTarget and onLocTraget )
@ -187,8 +196,7 @@ def main():
if not Opt.chunks:
dani.suspendPhysics()
Mouse.CenterCursor()
# Making settings executed
Settings.Execute()
@ -222,7 +230,7 @@ def main():
bge.logic.globalDict["allcars"] = []
bge.logic.globalDict["cars"] = []
bge.logic.globalDict["spawnedCarModels"] = []
# Cheat code modes
bge.logic.globalDict["pursuit-cheat"] = False
@ -294,13 +302,19 @@ def main():
race["during"] = object.get("during")
race["type"] = object.get("type", "race-car")
race["reward"] = object.get("reward", 1000)
race["TimeRange"] = list(object.get("TimeRange",[]))
# Race checkpoints ( the yellow cylinder )
else:
race["checkpoints"].append(tag)
bge.logic.globalDict["races"][collection.name] = race
print(collection.name, race["TimeRange"])
# Characters
@ -320,6 +334,7 @@ def main():
"to_spawn": object["to_spawn"],
"race":object.get("race"),
"npc":object.get("npc"),
"priority":object.get("priority"),
"selected":object.blenderObject.select_get()}
if object.get("race"):
@ -446,27 +461,39 @@ def main():
# Precalculating objects for smoothness
preData = {"MetalGate_good":100,
"GatePart":100,
"LightStand": 50,
"NormalTreeTrunk":30,
"TreeBillboard":50,
"PalmCutout":32,
"PalmLow":16,
"NormalPalmTrunk":16,
preData = {
"House_Shelf":4,
"Moria's Bed":1,
"Moria's Bed.001":1,
"Sparkle": 100,
"Smoke": 20,
"LightStand.Borked.Head": 5,
"LightStand.Borked.Tail": 5,
"GatePart.Level0": 50,
"GatePart.Level1": 50,
"Fire": 200,
"NitroCone":5,
"Road Blocker": 12
}
if settings.get("trees"):
preData["NormalTreeTrunk"] = 30
preData["TreeBillboard"] = 50
preData["PalmCutout"] = 32
preData["PalmLow"] = 16
preData["NormalPalmTrunk"] = 16
if settings.get("poles"):
preData["LightStand"] = 50
preData["LightStand.Borked.Head"] = 5
preData["LightStand.Borked.Tail"] = 5
if settings.get("fences"):
preData["MetalGate_good"] = 100
preData["GatePart"] = 100
preData["GatePart.Level0"] = 50
preData["GatePart.Level1"] = 50
print("Precalculating... ")
for n, object in enumerate(preData):
@ -513,10 +540,12 @@ def main():
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()
loading.visible = False
@ -548,131 +577,13 @@ def main():
spawnedCarModels = bge.logic.globalDict["spawnedCarModels"]
spawnedCars = len( bge.logic.globalDict["allcars"] )
Opt.ScheduleTask("Car Updates", 0.80, Vehicle.SpawnLogic,
if not settings.get("multiplayer"):
Opt.ScheduleTask("Car Updates", 0.80, Vehicle.SpawnLogic,
camSurroundCars)
#Vehicle.SpawnLogic(camSurroundCars)
Vehicle.UnspawnLogic()
#print("Cars:", spawnedCars)
# SpawnsCloseEnough = []
# for i in camSurroundCars:
# SpawnsCloseEnough += bge.logic.globalDict["spawns"].get(i, [])
# for spawnPoint in SpawnsCloseEnough:
# inview = cam.pointInsideFrustum(spawnPoint["position"]) == cam.INSIDE
# distance = cam.getDistanceTo(spawnPoint["position"])
# # Car information
# carModel = spawnPoint["spawn"]
# carBehaviour = spawnPoint.get("npc")
# carRace = spawnPoint.get("race")
# # If this is a road npc, we want to choose a random car model
# if carBehaviour == "npc":
# carModel = numpy.random.choice(NPC_cars, p=NPC_cars_probability)
# toSpawn = spawnPoint["to_spawn"] and inview and spawnAtDistance / 2 < distance < spawnAtDistance and spawnedCars < maxCars
# else:
# toSpawn = spawnPoint["to_spawn"] and inview and distance < spawnAtDistance
# # Trying not to add any more cars than nessesary
# if toSpawn and carModel in Reuse.amounts and not Reuse.reuse.get(carModel):
# force_add = False
# # Making sure that the race still works
# if carRace and not dani.get("race"):
# for car in bge.logic.globalDict["allcars"]:
# if car.name == carModel:
# if not car.get("active"):
# Reuse.Delete(car, inactive=True)
# else:
# force_add = True
# break
# if carRace:
# force_add = True
# if not force_add:
# continue
# # Spawning a car
# if toSpawn:
# def AddCar(carModel, carBehaviour, carRace, spawnPoint):
# print("Spawning Car at distance from Dani:", dani.getDistanceTo(spawnPoint["position"]))
# # Making car
# car, new = Reuse.Create(carModel, declarenew=True)
# # If you claimed the car, one more car!
# if car["active"]:
# car, new = Reuse.Create(carModel, declarenew=True)
# Vehicle.Spawn(car,
# spawnPoint["position"],
# spawnPoint["orientation"],
# color="pallete")
# if carBehaviour == "npc":
# car.setLinearVelocity([0,-15,0], True)
# else:
# car["spawnPoint"] = spawnPoint
# car["npc"] = carBehaviour
# car["anger"] = random.random()
# car["enemy"] = ""
# car["chased"] = False
# car["engine"] = 0
# car["launchtime"] = 300
# if carRace:
# car["race"] = carRace
# car["racing"] = False
# car["checkpoint"] = 0
# car["rescue"] = bge.logic.globalDict["races"][carRace]["starters"][0]["location"]
# car["lap"] = 0
# car["blown"] = False
# bge.logic.globalDict["races"][carRace]["racers"].append(car)
# bge.logic.globalDict["races"][carRace]["racer_spawns"].append(spawnPoint)
# # Cars are deformable during game, so we will need to restore them
# Vehicle.Fix(car)
# # Scheduling it for a task
# if not Reuse.reuse.get(carModel):
# Opt.ScheduleTask("Adding Car ["+carModel+"]", 0.80, AddCar,
# carModel, carBehaviour, carRace, spawnPoint)
# else:
# AddCar(carModel, carBehaviour, carRace, spawnPoint)
# spawnPoint["to_spawn"] = False
# spawnPoint["to_spawn_timer"] = 500
# # If player is standing still keep spawning cars near by
# if not spawnPoint["to_spawn"] and spawnPoint["to_spawn_timer"]:
# spawnPoint["to_spawn_timer"] -= 1
# elif not spawnPoint["to_spawn"] and carBehaviour == "npc":
# spawnPoint["to_spawn"] = True
# # Removing cars that were deleted
# for car in bge.logic.globalDict["allcars"]:
# try:
# car.position
# except:
# bge.logic.globalDict["allcars"].remove(car)
# ELEVATORS
@ -885,6 +796,7 @@ def main():
"DarkShadowBox": "DARKSHADOW",
"TruckBox": "THETRUCK",
"HatchBack01Box": "HATCHBACK1",
"KartBox": "KARTCAR",
}
for i in cheats:
@ -920,6 +832,7 @@ def main():
[[232.9, -120.4, 42.22], "NEARSEA"],
[[229.9, -811.9, 175.3], "PITOSTATUE"],
[[659.4, -616.1,202.9], "CONSTRUCTION"],
[[8.5, -45.28, 2.65], "KARTING"],
[[-2.122, 1322, 99.85], "TOWER0"],
[[-172.4, 1147, 99.68], "TOWER1"],
[[200, 1204, 100], "TOWER2"],
@ -942,6 +855,7 @@ def main():
else:
dani["driving"].position = i[0]
dani["driving"].position.z += 2
bge.logic.globalDict["cheat"] = [0]
@ -954,7 +868,14 @@ def main():
Money.Recieve(569)
bge.logic.globalDict["cheat"] = [0]
bge.logic.globalDict["print"] = "Enjoy The Money, Sir."
code = bge.logic.globalDict["cheat"][-(len("givemez")):]
if code == [29, 31, 44, 27, 35, 27, 48]:
bge.logic.globalDict["cheat"] = [0]
bge.logic.globalDict["print"] = "Enjoy The Nitro, Sir."
Vehicle.AddNitroCan(dani["driving"])
dani["driving"]["nitro"] = 10.0
# Puruit code
code = bge.logic.globalDict["cheat"][-(len("pursuit")):]
if code == [38, 43, 40, 41, 43, 31, 42]:
@ -1056,6 +977,8 @@ def main():
reward = race.get("reward", 1000)
bid = reward / (race.get("amount-racers", 1)+1)
intime = Racing.intime(race)
after = race.get("after")
during = race.get("during")
duringcheck = dani.get("race") == after and Script.Story.get(during)
@ -1084,6 +1007,11 @@ def main():
NPC_type_cars = bge.logic.globalDict.get("NPC_type_cars", {})
cartype = race.get("type")
if dani["driving"] and dani["driving"].name in NPC_type_cars.get(cartype,[]):
if not intime:
bge.logic.globalDict["print"] = "Come here "+Racing.renderTimeRange(race)
continue
if not duringcheck:
bge.logic.globalDict["print"] = "Press R to start the race.\nEverybody bids $"+str(int(bid))+"\nWinner gets $"+str(int(race.get("reward")))
else:
@ -1477,7 +1405,6 @@ def main():
bge.logic.globalDict["LODchunks"] = {"TheRacetrack":{
"object":scene.objects["TheRacetrack"],
"high":"TheRacetrackHigh",
#"low":"TheRacetrackLow",
"radius":1000,
"now":"high",
"name":"Papses Racetrack"
@ -1486,7 +1413,6 @@ def main():
"TheCity":{
"object":scene.objects["TheCity"],
"high":"TheCityHigh",
#"low":"TheCityLow",
"radius":1500,
"now":"high",
"name":"Dune Town"
@ -1496,10 +1422,69 @@ def main():
"object":scene.objects["TheHouse"],
"high":"TheHouseGood",
"low":"TheHouseBorked",
"parent":"TheCity",
"radius":200,
"now":"high",
"name":"Looparound 8\nDani's Home"
},
},
"HallwayPictures":{
"object":scene.objects["HallwayPictures"],
"high":"HallwayPictures",
"parent":"TheHouse",
"radius":180,
"now":"high"
},
"Computer":{
"object":scene.objects["Computer"],
"high":"Computer",
"parent":"TheHouse",
"radius":180,
"now":"high"
},
"Just3000Wreck":{
"object":scene.objects["Just3000Wreck"],
"high":"Just3000Wreck",
"parent":"TheHouse",
"radius":180,
"now":"high"
},
"KartingTrack":{
"object":scene.objects["KartingTrack"],
"high":"KartingTrack_High",
"low":"KartingTrack_Low",
"parent":"TheCity",
"radius":200,
"now":"high",
"name":"Karting Track"
},
"Karting_Decorations":{
"object":scene.objects["Karting_Decorations"],
"high":"Karting_Decorations",
"parent":"KartingTrack",
"radius":180,
"now":"high"
},
"KartingGamesCollider":{
"object":scene.objects["KartingGamesCollider"],
"high":"KartingGamesCollider",
"parent":"KartingTrack",
"radius":180,
"now":"high"
},
"KartingGamesObject":{
"object":scene.objects["KartingGamesObject"],
"high":"KartingGamesObject",
"parent":"KartingTrack",
"radius":180,
"now":"high"
},
}
@ -1509,22 +1494,32 @@ def main():
for chunkname in chunks:
chunk = chunks[chunkname]
# Making low when out of bounds
forcehide = False
if chunks.get(chunk.get("parent", ""), {}).get("now") == "low":
forcehide = True
if chunk["object"].visible:
chunk["now"] = "high"
if chunk["now"] == "low" and dani.getDistanceTo(chunk["object"]) < chunk["radius"]:
print(consoleForm(chunk["object"]), "is now highres.")
if "low" in chunk:
chunk["object"].replaceMesh(chunk["high"])
else:
chunk["object"].visible = True
chunk["object"].visible = True
chunk["object"].restorePhysics()
chunk["now"] = "high"
bge.logic.globalDict["print"] = chunk["name"]
if "name" in chunk:
bge.logic.globalDict["print"] = chunk["name"]
elif chunk["now"] == "high" and dani.getDistanceTo(chunk["object"]) > chunk["radius"]:
elif chunk["now"] == "high" and ( dani.getDistanceTo(chunk["object"]) > chunk["radius"] or forcehide):
print(consoleForm(chunk["object"]), "is now lowres.")
if "low" in chunk:
if "low" in chunk and not forcehide:
print("making mesh low")
chunk["object"].replaceMesh(chunk["low"])
else:
print("hiding mesh")
chunk["object"].visible = False
if not dani.get("race"):
@ -1671,3 +1666,16 @@ def main():
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

1677
Scripts/Main_update.py~ Normal file

File diff suppressed because it is too large Load diff

192
Scripts/Map.py~ Normal file
View file

@ -0,0 +1,192 @@
# This file is for map functions.
# The points where the map image file ends in the
# space of the game.
# ( Note the map is 180 degrees rotated from the in game orientation of everything.
# This is due to modeling of the map ( while Moria's Race movie was being made ) was
# made before the lore for whether this place is was made up. )
xs = -2633 # The most east point
xe = 2383 # The most west point
ys = -1911 # The most north point
ye = 3106 # THe most south point
# Widths of that image file in meters.
xd = xe - xs
yd = ye - ys
rr = 730 # Radius to the edge of the map in meters
mr = 0.05 # Same radius by as a point on the map.
map_factor = mr / rr # The factor by which the relative point is calculated.
import bge
import math
import mathutils
from Scripts import Reuse
from Scripts import Character_Controll
from Scripts import Vehicle
def UpdateMapUI():
# Scene stuff
scene = bge.logic.getCurrentScene()
dani = scene.objects["Dani_Box"]
cam = scene.active_camera
# Map widget
cui = scene.objects["Map_UI"]
# Rotation
# We use the orientation of the camera
# and rotating it 180 degrees for the map.
r = cam.orientation.to_euler().z
r += math.pi
if r > 2*math.pi: r -= 2*math.pi
r = [0,0,r]
cui.blenderObject["orientation"] = r
# Position
# This one is a bit harder, since it will
# move the mapping of the image texture arround
# in the material. And it's hard to tell it just
# the coordinations ( also there is 180 degree flip ).
dl = dani.position
px = 1-( ( dl.x - xs ) / xd ) - 0.13
py = 1-( ( dl.y - ys ) / yd ) - 0.12
p = [px,py,0]
cui.blenderObject["position"] = p
# Map Dani Indicator
# This is even harder. Since the map is rotated with camera
# this widget should by ofsetted by the camera rotation.
cr = r[2]
mdi = scene.objects["Map_Dani_Indicator"]
rig = Character_Controll.getRig(dani)
r = (2*math.pi)-rig.worldOrientation.to_euler().z
r += cr
if r > 2*math.pi: r -= 2*math.pi
r = [0,r,0]
mdi.localOrientation = r
# Removing old show marks
database = bge.logic.globalDict.get("map-icons", {})
for ID in list(database.keys()):
data = database[ID]
#if data["obj"] in Reuse.reuse.get(str(data["obj"]), [])\
if data["updated"]+0.5 < bge.logic.getRealTime():
print("Removed", data["updated"], bge.logic.getRealTime())
Reuse.Delete(data["icon"])
del database[ID]
def Show(obj, color=[1,0,0], icon="Map_Icon_Directional", ID=""):
# This function will show things on the map.
# Scene stuff
scene = bge.logic.getCurrentScene()
dani = scene.objects["Dani_Box"]
cam = scene.active_camera
cui = scene.objects["Map_UI"]
# Making the icon database to track changes.
if "map-icons" not in bge.logic.globalDict:
bge.logic.globalDict["map-icons"] = {}
database = bge.logic.globalDict["map-icons"]
# Making sure that there is an object in the database
if not ID:
if type(obj) == list: ID = str(obj)
else: ID = str(id(obj))
if ID not in database:
database[ID] = {"obj":obj}
data = database[ID]
data["updated"] = bge.logic.getRealTime()
# Making sure that there is an icon in the data
if "icon" not in data:
# Making an icon
icon = Reuse.Create(icon, frompoint=cui)
icon.setParent(cui, True, True)
icon.worldScale = cui.worldScale * 2
icon.applyRotation([math.pi/2,0,0], True)
icon.blenderObject["color"] = color
data["icon"] = icon
icon = data["icon"]
# Now that we have the icon we can map it to the map
f = map_factor
# Getting vector to the target
try:
t = obj.worldPosition.copy()
torot = True
except:
t = mathutils.Vector(obj)
torot = False
d = dani.getDistanceTo(t)
if d > rr: # If the target out of range of the map
f = mr / d # This puts the icon on the edge of the map
f *= cui.worldScale.x * 2
t = t - dani.worldPosition
cr = cam.worldOrientation.to_euler()
cr = mathutils.Euler((0,0,-cr.z))
t.rotate(cr)
t = t * f
t.z = 0.001
icon.worldPosition = Vehicle.RelativePoint(cui, t)
# Rotation
if torot:
cr = cr.z
r = obj.worldOrientation.to_euler().z
r += cr
if r > 2*math.pi: r -= 2*math.pi
r = [math.pi/2,0,r]
icon.localOrientation = r
else:
icon.localOrientation = [math.pi/2, 0,0]

3
Scripts/Money.py~ Normal file
View file

@ -0,0 +1,3 @@
# GPLv3 or later
# (C) J.Y.Amihud ( blenderdumbass )

View file

@ -12,6 +12,7 @@ def MouseLookActual(cont, workanyway=False):
if not bge.logic.globalDict.get("mouse-active", True):
return
# We need this to be able disable mouse look from the
# the code.
@ -25,7 +26,7 @@ def MouseLookActual(cont, workanyway=False):
dani = scene.objects["Dani_Box"]
# Disabling the camera rotation
if not workanyway and dani.get("driving") and dani["driving"].get("dynamiccam", True):
if not workanyway and dani.get("driving"):
return
@ -38,6 +39,12 @@ def MouseLookActual(cont, workanyway=False):
pos[0] -= 0.5
pos[1] -= 0.5
if round(pos[0], 2) == 0:
pos[0] = 0
if round(pos[1], 2) == 0:
pos[1] = 0
# Getting factor information about how to move the mouse
# from the object.
my = -obj.get("mouse_Y", 1.0)

64
Scripts/Mouse.py~ Normal file
View file

@ -0,0 +1,64 @@
# Gpl3 or later
# (C) J.Y.Amihud 2024
# Stuff related to mouse control
import bge
def MouseLook(cont):
MouseLookActual(cont)
def MouseLookActual(cont, workanyway=False):
if not bge.logic.globalDict.get("mouse-active", True):
return
# We need this to be able disable mouse look from the
# the code.
# Getting object that will rotate.
if type(cont) == bge.types.SCA_PythonController:
obj = cont.owner
else: obj = cont
scene = bge.logic.getCurrentScene()
dani = scene.objects["Dani_Box"]
# Disabling the camera rotation
if not workanyway and dani.get("driving") and dani["driving"].get("dynamiccam", True):
return
# Getting mouse position on the screen.
mouse = bge.logic.mouse
pos = list(mouse.position)
# Mouse positions are normalized to be 0.5 at the center.
# We need center to be 0.0.
pos[0] -= 0.5
pos[1] -= 0.5
if round(pos[0], 2) == 0:
pos[0] = 0
if round(pos[1], 2) == 0:
pos[1] = 0
# Getting factor information about how to move the mouse
# from the object.
my = -obj.get("mouse_Y", 1.0)
mx = -obj.get("mouse_X", 1.0)
mg = obj.get("mouse_global", True)
# Applying the rotation.
obj.applyRotation((pos[1]*my, 0, pos[0]*mx), mg)
# Centring the mouse.
CenterCursor()
def CenterCursor():
if not bge.logic.globalDict.get("mouse-active", True):
return
bge.render.setMousePosition(int(bge.render.getWindowWidth() / 2), int(bge.render.getWindowHeight() / 2))

View file

@ -103,6 +103,8 @@ def MainLoop():
chunksize,
cam.orientation.to_euler())
# Queue
networkQueue = bge.logic.globalDict["networkQueue"]
for key in networkQueue:
@ -111,8 +113,13 @@ def MainLoop():
######### DEALING WITH RESPONSE ############
beforeSend = time.time()
data = Send(host, data)
afterSend = time.time()
PING = afterSend - beforeSend
bge.logic.globalDict["ping"] = PING
for key in data:
@ -127,6 +134,13 @@ def MainLoop():
elif key == "message":
bge.logic.globalDict["print"] = payload
elif key == "timing":
bge.logic.globalDict["netTiming"] = payload
elif key == "serverTime":
bge.logic.globalDict["serverTime"] = payload
bge.logic.globalDict["recievedTime"] = time.time()
else:
print(key, payload)
@ -148,6 +162,7 @@ def LoginEncode(data):
data["login"]["userId"] = bge.logic.globalDict.get("userId")
data["login"]["username"] = settings.get("mp-name")
data["login"]["room"] = settings.get("mp-room")
data["login"]["ping"] = bge.logic.globalDict.get("ping", 0)
def LoginDecode(data):
@ -163,6 +178,8 @@ def SceneDecode(data):
if not data:
return
rIds = [] # Recieved netIds
for addr in data:
chunk = data[addr]
@ -188,6 +205,18 @@ def SceneDecode(data):
Vehicle.Decode(obj, network=True)
elif obj.get("type") == "chr":
Character_Controll.Decode(obj, network=True)
rIds.append(obj.get("netId"))
# Cleaning objects that disappeared
delete = []
for netId in netObjects["netId"]:
if netId not in rIds and netObjects["netId"][netId].get("ownerId") and netObjects["netId"][netId].get("ownerId") != bge.logic.globalDict.get("userId"):
delete.append(netId)
for netId in delete:
netObjects["netId"][netId]["netId"] = None
Reuse.Delete(netObjects["netId"][netId])
del netObjects["netId"][netId]
def QueueToSend(key, data):
@ -220,3 +249,22 @@ def GrabOwnership(obj):
})
obj["ownerId"] = userId
def Latency(obj):
# Calculates latency of the object.
ping = bge.logic.globalDict.get("ping", 0)
ownerId = obj.get("ownerId", "")
netTiming = bge.logic.globalDict.get("netTiming", 0)
serverTime = bge.logic.globalDict.get("serverTime", 0)
recievedTime = bge.logic.globalDict.get("recievedTime")
owner = netTiming.get(ownerId, {})
ownerTimeStamp = owner.get("timestamp",0)
ownerPing = owner.get("ping",0)
serverLatency = ( serverTime - ownerTimeStamp )
clientLatency = ( time.time() - recievedTime )
latency = ping + ownerPing + serverLatency + clientLatency
return latency

View file

@ -0,0 +1,153 @@
# GPLv3 or later
# (C) J.Y.Amihud ( blenderdumbass ) 2024
# Multiplayer client functions
import bge
import time
import json
import zlib
from Scripts import Vehicle
from Scripts import Character_Controll
from Scripts import Opt
from Scripts import Settings
from Scripts.Multiplayer_Shared import *
from Scripts import Reuse
from Scripts.Common import *
settings = Settings.load_settings()
host = settings.get("mp-host", "")
def DescribeScene():
scene = bge.logic.getCurrentScene()
dani = scene.objects["Dani_Box"]
cam = scene.active_camera
chunksize = 250
data = {}
addr = Opt.Address(dani.position, chunksize)
if addr not in data:
data[addr] = []
danidata = Character_Controll.Encode(dani)
data[addr].append(danidata)
for car in bge.logic.globalDict["allcars"]:
if car.get("inview"):
addr = Opt.Address(car.position, chunksize)
cardata = Vehicle.Encode(car)
if addr not in data:
data[addr] = []
data[addr].append(cardata)
return data
def MainLoop():
scene = bge.logic.getCurrentScene()
dani = scene.objects["Dani_Box"]
cam = scene.active_camera
chunksize = 250
while True:
try:
# Testing if the game is still runing.
# it will fail when the game engine stops.
try: bge.logic.getRealTime()
except: return
# A bit of delay, to not owerwhelm the server
time.sleep(0.2)
######### SENDING THE DATA TO SERVER ############
data = {}
# Login
LoginEncode(data)
# Scene
data["scene"] = DescribeScene()
data["vision"] = Opt.Surround(cam.position,
chunksize,
cam.orientation.to_euler())
######### DEALING WITH RESPONSE ############
data = Send(host, data)
for key in data:
payload = data[key]
if key == "login":
LoginDecode(payload)
elif key == "scene":
SceneDecode(payload)
else:
print(key, payload)
except Exception as e:
print(clr["tdrd"], e, clr["norm"])
def LoginEncode(data):
data["login"] = {}
data["login"]["userId"] = bge.logic.globalDict.get("userId")
data["login"]["username"] = settings.get("mp-name")
data["login"]["room"] = settings.get("mp-room")
def LoginDecode(data):
if data.get("userId"):
bge.logic.globalDict["userId"] = data["userId"]
def SceneDecode(data):
netObjects = bge.logic.globalDict["netObjects"]
if not data:
return
for addr in data:
chunk = data[addr]
for obj in chunk:
# Sometimes we want to update some things like netId.
if obj.get("ID") in netObjects["pythonId"]\
and obj.get("name") == netObjects["pythonId"][obj["ID"]].name:
netObjects["pythonId"][obj["ID"]]["netId"] = obj.get("netId")
else:
if obj.get("type") == "veh":
Vehicle.Decode(obj)
# elif obj.get("netId") not in netObjects["netId"]:
# try:
# OBJ = Reuse.Create(obj.get("name"))
# except:
# OBJ = Reuse.Create("MoriaBox")
# netObjects["netId"][obj.get("netId")] = OBJ
# OBJ = netObjects["netId"][obj.get("netId")]
# OBJ.position = obj.get("position", (0,0,0))
# OBJ.orientation = obj.get("orientation", (0,0,0))

View file

@ -13,6 +13,7 @@ import Settings
from Common import *
from Multiplayer_Shared import *
RAMDATA = {}
from http.server import BaseHTTPRequestHandler, HTTPServer
@ -74,6 +75,9 @@ def ParseRequest(data):
else:
print(key, payload)
# Timing data
resp["timing"] = Timing(data)
resp["serverTime"] = time.time()
userId = data.get("login", {}).get("userId")
room = Safe(data.get("login", {}).get("room"))
@ -84,6 +88,20 @@ def ParseRequest(data):
return resp
def Timing(data):
users = LoadData("users", {})
room = data.get('login', {}).get("room", "")
resp = {}
for userId in users:
user = users[userId]
if user.get("room") == room:
resp[userId] = {}
resp[userId]["ping"] = user.get("ping")
resp[userId]["timestamp"] = user.get("timestamp")
return resp
def Login(data):
resp = {}
@ -147,9 +165,7 @@ def ChangeOwnership(data):
else:
print(Format(data.get("netId")),"netId:",data.get("netId"), "NOT FOUND, WHILE CHANGING OWNERSHIP!")
return False
def Scene(data):
scene = data["scene"]
@ -271,6 +287,10 @@ def SaveData(name, data, room=None):
try: os.makedirs(folder)
except: pass
if "--useram" in sys.argv:
RAMDATA[folder+str(name)] = data
return
# Saving the json
with open(folder+str(name)+".json", "w") as save:
json.dump(data, save, indent=4)
@ -280,8 +300,13 @@ def LoadData(name, otherwise=None, room=None):
try:
folder = Settings.get_settings_folder()+"/server/"
if room: folder = folder+str(room)+"/"
if "--useram" in sys.argv:
return RAMDATA[folder+str(name)]
with open(folder+str(name)+".json") as o:
return json.load(o)
except: return otherwise
def Safe(string):
@ -345,6 +370,8 @@ an error.
--port """+clr["tdyl"]+"""<number>"""+clr["norm"]+""" : Sets up a port on which the
server will listen.
--ipv6 , -6 : Use IPv6 connection for global network.
--useram : Use the RAM memory to write the data to, instead of disk.
( Faster, but if server crashes, the state is lost ).
""")
exit()

View file

@ -0,0 +1,470 @@
# GNU GPL v3 or later
# ( C ) J.Y.Amihud ( blenderdumbass ) 2024
import os
import sys
import zlib
import json
import time
import threading
import subprocess
import Settings
from Common import *
from Multiplayer_Shared import *
from http.server import BaseHTTPRequestHandler, HTTPServer
class handler(BaseHTTPRequestHandler):
def do_POST(self):
data = self.Recieve()
response = ParseRequest(data)
self.Send(response)
def Send(self, data):
# Compressing
data = json.dumps(data)
data = data.encode("utf-8")
data = zlib.compress(data)
# Sending
self.send_response(200)
self.send_header("Content-type","application/zip")
self.end_headers()
self.wfile.write(data)
def Recieve(self):
length = int(self.headers.get('content-length'))
data = self.rfile.read(length)
data = zlib.decompress(data)
data = json.loads(data)
return data
def log_message(self, format, *args):
# I don't want any logs.
return
def ParseRequest(data):
resp = {}
for key in data:
payload = data[key]
if "login" == key:
resp[key] = Login(payload)
elif "change-ownership" == key:
resp[key] = ChangeOwnership(payload)
elif "scene" == key:
resp[key] = Scene(data)
elif "vision" == key:
pass
else:
print(key, payload)
# Timing data
resp["timing"] = Timing(data)
resp["serverTime"] = time.time()
userId = data.get("login", {}).get("userId")
room = Safe(data.get("login", {}).get("room"))
messages = LoadData("messages", {}, room)
if messages.get(userId):
resp["message"] = messages[userId].pop(0)
SaveData("messages", messages, room)
return resp
def Timing(data):
users = LoadData("users", {})
room = data.get('login', {}).get("room", "")
resp = {}
for userId in users:
user = users[userId]
if user.get("room") == room:
resp[userId] = {}
resp[userId]["ping"] = user.get("ping")
resp[userId]["timestamp"] = user.get("timestamp")
return resp
def Login(data):
resp = {}
newuser = False
# Checking userId
if not data.get("userId"):
resp["userId"] = RandomString()
# Checking room
if not data.get("room"):
resp["room"] = "MainRoom"
elif data.get("room") != Safe(data.get("room", "")):
resp["room"] = Safe(data["room"])
data["timestamp"] = time.time()
# Storring users data.
users = LoadData("users", {})
if data.get("userId") and data.get("userId") not in users:
newuser = True
if data.get("userId"):
users[data["userId"]] = data
SaveData("users", users)
if newuser:
userId = data.get("userId")
name = data.get("username")
room = Safe(data.get("room"))
NotifyOthers(userId, name+" joined game.", room)
print(Format(userId), "JOINED GAME!")
return resp
def ChangeOwnership(data):
print(Format(data.get("userId")), "GRABBED", Format(data.get("netId")))
objects = LoadData("objects", {})
if data.get("netId") in objects:
obj = objects[data.get("netId")]
obj["ownerId"] = data.get("userId")
SaveData("objects", objects)
# Changing ownership in chunk
addr = obj.get("chunk")
room = Safe(obj.get("room"))
chunk = LoadData(addr, {}, room)
for o in chunk:
if o.get("netId") == data.get("netId"):
o["ownerId"] = data.get("userId")
SaveData(addr, chunk, room)
return True
else:
print(Format(data.get("netId")),"netId:",data.get("netId"), "NOT FOUND, WHILE CHANGING OWNERSHIP!")
return False
def Scene(data):
scene = data["scene"]
userId = data.get("login", {}).get("userId")
room = Safe(data.get("login", {}).get("room", "MainRoom"))
# We are not updating scene if there is no userId yet.
if not userId:
return
# Reading scene payload.
resp = {}
objects = LoadData("objects", {})
for addr in scene:
chunk = scene[addr]
for obj in chunk:
# Some people might want to cheat by inputing
# values for other users.
if obj.get("netId"):
obj["ownerId"] = objects.get(obj.get("netId"), {}).get("ownerId")
if not obj["ownerId"]:
obj["ownerId"] = userId
if obj.get("ownerId") and obj.get("ownerId") != userId:
chunk.remove(obj)
# Saving chunks data.
for addr in scene:
chunk = scene[addr]
saved = LoadData(addr, [], room)
add = []
# Cleaning up
for obj in saved:
if obj.get("netId") not in objects or objects[obj.get("netId")].get("chunk") != addr:
saved.remove(obj)
ids = []
for obj in saved:
ids.append(obj.get("netId"))
for obj in chunk:
# If object is Dani and it has no netId
# we assume that somebody new joined the
# room.
if obj.get("name") == "Dani_Box" and not obj.get("netId"):
obj["netId"] = userId
obj["ownerId"] = userId
add.append(obj)
elif not obj.get("netId"):
obj["netId"] = RandomString()
obj["ownerId"] = userId
add.append(obj)
if obj.get("netId") not in ids:
saved.append(obj)
else:
saved[ids.index(obj.get("netId"))] = obj
objects[obj["netId"]] = {"chunk":addr,
"name":obj.get("name"),
"timestamp":time.time(),
"ownerId":obj.get("ownerId"),
"room":room}
SaveData(addr, saved, room)
if addr in data.get("vision", []):
resp[addr] = []
for obj in saved:
if obj.get("ownerId") != userId:
resp[addr].append(obj)
for obj in add:
resp[addr].append(obj)
SaveData("objects", objects)
return resp
def Notify(userId, message, room):
messages = LoadData("messages", {}, room)
if userId not in messages:
messages[userId] = []
messages[userId].append(message)
SaveData("messages", messages, room)
def NotifyOthers(userId, message, room):
users = LoadData("users", {})
for user in users:
if user != userId and users[user].get("room") == room:
Notify(user, message, room)
def SaveData(name, data, room=None):
# Making folder for server stuff
folder = Settings.get_settings_folder()+"/server/"
if room: folder = folder+str(room)+"/"
try: os.makedirs(folder)
except: pass
# Saving the json
with open(folder+str(name)+".json", "w") as save:
json.dump(data, save, indent=4)
def LoadData(name, otherwise=None, room=None):
try:
folder = Settings.get_settings_folder()+"/server/"
if room: folder = folder+str(room)+"/"
with open(folder+str(name)+".json") as o:
return json.load(o)
except: return otherwise
def Safe(string):
# This function stripts strings from any unsafe
# characters.
good = "1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM_"
new = ""
for i in string:
if i in good: new = new + i
else: new = new + "_"
return new
def Format(netId, room=True):
objects = LoadData("objects",{})
users = LoadData("users",{})
if netId in users:
name = users[netId].get("username", "Unknown")
room = users[netId].get("room", "Unknown Room")
ownerId = netId
owner = ""
else:
name = objects.get(netId, {}).get("name", "Unknown Object")
room = objects.get(netId, {}).get("room", "Unknown Room")
ownerId = objects.get(netId, {}).get("ownerId")
owner = users.get(ownerId, {}).get("username", "Unknown")
string = IDcolor(room)+" "+room+" "+IDcolor(netId)+" "+netId[-4:]+" "+name
if owner and ownerId:
string = string + " " + IDcolor(ownerId) + " by "+ownerId[-4:]+" " + owner
string = string + " " + clr["norm"]
return string
###### RUNNING THE SERVER #####
def ArgumentsHandler():
port = 6969
ipv6 = "-4"
if "--help" in sys.argv or "-h" in sys.argv:
print("""
This is the Multiplayer server for Dani's Race.
It is technically an HTTP server that handles
POST requests send by the game. Those requests
are in a JSON format compressed with python's
ZLIB library. There is no webpage, so trying to
access it with a browser will probably spit out
an error.
"""+clr["bold"]+clr["tdyl"]+"""RUN THIS SERVER FROM THE "Scripts" FOLDER!"""+clr["norm"]+"""
--help , -h : This Help Text.
--port """+clr["tdyl"]+"""<number>"""+clr["norm"]+""" : Sets up a port on which the
server will listen.
--ipv6 , -6 : Use IPv6 connection for global network.
""")
exit()
if "--port" in sys.argv:
try:
port = int(sys.argv[ sys.argv.index("--port")+1 ])
except:
print("Didn't specify port number.\nExample ( for port 8080 ): $ python3 Multiplayer_Server.py --port 8080")
exit()
if "--ipv6" in sys.argv or "-6" in sys.argv:
ipv6 = "-6"
return port, ipv6
PORT, IPV6 = ArgumentsHandler()
print(clr["bold"]+"Dani's Race Multiplayer Server!"+clr["norm"])
###### CLEANUPS #####
def CleanUps():
while True:
time.sleep(3)
# Cleaning up users
users = LoadData("users", {})
delete = []
for userId in users:
user = users[userId]
room = user.get("room")
name = user.get("username")
# If user missing for 10 seconds, he is gone.
if user.get("timestamp", 0) < time.time() -10:
NotifyOthers(userId, name+" left the game.", room)
print(Format(userId), "LEFT GAME!")
delete.append(userId)
for i in delete:
del users[i]
SaveData("users", users)
objects = LoadData("objects", {})
delete = []
for netId in objects:
obj = objects[netId]
# Deleting objects after 5 missing seconds
if obj.get("timestamp", 0) < time.time() -5:
delete.append(netId)
for i in delete:
del objects[i]
SaveData("objects", objects)
cleanups = threading.Thread(target=CleanUps)
cleanups.daemon = True
cleanups.start()
print("Started cleanups thread.")
print(clr["bold"]+"Starting server:", clr["norm"])
try:
IP = subprocess.check_output(["hostname", "-I"]).decode("utf-8").split(" ")[0]
except:
try:
# Some versions of hostname just have the -i option that acts like -I in
# other versions.
IP = subprocess.check_output(["hostname", "-i"]).decode("utf-8").split(" ")[0]
except:
IP = clr["tdrd"]+"127.0.0.1"+clr["norm"]
if not IP or IP == "\n":
IP = clr["tdrd"]+"127.0.0.1"+clr["norm"]
print(" Local IP:", clr["bold"], IP, clr["norm"])
try:
GLOBALIP = subprocess.check_output(["curl", "-s", IPV6, "ifconfig.co"]).decode("utf-8")[:-1]
print(" Global IP:", clr["bold"], GLOBALIP, clr["norm"])
except:
GLOBALIP = None
print(" Global IP:",clr["tdrd"]+clr["bold"], "No connection to Global Network.", clr["norm"])
print(" Port:", clr["bold"], PORT, clr["norm"])
print(" Local Hostname:", clr["bold"], "http://"+IP+":"+str(PORT), clr["norm"])
if GLOBALIP:
if IPV6 == "-4":
print(" Global Hostname:", clr["bold"], "http://"+GLOBALIP+":"+str(PORT), clr["norm"])
else:
print(" Global Hostname:", clr["bold"], "http://["+GLOBALIP+"]:"+str(PORT), clr["norm"])
print()
serve = HTTPServer(("", PORT), handler)
try:
serve.serve_forever()
except KeyboardInterrupt:
print()
print("Server Exited!")

View file

@ -0,0 +1,40 @@
# GPLv3 or later
# ( C ) J.Y.Amihud ( blenderdumbass ) 2024
import os
import json
import zlib
import random
import urllib.request
import urllib.parse
def RandomString(size=64):
# This will generate random strings, primarily
# for the purpose of recognizing the same objects
# on the network.
good = "1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM"
text = ""
for i in range(size):
text = text + random.choice(good)
return text
def Send(host, data):
# Compressing
data = json.dumps(data)
data = data.encode("utf-8")
data = zlib.compress(data)
# Sending
req = urllib.request.Request(host, data=data)
# Recieving
data = urllib.request.urlopen(req).read()
data = zlib.decompress(data)
data = json.loads(data)
return data

View file

@ -57,6 +57,7 @@ def ToFPS():
return 60/bge.logic.getAverageFrameRate()
# Global Variables for GoodFPS function to work.
fpshistory = {} # History of last 200 or so frames FPS
targetFPS = 1 # Target FPS which to aim to preserve
@ -70,8 +71,10 @@ expectedfps = 60 # Expected FPS with running functions tested effects removed fr
def GoodFPS(func="", factor=1, boolean=True, traceback=False, ):
settings = bge.logic.globalDict.get("settings", {})
global targetFPS
# Recording the framerate into buffer
@ -89,10 +92,17 @@ def GoodFPS(func="", factor=1, boolean=True, traceback=False, ):
# Setting the target fps
if frame > 5:# and fps > targetFPS:
targetFPS = max(fpshistory.values())
targetFPS *= 1.1
#targetFPS = min(targetFPS, 30)
if not settings.get("autofps"):
targetFPS = bge.logic.getLogicTicRate()
else:
targetFPS = max(fpshistory.values())
targetFPS *= 1.1
if not boolean and int(frame) % 30 == 0:
bge.logic.setLogicTicRate(int(targetFPS))
# Slicing buffer to contain only last 300 records
newfpshistory = {}
for i in list(fpshistory.keys())[-300:]:
@ -108,6 +118,14 @@ def GoodFPS(func="", factor=1, boolean=True, traceback=False, ):
global testFPS
global testingTarget
global testingTargetFrame
# Controlling the amount of how aggressively this function is executed.
optset = settings.get("opt", 1.0)
choice = numpy.random.choice([False, True], p=[optset, 1-optset])
if choice:
if boolean: return True
else: return 1.0
# This runs when the target for testing is already setup
if testingTarget:
@ -144,7 +162,7 @@ def GoodFPS(func="", factor=1, boolean=True, traceback=False, ):
targetFactor = min(n.get("fraction") for n in FPStargets.values()) * factor
except:
targetFactor = factor
# Limiting
if expectedfps * FPStargets.get(func, {}).get("fraction", 1) < targetFPS * targetFactor:
if boolean: return False

515
Scripts/Opt.py~ Normal file
View file

@ -0,0 +1,515 @@
import bge
import math
import numpy
import mathutils
r = math.radians
from Scripts import Reuse
from Scripts.Common import *
# Chunks to store data about parts of the world
chunks = {}
bge.logic.globalDict["Opt.chunks"] = chunks
camspeed = 0.0
camposition = mathutils.Vector((0,0,0))
camspeedframe = 0.0
def CameraSpeed():
# This function gives the average speed of the
# camera at any given frame.
frame = round(bge.logic.getRealTime(), 2)
global camspeed
global camposition
global camspeedframe
if frame != camspeedframe:
camspeedframe = frame
# Getting velocity of the camera
p = bge.logic.getCurrentScene().active_camera.worldPosition
v = p - camposition
camposition = p.copy()
# Averaging the velocity
av = 0
for i in v:
if i > 0: av += i
else : av -= i
av /= 3
# Storing the value
camspeed = av
# Returning the value
return camspeed
def ToFPS():
# Return a fraction that is useful to adjust FPS
# sensitive values like gravity.
return 60/bge.logic.getAverageFrameRate()
# Global Variables for GoodFPS function to work.
fpshistory = {} # History of last 200 or so frames FPS
targetFPS = 1 # Target FPS which to aim to preserve
FPStargets = {} # Database of how much a given function effects FPS
testingTarget = False # Fuction that is being tested for how much it effects FPS
testingTargetFrame = 0 # Frame where the test is started
testFPS = 60 # The FPS before the test started
limitframe = 0 # The Frame that is currently being calculated for expected FPS
expectedfps = 60 # Expected FPS with running functions tested effects removed from current FPS
def GoodFPS(func="", factor=1, boolean=True, traceback=False, ):
settings = bge.logic.globalDict.get("settings", {})
global targetFPS
# Recording the framerate into buffer
# This buffer will be used to regulate the target FPS
fps = bge.logic.getAverageFrameRate()
frame = round(bge.logic.getRealTime(), 2)
camspeed = min(CameraSpeed(), 1)
global fpshistory
fpshistory[frame] = fps
# Limiting execution based on camera speed.
if boolean and numpy.random.choice([True, False], p=[camspeed, 1-camspeed]):
return False
# Setting the target fps
if frame > 5:# and fps > targetFPS:
if not settings.get("autofps"):
targetFPS = bge.logic.getLogicTicRate()
else:
targetFPS = max(fpshistory.values())
targetFPS *= 1.1
if not boolean and int(frame) % 30 == 0:
bge.logic.setLogicTicRate(int(targetFPS))
# Slicing buffer to contain only last 300 records
newfpshistory = {}
for i in list(fpshistory.keys())[-300:]:
newfpshistory[i] = fpshistory[i]
fpshistory = newfpshistory
# Calculating the fraction ( of how much are we within the target FPS )
fraction = ( sum( min(f, targetFPS) for f in fpshistory.values()) / len(fpshistory) ) / targetFPS
# Testing FPS impacts of various functions to see
# how much to limit them.
global FPStargets
global testFPS
global testingTarget
global testingTargetFrame
# This runs when the target for testing is already setup
if testingTarget:
# If we have some decrease in performace, we calculate how much it effects the FPS
if frame > testingTargetFrame and fps+1 < testFPS:
FPStargets[testingTarget] = {"fraction":fps / testFPS, "frame":frame}
testingTarget = False
# Otherwise we cancel the test
elif frame -2 > testingTargetFrame:
testingTarget = False
# While we testing, we want to return False, so nothing else will effect the FPS
if boolean: return False
else: return 0.0
# This runs to start the test
if ( func and func not in FPStargets and 10 < frame or FPStargets.get(func, {}).get("frame", frame) + 60 < frame ) and fraction > factor:
testFPS = fps
testingTarget = func
testingTargetFrame = frame
# And we want to return True so the function will get launched.
if boolean: return True
else: return 1.0
# Limiting functions based on the tests
global limitframe
global expectedfps
# Findinf the limiting factor
try:
targetFactor = min(n.get("fraction") for n in FPStargets.values()) * factor
except:
targetFactor = factor
# Limiting
if expectedfps * FPStargets.get(func, {}).get("fraction", 1) < targetFPS * targetFactor:
if boolean: return False
# If we allow the function to run
# we want to recalculate the expected FPS
# based on the tests
if limitframe != frame:
# If the tests data is flawed
if int(expectedfps) > int(fps)+2:
FPStargets = {}
# Calculating expected FPS
expectedfps = fps*FPStargets.get(func, {}).get("fraction", 1)
limitframe = frame
else:
expectedfps *= FPStargets.get(func, {}).get("fraction", 1)
# Returning
if boolean:
return True#fraction > factor
else:
return fraction
def Address(location, precision):
# This function will return an adress of any given location
# Which could be used to compare between objects to see if they
# are close enough together.
ret = ""
for axis in location[:2]:
ret = ret + str(round(axis/precision))+":"
return ret
def Surround(location, precision, camera=None):
# This function will give a list of addresses around a certain point.
ret = []
ORL = []
addedtypes = []
for axis in location[:2]:
ORL.append(round(axis/precision))
ret.append(Address(ORL, 1))
if not camera:
# X
if (location[0]/precision) - round(location[0]/precision) < 0.5:
ret.append(Address([ORL[0]-1, ORL[1]], 1))
addedtypes.append("-x")
elif (location[0]/precision) - round(location[0]/precision) > 0.5:
ret.append(Address([ORL[0]+1, ORL[1]], 1))
addedtypes.append("+x")
# Y
if (location[1]/precision) - round(location[1]/precision) < 0.5:
ret.append(Address([ORL[0], ORL[1]-1], 1))
addedtypes.append("-y")
elif (location[1]/precision) - round(location[1]/precision) > 0.5:
ret.append(Address([ORL[0], ORL[1]+1], 1))
addedtypes.append("+y")
# Diagonals
if "+x" in addedtypes and "+y" in addedtypes:
ret.append(Address([ORL[0]+1, ORL[1]+1], 1))
elif "-x" in addedtypes and "-y" in addedtypes:
ret.append(Address([ORL[0]-1, ORL[1]-1], 1))
elif "-x" in addedtypes and "+y" in addedtypes:
ret.append(Address([ORL[0]-1, ORL[1]+1], 1))
elif "+x" in addedtypes and "-y" in addedtypes:
ret.append(Address([ORL[0]+1, ORL[1]-1], 1))
else:
if r(70) >= camera[2] >= r(-70):
ret.append(Address([ORL[0], ORL[1]+1], 1))
if r(25) >= camera[2] >= r(-115):
ret.append(Address([ORL[0]+1, ORL[1]+1], 1))
if r(-20) >= camera[2] >= r(-160):
ret.append(Address([ORL[0]+1, ORL[1]], 1))
if r(-65) >= camera[2] >= r(-180) or r(180) > camera[2] >= r(155):
ret.append(Address([ORL[0]+1, ORL[1]-1], 1))
if r(-110) >= camera[2] >= r(-180) or r(180) > camera[2] >= r(110):
ret.append(Address([ORL[0], ORL[1]-1], 1))
if r(-155) >= camera[2] >= r(180) or r(180) > camera[2] >= r(65):
ret.append(Address([ORL[0]-1, ORL[1]-1], 1))
if r(160) >= camera[2] >= r(20):
ret.append(Address([ORL[0]-1, ORL[1]], 1))
if r(115) >= camera[2] >= r(-25):
ret.append(Address([ORL[0]-1, ORL[1]+1], 1))
return ret
previousSurround = {}
def SurroundChanged(key, surround):
# This returns whether surround was changed between frames
if key not in previousSurround:
previousSurround[key] = surround.copy()
changed = surround != previousSurround[key]
previousSurround[key] = surround.copy()
return changed
def RegisterObject(object, precision, delete=True):
# This will move an object from scene.objects into
# chunks. So that they could be stored without
# effecting the BGE Depsgraph performance.
# Creating chunk
addr = Address(object.position, precision)
if addr not in chunks:
chunks[addr] = {"loaded":False,
"objects":[]}
# Adding properties
virtualObject = {}
virtualObject["name"] = object.name
virtualObject["position"] = object.position.copy()
virtualObject["orientation"] = object.orientation.to_euler()
virtualObject["scaling"] = object.scaling.copy()
for i in object.blenderObject.game.properties:
virtualObject[i.name] = i.value
# Adding the object to the chunk
chunks[addr]["objects"].append(virtualObject)
# Deleting real object
if delete:
object.endObject()
# Returning
return virtualObject
def SortByDistance(l, cam, withdistance=False):
# This sorts a chunk by the distance
distanced = []
for n, i in enumerate(l):
d = cam.getDistanceTo(i["position"])
distanced.append([d, n, i])
distanced = sorted(distanced)
if withdistance:
return distanced
ret = []
for i in distanced:
ret.append(i[2])
return ret
def UpdateScene(camobject, precision, camera=None):
# This function will update the scene. According to the camera
# view.
location = camobject.position
# Getting addresses
addrs = Surround(location, precision, camera)
# Checking if any of addresses are not up to date.
for addr in chunks:
# Delete object if address not in view
# It is done in a separate loop and first,
# because we might need elements from it
# to spawn later. Otherwise we might cache
# way too many objects into memory.
if addr not in addrs and chunks[addr]["loaded"]:
for object in chunks[addr]["objects"]:
if object.get("object"):
Reuse.Delete(object["object"])
object["object"] = None
chunks[addr]["loaded"] = False
# Breaking to skip to next frame and
# re-evaluate whether the FPS is good
return
lookthroughchunks = chunks
if addrs[0] in chunks:
lookthroughchunks = [chunks[addrs[0]]]+list(chunks.keys())
# Fixing random items at the chunks.
for i in range(5):
addr = random.choice(list(chunks.keys()))
item = random.choice(chunks[addr]["objects"])
if item.get("broken"):
item["broken"] = False
print(consoleForm(item["name"]), "Fixed")
for addr in chunks:
# Create objects when addres in view
if addr in addrs and not chunks[addr]["loaded"]:
for object in SortByDistance(chunks[addr]["objects"], camobject):
if not object.get("object") and not object.get("broken"):
object["object"] = Reuse.Create(object["name"])
object["object"].position = object["position"]
object["object"].orientation = object["orientation"]
object["object"].scaling = object["scaling"]
# Some objects have a height adjustment value
object["object"].position[2] += object["object"].get("movez", 0)
# Some effects require a reference point
object["object"]["spawned_by"] = object
# Some objects need dynamics to be suspended
if object.get("suspendDynamics"):
object["object"].suspendDynamics(True)
# Some objects might change mesh during game
if object["object"].get("good"):
object["object"].replaceMesh(object["object"]["good"])
chunks[addr]["loaded"] = True
# Breaking to skip to next frame and
# re-evaluate whether the FPS is good
return
# Level Of Details for spawn objects
# This is needed because normal LOD system
# with those objects sometimes gives a
# segmentation fault.
elif addr in addrs and chunks[addr]["loaded"]:
sortedObjects = SortByDistance(chunks[addr]["objects"], camobject, True)
# closestUnspawned = [1000000, 0, {}]
# for object in sortedObjects:
# if not object[2].get("object") and object[0] < closestUnspawned[0]:
# closestUnspawned = object
#
# if Reuse.reuse.get(closestUnspawned[2].get("name")):
# closestUnspawned[2]["object"] = Reuse.Create(closestUnspawned[2].get("name"))
# closestUnspawned[2]["object"].position = closestUnspawned[2]["position"]
# closestUnspawned[2]["object"].orientation = closestUnspawned[2]["orientation"]
# closestUnspawned[2]["object"].scaling = closestUnspawned[2]["scaling"]
#
# # Some objects have a height adjustment value
# closestUnspawned[2]["object"].position[2] += closestUnspawned[2]["object"].get("movez", 0)
#
# # Some effects require a reference point
# closestUnspawned[2]["object"]["spawned_by"] = closestUnspawned[2]
#
# # Some objects need dynamics to be suspended
# if closestUnspawned[2].get("suspendDynamics"):
# closestUnspawned[2]["object"].suspendDynamics(True)
for distance, n, object in sortedObjects:
#
# if object["name"] == closestUnspawned[2].get("name") and distance > closestUnspawned[0] and object.get("object"):
# Reuse.Delete(object["object"])
# object["object"] = None
if "lods" in object and object.get("object"):
distance = object["object"].getDistanceTo(location)
for lod in object["lods"]:
lodDistance = object["lods"][lod]
if int(distance) <= lodDistance:
break
if object["object"].name != lod:
Reuse.Delete(object["object"])
object["object"] = Reuse.Create(lod)
object["object"].position = object["position"]
object["object"].orientation = object["orientation"]
object["object"].scaling = object["scaling"]
# Some objects have a height adjustment value
object["object"].position[2] += object["object"].get("movez", 0)
# Some effects require a reference point
object["object"]["spawned_by"] = object
# Some objects need dynamics to be suspended
if object.get("suspendDynamics"):
object["object"].suspendDynamics(True)
taskschedule = {}
def ScheduleTask(taskname, FPSfactor, task, *args):
# This function adds a function to the schedule
taskObject = {"FPSfactor":FPSfactor,
"task":task,
"args":args}
taskschedule[taskname] = taskObject
def ExecuteScheduled():
# This function executes a scheduled task
# for taskname in taskschedule:
# print("Scheduled:", taskname)
# print()
# Trying to execute something
for taskname in taskschedule:
taskObject = taskschedule[taskname]
if GoodFPS("[Scheduled] "+taskname, taskObject["FPSfactor"]):
del taskschedule[taskname]
taskObject["task"](*taskObject["args"])
return
def Force(value):
# This function adjusts acceleration
# to fps
return value * ( ToFPS() ** 2 )
def Velocity(value):
# This function adjusts velocity
# to fps
return value * ToFPS()
def PrintTime():
# This function is used for testing
print(bge.logic.getRealTime())

39
Scripts/Racing.py Normal file
View file

@ -0,0 +1,39 @@
# GPLv3 or later
# ( C ) J.Y.Amihud 2024
# This module is to deal with racing.
import bge
def intime(race):
TimeRange = race.get("TimeRange")
timeis = bge.logic.globalDict.get("time", 0)
if not TimeRange:
return True
# Standard ranges, like 12 -> 14, or 6 -> 12
elif TimeRange[0] < TimeRange[1]:
return TimeRange[0] <= timeis <= TimeRange[1]
# Other ranges, like 21 -> 6, 17 -> 12
else:
return timeis < TimeRange[1] or timeis > TimeRange[0]
def renderTimeRange(race):
TimeRange = race.get("TimeRange")
min0 = str(int(60*(TimeRange[0]-int(TimeRange[0]))))
if len(min0) < 2: min0 = "0"+min0
min1 = str(int(60*(TimeRange[1]-int(TimeRange[1]))))
if len(min1) < 2: min1 ="0"+min1
hrs0 = str(int(TimeRange[0]))
if len(hrs0) < 2: hrs0 = "0"+hrs0
hrs1 = str(int(TimeRange[1]))
if len(hrs1) < 2: hrs1 = "0"+hrs1
r = "between "+hrs0+":"+min0+" and "+hrs1+":"+min1
return r

3
Scripts/Racing.py~ Normal file
View file

@ -0,0 +1,3 @@
# GPLv3 or later
# ( C ) J.Y.Amihud 2024

View file

@ -9,6 +9,7 @@ from Scripts import Vehicle
from Scripts import Map
from Scripts import Main_update
from Scripts import Garage
from Scripts import Money
from Scripts.Common import *
@ -203,7 +204,7 @@ def scene(scene, dani):
# 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"
@ -217,14 +218,14 @@ def scene(scene, dani):
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 dani.getDistanceTo(house) < 600 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
Story["lastring"] = bge.logic.getRealTime() + 400
# If the phone is still ringing we can answer it
if "ringing" in Story and Story["ringing"].status and AnsweredPhone():
@ -428,12 +429,22 @@ Story["01_Bring_Neonspeedster_To_Racetrack"] = scene
def scene(scene, dani):
global Story
# Stopping this scene from working in the night
if "stage" not in Story:
timeis = bge.logic.globalDict.get("time", 0)
if timeis > 19 or timeis < 8:
return
house = scene.objects["TheHouse"]
pointer = scene.objects["PointingArrow"]
fixGaragePosition = [-754.61, -1043.9, 409.32]
# Moria goes to the racetrack and does some racing by herself.
if "Moria" in Story:
if "Moria" in Story and Story.get("stage", 0) < 15:
# Moria goes to the car
if not dani.get("driving") and not Story["Moria"].get("driving"):
@ -524,8 +535,14 @@ def scene(scene, dani):
# 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"):
if dani.getDistanceTo(racetrack) > 450:
try:
del Story["blown-too-close"]
except: pass
if dani.getDistanceTo(racetrack) < 450 and "stage" not in Story and not dani.get("race")\
and "blown-too-close" not in Story:
# Restoring truck, Paps and Jack
@ -609,6 +626,10 @@ def scene(scene, dani):
if "dialogue2" not in Story:
Story["dialogue2"] = PlayDialogue("brief", Story["Paps"])
if Story["Truck"].get("blown"):
if "dialogue2" in Story:
Story["dialogue2"].stop()
# Paps emoting
if "dialogue2" in Story:
@ -658,14 +679,14 @@ def scene(scene, dani):
# 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"]
# 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
# try:
# Reuse.Delete(Story["Paps"])
# del Story["Paps"]
# except:pass
pointer.visible = False
if "dialogue3" in Story:
@ -763,18 +784,7 @@ def scene(scene, dani):
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:
@ -790,30 +800,394 @@ def scene(scene, dani):
if Story["Jack"].get("driving") != Story["DarkShadow"]:
Character_Controll.getIntoCar(Story["Jack"], Story["DarkShadow"], passanger=True)
# else:
# Story["stage"] = 6
# Detecting when the race ends.
if not dani.get("race"):
Story["stage"] = 6
# Jack is panicing about the broken car.
if Story.get("stage") == 6:
if "dialogue5" not in Story and ( not Story["Jack"].get("saying") or not Story["Jack"]["saying"].status ):
Story["dialogue5"] = PlayDialogue("after_race_brief")
Story["Jack"]["saying"] = Story["dialogue5"]
if "dialogue5" in Story:
emotion_data = [
[[ 0.1 , 2.5 ], "Talk" ],
[[ 3.5 , 9.2 ], "Talk" ],
[[ 9.7 , 10.4 ], "Talk" ],
[[ 11.6 , 15.6 ], "Talk" ],
]
emote(Story["Jack"], emotion_data, Story["dialogue5"])
if "dialogue5" in Story and not Story["dialogue5"].status:
Character_Controll.getOutCar(Story["Jack"])
Story["stage"] = 7
bge.logic.globalDict["print"] = "Pick the car up with the truck."
# Jack is coming back to the truck
if Story.get("stage") == 7:
if Story["Jack"].get("driving") != Story["Truck"]:
Character_Controll.getIntoCar(Story["Jack"], Story["Truck"], passanger=True)
elif dani.get("driving") == Story["Truck"]:
Story["stage"] = 8
# Jack is telling you to pick up the car.
if Story.get("stage") == 8:
if Story["Truck"].get("is_unloaded"):
if "dialogue6" not in Story and ( not Story["Jack"].get("saying") or not Story["Jack"]["saying"].status ):
Story["dialogue6"] = PlayDialogue("pick_up_the_car")
Story["Jack"]["saying"] = Story["dialogue6"]
bge.logic.globalDict["print"] = "Press D to pick the car back up."
if "dialogue6" in Story:
emotion_data = [
[[ 0.3 , 1.1 ], "Talk" ],]
emote(Story["Jack"], emotion_data, Story["dialogue6"])
elif Story["Truck"].get("cargo") != Story["DarkShadow"]:
if "dialogue7" not in Story and ( not Story["Jack"].get("saying") or not Story["Jack"]["saying"].status ):
Story["dialogue7"] = PlayDialogue("no_pick_up_the_car")
Story["Jack"]["saying"] = Story["dialogue7"]
if "dialogue7" in Story:
emotion_data = [
[[ 0.2 , 2.4 ], "Talk" ],]
emote(Story["Jack"], emotion_data, Story["dialogue7"])
elif Story["Truck"].get("cargo") == Story["DarkShadow"]:
Story["stage"] = 9
pointer.visible = True
bge.logic.globalDict["print"] = "Drive the Truck home."
# Going with the truck home.
if Story.get("stage") == 9:
Map.Show(fixGaragePosition, icon="Map_Circle", color=[1,0.8,0])
# Point to the house
tocheck = pointer.getVectTo(fixGaragePosition)
pointer.alignAxisToVect(tocheck[1], 1, 0.1)
pointer.alignAxisToVect( (0,0,1), 2, 1.0 )
# If we are at the place.
if Story["Truck"].getDistanceTo(fixGaragePosition) < 60:
Story["stage"] = 10
Character_Controll.getOutCar(Story["Jack"])
pointer.visible = False
# Fixing the car.
if Story.get("stage") == 10:
if "Jack-got-to-garage-door" not in Story:
garageDoor = [-789.7, -1035, 405.5]
if Story["Jack"].getDistanceTo(garageDoor) > 1.5:
Character_Controll.walkToward(Story["Jack"], garageDoor)
else:
Story["Jack-got-to-garage-door"] = True
else:
# Opening Garage door
doors = bge.logic.globalDict["doors"]["House_Garage"]
if doors.get("OpenClosed", "Closed") == "Closed":
doors["OpenClosed"] = "Open"
doors["doOpenClose"] = True
fixToolPoint = [-754.1, -1039, 405.8]
if Story["Jack"].getDistanceTo(fixToolPoint) > 1:
Character_Controll.walkToward(Story["Jack"], fixToolPoint, avoidObstacles=False)
elif "dialogue8" in Story and not Story["dialogue8"].status:
if Story["DarkShadow"] in Garage.Inside():
Story["stage"] = 11
if "dialogue8" not in Story and ( not Story["Jack"].get("saying") or not Story["Jack"]["saying"].status ):
Story["dialogue8"] = PlayDialogue("get_the_car_out_here", Story["Jack"])
Story["Jack"]["saying"] = Story["dialogue8"]
if "dialogue8" in Story:
emotion_data = [
[[ 0.5 , 1.8 ], "Talk" ],]
emote(Story["Jack"], emotion_data, Story["dialogue8"])
if Story.get("stage") == 11:
if "dialogue9" not in Story and ( not Story["Jack"].get("saying") or not Story["Jack"]["saying"].status ):
Story["dialogue9"] = PlayDialogue("take_this_power_wrench", Story["Jack"])
Story["Jack"]["saying"] = Story["dialogue9"]
if "dialogue9" in Story:
emotion_data = [
[[ 0.0 , 0.5 ], "Talk" ],
[[ 1.1 , 6.9 ], "Talk" ],
]
emote(Story["Jack"], emotion_data, Story["dialogue9"])
if "dialogue9" in Story and not Story["dialogue9"].status:
Story["stage"] = 12
if Story.get("stage") == 12:
fixComputerPoint = [-755, -1047, 405.8]
if Story["Jack"].getDistanceTo(fixComputerPoint) > 1:
Character_Controll.walkToward(Story["Jack"], fixComputerPoint, avoidObstacles=False)
else:
# Jack is buing parts that the car is missing.
wheels = 0
parts = 0
for wheel in Story["DarkShadow"].get("wheels", []):
if not wheel.visible: wheels += 1
for part in Story["DarkShadow"].get("doors", []):
if not part.visible: parts += 1
Garage.inventory["Parts" ] = max(Garage.inventory.get("Parts" , 0), parts )
Garage.inventory["Wheels"] = max(Garage.inventory.get("Wheels", 0), wheels)
Garage.UpdateShelfs()
Money.Sound()
Story["stage"] = 13
bge.logic.globalDict["print"] = "Fix the car."
if Story.get("stage") == 13:
if Story["Jack"].getDistanceTo(dani) > 3:
Character_Controll.walkToward(Story["Jack"], dani)
if "dialogue10" not in Story and ( not Story["Jack"].get("saying") or not Story["Jack"]["saying"].status ):
Story["dialogue10"] = PlayDialogue("seems_we_have_everything", Story["Jack"])
Story["Jack"]["saying"] = Story["dialogue10"]
if "dialogue10" in Story:
emotion_data = [
[[ 0.4 , 1.9 ], "Talk" ],
]
emote(Story["Jack"], emotion_data, Story["dialogue10"])
# Find out what is the health of the exteriour of the car.
parts = []
for wheel in Story["DarkShadow"].get("wheels", []):
parts.append(wheel.get("health", 1))
for part in Story["DarkShadow"].get("doors", []):
parts.append(part.get("health", 1))
health = sum(parts) / len(parts)
if health == 1.0:
Story["stage"] = 14
if Story.get("stage") == 14:
if Story["Jack"].getDistanceTo(dani) > 3:
Character_Controll.walkToward(Story["Jack"], dani)
if "dialogue11" not in Story and ( not Story["Jack"].get("saying") or not Story["Jack"]["saying"].status ):
Story["dialogue11"] = PlayDialogue("tidy_from_below", Story["Jack"])
Story["Jack"]["saying"] = Story["dialogue11"]
if "dialogue11" in Story:
emotion_data = [
[[ 0.1 , 3.8 ], "Talk" ],
]
emote(Story["Jack"], emotion_data, Story["dialogue11"])
if Story["DarkShadow"].getDistanceTo(fixGaragePosition) < 2:
Story["stage"] = 15
if Story.get("stage") == 15:
# Spawning neonspeedster
if "NeonSpeedster" not in Story:
Story["NeonSpeedster"] = Vehicle.Spawn("NeonSpeedsterBox",
(-798.3, -1006, 405.5),
(0,0,0))
if "Moria" not in Story:
Story["Moria"] = Reuse.Create("MoriaBox")
Character_Controll.getIntoCar(Story["Moria"],
Story["NeonSpeedster"],
immediately=True)
if "Paps" not in Story:
Story["Paps"] = Reuse.Create("PapsBox")
Character_Controll.getIntoCar(Story["Paps"],
Story["NeonSpeedster"],
passanger=True,
immediately=True)
# Opening Garage door
doors = bge.logic.globalDict["doors"]["House_Garage"]
if doors.get("OpenClosed", "Closed") == "Closed":
doors["OpenClosed"] = "Open"
doors["doOpenClose"] = True
if Story["NeonSpeedster"].getDistanceTo(fixGaragePosition) > 20:
Story["NeonSpeedster"]["npc"] = "story"
Story["NeonSpeedster"]["target"] = fixGaragePosition
Vehicle.TargetedNPC(Story["NeonSpeedster"])
else:
Character_Controll.getOutCar(Story["Paps"])
Character_Controll.getOutCar(Story["Moria"])
Story["stage"] = 16
if Story.get("stage") == 16:
Vehicle.IdleBraking(Story["NeonSpeedster"])
if "dialogue12" not in Story and ( not Story["Jack"].get("saying") or not Story["Jack"]["saying"].status ):
Story["dialogue12"] = PlayDialogue("final_jack", Story["Jack"])
Story["Jack"]["saying"] = Story["dialogue12"]
if "dialogue13" not in Story:
Story["dialogue13"] = PlayDialogue("final_paps", Story["Paps"])
if "dialogue14" not in Story:
Story["dialogue14"] = PlayDialogue("final_dani")
if "dialogue12" in Story:
emotion_data = [
[[ 2.6 , 3.5 ], "Talk" ],
[[ 4.3 , 7.8 ], "Talk" ],
[[ 9.8 , 10.3 ], "Talk" ],
[[ 11.6 , 12.3 ], "Talk" ],
[[ 15.1 , 16.0 ], "Talk" ],
[[ 16.3 , 17.3 ], "Talk" ],
[[ 18.9 , 20.2 ], "Talk" ],
[[ 21.3 , 22.2 ], "Talk" ],
[[ 29.8 , 31.2 ], "Talk" ],
[[ 32.0 , 33.3 ], "Talk" ],
]
emote(Story["Jack"], emotion_data, Story["dialogue12"])
if "dialogue13" in Story:
emotion_data = [
[[ 1.1 , 2.8 ], "Talk" ],
[[ 3.5 , 4.3 ], "Talk" ],
[[ 7.7 , 9.3 ], "Talk" ],
[[ 10.2 , 11.2 ], "Talk" ],
[[ 12.6 , 14.3 ], "Talk" ],
[[ 17.0 , 18.3 ], "Talk" ],
[[ 20.6 , 21.4 ], "Talk" ],
[[ 23.9 , 26.5 ], "Talk" ],
[[ 28.7 , 29.7 ], "Talk" ],
[[ 34.2 , 36.2 ], "Talk" ],
[[ 37.5 , 38.2 ], "Talk" ],
[[ 39.3 , 40.0 ], "Talk" ],
[[ 44.7 , 55.3 ], "Talk" ],
[[ 57.2 , 58.6 ], "Talk" ],
]
emote(Story["Paps"], emotion_data, Story["dialogue13"])
if "dialogue14" in Story:
emotion_data = [
[[ 14.5 , 14.9 ], "Talk" ],
[[ 26.8 , 27.4 ], "Laugh" ],
[[ 36.7 , 37.1 ], "Talk" ],
[[ 41.0 , 41.8 ], "Talk" ],
]
emote(dani, emotion_data, Story["dialogue14"])
# Paps and Jack walking after you.
if Story["Jack"].getDistanceTo(dani) > 3:
Character_Controll.walkToward(Story["Jack"], dani)
if Story["Paps"].getDistanceTo(dani) > 3:
Character_Controll.walkToward(Story["Paps"], dani)
if "dialogue13" in Story and not Story["dialogue13"].status:
Story["stage"] = 17
bge.logic.globalDict["print"] = "Go to your room."
pointer.visible = True
del Story["NeonSpeedster"]
del Story["DarkShadow"]
if Story.get("stage") == 17:
roomPosition = [-752.78, -937.4, 411.08]
# Point to the room
tocheck = pointer.getVectTo(roomPosition)
pointer.alignAxisToVect(tocheck[1], 1, 0.1)
pointer.alignAxisToVect( (0,0,1), 2, 1.0 )
if dani.getDistanceTo(roomPosition) < 7:
bge.logic.globalDict["print"] = "Mission Passed!"
if "Moria" in Story:
Reuse.Delete(Story["Moria"])
del Story["Moria"]
if "Paps" in Story:
Reuse.Delete(Story["Paps"])
del Story["Paps"]
if "Jack" in Story:
Reuse.Delete(Story["Jack"])
del Story["Jack"]
Story["passed"].append(Story["currentEvent"])
Story = {"passed":Story["passed"]}
Story["currentEvent"] = "03_Karting_Lessons"
# If Truck blows up you loose
if "Truck" in Story and Story["Truck"].get("blown"):
bge.logic.globalDict["print"] = "Mission failed! You broke the truck."
dani["race"] = ""
try:
del Story["stage"]
except:pass
try:
Reuse.Delete(Story["Paps"])
del Story["Paps"]
except:pass
pointer.visible = False
if dani.getDistanceTo(racetrack) < 450:
Story["blown-too-close"] = True
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.
##############################################################################
def scene(scene, dani):
# 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.
pass
##############################################################################
# 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 ).
Story["03_Karting_Lessons"] = scene
# Mission: Go to the karting lessons.

1193
Scripts/Script.py~ Normal file

File diff suppressed because it is too large Load diff

View file

@ -106,9 +106,23 @@ def Execute():
# Sun shadow res
bpy.data.scenes["Scene"].eevee.shadow_cascade_size = data.get("shadowssun", "1024")
# Logic Steps
#bge.logic.setMaxLogicFrame(100)
# Target FPS ( logic tic rate )
bge.logic.setLogicTicRate(data.get("fps", 30))
# Vsync
vsync = data.get("vsync", "Off")
if vsync == "Off":
vsync = bge.render.VSYNC_OFF
elif vsync == "On":
vsync = bge.render.VSYNC_ON
else:
vsync = bge.render.VSYNC_ADAPTIVE
bge.render.setVsync(vsync)
# Ambient Occlusion
bpy.data.scenes["Scene"].eevee.use_gtao = data.get("ao", False)
# Controlls
@ -143,6 +157,9 @@ def Execute():
except Exception as e:
print("Error assigning controls",e)
def SaveGame():
# Let's generate the data to save.

199
Scripts/Settings.py~ Normal file
View file

@ -0,0 +1,199 @@
# Gplv3 or any later version
# (C) J.Y.Amihud 2024
import os
import json
# Those modules don't work everywhere
try:
import bge
import bpy
from Scripts import Main_update
from Scripts import Script
from Scripts import Money
from Scripts import Garage
from Scripts import Character_Controll
from Scripts import Vehicle
from Scripts.Common import *
except:
pass
def get_settings_folder():
game = "danisrace"
try:
data_dir = os.environ["XDG_DATA_HOME"] + "/" + game
except:
data_dir = os.path.expanduser("~/.local/share/"+game)
try:
os.makedirs(data_dir)
except:
pass
return data_dir
def load_settings():
folder = get_settings_folder()
f = folder+"/config.json"
try:
with open(f) as o:
return json.load(o)
except: return {}
def Execute():
# This function will execute the various settings inside of the game
data = load_settings()
if not data: return
scene = bge.logic.getCurrentScene()
# SHADOWS
for obj in scene.lights:
# Use Shadow
try: obj.blenderObject.data.use_shadow = data.get("shadows", True)
except: pass
# Use Contact Shadow
try: obj.blenderObject.use_contact_shadow = data.get("cntctshadows", True)
except: pass
# Softshadows
bpy.data.scenes["Scene"].eevee.use_soft_shadows = data.get("softshadows", True)
# Reflections
bpy.data.scenes["Scene"].eevee.use_ssr = data.get("reflections", True)
# Samples TODO figure it out
bpy.data.scenes["Scene"].eevee.taa_render_samples = data.get("samples", 1)
# Volume samples
bpy.data.scenes["Scene"].eevee.volumetric_samples = data.get("volumesamples", 32)
# Compositor
if data.get("compositor"):
bpy.context.space_data.shading.use_compositor = 'ALWAYS'
else:
bpy.context.space_data.shading.use_compositor = 'DISABLED'
# Skin samples
bpy.data.scenes["Scene"].eevee.sss_samples = data.get("skinsamples", 5)
# Volume shadows
bpy.data.scenes["Scene"].eevee.use_volumetric_shadows = data.get("volumeshadow", False)
# Volume lights
bpy.data.scenes["Scene"].eevee.use_volumetric_lights = data.get("volumelight", True)
# Volume shadows samp
bpy.data.scenes["Scene"].eevee.volumetric_shadow_samples = data.get("volshadsampl", 3)
# Cube Shadow res
bpy.data.scenes["Scene"].eevee.shadow_cube_size = data.get("shadowslamps", "512")
# Sun shadow res
bpy.data.scenes["Scene"].eevee.shadow_cascade_size = data.get("shadowssun", "1024")
# Logic Steps
#bge.logic.setMaxLogicFrame(100)
# Controlls
controlmap = {
"veh_forward" :"forward",
"veh_backward" :"backward",
"veh_left" :"left",
"veh_right" :"right",
"veh_drift" :"drift",
"veh_nitro" :"nitro",
"veh_resque" :"resque",
"veh_gear_up" :"gearup",
"veh_gear_down":"geardown",
"veh_auto_gear":"autogear",
"veh_dynamcam" :"dynamcam",
"veh_upload" :"unload",
"chr_forward" :"forward",
"chr_backward" :"backward",
"chr_left" :"left",
"chr_right" :"right",
"chr_jump" :"jump",
"chr_get_car" :"getcar",
"chr_swimdown" :"swimdown"
}
for control in controlmap:
if control.startswith("chr"): folder = bge.logic.globalDict["chr_controls"]
else: folder = bge.logic.globalDict["veh_controls"]
try: folder[controlmap[control]] = keycodes[data[control]]
except Exception as e:
print("Error assigning controls",e)
def SaveGame():
# Let's generate the data to save.
data = {
"currentEvent" : Script.Story["currentEvent"],
"passedEvents" : Script.Story["passed"]
}
data["cars"] = Garage.Encode()
data["money"] = Money.Get()
data["inventory"] = Garage.inventory
data["time"] = bge.logic.globalDict["time"]
folder = get_settings_folder()
f = folder+"/save.json"
try:
with open(f, "w") as save:
json.dump(data, save, indent=4, sort_keys=True)
print(clr["bold"]+clr["tdgr"]+"Game saved!"+clr["norm"], f)
except Exception as e:
print(clr["bold"]+clr["tdrd"]+"Failed to save game:"+clr["norm"], e)
def LoadGame():
# loading game
folder = get_settings_folder()
f = folder+"/save.json"
try:
with open(f) as o:
data = json.load(o)
except Exception as e:
print("Couldn't Load Game:", e)
return
bge.logic.globalDict["garage-saved"] = data.get("cars", [])
Script.Story["currentEvent"] = data.get("currentEvent", "01_Bring_Neonspeedster_To_Racetrack")
Script.Story["passed"] = data.get("passedEvents", [])
Money.Set(data.get("money", 0.0))
Garage.inventory = data.get("inventory", {})
Garage.UpdateShelfs()
bge.logic.globalDict["start-time"] = data.get("time")

View file

@ -83,7 +83,7 @@ def MainLoop():
if ray[1]:
point = ray[1]
d = 10
d = 5
c = None
for obj in objs:
od = obj.getDistanceTo(point)
@ -164,7 +164,7 @@ def MainLoop():
if c == car:
car["blown"] = False
if c["health"] > 0.1:
if c["health"] > 0.2:
if not c.visible:
dani["tool-attachment"] = None
@ -257,8 +257,68 @@ def MainLoop():
dani["tool-attachment"] = None
# If not model
else:
ray = DaniPoint(dani, camera)
if dani.get("tool-attachment"):
# Telling the user that her can drop the part
if ray[1]:
box.position = ray[1]
box.position.z += 1
box.scaling = (1,1,1)
# Dropping the part
if mousecodes["LMB"] in mouse and ray[1] and not tool.get("active-timer"):
name = dani["tool-attachment"]
item = Garage.shop.get(name, {})
usemodel = item.get("usemodel")
dropmodel = Reuse.Create(usemodel)
dropmodel.position = box.position
dropmodel.blenderObject["MainColor"] = [1.000000, 0.008796, 0.000000]
dropmodel.blenderObject["SecondaryColor"] = [1.000000, 0.500000, 0.000000]
# Remembering what it was
dropmodel["tool-attachment"] = dani["tool-attachment"]
if "dropped" not in bge.logic.globalDict:
bge.logic.globalDict["dropped"] = []
bge.logic.globalDict["dropped"].append(dropmodel)
dani["tool-attachment"] = None
tool["active-timer"] = 10
elif ray[1]:
closest = None
cldist = 10000
for dropmodel in bge.logic.globalDict.get("dropped", []):
distance = dropmodel.getDistanceTo(ray[1])
if distance < cldist:
closest = dropmodel
cldist = distance
if closest:
dropmodel = closest
Boxify(dropmodel)
# Taking it back
if ( mousecodes["LMB"] in mouse or mousecodes["RMB"] in mouse ) and not tool["active-timer"]:
dani["tool-attachment"] = dropmodel.get("tool-attachment")
Reuse.Delete(dropmodel)
tool["active-timer"] = 10
if tool.get("active-timer"): tool["active-timer"] -= 1

516
Scripts/Tools.py~ Normal file
View file

@ -0,0 +1,516 @@
# GPLv3 or any later version
# (C) J.Y.Amihud ( blenderdumbass )
# This file will dealwith tools and stuff.
import bge
import bpy
import aud
import math
import mathutils
from Scripts import Reuse
from Scripts.Common import *
from Scripts import Vehicle
from Scripts import Script
from Scripts import Garage
def MainLoop():
keys = bge.logic.globalDict["keys"]
mouse = bge.logic.globalDict["mouse"]
scene = bge.logic.getCurrentScene()
dani = scene.objects["Dani_Box"]
if dani.get("driving"):
return
camera = scene.active_camera
hand = scene.objects["Tool_Hand"]
hc = scene.objects["Health_Circle"]
box = scene.objects["Boxify"]
if box.get("timer"): box["timer"] -= 1
else: box.position = [0,0,-1000]
# If dani is using a fix tool
if str(dani.get("tool")) == "FixTool":
dis = 10000
car = None
for thecar in bge.logic.globalDict["allcars"]:
cd = thecar.getDistanceTo(dani)
if cd < dis:
dis = cd
car = thecar
ray = DaniPoint(dani, camera)
found = False
if car:
# First we gonna create a list of all objects
# that the car can get fixed.
attachment = dani.get("tool-attachment")
objs = []
if not Vehicle.OnGround(car):
objs = [car]
for wheel in car["wheels"]:
if ( wheel.visible and not attachment ) or attachment == "Wheels" :
objs.append(wheel)
for door in car.get("doors", []):
if ( door.visible and not attachment ) or attachment == "Parts" :
objs.append(door)
if "NitroCanProxy" in car.childrenRecursive and\
(( not car.get("NitroCan") and attachment == "Nitros") or ( car.get("NitroCan") and not attachment )):
objs.append(car.childrenRecursive["NitroCanProxy"])
if "SpoilerProxy" in car.childrenRecursive and\
( ( not car.get("Spoiler") and "Spoiler" in str(attachment) ) or ( car.get("Spoiler") and not attachment )):
objs.append(car.childrenRecursive["SpoilerProxy"])
if ray[1]:
point = ray[1]
d = 10
c = None
for obj in objs:
od = obj.getDistanceTo(point)
if od < d:
d = od
c = obj
if c:
found = True
if c not in car["wheels"]:
center = Boxify(c)
else:
center = Boxify(c, True)
text = ""
if c in car["wheels"]:
text = "Wheel"
elif str(c) == "NitroCanProxy":
text = "Nitros"
elif "Spoiler" in str(c):
text = "Spoiler"
elif c == car:
text = "Engine and Chassis"
elif c in car["doors"]:
text = "Bodywork"
orange = range(len(text))
text = text + "\n" + str(int(round(c.get("health", 1.0)*100)))+"%"
Script.StatusText(text, orange)
# Activate the tool
if mousecodes["LMB"] in mouse:
FixToolSound()
if str(c) == "NitroCanProxy":
Vehicle.AddNitroCan(car)
dani["tool-attachment"] = None
car["nitro"] = 10.0
if str(c) == "SpoilerProxy" and attachment:
spoilertype = Garage.shop.get(attachment, {}).get("usemodel")
Vehicle.AddSpoiler(car, spoilertype)
dani["tool-attachment"] = None
c["health"] = c.get("health", 1.0) + 0.01
if c["health"] >= 1.0:
c["health"] = 1.0
# Replacing mesh, to looks nice.
if c.get("Good"):
c.replaceMesh(c.get("Good"))
# Doors
if c in car["doors"]:
c["locked"] = True
rot = door.orientation.to_euler()
for i in range(3):
if i == door.get("axis",2):
rot[i] = door.get("lockat", 0)
else:
rot[i] = 0
c.orientation = rot
c.suspendPhysics()
door.orientation = rot
if c == car:
Vehicle.ChangeBody(car, good=True)
if c == car:
car["blown"] = False
if c["health"] > 0.1:
if not c.visible:
dani["tool-attachment"] = None
c.visible = True
# Removing parts
if mousecodes["RMB"] in mouse:
FixToolSound()
# Removing spoilers
if str(c) == "SpoilerProxy" and not attachment:
spoilertype = Vehicle.RemoveSpoiler(car)
for name in Garage.shop:
item = Garage.shop[name]
if item.get("usemodel") == spoilertype:
dani["tool-attachment"] = name
# Removing nitros
if str(c) == "NitroCanProxy" and not attachment:
Vehicle.RemoveNitroCan(car)
dani["tool-attachment"] = "Nitros"
# Removing bodywork
if c in car["doors"] and not attachment:
c["health"] = 0.0
c.visible = False
dani["tool-attachment"] = "Parts"
# Removing wheels
elif c in car["wheels"] and not attachment:
c["health"] = 0.0
c.visible = False
dani["tool-attachment"] = "Wheels"
# Shelf
if not found:
tool = dani["tool"]
closest = 5
theitem = ""
themodel = None
for name in Garage.inventory:
amount = Garage.inventory[name]
item = Garage.shop.get(name, {})
model = item.get('model')
if model: model= scene.objects[model]
if ( amount or name == dani.get("tool-attachment") ) and model:
d = dani.getDistanceTo(model)
if d < closest:
closest = d
theitem = name
themodel = model
if themodel:
name = theitem
amount = Garage.inventory[name]
item = Garage.shop.get(name, {})
printname = item.get("name", name)
Boxify(themodel)
Script.StatusText(printname+"\nIn Stock: "+str(amount), range(len(printname)))
if mousecodes["LMB"] in mouse and not tool.get("active-timer"):
tool["active-timer"] = 30
print("pressed", dani.get("tool-attachment"))
if not dani.get("tool-attachment"):
dani["tool-attachment"] = name
Garage.Use(name)
else:
name = dani["tool-attachment"]
if name not in Garage.inventory: Garage.inventory[name] = 1
else: Garage.inventory[name] += 1
Garage.UpdateShelfs()
dani["tool-attachment"] = None
# If not model
else:
ray = DaniPoint(dani, camera)
if dani.get("tool-attachment"):
# Telling the user that her can drop the part
if ray[1]:
box.position = ray[1]
box.position.z += 1
box.scaling = (1,1,1)
# Dropping the part
if mousecodes["LMB"] in mouse and ray[1] and not tool.get("active-timer"):
name = dani["tool-attachment"]
item = Garage.shop.get(name, {})
usemodel = item.get("usemodel")
dropmodel = Reuse.Create(usemodel)
dropmodel.position = box.position
dropmodel.blenderObject["MainColor"] = [1.000000, 0.008796, 0.000000]
dropmodel.blenderObject["SecondaryColor"] = [1.000000, 0.500000, 0.000000]
# Remembering what it was
dropmodel["tool-attachment"] = dani["tool-attachment"]
if "dropped" not in bge.logic.globalDict:
bge.logic.globalDict["dropped"] = []
bge.logic.globalDict["dropped"].append(dropmodel)
dani["tool-attachment"] = None
tool["active-timer"] = 10
elif ray[1]:
closest = None
cldist = 10000
for dropmodel in bge.logic.globalDict.get("dropped", []):
distance = dropmodel.getDistanceTo(ray[1])
if distance < cldist:
closest = dropmodel
cldist = distance
if closest:
dropmodel = closest
Boxify(dropmodel)
# Taking it back
if ( mousecodes["LMB"] in mouse or mousecodes["RMB"] in mouse ) and not tool["active-timer"]:
dani["tool-attachment"] = dropmodel.get("tool-attachment")
Reuse.Delete(dropmodel)
tool["active-timer"] = 10
if tool.get("active-timer"): tool["active-timer"] -= 1
# Tool attachment
if dani.get("tool-attachment"):
name = dani["tool-attachment"]
item = Garage.shop.get(name, {})
usemodel = item.get("usemodel")
if not dani.get("tool-attachment-model") and usemodel:
dani["tool-attachment-model"] = Reuse.Create(usemodel)
dani["tool-attachment-model"].suspendPhysics()
dani["tool-attachment-model"].blenderObject["MainColor"] = [1.000000, 0.008796, 0.000000]
dani["tool-attachment-model"].blenderObject["SecondaryColor"] = [1.000000, 0.500000, 0.000000]
s = item.get("usescale", 1)
dani["tool-attachment-model"].scaling = [s,s,s]
else:
usemodel = dani["tool-attachment-model"]
usemodel.position = Vehicle.RelativePoint(dani, (-0.5,-0.5,0.5))
usemodel.applyRotation((0.03,-0.01,0.05),False)
elif dani.get("tool-attachment-model"):
Reuse.Delete(dani["tool-attachment-model"])
dani["tool-attachment-model"] = None
# If dani is using a paint tool
elif str(dani.get("tool")) == "PaintTool":
ray = DaniPoint(dani, camera)
tool = dani["tool"]
if ray[0] in bge.logic.globalDict["allcars"]:
car = ray[0]
Boxify(car)
if mousecodes["LMB"] in mouse:
PaintToolSound()
if not tool.get("active-timer"):
Vehicle.SmartColor(car, "pallete")
tool["active-timer"] = 30
elif mousecodes["RMB"] in mouse:
PaintToolSound()
if not tool.get("active-timer"):
Vehicle.SmartColor(car)
tool["active-timer"] = 30
if tool.get("active-timer"): tool["active-timer"] -= 1
def UpdateTool(tool):
tool = tool.owner
scene = bge.logic.getCurrentScene()
dani = scene.objects["Dani_Box"]
hand = scene.objects["Tool_Hand"]
box = scene.objects["Boxify"]
icon = scene.objects["Dani_Tool_Icon"]
if "taken" not in tool:
tool["taken"] = None
tool["wasat"] = tool.position.copy()
if not tool["taken"]:
if dani.getDistanceTo(tool["wasat"]) < 2 and not tool.get("timer") and not dani.get("tool"):
tool["taken"] = dani
tool["timer"] = 100
dani["tool"] = tool
tool.position = hand.position
tool.orientation = hand.orientation
tool.setParent(hand, True)
icon.blenderObject["raw"] = tool.get("icon_raw", 1)
icon.blenderObject["column"] = tool.get("icon_column", 0)
tool.applyRotation([0,0,0.1], False)
elif dani.getDistanceTo(tool["wasat"]) < 2 and not tool.get("timer"):
tool["taken"] = None
tool["timer"] = 100
dani["tool"] = None
box.position = [0,0,-1000]
tool.removeParent()
tool.position = tool["wasat"]
tool.orientation = [0,0,0]
Script.StatusText(" ")
icon.blenderObject["raw"] = 1
icon.blenderObject["column"] = 0
if tool.get("timer"): tool["timer"] -= 1
def Boxify(obj, orcenter=False):
# This function will draw a box around the object
scene = bge.logic.getCurrentScene()
box = scene.objects["Boxify"]
box["timer"] = 10
if not orcenter:
# Finding bounding box
bbox = obj.blenderObject.bound_box
# finding the center of the box
center = 0.125 * sum((mathutils.Vector(b) for b in bbox), mathutils.Vector())
center.rotate(obj.orientation)
center * obj.scaling
center = obj.position + center
box.position = center
else:
box.position = obj.position
center = obj.position
box.orientation = obj.orientation
box.scaling = obj.blenderObject.dimensions
return center
def DaniPoint(dani, camera):
# Then we want to see if any of them are pointed at
fro = dani.position.copy()
fro.z += 1
to = fro.copy()
to.z -= 1
to -= fro
to.rotate(camera.worldOrientation.to_euler())
to += fro
ray = Vehicle.BeautyRayCast(dani, "tool", to, fro, dist=5)
return ray
#### SOUNDS #####
def FixToolSound():
# Engine Sound
device = bge.logic.globalDict["SoundDevice"]
code = "//sfx/fixtool.ogg"
if code not in bge.logic.globalDict["sounds"]:
bge.logic.globalDict["sounds"][code] = {"sound":aud.Sound(bge.logic.expandPath(code)),
"play":None}
sound = bge.logic.globalDict["sounds"][code]
if not sound["play"] or not sound["play"].status:
sound["play"] = device.play(sound["sound"])
sound["play"].volume = 1
def PaintToolSound():
# Engine Sound
device = bge.logic.globalDict["SoundDevice"]
code = "//sfx/painttool.ogg"
if code not in bge.logic.globalDict["sounds"]:
bge.logic.globalDict["sounds"][code] = {"sound":aud.Sound(bge.logic.expandPath(code)),
"play":None}
sound = bge.logic.globalDict["sounds"][code]
if not sound["play"] or not sound["play"].status:
sound["play"] = device.play(sound["sound"])
sound["play"].volume = 1

View file

@ -11,6 +11,7 @@ import random
import numpy
import aud
import mathutils
import traceback
from Scripts import Reuse
@ -136,8 +137,11 @@ def UpdateCar(car):
# Make sure this car is not deleted when we see it
if CloseToCamera(car, 200):
if car in Reuse.reuse.get(car.name):
if car in Reuse.reuse.get(car.name, []):
Reuse.reuse[car.name].remove(car)
if car.get("driver"):
driver = car.get("driver")
Character_Controll.getIntoCar(driver, car, immediately=True)
print(consoleForm(car),clr["bold"]+clr["tdyl"],"Removed from Reuse.", clr["norm"])
car["nodespawn"] = 100
if car not in bge.logic.globalDict["allcars"]:
@ -169,11 +173,21 @@ def UpdateCar(car):
elif car.get("racing"):
RacingAI(car)
elif NetworkControlled(car):
pass
# If nobody controls the car.
else:
IdleBraking(car)
# Network control
if NetworkControlled(car):
NetworkControl(car)
# Apply Turn
ApplyTurn(car)
@ -188,10 +202,14 @@ def UpdateCar(car):
z = -DownForce(car)
car.applyForce([x, y, 0], True)
car.applyForce([0, 0, z], True)
if not car.get("underwater"):
car.applyTorque([-z/2*(car.localLinearVelocity[1] < 0)
, 0,0], True)
#if not car.get("underwater"):
# car.applyTorque([-z/2*(car.localLinearVelocity[1] < 0)
# , 0,0], True)
if car.get("handbraking"):
HandBraking(car)
# Give car the sound
EngineSound(car)
DriftSound(car)
@ -267,8 +285,8 @@ def PhysicsUpdate(car):
# Making sure to clear the acceleration
# for the next frame.
if not car.get("braking"):
car["driftturn"] = 0.0
# if not car.get("braking"):
# car["driftturn"] = 0.0
car["accelerating"] = False
car["braking"] = False
@ -540,6 +558,16 @@ def MouseControl(car):
mouse = bge.logic.mouse
pos = list(mouse.position)
# Centering the cursor when pressing RMB
mouseinput = bge.logic.globalDict["mouse"]
if mousecodes["RMB"] in mouseinput:
Mouse.CenterCursor()
# LMB brakes
if mousecodes["LMB"] in mouseinput:
v = -car.localLinearVelocity[1]
ActivateBreaks(car, v, True)
# Making sure that the mouse doesn't escape the window
if pos[0] > 0.9:
@ -581,7 +609,7 @@ def MouseControl(car):
if pos[1] > bs or pos[1] < -bs:
pos[1] = (( (pos[1] * p1) * (1+bs) ) - bs) * p1
pos[1] = ( ( ( pos[1] * p1 ) ** 3 ) * p1)
pos[1] = ( ( ( pos[1] * p1 ) ** 2 ) * p1)
Accelerate(car, -pos[1] , mouse=True)
else:
pos[1] = 0.0
@ -593,7 +621,7 @@ def MouseControl(car):
IdleBraking(car)
car["turn"] = -( ( ( pos[0] * p0 ) ** 3 ) * p0)
car["turn"] = -( ( ( pos[0] * p0 ) ** 2 ) * p0)
# UI indication
turnpiece = scene.objects["Mouse_Turn_UI_Piece"]
@ -636,7 +664,9 @@ def Accelerate(car, factor=1, mouse=False):
def ActivateBreaks(car, factor=1, stable=False):
# Activating brakes.
strenght = factor
if strenght < 0: strenght *= -1
Abs = ABS(car)
turn = Turning(car)
for n, wheel in enumerate(car["specs"]["wheels"]):
@ -647,12 +677,12 @@ def ActivateBreaks(car, factor=1, stable=False):
# If the car moves forward stopping only with back
# wheels so it will not fly into the air.
if ( factor < 0 and not wheel["front"] ) or ( factor > 0 and wheel["front"] ):
getCarPhysics(car).applyBraking(Abs*health, n)
getCarPhysics(car).applyBraking(Abs*health*strenght, n)
else:
getCarPhysics(car).applyBraking(0, n)
# Stablizing the brakes
if stable:
if stable and car["specs"].get("stableBrake", True):
r = car.localAngularVelocity[2]
car.applyTorque([0,0,-r*car.mass*20], True)
@ -1180,7 +1210,7 @@ def ApplyEngine(car):
for n, wheel in enumerate(car["specs"]["wheels"]):
wheelObject = car["wheels"][n]
health = wheelObject["health"] ** 2
health = (wheelObject["health"] + car["health"]) / 2
rightwheel = ( wheel["front"] and force > 1 ) or ( not wheel["front"] and force < 1 )
@ -1191,7 +1221,7 @@ def ApplyEngine(car):
# Decrease RPMS
if not car.get("accelerating"):
if not car.get("accelerating") and not NetworkControlled(car):
car["rpm"] *= 0.98 * EngineResistance(car)
def ApplyTurn(car):
@ -1224,11 +1254,15 @@ def ApplyTurn(car):
v = vo
if v < 0: v *= -1
if v > 0.01 and vo < 0:
car.applyTorque([0,0,car["turn"] * 20 * car.mass],True)
elif v > 0.01 and vo > 0:
car.applyTorque([0,0,car["turn"] * -20 * car.mass],True)
if not car.get("handbraking", 0):
S = car["specs"].get("turnFake", 20)
if v > 0.01 and vo < 0:
car.applyTorque([0,0,car["turn"] * S * car.mass],True)
elif v > 0.01 and vo > 0:
car.applyTorque([0,0,car["turn"] * -S * car.mass],True)
# Auto going straiter
if not car.get("turning"):
@ -1246,21 +1280,27 @@ def ApplyTurn(car):
def TurnRight(car):
toFPS = Opt.ToFPS()
settings = bge.logic.globalDict.get("settings", {})
if car["turn"] > 0: car["turn"] *= -0.5
car["turn"] -= 0.005 * toFPS
car["turn"] -= 0.005 * toFPS * settings.get("turn", 1.0)
car["turning"]= True
def TurnLeft(car):
toFPS = Opt.ToFPS()
settings = bge.logic.globalDict.get("settings", {})
if car["turn"] < 0: car["turn"] *= -0.5
car["turn"] += 0.005 * toFPS
car["turn"] += 0.005 * toFPS * settings.get("turn", 1.0)
car["turning"]= True
def HandBrake(car):
car["handbraking"] = 30
def HandBraking(car):
# This is an implementation of
# a fake handbrake. It is fake
# since normal drifting could
@ -1272,8 +1312,38 @@ def HandBrake(car):
# that is used instead to approximate
# the behaviour of the drift.
cv = car.localLinearVelocity
v = cv.y
if v <0: v *= -1
car["handbraking"] = car.get("handbraking", 30) - 1
if v < 10:
car["handbraking"] = 0
if car.get("accelerating"):
return
turning = Turning(car)
if turning and not car["handbraking"]:
car["handbraking"] = 2
hbf = car["handbraking"] / 30
if car["handbraking"] <= 0:
car["driftturn"] = 0.0
if not OnGround(car):
return
factor = car.localLinearVelocity[1]
ActivateBreaks(car, factor)
if factor > 0: factor = 1.0
else : factor = -1.0
if car.get("accelerating"):
factor /= 20
ActivateBreaks(car, factor*hbf)
# Recording the turn at which the drift started.
@ -1285,14 +1355,24 @@ def HandBrake(car):
if dt < 0: dt *= -1
# If turn increased in the same direction as the drift turn, we increase drift turn
if dt > Turning(car) and ( ( car.get("driftturn",0 ) < 0 ) == ( car["turn"] < 0 ) ):
car["driftturn"] = float(car["turn"])
if ( dt < turning and ( ( car.get("driftturn",0 ) < 0 ) == ( car["turn"] < 0 ) ) )\
or not car.get("driftturn",0 ):
car["driftturn"] = float(car["turn"])
# Adding fake turn to the car
car.applyTorque([-car.mass*5,
car.applyTorque([0,
0,
car["driftturn"]*car.mass*10
((car["driftturn"])+(car["turn"]/2))*car.mass*5*hbf
], True)
# Instead of reducing friction on the wheels, this
# will simulate that, but with more control.
if car.get("accelerating"):
cv.x += -car["driftturn"] * v / 50 *hbf
cv.y += turning * v / 20 * hbf
car.applyForce(cv * car.mass * 0.5 * hbf, True)
def Turning(car):
@ -1663,7 +1743,7 @@ def OnCollision(car, obj, point, normal, points):
# For when we collide with water, we want to
# make it so the car will behave underwaterly.
if "water" in str(material).lower():
if "water" in str(material).lower() or "water" in str(obj).lower():
# Setting car as underwater
if not car.get("underwater"):
@ -1748,10 +1828,10 @@ def OnCollision(car, obj, point, normal, points):
# Scrape sound
if force < 2:
ScrapeSound(car, position=point.worldPoint, volume=max(1,min(3,force)))
if force < 0.1:
ScrapeSound(car, position=point.worldPoint, volume=max(1,min(3,force*200)))
else:
HitSound(car, position=point.worldPoint, volume=min(3,force/20))
HitSound(car, position=point.worldPoint, volume=min(3,force/2))
# For each wheel, we are going to specify health as well
# so that the car to loose handling as well as engine power
@ -1762,7 +1842,7 @@ def OnCollision(car, obj, point, normal, points):
wheelObject = car["wheels"][n]
if ( wheel["xyz"][0] < 0 ) == ( point.localPointA[0] < 0 ) \
and ( wheel["xyz"][1] < 0 ) == ( point.localPointA[1] < 0 ) :
wheelObject["health"] = max(0, wheelObject["health"] - ( force / 100 ))
wheelObject["health"] = max(0, wheelObject["health"] - ( force / 50 ))
# Popping the wheel.
@ -1831,6 +1911,8 @@ def OnCollision(car, obj, point, normal, points):
car.worldLinearVelocity = [0,0,10]
car.localAngularVelocity = [10,0,0]
character["carblewup"] = car
character["target"] = car.get("target")
for p in car.get("passangers", []):
Character_Controll.getOutCar(p)
@ -1886,12 +1968,12 @@ def Material(car, value=(0,1,0), attribute="MainColor"):
for obj in car.childrenRecursive:
ColorPart(car, obj)
for wheel in car["wheels"]:
for wheel in car.get("wheels", []):
ColorPart(car, wheel)
# Neon
if attribute == "SecondaryColor":
if attribute == "SecondaryColor" and car in bge.logic.globalDict["cars"]:
if "Neon" not in car:
light = Reuse.Create("NeonLamp")
light.blenderObject.data = light.blenderObject.data.copy()
@ -1916,7 +1998,7 @@ def SmartColor(car, color=None):
Material(car, value, attribute)
elif color == "random":
for attribute in car["specs"].get("material", []):
for attribute in ["MainColor", "SecondaryColor"]:
value = (random.random(),
random.random(),
random.random())
@ -2025,8 +2107,10 @@ def ChangeBody(car, good=False):
body["good"] = body.meshes[0].name
# And then execute the change of mesh
body.replaceMesh(car.get("borked", "Borked"))
GlassSound(car, position=car.position, volume=3)
if not body.get("mesh", "Good") == "Borked":
body.replaceMesh(car.get("borked", "Borked"))
GlassSound(car, position=car.position, volume=3)
body["mesh"] = "Borked"
if "Neon" in car:
car["Neon"].blenderObject.data.energy = 0
@ -2034,7 +2118,9 @@ def ChangeBody(car, good=False):
# Otherwise restore the car
else:
try:
body.replaceMesh(body["good"])
if not body.get("mesh", "Good") == "Good":
body.replaceMesh(body["good"])
body["mesh"] = "Good"
except:
pass
@ -2052,13 +2138,14 @@ def SmokeAndFire(car):
smokeCoefitient = max(0, 1-health*2)*0.1
fireCoefitient = max(0, 1-health*4)*0.1
smokeemiter = car.children["SmokeEmmiter"]
Destruction.Smoke(smokeemiter.position, smokeCoefitient)
Destruction.Smoke(smokeemiter.position, smokeCoefitient, smokeemiter.scaling.x)
Destruction.Fire(smokeemiter.position, fireCoefitient)
if "FireBall" not in car and health < 0.3:
car["FireBall"] = Destruction.AttatchFireBall(smokeemiter.position,
smokeemiter,
1.5)
car["FireBall"].scaling = smokeemiter.scaling
else:
RemoveFireBall(car)
@ -2567,7 +2654,8 @@ def SpawnLogic(camSurroundCars):
# If it's way too close, abort
if len(spawnSorted) > n+1 and distance < 100 \
and spawn.get("npc") != "racer":
and spawn.get("npc") != "racer"\
and not spawn.get("priority") == True:
continue
# Spawn timer ( to avoid, over spawning )
@ -2600,12 +2688,18 @@ def SpawnLogic(camSurroundCars):
aftercheck = False
# For NPC cars
if ( spawn.get("npc") == "npc" )\
if ( spawn.get("to_spawn", True) or spawn.get("npc") == "npc" )\
or ( spawn.get("npc") == "racer" and aftercheck
and spawn.get("to_spawn") and ( not dani.get("race") or duringcheck )):
# Spawning the car.
driver = "Man1Box"
if not spawn.get("npc"):
carModel = spawn.get("spawn")
driver = None
car = Spawn(
carModel,
spawn["position"],
@ -2613,9 +2707,11 @@ def SpawnLogic(camSurroundCars):
True,
"pallete",
spawnanyway=False,
spawn=spawn)
spawn=spawn,
driver=driver)
if not car and (spawnedCars < maxCars or spawn.get("npc") == "racer"):
if not car and (spawnedCars < maxCars or spawn.get("npc") == "racer"\
or spawn.get("priority")):
car = Spawn(
carModel,
@ -2624,7 +2720,8 @@ def SpawnLogic(camSurroundCars):
True,
"pallete",
spawnanyway=True,
spawn=spawn)
spawn=spawn,
driver=driver)
if not car: return
@ -2645,6 +2742,7 @@ def SpawnLogic(camSurroundCars):
spawn["to_spawn"] = False
car["spawn"] = spawn
return
def Spawn(carname, position, orientation,
@ -2652,11 +2750,16 @@ def Spawn(carname, position, orientation,
color=None, # What color to assign to the car
spawnanyway=True, # Spawn it no matter what.
anything=False, # Spawn anything at all.
spawn=None): # Spawn data from SpawnLogic()
spawn=None, # Spawn data from SpawnLogic()
driver=None):
# This function is simplify spawning
#traceback.print_stack()
# This function is to simplify spawning
# of the car.
cam = bge.logic.getCurrentScene().active_camera
# If we recieved a name of a car and not an object.
if type(carname) == str:
@ -2752,6 +2855,42 @@ def Spawn(carname, position, orientation,
pass
# Adding a driver
if driver:
if not car.get("driver"):
if "drivers" not in bge.logic.globalDict:
bge.logic.globalDict["drivers"] = []
found = False
for d in bge.logic.globalDict["drivers"]:
if d.name == driver and d.getDistanceTo(cam) > 200\
and not d.get("driving"):
driver = d
Character_Controll.getOutCar(driver)
found = True
print(consoleForm(driver),clr["tdgr"], "reusing driver", clr["norm"])
if not found:
driver = Reuse.Create(driver)
bge.logic.globalDict["drivers"].append(driver)
SmartColor(driver, "random")
print(consoleForm(driver),clr["tdrd"], "new driver", clr["norm"])
Character_Controll.getIntoCar(driver, car, immediately=True)
elif car.get("driver"):
print(consoleForm(car),clr["tdrd"], "Driver Deleted", clr["norm"])
driver = car["driver"]
car["driver"] = ""
Character_Controll.getOutCar(driver)
Reuse.Delete(driver)
print(consoleForm(car), consoleForm(car.get("driver")), car.get("npc"))
return car
@ -2966,6 +3105,13 @@ def AngryPursuit(car):
if target.get("blown"):
car["npc"] = "npc"
# Getting the target car
elif not target.get("driver") and car.get("driver") and target in bge.logic.globalDict["cars"]:
driver = car["driver"]
Character_Controll.getOutCar(driver)
driver["NPCcar"] = target
car["npc"] = ""
if car.get("blown"):
car["npc"] = ""
@ -2998,8 +3144,12 @@ def AngryPursuit(car):
nitro = False
if ontarget > -0.3:
Accelerate(car, 1)
#car["turn"] = turn
if vect[0] > 5:
Accelerate(car, 1)
else:
Accelerate(car, -1)
SoftTurn(car, turn)
if OnGround(car):
nitro = True
@ -3253,7 +3403,7 @@ def RacingAI(car):
# If there is a nessesity, use handbrake.
if t > 0.3 and v > 7 and onground:
HandBrake(car)
ActivateBreaks(car, v)
# Applying acceleration. ( also ignore the accel if you see that the road is straight )
if v < accel or (ontarget > 0.8
@ -3361,6 +3511,10 @@ def ResqueRacer(car, visible=True):
try: checkpoint1 = race["checkpoints"][ checknumber - 1 ]
except: checkpoint1 = race["checkpoints"][ 0 ]
try: checkpoint0 = race["checkpoints"][ checknumber - 2 ]
except: checkpoint0 = race["checkpoints"][ 0 ]
while checkpoint1.get("OnLoop"):
print(car, checkpoint1.get("OnLoop"), checknumber)
checknumber -= 1
@ -3380,7 +3534,7 @@ def ResqueRacer(car, visible=True):
# Fixing wheels
for wheel in car.get("wheels", []):
wheel["health"] = max(wheel["health"], 0.7)
wheel["health"] = max(wheel["health"], 0.5)
wheel.visible = True
# Nothing is done to restore the look of the car, so the user will be
@ -3409,10 +3563,14 @@ def ResqueRacer(car, visible=True):
# car.orientation = targets.get("rot")
# else:
tocheck = car.getVectTo(checkpoint2["location"])
# tocheck = car.getVectTo(checkpoint0["location"])
# car.alignAxisToVect(tocheck[1], 1, 0.5)
car.alignAxisToVect( (0,0,1), 2, 1.0 )
car.alignAxisToVect(-tocheck[1], 1, 1.0)
tocheck = car.getVectTo(checkpoint2["location"])
car.alignAxisToVect(-tocheck[1], 1, 1)
#if UpSideDown(car):
@ -3566,21 +3724,22 @@ def VisionTurn(car, return_min=False):
road = "ROAD"
vo = car.get("visionOffset", 0)
vs = car["specs"].get("visionSize", 1.0)
# Making sure we scan a wider range
height = -3#random.uniform(-6, -3)
height = -3*vs#random.uniform(-6, -3)
width = -10#random.uniform(-15, -10)
# Getting the rays
toright = RelativePoint(car, (-5, width, height))
fromright = RelativePoint(car, (-0.8,0+vo,0.5))
fromright = RelativePoint(car, (-0.8*vs,0+vo,0.5*vs))
rightray = BeautyRayCast(car, "right", toright, fromright, dist=50, poly=True)
try: rightm = str(rightray[3].material).upper()
except:rightm = ""
# And for the left too
toleft = RelativePoint(car, (5, width, height))
fromleft = RelativePoint(car, (0.8,0+vo,0.5))
fromleft = RelativePoint(car, (0.8*vs,0+vo,0.5*vs))
leftray = BeautyRayCast(car, "left", toleft, fromleft, dist=50, poly=True)
try: leftm = str(leftray[3].material).upper()
except:leftm = ""
@ -3588,14 +3747,14 @@ def VisionTurn(car, return_min=False):
# Upper Forward rays
toupright = RelativePoint(car, (-5, width, 0.5))
fromupright = RelativePoint(car, (-0.8,0+vo,0.5))
fromupright = RelativePoint(car, (-0.8*vs,0+vo,0.5*vs))
uprightray = BeautyRayCast(car, "upright", toupright, fromupright, dist=50, poly=True)
try: uprightm = str(uprightray[3].material).upper()
except:uprightm = ""
toupleft = RelativePoint(car, (5, width, 0.5))
fromupleft = RelativePoint(car, (0.8,0+vo,0.5))
fromupleft = RelativePoint(car, (0.8*vs,0+vo,0.5*vs))
upleftray = BeautyRayCast(car, "upleft", toupleft, fromupleft, dist=50, poly=True)
try: upleftm = str(upleftray[3].material).upper()
except:upleftm = ""
@ -3606,13 +3765,13 @@ def VisionTurn(car, return_min=False):
# Forward ray
#if return_min:
toforward = RelativePoint(car, (0, -10, -1))
fromforward = RelativePoint(car, (0,-2+vo,0.5))
fromforward = RelativePoint(car, (0,-2+vo,0.5 *vs))
forwardray = BeautyRayCast(car, "forward", toforward, fromforward, dist=50, poly=True)
try: forwardm = str(forwardray[3].material).upper()
except:forwardm = ""
toupforward = RelativePoint(car, (0, -10, 0.5))
fromupforward = RelativePoint(car, (0,-2+vo,0.5))
fromupforward = RelativePoint(car, (0,-2+vo,0.5*vs))
upforwardray = BeautyRayCast(car, "upforward", toupforward, fromupforward, dist=50, poly=True)
try: upforwardm = str(upforwardray[3].material).upper()
except:upforwardm = ""
@ -3666,9 +3825,10 @@ def VisionTurn(car, return_min=False):
mindist = min(left, right, forward, upright, upleft)
#maxdist = max(left, right, forward, upright, upleft)
st = 5
st = 5 / vs
turn = max(-0.8, min(0.8, (( max(0, min(1, ( right / st ))) - max(0, min(1, ( left / st ))) ) *-2 )))
turn /= ( vs ** 2 )
# Another version of the turn calculation
# minturn = min(left, right)
@ -4146,6 +4306,13 @@ def HitEnemySound(car):
#### SAVE / MULTIPLAYER FUNCTIONS #####
def EncodeRotation(car):
rot = list(car.worldOrientation)
for n, i in enumerate(rot):
rot[n] = list(i)
return rot
def Encode(car):
# This function will generate a copy of the car's
@ -4159,9 +4326,18 @@ def Encode(car):
"cid" : int(car["cid"]),
"netId" : car.get("netId"),
"position" : list(car.position),
"orientation" : list(car.orientation.to_euler())
"orientation" : EncodeRotation(car),
"linvelocity" : list(car.worldLinearVelocity),
"angvelocity" : list(car.worldAngularVelocity),
"npc" : car.get("npc", ""),
"rpm" : car.get("rpm", 0),
"gear" : car.get("gear", 0),
"turn" : car.get("turn", 0)
}
# Health data
cardata["health"] = car.get("health" , 1.0)
cardata["nitro"] = car.get("nitro" , 0.0)
@ -4220,6 +4396,11 @@ def Decode(cardata, new=False, network=False):
if netId and netId not in netObjects["netId"] or new:
car = Spawn(carModel, position, orientation)
for attribute in cardata.get("colors", {}):
value = cardata["colors"][attribute]
Material(car, value, attribute)
UpdateCar(car)
print("Spawned cause", netId, "netId isn't in", list(netObjects["netId"].keys()))
@ -4232,10 +4413,28 @@ def Decode(cardata, new=False, network=False):
car["netId"] = netId
car["ownerId"] = cardata.get("ownerId")
if math.dist(car.position, position) > 0.1:
car.position = position
if math.dist(car.orientation.to_euler(), orientation) > 0.1:
car.orientation = orientation
if network:
latency = Multiplayer_Client.Latency(car)
else:
latency = 0
car["npc"] = cardata.get("npc", "")
car["rpm"] = cardata.get("rpm", 0)
car["gear"] = cardata.get("gear", 0)
car["turn"] = cardata.get("turn", 0)
car.worldLinearVelocity = cardata.get("linvelocity", car.localLinearVelocity)
car.worldAngularVelocity = cardata.get("angvelocity", car.localAngularVelocity)
position = mathutils.Vector(position)+(car.worldLinearVelocity*latency)
if math.dist(car.position, position) > 5:
car.position = position
car.worldOrientation = orientation
#car.applyRotation(car.worldAngularVelocity*latency,False)
# Health stuff
@ -4265,7 +4464,8 @@ def Decode(cardata, new=False, network=False):
# Restoring the door
door["health"] = doordata.get("health", 1.0)
door["locked"] = doordata.get("locked", True)
door.visible = doordata.get("visible", True)
if door.visible != doordata.get("visible", True):
door.visible = doordata.get("visible", True)
if door["health"] < 1.0:
if "Borked" in door and door.get("mesh", "Good") != "Borked":
@ -4285,9 +4485,9 @@ def Decode(cardata, new=False, network=False):
wheel.visible = wheeldata.get("visible", True)
# Colors
for attribute in cardata.get("colors", {}):
value = cardata["colors"][attribute]
Material(car, value, attribute)
#for attribute in cardata.get("colors", {}):
# value = cardata["colors"][attribute]
# Material(car, value, attribute)
def RemoveNetId(car):
@ -4303,8 +4503,16 @@ def RemoveNetId(car):
if netId in netCars:
del car["netId"]
del netCars[netId]
def NetworkControlled(car):
return car.get("netId") in bge.logic.globalDict.get("netObjects", {}).get("netId", {})\
and car.get("onwerId") != bge.logic.globalDict.get("userId")
def NetworkControl(car):
return
#### DEBUGGIN FUNCTIONS ######
def DrawLine(car, name, point1, point2):

4560
Scripts/Vehicle.py~ Normal file

File diff suppressed because it is too large Load diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

38
Tux_license.txt Normal file
View file

@ -0,0 +1,38 @@
Tux (Linux) Kart by Julian Schönbächler for SuperTuxKart
Last edited on 15.03.2015
Please contact me for any use which is not allowed by this license.
Julian Schönbächler
http://creative-forge.ch/
info@creative-forge.ch
Character information:
----------------------------------------------------------------------------
Tux is the official mascot of the Linux kernel. Tux is also the most
commonly used icon for Linux.
See for example: http://www.linux.org/
License information:
----------------------------------------------------------------------------
- Creative Commons Attribution-ShareAlike 3.0 Unported (CC BY-SA 3.0)
Visit the following link for detailed informations:
http://creativecommons.org/licenses/by-sa/3.0/
- GNU General Public License (GPL)
Visit following the link for detailed informations:
http://www.gnu.org/licenses/gpl
Licensing of this work
----------------------------------------------------------------------------
Tux 2dVector icon: "tux_icon.png"
- GPL / Author: yekCim
Tux textures
- CC BY-SA 3.0 / Author: Julian Schönbächler
Tux all other kart files
- CC BY-SA 3.0 / Author: Julian Schönbächler

Binary file not shown.

View file

@ -28,6 +28,10 @@
"Frames":[340,353]
},
"SwimIdle":{
"Frames":[400,450]
},
"Fly":{
"Frames":[358,371],
"kwargs":{"priority":-1,

View file

@ -0,0 +1,61 @@
{
"Talk":{
"Action":"DaniEmotions",
"Frames":[0, 10],
"kwargs":{"layer":3}
},
"Laugh":{
"Action":"DaniEmotions",
"Frames":[10, 20],
"kwargs":{"layer":3}
},
"Stand":{
"Frames":[0, 290]
},
"Walk":{
"Frames":[301, 313]
},
"Drive":{
"Frames":[330,330]
},
"Swim":{
"Frames":[340,353]
},
"Fly":{
"Frames":[358,371],
"kwargs":{"priority":-1,
"blendin":5}
},
"Hang":{
"Frames":[390,390],
"kwargs":{"priority":-1}
},
"Land":{
"Frames":[371,384],
"kwargs":{"priority":-1}
},
"AnswerPhone":{
"Action":"DanisPhone",
"Frames":[32, 100],
"kwargs":{"layer":2},
"Keep":true
},
"PutPhoneAway":{
"Action":"DanisPhone",
"Frames":[0, 32],
"kwargs":{"layer":2}
}
}

View file

@ -0,0 +1,15 @@
{
"Stand":{
"Frames":[0,300]
},
"Walk":{
"Frames":[330, 350]
},
"Drive":{
"Frames":[360,361]
}
}

14
animdata/chr/Man1Box.json Normal file
View file

@ -0,0 +1,14 @@
{
"Stand":{
"Frames":[0,276]
},
"Walk":{
"Frames":[300, 332]
},
"Drive":{
"Frames":[335,335]
}
}

View file

@ -0,0 +1,14 @@
{
"Stand":{
"Frames":[0,276]
},
"Walk":{
"Frames":[300, 320]
},
"Drive":{
"Frames":[325,325]
}
}

View file

@ -0,0 +1,7 @@
{
"Stand":{
"Frames":[0,276]
}
}

View file

@ -7,11 +7,16 @@
"Frames":[0, 290]
},
"Drive":{
"Frames":[350,351]
},
"Talk":{
"Action":"PapsTalk",
"Frames":[0, 10],
"kwargs":{"layer":3}
}
}

View file

@ -0,0 +1,17 @@
{
"Walk":{
"Frames":[301, 330]
},
"Stand":{
"Frames":[0, 290]
},
"Talk":{
"Action":"PapsTalk",
"Frames":[0, 10],
"kwargs":{"layer":3}
}
}

Binary file not shown.

BIN
assembly.blend1 Normal file

Binary file not shown.

BIN
assembly_copy.blend Normal file

Binary file not shown.

BIN
assembly_copy.blend1 Normal file

Binary file not shown.

BIN
ast/chr/Man1.blend Normal file

Binary file not shown.

BIN
ast/chr/Man1.blend1 Normal file

Binary file not shown.

BIN
ast/chr/Moria.blend Normal file

Binary file not shown.

BIN
ast/chr/Moria.blend1 Normal file

Binary file not shown.

BIN
ast/loc/City_source.blend1 Normal file

Binary file not shown.

BIN
ast/loc/city.blend1 Normal file

Binary file not shown.

Binary file not shown.

BIN
ast/veh/DarkShadow.blend1 Normal file

Binary file not shown.

BIN
ast/veh/HatchBack01.blend1 Normal file

Binary file not shown.

BIN
ast/veh/Kart.blend Normal file

Binary file not shown.

BIN
ast/veh/Kart.blend1 Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
ast/veh/RedKiss.blend1 Normal file

Binary file not shown.

BIN
ast/veh/Truck.blend1 Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -7,10 +7,10 @@
"SecondaryColor":[1.000000, 0.147027, 0.000000]},
"wheels":[
{ "radius":0.425, "xyz":[ 0.915, -1.427, -0.150], "down":[0,0,-1], "axel":[-1,0,0], "suspensionRest": 0.2, "front":true , "object":""},
{ "radius":0.425, "xyz":[-0.915, -1.427, -0.150], "down":[0,0,-1], "axel":[-1,0,0], "suspensionRest": 0.2, "front":true , "object":".001"},
{ "radius":0.425, "xyz":[-0.915, 1.184, -0.150], "down":[0,0,-1], "axel":[-1,0,0], "suspensionRest": 0.2, "front":false, "object":".003"},
{ "radius":0.425, "xyz":[ 0.915, 1.184, -0.150], "down":[0,0,-1], "axel":[-1,0,0], "suspensionRest": 0.2, "front":false, "object":".002"}
{ "radius":0.425, "xyz":[ 0.915, -1.427, 0.150], "down":[0,0,-1], "axel":[-1,0,0], "suspensionRest": 0.2, "front":true , "object":""},
{ "radius":0.425, "xyz":[-0.915, -1.427, 0.150], "down":[0,0,-1], "axel":[-1,0,0], "suspensionRest": 0.2, "front":true , "object":".001"},
{ "radius":0.425, "xyz":[-0.915, 1.184, 0.150], "down":[0,0,-1], "axel":[-1,0,0], "suspensionRest": 0.2, "front":false, "object":".003"},
{ "radius":0.425, "xyz":[ 0.915, 1.184, 0.150], "down":[0,0,-1], "axel":[-1,0,0], "suspensionRest": 0.2, "front":false, "object":".002"}
],
"mass" : 1993 ,

View file

@ -0,0 +1,43 @@
{
"name":"Dark Shadow",
"probability":1,
"type":"race-car",
"material":{"MainColor" :[0.033096, 0.033096, 0.033096],
"SecondaryColor":[1.000000, 0.147027, 0.000000]},
"wheels":[
{ "radius":0.425, "xyz":[ 0.915, -1.427, -0.150], "down":[0,0,-1], "axel":[-1,0,0], "suspensionRest": 0.2, "front":true , "object":""},
{ "radius":0.425, "xyz":[-0.915, -1.427, -0.150], "down":[0,0,-1], "axel":[-1,0,0], "suspensionRest": 0.2, "front":true , "object":".001"},
{ "radius":0.425, "xyz":[-0.915, 1.184, -0.150], "down":[0,0,-1], "axel":[-1,0,0], "suspensionRest": 0.2, "front":false, "object":".003"},
{ "radius":0.425, "xyz":[ 0.915, 1.184, -0.150], "down":[0,0,-1], "axel":[-1,0,0], "suspensionRest": 0.2, "front":false, "object":".002"}
],
"mass" : 1993 ,
"hp" : 610 ,
"torque" : 100 ,
"drag" : 0.5 ,
"roll" : -0.4 ,
"grip" : 0.3 ,
"maxturn" : 0.8 ,
"brakes" : 2.0 ,
"abs" : 0.01 ,
"downforce" : 2.0 ,
"suspention" : 100.0 ,
"suspentionDamping" : 0.8 ,
"maxrpm" : 8000 ,
"idle" : 1100 ,
"redline" : 6000 ,
"gears":[
5.00,
3.00,
2.00,
1.00,
0.75,
0.50,
0.25,
0.20,
0.15
]
}

View file

@ -0,0 +1,39 @@
{
"name":"Dark Shadow",
"probability":1,
"wheels":[
{ "radius":0.425, "xyz":[ 0.915, -1.427, -0.150], "down":[0,0,-1], "axel":[-1,0,0], "suspensionRest": 0.2, "front":true , "object":""},
{ "radius":0.425, "xyz":[-0.915, -1.427, -0.150], "down":[0,0,-1], "axel":[-1,0,0], "suspensionRest": 0.2, "front":true , "object":".001"},
{ "radius":0.425, "xyz":[-0.915, 1.184, -0.150], "down":[0,0,-1], "axel":[-1,0,0], "suspensionRest": 0.2, "front":false, "object":".003"},
{ "radius":0.425, "xyz":[ 0.915, 1.184, -0.150], "down":[0,0,-1], "axel":[-1,0,0], "suspensionRest": 0.2, "front":false, "object":".002"}
],
"mass" : 1993 ,
"hp" : 610 ,
"torque" : 100 ,
"drag" : 0.5 ,
"roll" : -0.4 ,
"grip" : 0.2 ,
"maxturn" : 0.8 ,
"brakes" : 2.0 ,
"abs" : 0.01 ,
"downforce" : 2.0 ,
"suspention" : 100.0 ,
"suspentionDamping" : 0.8 ,
"maxrpm" : 8000 ,
"idle" : 1100 ,
"redline" : 6000 ,
"gears":[
5.00,
3.00,
2.00,
1.00,
0.75,
0.50,
0.25,
0.20,
0.15
]
}

38
cardata/KartBox.json Normal file
View file

@ -0,0 +1,38 @@
{
"name":"Kart",
"probability":0,
"type":"kart",
"wheels":[
{ "radius":0.095, "xyz":[ 0.323, -0.327, 0.17], "down":[0,0,-1], "axel":[-1,0,0], "suspensionRest": 0.2, "front":true , "object":""},
{ "radius":0.095, "xyz":[-0.323, -0.327, 0.17], "down":[0,0,-1], "axel":[-1,0,0], "suspensionRest": 0.2, "front":true , "object":".001"},
{ "radius":0.095, "xyz":[-0.323, 0.654, 0.17], "down":[0,0,-1], "axel":[-1,0,0], "suspensionRest": 0.2, "front":false, "object":".003"},
{ "radius":0.095, "xyz":[ 0.323, 0.654, 0.17], "down":[0,0,-1], "axel":[-1,0,0], "suspensionRest": 0.2, "front":false, "object":".002"}
],
"mass" : 50 ,
"hp" : 5 ,
"torque" : 0.2 ,
"drag" : 0.1 ,
"roll" : -0.2 ,
"grip" : 0.4 ,
"maxturn" : 0.8 ,
"brakes" : 3.0 ,
"abs" : 0 ,
"downforce" : 2.0 ,
"suspention" : 150.0 ,
"suspentionDamping" : 0.8 ,
"maxrpm" : 12000 ,
"idle" : 1100 ,
"redline" : 10000 ,
"cameraZoom" : 1 ,
"stableBrake" : false ,
"turnFake" : 5 ,
"visionSize" : 0.4 ,
"gears":[
5.00,
1.00,
0.50
]
}

35
cardata/KartBox.json~ Normal file
View file

@ -0,0 +1,35 @@
{
"name":"Hatchback Model 1",
"probability":10,
"type":"street-car",
"wheels":[
{ "radius":0.383, "xyz":[ 0.919, -1.519, -0.200], "down":[0,0,-1], "axel":[-1,0,0], "suspensionRest": 0.2, "front":true , "object":""},
{ "radius":0.383, "xyz":[-0.919, -1.519, -0.200], "down":[0,0,-1], "axel":[-1,0,0], "suspensionRest": 0.2, "front":true , "object":".001"},
{ "radius":0.383, "xyz":[-0.919, 1.522, -0.200], "down":[0,0,-1], "axel":[-1,0,0], "suspensionRest": 0.2, "front":false, "object":".003"},
{ "radius":0.383, "xyz":[ 0.919, 1.522, -0.200], "down":[0,0,-1], "axel":[-1,0,0], "suspensionRest": 0.2, "front":false, "object":".002"}
],
"mass" : 1993 ,
"hp" : 50 ,
"torque" : 50 ,
"drag" : 1.5 ,
"roll" : 0.4 ,
"grip" : 0.1 ,
"maxturn" : 0.8 ,
"brakes" : 1.0 ,
"abs" : 0.1 ,
"downforce" : 0.5 ,
"suspention" : 50.0 ,
"suspentionDamping" : 0.8 ,
"maxrpm" : 6000 ,
"idle" : 1100 ,
"redline" : 5000 ,
"gears":[
5.00,
2.00,
1.00,
0.50
]
}

View file

@ -7,12 +7,12 @@
"SecondaryColor":[0.051525, 0.514757, 1.000000]},
"wheels":[
{ "radius":0.42, "xyz":[ 0.89, -1.25, -0.100], "down":[0,0,-1], "axel":[-1,0,0], "suspensionRest": 0.2, "front":true , "object":""},
{ "radius":0.42, "xyz":[-0.89, -1.25, -0.100], "down":[0,0,-1], "axel":[-1,0,0], "suspensionRest": 0.2, "front":true , "object":".001"},
{ "radius":0.42, "xyz":[-0.89, 1.65, -0.100], "down":[0,0,-1], "axel":[-1,0,0], "suspensionRest": 0.2, "front":false, "object":".003"},
{ "radius":0.42, "xyz":[ 0.89, 1.65, -0.100], "down":[0,0,-1], "axel":[-1,0,0], "suspensionRest": 0.2, "front":false, "object":".002"}
{ "radius":0.42, "xyz":[ 0.89, -1.25, 0.150], "down":[0,0,-1], "axel":[-1,0,0], "suspensionRest": 0.2, "front":true , "object":""},
{ "radius":0.42, "xyz":[-0.89, -1.25, 0.150], "down":[0,0,-1], "axel":[-1,0,0], "suspensionRest": 0.2, "front":true , "object":".001"},
{ "radius":0.42, "xyz":[-0.89, 1.65, 0.150], "down":[0,0,-1], "axel":[-1,0,0], "suspensionRest": 0.2, "front":false, "object":".003"},
{ "radius":0.42, "xyz":[ 0.89, 1.65, 0.150], "down":[0,0,-1], "axel":[-1,0,0], "suspensionRest": 0.2, "front":false, "object":".002"}
],
"mass" : 1800 ,
"hp" : 600 ,
"torque" : 120 ,

View file

@ -0,0 +1,43 @@
{
"name":"Neonspeedster",
"probability":1,
"type":"race-car",
"material":{"MainColor" :[0.051525, 0.514757, 1.000000],
"SecondaryColor":[0.051525, 0.514757, 1.000000]},
"wheels":[
{ "radius":0.42, "xyz":[ 0.89, -1.25, -0.100], "down":[0,0,-1], "axel":[-1,0,0], "suspensionRest": 0.2, "front":true , "object":""},
{ "radius":0.42, "xyz":[-0.89, -1.25, -0.100], "down":[0,0,-1], "axel":[-1,0,0], "suspensionRest": 0.2, "front":true , "object":".001"},
{ "radius":0.42, "xyz":[-0.89, 1.65, -0.100], "down":[0,0,-1], "axel":[-1,0,0], "suspensionRest": 0.2, "front":false, "object":".003"},
{ "radius":0.42, "xyz":[ 0.89, 1.65, -0.100], "down":[0,0,-1], "axel":[-1,0,0], "suspensionRest": 0.2, "front":false, "object":".002"}
],