1 ////////////////////////////////////////////////////////////////////////////////
2 //    Scorched3D (c) 2000-2011
3 //
4 //    This file is part of Scorched3D.
5 //
6 //    Scorched3D is free software; you can redistribute it and/or modify
7 //    it under the terms of the GNU General Public License as published by
8 //    the Free Software Foundation; either version 2 of the License, or
9 //    (at your option) any later version.
10 //
11 //    Scorched3D is distributed in the hope that it will be useful,
12 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //    GNU General Public License for more details.
15 //
16 //    You should have received a copy of the GNU General Public License along
17 //    with this program; if not, write to the Free Software Foundation, Inc.,
18 //    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 ////////////////////////////////////////////////////////////////////////////////
20 
21 #include <movement/TargetMovementEntryShips.h>
22 #include <common/Defines.h>
23 #include <common/RandomGenerator.h>
24 #include <engine/ScorchedContext.h>
25 #include <engine/ObjectGroups.h>
26 #include <engine/ObjectGroupEntry.h>
27 #include <target/Target.h>
28 #include <target/TargetLife.h>
29 #include <target/TargetState.h>
30 #include <landscapemap/LandscapeMaps.h>
31 #include <landscapedef/LandscapeTex.h>
32 #include <landscapedef/LandscapeMovement.h>
33 
TargetMovementEntryShips()34 TargetMovementEntryShips::TargetMovementEntryShips()
35 {
36 }
37 
~TargetMovementEntryShips()38 TargetMovementEntryShips::~TargetMovementEntryShips()
39 {
40 }
41 
generate(ScorchedContext & context,RandomGenerator & random,LandscapeMovementType * movementType)42 void TargetMovementEntryShips::generate(ScorchedContext &context,
43 	RandomGenerator &random, LandscapeMovementType *movementType)
44 {
45 	int mapWidth = context.getLandscapeMaps().getGroundMaps().getLandscapeWidth();
46 	int mapHeight = context.getLandscapeMaps().getGroundMaps().getLandscapeHeight();
47 	LandscapeTex &tex = *context.getLandscapeMaps().getDefinitions().getTex();
48 
49 	// Get the water height (if water is on)
50 	fixed waterHeight = 0;
51 	if (tex.border->getType() == LandscapeTexType::eWater)
52 	{
53 		LandscapeTexBorderWater *water =
54 			(LandscapeTexBorderWater *) tex.border;
55        	waterHeight = water->height;
56 	}
57 
58 	// Create the spline path the ships will move on
59 	// Do this from the set of control points specified in the xml file
60 	LandscapeMovementTypeShips *shipGroup =
61 		(LandscapeMovementTypeShips *) movementType;
62 	std::vector<FixedVector> controlPoints;
63 	controlPoints.push_back(FixedVector::getNullVector());
64 	fixed diff = fixed(360) / fixed(shipGroup->controlpoints);
65 	for (fixed i=0; i<360; i+=diff)
66 	{
67 		fixed distWidth = random.getRandFixed("ShipMovement") *
68 			shipGroup->controlpointsrand + shipGroup->controlpointswidth;
69 		fixed distHeight = random.getRandFixed("ShipMovement") *
70 			shipGroup->controlpointsrand + shipGroup->controlpointsheight;
71 		fixed x = (i / 180 * fixed::XPI).sin() * distWidth + fixed(mapWidth) / 2;
72 		fixed y = (i / 180 * fixed::XPI).cos() * distHeight + fixed(mapHeight) / 2;
73 
74 		FixedVector pt(x,y,waterHeight);
75 		controlPoints.push_back(pt);
76 	}
77 
78 	// Add a control point at the end to join the loop
79 	FixedVector midPt = (controlPoints[1] + controlPoints.back()) / 2;
80 	controlPoints.push_back(midPt);
81 	controlPoints.front() = midPt;
82 
83 	// Generate the spline path
84 	path_.generate(controlPoints, 200, 3, shipGroup->speed);
85 	path_.simulate(shipGroup->starttime);
86 
87 	// Find the group to move the objects in
88 	objectGroup_ = context.getObjectGroups().getGroup(shipGroup->groupname.c_str());
89 	if (!objectGroup_)
90 	{
91 		S3D::dialogExit("TargetMovementEntryShips",
92 			S3D::formatStringBuffer("Group entry %s has no objects defined for it",
93 			shipGroup->groupname.c_str()));
94 	}
95 
96 	// Generate the list of offsets for all of the targets in the group
97 	ObjectGroup::ObjectGroupEntryHolderIterator iterator(objectGroup_);
98 	ObjectGroupEntry *entry;
99 	while (entry = iterator.getNext())
100 	{
101 		if (entry->getType() != ObjectGroupEntry::TypeTarget)
102 		{
103 			S3D::dialogExit("TargetMovementEntryShips",
104 				"Movement can be assigned to level targets only (no particles)");
105 		}
106 
107 		Target *target = (Target *) entry->getObject();
108 		if (target->getType() == Target::TypeTank ||
109 			target->getPlayerId() >= TargetID::MIN_TARGET_TRANSIENT_ID)
110 		{
111 			S3D::dialogExit("TargetMovementEntryShips",
112 				"Movement can be assigned to level targets only (no tanks)");
113 		}
114 		if (target->getTargetState().getMovement())
115 		{
116 			S3D::dialogExit("TargetMovementEntryBoids",
117 				"Only one movement can be assigned to each target");
118 		}
119 
120 		// Generate the offsets for each target
121 		fixed offX = random.getRandFixed("ShipMovement") * 200;
122 		fixed offY = random.getRandFixed("ShipMovement") * 200;
123 		FixedVector offset(offX, offY - 100, 0);
124 		TargetMovementEntryShipsOffset *offsetEntry = new TargetMovementEntryShipsOffset();
125 		offsetEntry->offset = offset;
126 
127 		// Set this target as moving
128 		target->getTargetState().setMovement(offsetEntry);
129 	}
130 }
131 
simulate(ScorchedContext & context,fixed frameTime)132 void TargetMovementEntryShips::simulate(ScorchedContext &context, fixed frameTime)
133 {
134 	// Update the position of all of the ships along the path
135 	path_.simulate(frameTime);
136 
137 	// Get the position and direction along the current ship path
138 	FixedVector position;
139 	FixedVector direction;
140 	path_.getPathAttrs(position, direction);
141 	FixedVector directionPerp = direction.get2DPerp();
142 
143 	// For each target set position and rotation based on its offset
144 	ObjectGroup::ObjectGroupEntryHolderIterator iterator(objectGroup_);
145 	ObjectGroupEntry *entry;
146 	while (entry = iterator.getNext())
147 	{
148 		if (entry->getType() != ObjectGroupEntry::TypeTarget)
149 		{
150 			S3D::dialogExit("TargetMovementEntryShips",
151 				"Movement can be assigned to level targets only (no particles)");
152 		}
153 
154 		Target *target = (Target *) entry->getObject();
155 		TargetMovementEntryShipsOffset *offsetEntry = (TargetMovementEntryShipsOffset *)
156 			target->getTargetState().getMovement();
157 		if (offsetEntry)
158 		{
159 			// Calculate position
160 			FixedVector &offset = offsetEntry->offset;
161 			FixedVector shipPosition = position;
162 			shipPosition += directionPerp * -offset[0];
163 			shipPosition += direction * offset[1];
164 			fixed angle = atan2x(direction[1], direction[0]);
165 			fixed angleDegs = (angle / fixed::XPI) * 180 - 90;
166 
167 			// Update target
168 			target->getLife().setTargetPositionAndRotation(shipPosition, angleDegs);
169 		}
170 	}
171 }
172 
reset()173 void TargetMovementEntryShips::reset()
174 {
175 }
176 
draw()177 void TargetMovementEntryShips::draw()
178 {
179 #ifndef S3D_SERVER
180 	path_.draw();
181 #endif
182 }
183