1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
|
//Makes objects follow the solid mask of a vehicle if they are touching it (within a specified rectangle)
//Works for both livings and vehicles.
//To enable in a vehicle, you need two things:
//1. A parent object which will rotate 'children' to match it's rotation on the Z axis (screen-vertical)
// which either AlignObjectsToRotation or AlignToRotation will be called from, and
//2. A 'turnTarget' which will be queried for the Z-angle, in the form of 'turnTarget->GetTurnAngle()'.
// This function should return a value from 0-180, where 0 is turned completely left, and 180 right.
// The turnTarget can be the same object as the parent object. The reason they are separated is due
// to the separation of the 3D graphic and solidmask object of any solidmask enabled 3D vehicle.
// In this way, the 3D graphic module of a vehicle can query its own animation position.
///Function must be called from vehicle context
///param x,y,w,h = target rectangle to look for objects in to follow the vehicle's rotation
func AlignObjectsToRotation(object turnTarget, int x, int y, int w, int h)
{
if(!this) FatalError("Function AlignToRotation must be called from object (vehicle) context");
if(!turnTarget) FatalError("Function requires a valid turnTarget to get rotation value from");
if(x == nil) x = this->GetDefCoreVal("Offset", "DefCore", 0);
if(y == nil) y = this->GetDefCoreVal("Offset", "DefCore", 1);
if(w == nil) w = this->GetDefCoreVal("Width", "DefCore");
if(h == nil) h = this->GetDefCoreVal("Height", "DefCore");
//make objects follow ship rotation
for(var targetObj in FindObjects(Find_Not(Find_ID(this)), Find_NoContainer(), Find_Or(Find_Category(C4D_Living), Find_Category(C4D_Object), Find_Func("IsVehicle")), Find_InRect(x,y,w,h))){
AlignToRotation(targetObj, turnTarget);
}
}
//Used to parent a single object to the vehicle's rotation
/// param 'target' is the child object. Function is called from the vehicle context.
/// turnTarget is the object which must have a function returning the angle from
/// 0-180 (left to right), from the function GetTurnAngle()
func AlignToRotation(object target, object turnTarget)
{
if(target){
//only objects with lower indexes can ride
if(target.Plane <= this.Plane) return false;
//Must have a turnTarget to check the rotation
if(turnTarget == nil){
FatalError("No defined turnTarget object to get rotation from");
}
//turnTarget must have a function returning what angle the vehicle is at
else {
if(turnTarget->~GetTurnAngle() == nil){
FatalError(Format("turnTarget %s has no GetTurnAngleFunction", turnTarget->GetName()));
}
}
// if(target->GetContact(-1) > 0){
if(target->GetY() > -1 || target->GetY() < 1){
var oldNewX = nil;
var oldNewR = nil;
var oldEffect = GetEffect("AlignRotation", target);
//Get originalX from previous effect if it existed
if(oldEffect){
oldNewX = oldEffect.originalX * -1;
if(oldEffect.originalR != nil) oldNewR = oldEffect.originalR * -1;
RemoveEffect(nil,target,oldEffect);
}
//Create the turn effect
var effect = AddEffect("AlignRotation", target, 1, 1, this);
//set effect vars
effect.turnTarget = turnTarget;
//If the turn was already in progress, reuse the last one
if(oldNewX) effect.originalX = oldNewX;
if(oldNewR) effect.originalR = oldNewR;
}
}
}
private func FxAlignRotationStart(object target, proplist effect)
{
/// param 'target' is the object which follows 'this'
/// 'this' refers to the vehicle the effect is created in the object context of.
DebugLog(Format("Added AlignRotation effect to %s, child of %s", target->GetName(), GetName()));
effect.originalX = target->GetX(100) - this->GetX(100);
effect.originalY = target->GetY(100) - this->GetY(100);
effect.originalR = nil;
if(target->GetDefCoreVal("Rotate", "DefCore") >= 1){
effect.originalR = Normalize(target->GetR(),-180);
if(target->GetDefCoreVal("Rotate", "DefCore") == 1){
effect.noRSmooth = true;
}
}
//Temporary no collection effect
effect.oldCollect = target.Collectible;
if(effect.oldCollect == 1) target.Collectible = 0;
effect.floorYOff = (effect.originalY + ((target->GetDefCoreVal("Height", "DefCore") / 2 + 2) * 100));
//Create floor helper. Makes certain clonks don't fall while boat is turning
//(due to the solid mask flipping and such); so they keep a solid footing.
if(target->GetCategory() & C4D_Living){
// if(target->GetY() == 0){
effect.floorHelper = this->CreateObjectAbove(Vehicle_FloorHelper, effect.originalX / 100, (effect.originalY / 100) + (effect.floorYOff / 100) + 1);
//adjust floor helper size
var width = BoundBy(target->GetDefCoreVal("Width", "DefCore"),6,64);
effect.floorHelper->SetSolidMask(0,0,width,2, (width * -1) / 2 + 1,0);
}
return 1;
}
//Basically what this does is move the target object in a sinal path to emulate
//rotating with the boat.
private func FxAlignRotationTimer(object target, proplist effect, int timer)
{
//Z-Rotation value of the vehicle
var ang = effect.turnTarget->GetTurnAngle() - 90;
//sinal movement and rotation
var newX = Sin(ang, Abs(effect.originalX));
var newR = Sin(ang, Abs(effect.originalR)) * -1;
//Is the target on the left side of the vehicle, and the vehicle is turning left?
//Is the target on the right side of the vehicle, and the vehicle is turning right?
if((effect.originalX < 0 && this->GetDir() == 0) || (effect.originalX > 0 && this->GetDir() == 1)){
newX = Sin(ang, Abs(effect.originalX)) * -1;
newR = Sin(ang, Abs(effect.originalR));
}
//Debug
//target->Message(Format("%d,%d; %d", effect.originalX, newX, effect.floorYOff));
if(newX != effect.originalX * -1){
target->SetPosition(newX + this->GetX(100), target->GetY(100), true, 100);
//change rotation
if(effect.originalR != nil){
//debug
// target->Message(Format("R=%d", newR));
// target->SetR(newR);
if(target->GetCategory() & C4D_Object) target->SetR();
}
//Make sure vehicles aren't affected by gravity when rotating
if((target->GetCategory() & C4D_Living) == 0){
if(target->GetProcedure() == "FLOAT") target->SetYDir(0);
else target->SetYDir(-2);
}
//update floor-helper position for clonks/livings
if(effect.floorHelper != nil){
effect.floorHelper->SetPosition(this->GetX(100) + newX, this->GetY(100) + effect.floorYOff, true, 100);
}
}
else{
return -1;
}
}
private func FxAlignRotationStop(object target, proplist effect)
{
//re-enable collection
target.Collectible = effect.oldCollect;
var newX = effect.originalX * -1;
//push vehicle up out of solidmask if it got stuck in it
while(target->Stuck()) target->SetPosition(newX + this->GetX(100), target->GetY(100) - 50, true, 100);
//Get rid of the floor helper object
if(effect.floorHelper) effect.floorHelper->RemoveObject();
}
|