Version 08-08-24
This commit is contained in:
parent
6cb5deb94f
commit
db92590087
204 changed files with 15350 additions and 419 deletions
4
LICENSE~
Normal file
4
LICENSE~
Normal 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.
|
27
README.md
27
README.md
|
@ -1,27 +0,0 @@
|
|||
# Dani's Race
|
||||
|
||||

|
||||
|
||||
A Free / Libre Open World Game.
|
||||
|
||||
## What is Dani's Race?
|
||||
|
||||

|
||||
|
||||
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
45
SOUNDLICENSES~
Normal 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
|
|
@ -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
106
ScriptSnippits.txt~
Normal 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!
|
||||
|
||||
|
|
@ -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
|
||||
|
|
1263
Scripts/Character_Controll.py~
Normal file
1263
Scripts/Character_Controll.py~
Normal file
File diff suppressed because it is too large
Load diff
183
Scripts/Cinema.py~
Normal file
183
Scripts/Cinema.py~
Normal 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
156
Scripts/Common.py~
Normal 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"]
|
|
@ -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
683
Scripts/Destruction.py~
Normal 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
3
Scripts/Garage.py~
Normal file
|
@ -0,0 +1,3 @@
|
|||
# GPLv3-or-later
|
||||
# (C) J.Y.Amihud ( blenderdumbass )
|
||||
|
|
@ -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
1677
Scripts/Main_update.py~
Normal file
File diff suppressed because it is too large
Load diff
192
Scripts/Map.py~
Normal file
192
Scripts/Map.py~
Normal 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
3
Scripts/Money.py~
Normal file
|
@ -0,0 +1,3 @@
|
|||
# GPLv3 or later
|
||||
# (C) J.Y.Amihud ( blenderdumbass )
|
||||
|
|
@ -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
64
Scripts/Mouse.py~
Normal 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))
|
||||
|
|
@ -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
|
||||
|
|
153
Scripts/Multiplayer_Client.py~
Normal file
153
Scripts/Multiplayer_Client.py~
Normal 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))
|
||||
|
||||
|
|
@ -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()
|
||||
|
|
470
Scripts/Multiplayer_Server.py~
Normal file
470
Scripts/Multiplayer_Server.py~
Normal 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!")
|
40
Scripts/Multiplayer_Shared.py~
Normal file
40
Scripts/Multiplayer_Shared.py~
Normal 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
|
|
@ -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
515
Scripts/Opt.py~
Normal 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
39
Scripts/Racing.py
Normal 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
3
Scripts/Racing.py~
Normal file
|
@ -0,0 +1,3 @@
|
|||
# GPLv3 or later
|
||||
# ( C ) J.Y.Amihud 2024
|
||||
|
|
@ -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
1193
Scripts/Script.py~
Normal file
File diff suppressed because it is too large
Load diff
|
@ -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
199
Scripts/Settings.py~
Normal 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")
|
||||
|
|
@ -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
516
Scripts/Tools.py~
Normal 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
|
||||
|
|
@ -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
4560
Scripts/Vehicle.py~
Normal file
File diff suppressed because it is too large
Load diff
BIN
Scripts/__pycache__/Character_Controll.cpython-310.pyc
Normal file
BIN
Scripts/__pycache__/Character_Controll.cpython-310.pyc
Normal file
Binary file not shown.
BIN
Scripts/__pycache__/Cinema.cpython-310.pyc
Normal file
BIN
Scripts/__pycache__/Cinema.cpython-310.pyc
Normal file
Binary file not shown.
BIN
Scripts/__pycache__/Common.cpython-310.pyc
Normal file
BIN
Scripts/__pycache__/Common.cpython-310.pyc
Normal file
Binary file not shown.
BIN
Scripts/__pycache__/Destruction.cpython-310.pyc
Normal file
BIN
Scripts/__pycache__/Destruction.cpython-310.pyc
Normal file
Binary file not shown.
BIN
Scripts/__pycache__/Garage.cpython-310.pyc
Normal file
BIN
Scripts/__pycache__/Garage.cpython-310.pyc
Normal file
Binary file not shown.
BIN
Scripts/__pycache__/Main_update.cpython-310.pyc
Normal file
BIN
Scripts/__pycache__/Main_update.cpython-310.pyc
Normal file
Binary file not shown.
BIN
Scripts/__pycache__/Map.cpython-310.pyc
Normal file
BIN
Scripts/__pycache__/Map.cpython-310.pyc
Normal file
Binary file not shown.
BIN
Scripts/__pycache__/Money.cpython-310.pyc
Normal file
BIN
Scripts/__pycache__/Money.cpython-310.pyc
Normal file
Binary file not shown.
BIN
Scripts/__pycache__/Mouse.cpython-310.pyc
Normal file
BIN
Scripts/__pycache__/Mouse.cpython-310.pyc
Normal file
Binary file not shown.
BIN
Scripts/__pycache__/Multiplayer_Client.cpython-310.pyc
Normal file
BIN
Scripts/__pycache__/Multiplayer_Client.cpython-310.pyc
Normal file
Binary file not shown.
BIN
Scripts/__pycache__/Multiplayer_Shared.cpython-310.pyc
Normal file
BIN
Scripts/__pycache__/Multiplayer_Shared.cpython-310.pyc
Normal file
Binary file not shown.
BIN
Scripts/__pycache__/Opt.cpython-310.pyc
Normal file
BIN
Scripts/__pycache__/Opt.cpython-310.pyc
Normal file
Binary file not shown.
BIN
Scripts/__pycache__/Racing.cpython-310.pyc
Normal file
BIN
Scripts/__pycache__/Racing.cpython-310.pyc
Normal file
Binary file not shown.
BIN
Scripts/__pycache__/Reuse.cpython-310.pyc
Normal file
BIN
Scripts/__pycache__/Reuse.cpython-310.pyc
Normal file
Binary file not shown.
BIN
Scripts/__pycache__/Script.cpython-310.pyc
Normal file
BIN
Scripts/__pycache__/Script.cpython-310.pyc
Normal file
Binary file not shown.
BIN
Scripts/__pycache__/Settings.cpython-310.pyc
Normal file
BIN
Scripts/__pycache__/Settings.cpython-310.pyc
Normal file
Binary file not shown.
BIN
Scripts/__pycache__/Tools.cpython-310.pyc
Normal file
BIN
Scripts/__pycache__/Tools.cpython-310.pyc
Normal file
Binary file not shown.
BIN
Scripts/__pycache__/Vehicle.cpython-310.pyc
Normal file
BIN
Scripts/__pycache__/Vehicle.cpython-310.pyc
Normal file
Binary file not shown.
38
Tux_license.txt
Normal file
38
Tux_license.txt
Normal 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
|
BIN
__pycache__/Car_controll.cpython-310.pyc
Normal file
BIN
__pycache__/Car_controll.cpython-310.pyc
Normal file
Binary file not shown.
|
@ -28,6 +28,10 @@
|
|||
"Frames":[340,353]
|
||||
},
|
||||
|
||||
"SwimIdle":{
|
||||
"Frames":[400,450]
|
||||
},
|
||||
|
||||
"Fly":{
|
||||
"Frames":[358,371],
|
||||
"kwargs":{"priority":-1,
|
||||
|
|
61
animdata/chr/Dani_Box.json~
Normal file
61
animdata/chr/Dani_Box.json~
Normal 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}
|
||||
}
|
||||
}
|
15
animdata/chr/JackBox.json~
Normal file
15
animdata/chr/JackBox.json~
Normal file
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
|
||||
"Stand":{
|
||||
"Frames":[0,300]
|
||||
},
|
||||
|
||||
"Walk":{
|
||||
"Frames":[330, 350]
|
||||
},
|
||||
|
||||
"Drive":{
|
||||
"Frames":[360,361]
|
||||
}
|
||||
|
||||
}
|
14
animdata/chr/Man1Box.json
Normal file
14
animdata/chr/Man1Box.json
Normal file
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
|
||||
"Stand":{
|
||||
"Frames":[0,276]
|
||||
},
|
||||
|
||||
"Walk":{
|
||||
"Frames":[300, 332]
|
||||
},
|
||||
|
||||
"Drive":{
|
||||
"Frames":[335,335]
|
||||
}
|
||||
}
|
14
animdata/chr/Man1Box.json~
Normal file
14
animdata/chr/Man1Box.json~
Normal file
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
|
||||
"Stand":{
|
||||
"Frames":[0,276]
|
||||
},
|
||||
|
||||
"Walk":{
|
||||
"Frames":[300, 320]
|
||||
},
|
||||
|
||||
"Drive":{
|
||||
"Frames":[325,325]
|
||||
}
|
||||
}
|
7
animdata/chr/MoriaBox.json~
Normal file
7
animdata/chr/MoriaBox.json~
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
|
||||
"Stand":{
|
||||
"Frames":[0,276]
|
||||
}
|
||||
|
||||
}
|
|
@ -7,11 +7,16 @@
|
|||
"Frames":[0, 290]
|
||||
},
|
||||
|
||||
"Drive":{
|
||||
"Frames":[350,351]
|
||||
},
|
||||
|
||||
"Talk":{
|
||||
"Action":"PapsTalk",
|
||||
"Frames":[0, 10],
|
||||
"kwargs":{"layer":3}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
17
animdata/chr/PapsBox.json~
Normal file
17
animdata/chr/PapsBox.json~
Normal file
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"Walk":{
|
||||
"Frames":[301, 330]
|
||||
},
|
||||
|
||||
"Stand":{
|
||||
"Frames":[0, 290]
|
||||
},
|
||||
|
||||
"Talk":{
|
||||
"Action":"PapsTalk",
|
||||
"Frames":[0, 10],
|
||||
"kwargs":{"layer":3}
|
||||
}
|
||||
|
||||
|
||||
}
|
BIN
assembly.blend
BIN
assembly.blend
Binary file not shown.
BIN
assembly.blend1
Normal file
BIN
assembly.blend1
Normal file
Binary file not shown.
BIN
assembly_copy.blend
Normal file
BIN
assembly_copy.blend
Normal file
Binary file not shown.
BIN
assembly_copy.blend1
Normal file
BIN
assembly_copy.blend1
Normal file
Binary file not shown.
BIN
ast/chr/Man1.blend
Normal file
BIN
ast/chr/Man1.blend
Normal file
Binary file not shown.
BIN
ast/chr/Man1.blend1
Normal file
BIN
ast/chr/Man1.blend1
Normal file
Binary file not shown.
BIN
ast/chr/Moria.blend
Normal file
BIN
ast/chr/Moria.blend
Normal file
Binary file not shown.
BIN
ast/chr/Moria.blend1
Normal file
BIN
ast/chr/Moria.blend1
Normal file
Binary file not shown.
BIN
ast/loc/City_source.blend1
Normal file
BIN
ast/loc/City_source.blend1
Normal file
Binary file not shown.
BIN
ast/loc/city.blend1
Normal file
BIN
ast/loc/city.blend1
Normal file
Binary file not shown.
Binary file not shown.
BIN
ast/veh/DarkShadow.blend1
Normal file
BIN
ast/veh/DarkShadow.blend1
Normal file
Binary file not shown.
BIN
ast/veh/HatchBack01.blend1
Normal file
BIN
ast/veh/HatchBack01.blend1
Normal file
Binary file not shown.
BIN
ast/veh/Kart.blend
Normal file
BIN
ast/veh/Kart.blend
Normal file
Binary file not shown.
BIN
ast/veh/Kart.blend1
Normal file
BIN
ast/veh/Kart.blend1
Normal file
Binary file not shown.
Binary file not shown.
BIN
ast/veh/NeonSpeedster.blend1
Normal file
BIN
ast/veh/NeonSpeedster.blend1
Normal file
Binary file not shown.
Binary file not shown.
BIN
ast/veh/RedKiss.blend1
Normal file
BIN
ast/veh/RedKiss.blend1
Normal file
Binary file not shown.
BIN
ast/veh/Truck.blend1
Normal file
BIN
ast/veh/Truck.blend1
Normal file
Binary file not shown.
BIN
bgelogic/__pycache__/NLNodeTree.cpython-39.pyc
Normal file
BIN
bgelogic/__pycache__/NLNodeTree.cpython-39.pyc
Normal file
Binary file not shown.
BIN
bgelogic/__pycache__/__init__.cpython-39.pyc
Normal file
BIN
bgelogic/__pycache__/__init__.cpython-39.pyc
Normal file
Binary file not shown.
|
@ -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 ,
|
||||
|
|
43
cardata/DarkShadowBox.json~
Normal file
43
cardata/DarkShadowBox.json~
Normal 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
|
||||
]
|
||||
}
|
39
cardata/HatchBack01Box.json~
Normal file
39
cardata/HatchBack01Box.json~
Normal 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
38
cardata/KartBox.json
Normal 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
35
cardata/KartBox.json~
Normal 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
|
||||
]
|
||||
}
|
|
@ -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 ,
|
||||
|
|
43
cardata/NeonSpeedsterBox.json~
Normal file
43
cardata/NeonSpeedsterBox.json~
Normal 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"}
|
||||
],
|
||||