1 /*--License:
2 	Kyra Sprite Engine
3 	Copyright Lee Thomason (Grinning Lizard Software) 2001-2005
4 	www.grinninglizard.com/kyra
5 	www.sourceforge.net/projects/kyra
6 
7 	Kyra is provided under the LGPL.
8 
9 	I kindly request you display a splash screen (provided in the HTML documentation)
10 	to promote Kyra and acknowledge the software and everyone who has contributed to it,
11 	but it is not required by the license.
12 
13 --- LGPL License --
14 
15     This library is free software; you can redistribute it and/or
16     modify it under the terms of the GNU Lesser General Public
17     License as published by the Free Software Foundation; either
18     version 2.1 of the License, or (at your option) any later version.
19 
20     This library is distributed in the hope that it will be useful,
21     but WITHOUT ANY WARRANTY; without even the implied warranty of
22     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23     Lesser General Public License for more details.
24 
25     You should have received a copy of the GNU Lesser General Public
26     License along with this library; if not, write to the Free Software
27     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
28 
29 	The full text of the license can be found in lgpl.txt
30 */
31 
32 
33 
34 #include "SDL.h"
35 #include "demos.h"
36 #include "space.h"
37 #include <math.h>
38 
39 
SpaceGame(SDL_Surface * screen,bool _tracking)40 SpaceGame::SpaceGame( SDL_Surface* screen, bool _tracking )
41 {
42 	random.SetSeed( 0 );
43 
44 	GlFixed camera = -50;
45 	for( int i=0; i<NUM_SCALES; ++i )
46 	{
47 		int z = ( i * MAXDEPTH / ( NUM_SCALES - 1 ) );
48 		GlFixed scale = GlFixed( z - camera ) / GlFixed( BIGDEPTH - camera );
49 		scalesToUse[i] = scale;
50 	}
51 
52 	tracking = _tracking;
53 	engine = new KrEngine( screen );
54 	GLASSERT( engine );
55 
56 	if ( !engine->Vault()->LoadDatFile( "space.dat" ) )
57 	{
58 		#ifdef DEBUG
59 		GLOUTPUT(( "Error loading 'space.dat'!\n" ));
60 		GLASSERT( 0 );
61 		#endif
62 		exit(100);
63 	}
64 
65 	// Calculate the size of the space field and fill
66 	// it with space tiles.
67 	field.min.x = -engine->ScreenBounds().Width() * 3;
68 	field.max.x =  engine->ScreenBounds().Width();
69 	field.min.y =  engine->ScreenBounds().min.y;
70 	field.max.y =  engine->ScreenBounds().max.y;
71 
72 	xResetAt = -engine->ScreenBounds().Width() * 2;
73 	xResetTo =  engine->ScreenBounds().Width() / 2;
74 
75 //	// Only useful if the demo runs past the end of the screen.
76 //	// For a "real" app, this should be set to 0 because the
77 //	// background shouldn't show through.
78 //	KrRGBA black;
79 //    black.Set( 0, 0, 0, 255 );
80 //	engine->FillBackground( &black );
81 	engine->FillBackground( 0 );	// Turn off background.
82 
83 	// We use 2 container ImNodes:
84 	// - one for the starfield
85 	// - one for everything else.
86 	starfieldNode = new KrImNode;
87 	mainNode	  = new KrImNode;
88 
89 	engine->Tree()->AddNode( 0, starfieldNode );
90 	engine->Tree()->AddNode( 0, mainNode );
91 
92 	AddStarfield();
93 	AddShips();
94 
95 	TrackCamera();
96 }
97 
98 
~SpaceGame()99 SpaceGame::~SpaceGame()
100 {
101 	delete engine;
102 }
103 
104 
TrackCamera()105 void SpaceGame::TrackCamera()
106 {
107 	// Find the tracker object and put it on the right side of the screen.
108 	KrImNode* node;
109 
110 	node = engine->Tree()->FindNodeByName( "track" );
111 	if ( node )
112 	{
113 		// We scoll the screen to position the node in the view.
114 		// We want the ship to end up at 3/4 width and 1/2 height.
115 		// (the height doesn't change, so we only have to play
116 		// with the x)
117 
118 		int desiredX = engine->ScreenBounds().Width() * 3 / 4;
119 		int offsetX  = node->X() - desiredX;
120 		engine->Tree()->Root()->SetPos( -offsetX, 0 );
121 	}
122 }
123 
124 
AddStarfield()125 void SpaceGame::AddStarfield()
126 {
127 	int x, y;
128 	KrTileResource* starRes = engine->Vault()->GetTileResource( "STARS" );
129 	GLASSERT( starRes );
130 // 	GlFixed scalex = 1.3;
131 // 	GlFixed scaley = 1.3;
132 // 	starRes->CacheScale( scalex, scaley );
133 
134  	for( x = field.min.x; x <= field.max.x; x += starRes->Size() )
135 	{
136 	 	for( y = field.min.y; y <= field.max.y; y += starRes->Size()  )
137 		{
138 			KrTile* tile = new KrTile( starRes );
139 			GLASSERT( tile );
140 
141 			tile->SetRotation( random.Rand( 8 ) );
142 			tile->SetPos( x, y );
143 			engine->Tree()->AddNode( starfieldNode, tile );
144 // 			tile->SetScale( scalex, scaley );
145 		}
146 	}
147 }
148 
149 
GetScale(int z)150 GlFixed SpaceGame::GetScale( int z )
151 {
152 	if ( z == BIGDEPTH ) return 1;
153 
154 	GlFixed camera = -50;
155 	GlFixed scale = GlFixed( z - camera ) / GlFixed( BIGDEPTH - camera );
156 
157 	int index = 0;
158 	int error = abs( scale.v - scalesToUse[0].v );
159 
160 	for( int i=1; i<NUM_SCALES; ++i )
161 	{
162 		int thisError = abs( scale.v - scalesToUse[i].v );
163 		if ( thisError < error )
164 		{
165 			error = thisError;
166 			index = i;
167 		}
168 	}
169 	return scalesToUse[ index ];
170 }
171 
172 
AddShips()173 void SpaceGame::AddShips()
174 {
175 	// Put one big ship in, some random med size, and a bunch of
176 	// small ones.
177 
178 	KrSpriteResource* bigRes;
179 	KrSpriteResource* medRes;
180 	KrSpriteResource* smallRes;
181 	KrSprite* sprite;
182 	KrSprite* insignia;
183 	int i, x, y;
184 
185 	GlFixed scale;
186 
187 	bigRes = engine->Vault()->GetSpriteResource( "LARGE" );
188 	GLASSERT( bigRes );
189 	medRes = engine->Vault()->GetSpriteResource( "MED" );
190 	GLASSERT( medRes );
191 	smallRes = engine->Vault()->GetSpriteResource( "SMALL" );
192 	GLASSERT( smallRes );
193 
194 	// Cache scale the ships.
195 	for( i=0; i<NUM_SCALES; ++i )
196 	{
197 		medRes->CacheScale( scalesToUse[i], scalesToUse[i] );
198 		smallRes->CacheScale( scalesToUse[i], scalesToUse[i] );
199 	}
200 
201 	// Big ship. Noting that the big ship is 2 sprites: the
202 	// body and the tail.
203 	sprite = new KrSprite( bigRes );
204 	sprite->SetPos( field.min.x + engine->ScreenBounds().Width() * 3 / 2,
205 				    engine->ScreenBounds().Height() / 2 );
206 	sprite->SetZDepth( BIGDEPTH );
207 	sprite->SetNodeName( "track" );
208 	sprite->SetAction( "BODY" );
209 
210 	engine->Tree()->AddNode( mainNode, sprite );
211 
212 	KrSprite* tail = new KrSprite( bigRes );
213 	tail->SetAction( "TAIL" );
214 	engine->Tree()->AddNode( sprite, tail );
215 
216 	// Med ships. These are a little special because they
217 	// each have a triangle insignia on them that is a child
218 	// node which is color transformed.
219 	for( i=0; i<NUM_MED; i++ )
220 	{
221 		// The ship:
222 		x = random.Rand( field.Width() );
223 		y = random.Rand( field.Height() );
224 
225 		sprite = new KrSprite( medRes );
226 		sprite->SetPos( field.min.x + x, field.min.y + y );
227 		sprite->SetZDepth( random.Rand( MAXDEPTH ) );
228 		scale = GetScale( sprite->ZDepth() );
229 		sprite->SetScale( scale, scale );
230 		sprite->SetAction( "BODY" );
231 
232 		engine->Tree()->AddNode( mainNode, sprite );
233 
234 		// The insignia. It will move with the ship
235 		// since it is a child, so we don't set coordinates.
236 		insignia = new KrSprite( medRes );
237 		insignia->SetAction( "INSIGNIA" );
238 
239 		KrColorTransform color;
240 		switch( random.Rand( 3 ) )
241 		{
242 			case 0:
243 				color.TintBlue( 200 );
244 				break;
245 			case 1:
246 				color.TintRed( 200 );
247 				break;
248 			case 2:
249 				color.TintGreen( 200 );
250 				break;
251 		}
252 		insignia->SetColor( color );
253 		engine->Tree()->AddNode( sprite, insignia );
254 	}
255 
256 	// Small ships.
257 	for( i=0; i<NUM_SMALL; i++ )
258 	{
259 		x = random.Rand( field.Width() );
260 		y = random.Rand( field.Height() );
261 
262 		sprite = new KrSprite( smallRes );
263 		sprite->SetPos( field.min.x + x, field.min.y + y );
264 		sprite->SetZDepth( random.Rand( MAXDEPTH ) );
265 		scale = GetScale ( sprite->ZDepth() );
266 		sprite->SetScale( scale, scale );
267 		engine->Tree()->AddNode( mainNode, sprite );
268 	}
269 }
270 
271 
DrawFrame()272 void SpaceGame::DrawFrame()
273 {
274 	AddText( engine );
275 
276 	// Move ships
277 	GlInsideNodeIt<KrImNode*> it = mainNode->ChildTreeIterator();
278 
279 	const float SPEED_MED = 2.f;
280 	const float SPEED_SMALL = 3.f;
281 
282 	for ( it.Begin(); !it.Done(); it.Next() )
283 	{
284 		KrSprite* sprite = it.CurrentData()->ToSprite();
285 		if ( sprite )
286 		{
287 			//int bonus = ( sprite->ZDepth() > BIGDEPTH ) ? 1 : 0;
288 
289 			if ( sprite->SpriteResource()->ResourceName() == "LARGE" )
290 			{
291 				sprite->DeltaPos( -1, 0 );
292 			}
293 			else if ( sprite->SpriteResource()->ResourceName() == "MED" )
294 			{
295 				GlFixed scale = GetScale( sprite->ZDepth() );
296 				float speed = SPEED_MED * scale.ToFloat();
297 				int d = (int)(speed * (float)(Frame()-1) ) - (int)(speed * Frame() );
298 				sprite->DeltaPos( d,  0 );
299 
300 				//sprite->DeltaPos( -2 - bonus, 0 );
301 			}
302 			else if ( sprite->SpriteResource()->ResourceName() == "SMALL" )
303 			{
304 				GlFixed scale = GetScale( sprite->ZDepth() );
305 				float speed = SPEED_SMALL * scale.ToFloat();
306 				int d = (int)(speed * (float)(Frame()-1) ) - (int)(speed * Frame() );
307 				sprite->DeltaPos( d,  0 );
308 
309 				//sprite->DeltaPos( -3 - bonus , 0 );
310 			}
311 
312 			// Reset the ships, so the demo can keep running.
313 			// Regrettably, different logic for tracking and not-tracking.
314 			if ( tracking )
315 			{
316 				if ( sprite->SpriteResource()->ResourceName() == "LARGE" )
317 				{
318 					if ( sprite->X() < xResetAt )
319 						sprite->SetPos( xResetTo, sprite->Y() );
320 				}
321 				else
322 				{
323 					if ( sprite->X() < xResetAt - engine->ScreenBounds().Width() )
324 						sprite->SetPos( xResetTo + engine->ScreenBounds().Width(), sprite->Y() );
325 				}
326 			}
327 			else
328 			{
329 				if ( sprite->X() < field.min.x )
330 					sprite->SetPos( field.max.x, sprite->Y() );
331 			}
332 		}
333 	}
334 
335 	if ( tracking )
336 		TrackCamera();
337 
338 	engine->Draw();
339 }
340 
341