File: Script.c

package info (click to toggle)
openclonk 7.0-4
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 145,828 kB
  • ctags: 33,094
  • sloc: cpp: 163,891; ansic: 82,846; xml: 29,876; python: 1,203; php: 767; makefile: 138; sh: 77
file content (176 lines) | stat: -rwxr-xr-x 6,851 bytes parent folder | download
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();
}