1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 1998-2000, Matthes Bender
5  * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
6  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
7  *
8  * Distributed under the terms of the ISC license; see accompanying file
9  * "COPYING" for details.
10  *
11  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
12  * See accompanying file "TRADEMARK" for details.
13  *
14  * To redistribute this file separately, substitute the full license texts
15  * for the above references.
16  */
17 
18 /* Create map from dynamic landscape data in scenario */
19 
20 #include "C4Include.h"
21 #include "landscape/C4Map.h"
22 
23 #include "landscape/C4Texture.h"
24 #include "lib/C4Random.h"
25 #include "graphics/CSurface8.h"
26 
C4MapCreator()27 C4MapCreator::C4MapCreator()
28 {
29 	Reset();
30 }
31 
Reset()32 void C4MapCreator::Reset()
33 {
34 	MapBuf=nullptr;
35 	Exclusive=-1;
36 }
37 
SetPix(int32_t x,int32_t y,BYTE col)38 void C4MapCreator::SetPix(int32_t x, int32_t y, BYTE col)
39 {
40 	// Safety
41 	if (!Inside<int32_t>(x,0,MapWdt-1) || !Inside<int32_t>(y,0,MapHgt-1)) return;
42 	// Exclusive
43 	if (Exclusive>-1) if (GetPix(x,y)!=Exclusive) return;
44 	// Set pix
45 	MapBuf->SetPix(x,y,col);
46 }
47 
SetSpot(int32_t x,int32_t y,int32_t rad,BYTE col)48 void C4MapCreator::SetSpot(int32_t x, int32_t y, int32_t rad, BYTE col)
49 {
50 	int32_t ycnt,xcnt,lwdt,dpy;
51 	for (ycnt=-rad; ycnt<=rad; ycnt++)
52 	{
53 		lwdt= (int32_t) sqrt(double(rad*rad-ycnt*ycnt)); dpy=y+ycnt;
54 		for (xcnt=-lwdt; xcnt<lwdt+(lwdt==0); xcnt++)
55 			SetPix(x+xcnt,dpy,col);
56 	}
57 }
58 
DrawLayer(int32_t x,int32_t y,int32_t size,BYTE col)59 void C4MapCreator::DrawLayer(int32_t x, int32_t y, int32_t size, BYTE col)
60 {
61 	int32_t cnt,cnt2;
62 	for (cnt=0; cnt<size; cnt++)
63 	{
64 		x+=Random(9)-4; y+=Random(3)-1;
65 		for (cnt2=Random(3); cnt2<5; cnt2++)
66 			{ SetPix(x+cnt2,y,col); SetPix(x+cnt2+1,y+1,col); }
67 	}
68 }
69 
GetPix(int32_t x,int32_t y)70 BYTE C4MapCreator::GetPix(int32_t x, int32_t y)
71 {
72 	// Safety
73 	if (!Inside<int32_t>(x,0,MapWdt-1) || !Inside<int32_t>(y,0,MapHgt-1)) return 0;
74 	// Get pix
75 	return MapBuf->GetPix(x,y);
76 }
77 
Create(CSurface8 * sfcMap,C4SLandscape & rLScape,C4TextureMap & rTexMap,int32_t iPlayerNum)78 void C4MapCreator::Create(CSurface8 *sfcMap,
79                           C4SLandscape &rLScape, C4TextureMap &rTexMap,
80                           int32_t iPlayerNum)
81 {
82 	double fullperiod= 20.0 * M_PI;
83 	BYTE ccol;
84 	int32_t cx,cy;
85 
86 	// Safeties
87 	if (!sfcMap) return;
88 	iPlayerNum=Clamp<int32_t>(iPlayerNum,1,C4S_MaxPlayer);
89 
90 	// Set creator variables
91 	MapBuf = sfcMap;
92 	MapWdt = MapBuf->Wdt; MapHgt = MapBuf->Hgt;
93 
94 	// Reset map (0 is sky)
95 	MapBuf->ClearBox8Only(0,0,MapBuf->Wdt, MapBuf->Hgt);
96 
97 	// Surface
98 	ccol=rTexMap.GetIndexMatTex(rLScape.Material.c_str());
99 	auto amplitude= (float) rLScape.Amplitude.Evaluate();
100 	auto phase=     (float) rLScape.Phase.Evaluate();
101 	auto period=    (float) rLScape.Period.Evaluate();
102 	if (rLScape.MapPlayerExtend) period *= std::min(iPlayerNum, C4S_MaxMapPlayerExtend);
103 	float natural=   (float) rLScape.Random.Evaluate();
104 	int32_t level0=    std::min(MapWdt,MapHgt)/2;
105 	int32_t maxrange=  level0*3/4;
106 	double cy_curve,cy_natural; // -1.0 - +1.0 !
107 
108 	double rnd_cy,rnd_tend; // -1.0 - +1.0 !
109 	rnd_cy= (double) (Random(2000+1)-1000)/1000.0;
110 	rnd_tend= (double) (Random(200+1)-100)/20000.0;
111 
112 	for (cx=0; cx<MapWdt; cx++)
113 	{
114 
115 		rnd_cy+=rnd_tend;
116 		rnd_tend+= (double) (Random(100+1)-50)/10000;
117 		if (rnd_tend>+0.05) rnd_tend=+0.05;
118 		if (rnd_tend<-0.05) rnd_tend=-0.05;
119 		if (rnd_cy<-0.5) rnd_tend+=0.01;
120 		if (rnd_cy>+0.5) rnd_tend-=0.01;
121 
122 		cy_natural=rnd_cy*natural/100.0;
123 		cy_curve=sin(fullperiod*period/100.0*(float)cx/(float)MapWdt
124 		             +2.0*M_PI*phase/100.0) * amplitude/100.0;
125 
126 		cy=level0+Clamp((int32_t)((float)maxrange*(cy_curve+cy_natural)),
127 		                  -maxrange,+maxrange);
128 
129 
130 		SetPix(cx,cy,ccol);
131 	}
132 
133 	// Raise bottom to surface
134 	for (cx=0; cx<MapWdt; cx++)
135 		for (cy=MapHgt-1; (cy>=0) && !GetPix(cx,cy); cy--)
136 			SetPix(cx,cy,ccol);
137 	// Raise liquid level
138 	Exclusive=0;
139 	ccol=rTexMap.GetIndexMatTex(rLScape.Liquid.c_str());
140 	int32_t wtr_level=rLScape.LiquidLevel.Evaluate();
141 	for (cx=0; cx<MapWdt; cx++)
142 		for (cy=MapHgt*(100-wtr_level)/100; cy<MapHgt; cy++)
143 			SetPix(cx,cy,ccol);
144 	Exclusive=-1;
145 
146 	// Layers
147 	// Base material
148 	Exclusive=rTexMap.GetIndexMatTex(rLScape.Material.c_str());
149 
150 	int32_t cnt,clayer,layer_num,sptx,spty;
151 
152 	// Process layer name list
153 	for (clayer=0; clayer<C4MaxNameList; clayer++)
154 		if (rLScape.Layers.Name[clayer][0])
155 		{
156 			// Draw layers
157 			ccol=rTexMap.GetIndexMatTex(rLScape.Layers.Name[clayer]);
158 			layer_num=rLScape.Layers.Count[clayer];
159 			layer_num=layer_num*MapWdt*MapHgt/15000;
160 			for (cnt=0; cnt<layer_num; cnt++)
161 			{
162 				// Place layer
163 				sptx=Random(MapWdt);
164 				for (spty=0; (spty<MapHgt) && (GetPix(sptx,spty)!=Exclusive); spty++) {}
165 				spty+=5+Random((MapHgt-spty)-10);
166 				DrawLayer(sptx,spty,Random(15),ccol);
167 
168 			}
169 		}
170 
171 	Exclusive=-1;
172 }
173 
ValidateTextureIndices(C4TextureMap & rTextureMap)174 void C4MapCreator::ValidateTextureIndices(C4TextureMap &rTextureMap)
175 {
176 	int32_t iX,iY;
177 	for (iY=0; iY<MapHgt; iY++)
178 		for (iX=0; iX<MapWdt; iX++)
179 			if (!rTextureMap.GetEntry(GetPix(iX,iY)))
180 				SetPix(iX,iY,0);
181 }
182