Merge remote-tracking branch '_origin/master' into lights

Conflicts:
	src/c4group/C4Components.h
issue1247
Tobias Zwick 2014-12-15 21:16:40 +01:00
commit 4981182cf8
552 changed files with 3544 additions and 816 deletions

View File

@ -1554,12 +1554,11 @@ add_custom_target(setup
set(CPACK_PACKAGE_NAME "openclonk")
set(CPACK_PACKAGE_VENDOR "${C4PROJECT_URL}")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "OpenClonk - A game mix out of tactic, strategy and Jump & Run")
set(CPACK_PACKAGE_VERSION "${C4XVER1}.${C4XVER2}.${C4XVER3}")
set(CPACK_PACKAGE_VERSION "${C4XVER1}.${C4XVER2}")
set(CPACK_PACKAGE_VERSION_MAJOR "${C4XVER1}")
set(CPACK_PACKAGE_VERSION_MINOR "${C4XVER2}")
set(CPACK_PACKAGE_VERSION_PATCH "${C4XVER3}")
set(CPACK_PACKAGE_FILE_NAME "openclonk-${C4XVER1}.${C4XVER2}.${C4XVER3}")
set(CPACK_SOURCE_PACKAGE_FILE_NAME "openclonk-src-${C4XVER1}.${C4XVER2}.${C4XVER3}")
set(CPACK_PACKAGE_FILE_NAME "openclonk-${C4XVER1}.${C4XVER2}")
set(CPACK_SOURCE_PACKAGE_FILE_NAME "openclonk-src-${C4XVER1}.${C4XVER2}")
set(CPACK_SOURCE_GENERATOR "TGZ;ZIP")
# Somebody who uses Debian/Ubuntu should set this
#set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6, libgcc1, libx11, libXrandr, libXpm, libGLEW, libGL, libpng, libSDL-1.2, libSDL_mixer-1.2, gtk2, libjpeg, zlib")

View File

@ -11,9 +11,8 @@ SET(C4ENGINENAME "OpenClonk")
SET(C4ENGINENICK "openclonk")
SET(C4ENGINEID "${C4PROJECT_TLD}.${C4PROJECT_DOMAIN}.${C4ENGINENICK}")
SET(C4XVER1 5)
SET(C4XVER2 5)
SET(C4XVER3 1)
SET(C4XVER1 6)
SET(C4XVER2 0)
# C4VERSIONBUILDNAME should be witty and somewhat frequently changing
# for alpha and beta releases, and meaningful and stable for stable releases.
@ -46,7 +45,7 @@ SET(C4COPYRIGHT_YEAR ${YEARFIXED})
SET(C4ENGINECAPTION "${C4ENGINENAME}{$C4VERSIONBUILDNAME}")
set(C4ENGINEINFO "${C4ENGINENAME}")
set(C4VERSION "${C4XVER1}.${C4XVER2}.${C4XVER3}")
set(C4VERSION "${C4XVER1}.${C4XVER2}")
if(C4XVER4 LESS 10)
set(C4VERSION "${C4VERSION} [00${C4XVER4}]")

View File

@ -45,6 +45,10 @@
<row>
<literal_col>AM_DrawBefore</literal_col>
<col>Normally the mesh of the object itself is drawn first and afterwards the attached mesh. If this flag is present then the attached mesh is drawn before the object's mesh is drawn. Note that normally this makes no difference since a Z buffer is used to make sure the drawing order is correct. However if one or both of the meshes make use of alpha blending then the drawing order becomes relevant so that a mesh is not hidden behind otherwise (partly) translucent parts of the other mesh.</col>
</row>
<row>
<literal_col>AM_MatchSkeleton</literal_col>
<col>Normally the attached mesh uses its own animations. If this flag is set, then the attached mesh uses the animation data of the parent mesh for all bones that have the same name as a bone in the parent mesh skeleton.</col>
</row>
</table>
</desc>

View File

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE funcs
SYSTEM '../../../clonk.dtd'>
<?xml-stylesheet type="text/xsl" href="../../../clonk.xsl"?>
<funcs>
<func>
<title>GetPXSCount</title>
<category>Landscape</category>
<subcat>Material</subcat>
<version>5.2 OC</version>
<syntax>
<rtype>int</rtype>
<params>
<param>
<type>int</type>
<name>material</name>
<desc>Index of material. If nil or -1, any material is counted.</desc>
<optional />
</param>
<param>
<type>int</type>
<name>x</name>
<desc>Left side of search rectangle. Offset in local calls. Set to nil to search the whole map.</desc>
<optional />
</param>
<param>
<type>int</type>
<name>y</name>
<desc>Top side of search rectangle. Offset in local calls.</desc>
<optional />
</param>
<param>
<type>int</type>
<name>wdt</name>
<desc>Width of search rectangle. Right border is not included in search.</desc>
<optional />
</param>
<param>
<type>int</type>
<name>wdt</name>
<desc>Height of search rectangle. Bottom border is not included in search.</desc>
<optional />
</param>
</params>
</syntax>
<desc>Determines how many loose pixels (PXS) are present of a given material in a given rectangle.</desc>
<examples>
<example>
<code><funclink>if</funclink>(GetPXSCount(<funclink>Material</funclink>(&quot;Snow&quot;), -100,-100,200,100) > 5) <funclink>Message</funclink>(&quot;It is snowing!&quot;);</code>
<text>Part of a clonk script: if snow is found around the clonk, he shows a message above his head.</text>
</example>
</examples>
<related>
<funclink>Material</funclink>
<funclink>CastPXS</funclink>
<funclink>InsertMaterial</funclink>
<funclink>GetMaterial</funclink>
</related>
</func>
<author>Sven2</author><date>2014-12</date>
</funcs>

View File

@ -22,6 +22,12 @@
<desc>If 1, the specified track will be looped forever.</desc>
<optional />
</param>
<param>
<type>int</type>
<name>fadetime_ms</name>
<desc>Fading time between any currently playing piece and the newly selected song. Ignored if both are the same. Set to zero to avoid fading.</desc>
<optional />
</param>
</params>
</syntax>
<desc>Plays a music track. The corresponding music file must be available in the active music group. If the loaded scenario contains music files, the scenario file will be the music group. Otherwise, the global file Music.ocg will be used.</desc>

View File

@ -13,7 +13,7 @@
<param>
<type>string</type>
<name>playlist</name>
<desc>List of pieces of music to be played. The individual file names are separated with semicolons (";"). Wildcards are expanded. If the parameter is left out, the standard playlist is restored.</desc>
<desc>List of pieces of music to be played. The individual file and category names are separated with semicolons (";"). Wildcards are expanded. If the parameter is left out, the standard playlist is restored.</desc>
<optional />
</param>
<param>
@ -22,9 +22,22 @@
<desc>The playlist is changed only on clients where the player with this player number is local. If left out or NO_OWNER, the playlist is changed for all clients. If the player number is invalid, no playlists are changed.</desc>
<optional />
</param>
<param>
<type>bool</type>
<name>force_change</name>
<desc>If true and the new playlist does not contain the piece currently playing, a new song is selected and played.</desc>
<optional />
</param>
<param>
<type>int</type>
<name>fadetime_ms</name>
<desc>Fade time to the new piece if force_change is true and the current song is changed in response to this call. Set to zero to change music instantly.</desc>
<optional />
</param>
</params>
</syntax>
<desc>Sets the play list of pieces of music to be played in random order, if music is activated. The actual number of pieces of music in the playlist is returned, or 0 in network mode.</desc>
<remark>Pieces are identified either by matching file name or any matching category. Categories are only available for .ogg files and may be set as a semicolon-delimited list in the comment field. Matching is case-insensitive, but case insensitive matching does not work for extended UTF8 characters.</remark>
<remark>SetPlayList does not activate music playback when the player has turned the music off. If the player enables music, the new playlist takes effect.</remark>
<remark><code>SetPlayList("*.*")</code> is not identical to <code>SetPlayList()</code>. The former activates all music, the latter only those not starting with "@", the standard behavior.</remark>
<related><funclink>Music</funclink></related>

View File

@ -1,6 +1,6 @@
[DefCore]
id=Goal_FlagMeshes
Version=5,2,0,1
Version=6,0
Category=C4D_Object
Width=30
Height=40

View File

@ -1,7 +1,7 @@
[Head]
Icon=13
Title=FrozenFortress
Version=5,2,0,1
Version=6,0
MinPlayer=2
Difficulty=80

View File

@ -1,6 +1,6 @@
[DefCore]
id=FrostboltScroll
Version=5,2,0,1
Version=6,0
Category=C4D_Object
Width=8
Height=8

View File

@ -1,6 +1,6 @@
[DefCore]
id=HardeningScroll
Version=5,2,0,1
Version=6,0
Category=C4D_Object
Width=8
Height=8

View File

@ -1,6 +1,6 @@
[DefCore]
id=WindScroll
Version=5,2,0,1
Version=6,0
Category=C4D_Object
Width=8
Height=8

View File

@ -1,6 +1,6 @@
[DefCore]
id=Goal_FlagMeshes
Version=5,2,0,1
Version=6,0
Category=C4D_Object
Width=30
Height=40

View File

@ -1,6 +1,6 @@
[DefCore]
id=LifeGem
Version=5,2,0,1
Version=6,0
Category=C4D_Object
Width=8
Height=8

View File

@ -1,6 +1,6 @@
[DefCore]
id=PyreGem
Version=5,2,0,1
Version=6,0
Category=C4D_Object
Width=8
Height=8

View File

@ -1,7 +1,7 @@
[Head]
Icon=13
Title=Hideout
Version=5,2,0,1
Version=6,0
MinPlayer=2
Difficulty=90

View File

@ -1,6 +1,6 @@
[DefCore]
id=ShieldGem
Version=5,2,0,1
Version=6,0
Category=C4D_Object
Width=8
Height=8

View File

@ -1,6 +1,6 @@
[DefCore]
id=CrystalShield
Version=5,2,0,1
Version=6,0
Category=C4D_StaticBack
Width=8
Height=7

View File

@ -1,6 +1,6 @@
[DefCore]
id=SlowGem
Version=5,2,0,1
Version=6,0
Category=C4D_Object
Width=8
Height=8

View File

@ -1,6 +1,6 @@
[Head]
Title=HotIce
Version=5,3,2
Version=6,0
MinPlayer=2
MaxPlayer=20
Icon=21

View File

@ -1,4 +1,4 @@
[DefCore]
id=KingWeapons
Version=5,2,0,1
Version=6,0
Category=C4D_StaticBack

View File

@ -1,6 +1,6 @@
[Head]
Title=MoltenMonarch
Version=5,2,0,1
Version=6,0
Icon=23
MinPlayer=2
Difficulty=70

View File

@ -1,6 +1,6 @@
[Head]
Title=Overcast
Version=5,2,0,1
Version=6,0
MinPlayer=2
Difficulty=50

View File

@ -1,6 +1,6 @@
[DefCore]
id=FireballScroll
Version=5,2,0,1
Version=6,0
Category=C4D_Object
Width=8
Height=8

View File

@ -1,6 +1,6 @@
[DefCore]
id=TeleportScroll
Version=5,2,0,1
Version=6,0
Category=C4D_Object
Width=8
Height=8

View File

@ -1,6 +1,6 @@
[DefCore]
id=WindScroll
Version=5,2,0,1
Version=6,0
Category=C4D_Object
Width=8
Height=8

View File

@ -1,6 +1,6 @@
[Head]
Title=Bottom
Version=5,2,0,1
Version=6,0
MinPlayer=2
Difficulty=20

View File

@ -1,6 +1,6 @@
[Head]
Title=Ruins
Version=5,2,0,1
Version=6,0
MinPlayer=2
Difficulty=30

View File

@ -1,6 +1,6 @@
[DefCore]
id=Grass
Version=5,2,0,1
Version=6,0
Category=C4D_StaticBack|C4D_Background
Width=12
Height=7

View File

@ -1,6 +1,6 @@
[Head]
Title=ScorchedGardens
Version=5,2,0,1
Version=6,0
MinPlayer=2
Difficulty=40

View File

@ -1,6 +1,6 @@
[Head]
Title=Overcast
Version=5,2,0,1
Version=6,0
MinPlayer=2
Difficulty=60

View File

@ -1,6 +1,6 @@
[DefCore]
id=FireballScroll
Version=5,2,0,1
Version=6,0
Category=C4D_Object
Width=8
Height=8

View File

@ -1,6 +1,6 @@
[DefCore]
id=ThunderScroll
Version=5,2,0,1
Version=6,0
Category=C4D_Object
Width=8
Height=8

View File

@ -1,6 +1,6 @@
[DefCore]
id=WindScroll
Version=5,2,0,1
Version=6,0
Category=C4D_Object
Width=8
Height=8

View File

@ -1,6 +1,6 @@
[DefCore]
id=TargetBalloon
Version=4,9,8
Version=6,0
Category=C4D_Vehicle
Width=64
Height=64

View File

@ -1,6 +1,6 @@
[DefCore]
id=BigBoomattack
Version=5,2,0,1
Version=6,0
Category=C4D_Object
ContactCalls=1
Width=60

View File

@ -1,6 +1,6 @@
[DefCore]
id=Boomattack
Version=5,2,0,1
Version=6,0
Category=C4D_Object
ContactCalls=1
Width=15

View File

@ -1,6 +1,6 @@
[DefCore]
id=Goal_SaveTheWindmills
Version=5,2,0,1
Version=6,0
Category=C4D_StaticBack|C4D_Goal
Width=1
Height=1

View File

@ -1,7 +1,7 @@
[Head]
Icon=39
Title=Windmill
Version=5,2,0,1
Version=6,0
Difficulty=10
[Definitions]

View File

@ -1,6 +1,6 @@
[DefCore]
id=Deco_AltMaterials
Version=5,2,0,1
Version=6,0
Category=C4D_StaticBack
Width=1
Height=1

View File

@ -1,6 +1,6 @@
[DefCore]
id=Hat
Version=5,2,0,1
Version=6,0
Category=C4D_Object
Width=8
Height=8

View File

@ -1,6 +1,6 @@
[DefCore]
id=LotsOfCoins
Version=5,2,0,1
Version=6,0
Category=C4D_StaticBack
Width=55
Height=17

View File

@ -1,6 +1,6 @@
[DefCore]
id=Bone
Version=5,2,0,1
Version=6,0
Category=C4D_Object
Width=8
Height=8

View File

@ -1,6 +1,6 @@
[DefCore]
id=Ruin_ChemicalLab
Version=5,4,0,0
Version=6,0
Category=C4D_Structure
Width=50
Height=52

View File

@ -1,6 +1,6 @@
[DefCore]
id=Ruin_Windmill
Version=5,4,0,0
Version=6,0
Category=C4D_Structure
Width=80
Height=96

View File

@ -1,6 +1,6 @@
[DefCore]
id=Ruin_WoodenCabin
Version=5,4,0,0
Version=6,0
Category=C4D_Structure
Width=94
Height=43

View File

@ -1,6 +1,6 @@
[DefCore]
id=Skull
Version=5,2,0,1
Version=6,0
Category=C4D_Object
Width=11
Height=13

View File

@ -1,6 +1,6 @@
[DefCore]
id=EnvPack_ManaAltar
Version=4,10,0,0
Version=6,0
Category=C4D_Object
Width=8
Height=8

View File

@ -1,6 +1,6 @@
[DefCore]
id=StrawMan
Version=5,4,0,0
Version=6,0
Category=C4D_StaticBack
Width=12
Height=20

View File

@ -0,0 +1,5 @@
[DefCore]
id=Ambience
Version=6,0
Category=C4D_StaticBack | C4D_Rule
Picture=0,0,128,128

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -0,0 +1,299 @@
/**
Ambience
Controls sound and music depending on the environment the player is in
@author Sven2
*/
local exec_counter; // counter to distribute execution of players across frames
local last_environment; // array indexed by player number: pointer to environment the player was in last
local environments; // array of available environments for which it is checked if the player is in. sorted by priority.
// Initialization
protected func Initialize()
{
// Base environment
Environment = {
actions = [],
min_change_delay = 1,
min_initial_change_delay = 5,
AddSound = this.Env_AddSound,
AddAction = this.Env_AddAction,
SetMusic = this.Env_SetMusic
};
// Register default environments (overloadable)
this->InitializeEnvironments();
// Periodic execution of ambience events
last_environment = [];
AddTimer(this.Execute, 10);
return true;
}
func InitializeEnvironments()
{
// Register all standard environments
environments = [];
// Underwater: Clonk is swimming in water
var underwater = this.env_underwater = new Environment {};
underwater->SetMusic("underwater");
underwater.CheckPlayer = this.EnvCheck_Underwater;
AddEnvironment(underwater, 1400);
// City: Clonk is surrounded by buildings
var city = this.env_city = new Environment {};
city->SetMusic("city");
city.CheckPlayer = this.EnvCheck_City;
AddEnvironment(city, 1200);
// Lava: Lava material is nearby
var lava = this.env_lava = new Environment {};
lava->SetMusic("lava");
lava.CheckPlayer = this.EnvCheck_Lava;
lava.mat_mask = CreateArray(); // material mask for lava materials. +1 cuz sky.
lava.mat_mask[Material("Lava")+1] = true; // loop over materials and check incindiary instead? Whoever introduces the next lava type can do that...
lava.mat_mask[Material("DuroLava")+1] = true;
lava.min_change_delay = 3; // Easy to miss lava on search.
AddEnvironment(lava, 1000);
// Underground: Clonk in front of tunnel
var underground = this.env_underground = new Environment {};
underground->SetMusic("underground");
underground.CheckPlayer = this.EnvCheck_Underground;
AddEnvironment(underground, 800);
// Mountains: Overground and lots of rock around
var mountains = this.env_mountains = new Environment {};
mountains->SetMusic("mountains");
mountains.CheckPlayer = this.EnvCheck_Mountains;
mountains.mat_mask = CreateArray(); // material mask for mountain materials. +1 cuz sky.
mountains.mat_mask[Material("Rock")+1] = true;
mountains.mat_mask[Material("Granite")+1] = true;
mountains.mat_mask[Material("Ore")+1] = true;
mountains.mat_mask[Material("Gold")+1] = true;
mountains.min_change_delay = 3; // Pretty unstable condition
AddEnvironment(mountains, 600);
// Snow: It's snowing around the clonk
var snow = this.env_snow = new Environment {};
snow->SetMusic("snow");
snow.CheckPlayer = this.EnvCheck_Snow;
snow.min_change_delay = 6; // Persist a while after snowing stopped
snow.mat = Material("Snow");
AddEnvironment(snow, 400);
// Night: Sunlight blocked by planet
var night = this.env_night = new Environment {};
night->SetMusic("night");
night.CheckPlayer = this.EnvCheck_Night;
AddEnvironment(night, 200);
// Overground: Default environment
var overground = this.env_overground = new Environment {};
overground->SetMusic("overground");
overground.CheckPlayer = this.EnvCheck_Overground;
overground->AddSound("Ding", 100);
AddEnvironment(overground, 0);
return true;
}
private func Execute()
{
// Per-player execution every third timer (~.8 seconds)
var i=GetPlayerCount(C4PT_User);
while (i--) if (!(++exec_counter % 3))
{
ExecutePlayer(GetPlayerByIndex(i, C4PT_User));
}
return true;
}
private func ExecutePlayer(int plr)
{
var cursor = GetCursor(plr);
// Determine environment the player is currently in
var environment = nil;
if (cursor)
{
var last_env = last_environment[plr];
var x = cursor->GetX(), y = cursor->GetY();
for (test_environment in environments)
{
if (environment = test_environment->CheckPlayer(cursor, x, y, test_environment == last_env))
{
// We've found a matchign environment.
// Was it a change? Then check delays first
if (test_environment != last_env)
{
if (last_env && last_env.no_change_delay)
{
// Environment should change but a delay is specified. Keep last environment for now.
--last_env.no_change_delay;
environment = last_env;
break;
}
// New environment and change delay has passed.
environment.no_change_delay = environment.min_initial_change_delay;
Log("%s environment: %s", GetPlayerName(plr), environment.music);
}
else
{
// Was no change: Reset change delays
environment.no_change_delay = Max(environment.no_change_delay, environment.min_change_delay);
}
break;
}
}
}
last_environment[plr] = environment;
if (!environment) return true;
// Music by environment
this->SetPlayList(environment.music, plr, true, 3000);
// Sounds and actions by environment
for (var action in environment.actions)
if (Random(1000) < action.chance)
cursor->Call(action.fn, action.par[0], action.par[1], action.par[2], action.par[3], action.par[4]);
return true;
}
func InitializePlayer(int plr)
{
// Newly joining players should have set playlist immediately (so they don't start playing a random song just to switch it immediately)
ExecutePlayer(plr);
return true;
}
func RemovePlayer(int plr)
{
// Ensure newly joining players don't check on another player's environment
last_environment[plr] = nil;
return true;
}
protected func Activate(int byplr)
{
MessageWindow(this.Description, byplr);
return true;
}
/* Environment functions */
func AddEnvironment(proplist new_env, priority)
{
if (GetType(priority)) new_env.Priority = priority;
this.environments[GetLength(environments)] = new_env;
SortArrayByProperty(this.environments, "Priority", true);
return true;
}
private func Env_AddSound(string snd_name, chance)
{
return Env_AddAction(Global.Sound, snd_name, chance ?? 50);
}
private func Env_AddAction(afn, par0, par1, par2, par3, par4)
{
return this.actions[GetLength(this.actions)] = { fn=afn, par=[par0, par1, par2, par3, par4] };
}
private func Env_SetMusic(string playlist)
{
this.music = playlist;
return true;
}
/* Default environment checks */
private func EnvCheck_Underwater(object cursor, int x, int y, bool is_current)
{
// Clonk should be swimming
if (cursor->GetProcedure() != "SWIM") return nil;
// For initial change, clonk should also be diving: Check for breath below 80%
// Use > instead of >= to ensure 0-breath-clonks can also get the environment
if (!is_current && cursor->GetBreath() > cursor.MaxBreath*4/5) return nil;
return this;
}
private func EnvCheck_City(object cursor, int x, int y, bool is_current)
{
// There must be buildings around the clonk
var building_count = cursor->ObjectCount(cursor->Find_AtRect(-180,-100,360,200), Find_Func("IsStructure"));
// 3 buildings to start the environment. Just 1 building to sustain it.
if (building_count < 3-2*is_current) return nil;
return this;
}
private func EnvCheck_Lava(object cursor, int x, int y, bool is_current)
{
// Check for lava pixels. First check if the last lava pixel we found is still in place.
var search_range;
if (is_current)
{
if (this.mat_mask[GetMaterial(this.last_x, this.last_y)+1])
if (Distance(this.last_x, this.last_y, x, y) < 140)
return this;
search_range = 140;
}
else
{
search_range = 70;
}
// Now search for lava in search range
var ang = Random(360);
for (; search_range >= 0; search_range -= 10)
{
ang += 200;
var x2 = x + Sin(ang, search_range);
var y2 = y + Cos(ang, search_range);
if (this.mat_mask[GetMaterial(x2, y2)+1])
{
// Lava found!
this.last_x = x2;
this.last_y = y2;
return this;
}
}
// No lava found
return nil;
}
private func EnvCheck_Underground(object cursor, int x, int y, bool is_current)
{
// Check for underground: No sky at cursor or above
if (GetMaterial(x,y)<0) return nil;
if (GetMaterial(x,y-30)<0) return nil;
if (GetMaterial(x-10,y-20)<0) return nil;
if (GetMaterial(x+10,y-20)<0) return nil;
return this;
}
private func EnvCheck_Mountains(object cursor, int x, int y, bool is_current)
{
// Check for mountains: Rock materials below
var num_rock;
for (var y2=0; y2<=45; y2+=15)
for (var x2=-75; x2<=75; x2+=15)
num_rock += this.mat_mask[GetMaterial(x+x2,y+y2)+1];
// need 15pts on first check; 5 to sustain
if (num_rock < 15-is_current*10) return nil;
return this;
}
private func EnvCheck_Snow(object cursor, int x, int y, bool is_current)
{
// Must be snowing from above
if (GetPXSCount(this.mat, x-300, y-200, 600, 300) < 20 - is_current*15) return nil;
return this;
}
private func EnvCheck_Night(object cursor, int x, int y, bool is_current)
{
// Night time.
var time = FindObject(Find_ID(Environment_Time));
if (!time || !time->IsNight()) return nil;
return this;
}
private func EnvCheck_Overground(object cursor, int x, int y, bool is_current)
{
// This is the fallback environment
return this;
}
/*-- Proplist --*/
local Name = "$Name$";
local Description = "$Description$";
local Environment;

View File

@ -0,0 +1,2 @@
Name=Ambiente
Description=Regelt die Geraeuschkulisse.

View File

@ -0,0 +1,3 @@
Name=Ambience
Description=Controls environmental sounds and music.

View File

@ -1,6 +1,6 @@
[DefCore]
id=VisualPath
Version=5,2,0,1
Version=6,0
Category=C4D_StaticBack
Width=1
Height=1

View File

Before

Width:  |  Height:  |  Size: 525 KiB

After

Width:  |  Height:  |  Size: 525 KiB

View File

@ -1,6 +1,6 @@
[DefCore]
id=Hatch
Version=5,2,0,1
Version=6,0
Category=C4D_Structure
Width=26
Height=26

View File

@ -1,6 +1,6 @@
[DefCore]
id=Hatch_Graphic
Version=5,2,0,1
Version=6,0
Width=26
Height=26
Offset=-13,-13

View File

@ -1,6 +1,6 @@
[DefCore]
id=LiftTower
Version=5,2,0,1
Version=6,0
Category=C4D_Structure
Width=23
Height=68

View File

@ -1,6 +1,6 @@
[DefCore]
id=LiftTower_Hook
Version=5,2,0,1
Version=6,0
Category=C4D_Object
Width=8
Height=8

View File

@ -1,6 +1,6 @@
[DefCore]
id=LiftTower_Rope
Version=5,2,0,1
Version=6,0
Category=C4D_StaticBack
Vertices=2
Width=2

View File

@ -1,6 +1,6 @@
[DefCore]
id=Moss
Version=5,2,0,1
Version=6,0
Category=C4D_Object
Width=8
Height=8

View File

@ -1,6 +1,6 @@
[DefCore]
id=Moss_Lichen
Version=5,2,0,1
Version=6,0
Category=C4D_StaticBack | C4D_Object
Width=20
Height=20

View File

@ -0,0 +1,5 @@
[DefCore]
id=Ambience
Version=6,0
Category=C4D_StaticBack | C4D_Rule
Picture=0,0,128,128

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -0,0 +1,299 @@
/**
Ambience
Controls sound and music depending on the environment the player is in
@author Sven2
*/
local exec_counter; // counter to distribute execution of players across frames
local last_environment; // array indexed by player number: pointer to environment the player was in last
local environments; // array of available environments for which it is checked if the player is in. sorted by priority.
// Initialization
protected func Initialize()
{
// Base environment
Environment = {
actions = [],
min_change_delay = 1,
min_initial_change_delay = 5,
AddSound = this.Env_AddSound,
AddAction = this.Env_AddAction,
SetMusic = this.Env_SetMusic
};
// Register default environments (overloadable)
this->InitializeEnvironments();
// Periodic execution of ambience events
last_environment = [];
AddTimer(this.Execute, 10);
return true;
}
func InitializeEnvironments()
{
// Register all standard environments
environments = [];
// Underwater: Clonk is swimming in water
var underwater = this.env_underwater = new Environment {};
underwater->SetMusic("underwater");
underwater.CheckPlayer = this.EnvCheck_Underwater;
AddEnvironment(underwater, 1400);
// City: Clonk is surrounded by buildings
var city = this.env_city = new Environment {};
city->SetMusic("city");
city.CheckPlayer = this.EnvCheck_City;
AddEnvironment(city, 1200);
// Lava: Lava material is nearby
var lava = this.env_lava = new Environment {};
lava->SetMusic("lava");
lava.CheckPlayer = this.EnvCheck_Lava;
lava.mat_mask = CreateArray(); // material mask for lava materials. +1 cuz sky.
lava.mat_mask[Material("Lava")+1] = true; // loop over materials and check incindiary instead? Whoever introduces the next lava type can do that...
lava.mat_mask[Material("DuroLava")+1] = true;
lava.min_change_delay = 3; // Easy to miss lava on search.
AddEnvironment(lava, 1000);
// Underground: Clonk in front of tunnel
var underground = this.env_underground = new Environment {};
underground->SetMusic("underground");
underground.CheckPlayer = this.EnvCheck_Underground;
AddEnvironment(underground, 800);
// Mountains: Overground and lots of rock around
var mountains = this.env_mountains = new Environment {};
mountains->SetMusic("mountains");
mountains.CheckPlayer = this.EnvCheck_Mountains;
mountains.mat_mask = CreateArray(); // material mask for mountain materials. +1 cuz sky.
mountains.mat_mask[Material("Rock")+1] = true;
mountains.mat_mask[Material("Granite")+1] = true;
mountains.mat_mask[Material("Ore")+1] = true;
mountains.mat_mask[Material("Gold")+1] = true;
mountains.min_change_delay = 3; // Pretty unstable condition
AddEnvironment(mountains, 600);
// Snow: It's snowing around the clonk
var snow = this.env_snow = new Environment {};
snow->SetMusic("snow");
snow.CheckPlayer = this.EnvCheck_Snow;
snow.min_change_delay = 6; // Persist a while after snowing stopped
snow.mat = Material("Snow");
AddEnvironment(snow, 400);
// Night: Sunlight blocked by planet
var night = this.env_night = new Environment {};
night->SetMusic("night");
night.CheckPlayer = this.EnvCheck_Night;
AddEnvironment(night, 200);
// Overground: Default environment
var overground = this.env_overground = new Environment {};
overground->SetMusic("overground");
overground.CheckPlayer = this.EnvCheck_Overground;
overground->AddSound("Ding", 100);
AddEnvironment(overground, 0);
return true;
}
private func Execute()
{
// Per-player execution every third timer (~.8 seconds)
var i=GetPlayerCount(C4PT_User);
while (i--) if (!(++exec_counter % 3))
{
ExecutePlayer(GetPlayerByIndex(i, C4PT_User));
}
return true;
}
private func ExecutePlayer(int plr)
{
var cursor = GetCursor(plr);
// Determine environment the player is currently in
var environment = nil;
if (cursor)
{
var last_env = last_environment[plr];
var x = cursor->GetX(), y = cursor->GetY();
for (test_environment in environments)
{
if (environment = test_environment->CheckPlayer(cursor, x, y, test_environment == last_env))
{
// We've found a matchign environment.
// Was it a change? Then check delays first
if (test_environment != last_env)
{
if (last_env && last_env.no_change_delay)
{
// Environment should change but a delay is specified. Keep last environment for now.
--last_env.no_change_delay;
environment = last_env;
break;
}
// New environment and change delay has passed.
environment.no_change_delay = environment.min_initial_change_delay;
Log("%s environment: %s", GetPlayerName(plr), environment.music);
}
else
{
// Was no change: Reset change delays
environment.no_change_delay = Max(environment.no_change_delay, environment.min_change_delay);
}
break;
}
}
}
last_environment[plr] = environment;
if (!environment) return true;
// Music by environment
this->SetPlayList(environment.music, plr, true, 3000);
// Sounds and actions by environment
for (var action in environment.actions)
if (Random(1000) < action.chance)
cursor->Call(action.fn, action.par[0], action.par[1], action.par[2], action.par[3], action.par[4]);
return true;
}
func InitializePlayer(int plr)
{
// Newly joining players should have set playlist immediately (so they don't start playing a random song just to switch it immediately)
ExecutePlayer(plr);
return true;
}
func RemovePlayer(int plr)
{
// Ensure newly joining players don't check on another player's environment
last_environment[plr] = nil;
return true;
}
protected func Activate(int byplr)
{
MessageWindow(this.Description, byplr);
return true;
}
/* Environment functions */
func AddEnvironment(proplist new_env, priority)
{
if (GetType(priority)) new_env.Priority = priority;
this.environments[GetLength(environments)] = new_env;
SortArrayByProperty(this.environments, "Priority", true);
return true;
}
private func Env_AddSound(string snd_name, chance)
{
return Env_AddAction(Global.Sound, snd_name, chance ?? 50);
}
private func Env_AddAction(afn, par0, par1, par2, par3, par4)
{
return this.actions[GetLength(this.actions)] = { fn=afn, par=[par0, par1, par2, par3, par4] };
}
private func Env_SetMusic(string playlist)
{
this.music = playlist;
return true;
}
/* Default environment checks */
private func EnvCheck_Underwater(object cursor, int x, int y, bool is_current)
{
// Clonk should be swimming
if (cursor->GetProcedure() != "SWIM") return nil;
// For initial change, clonk should also be diving: Check for breath below 80%
// Use > instead of >= to ensure 0-breath-clonks can also get the environment
if (!is_current && cursor->GetBreath() > cursor.MaxBreath*4/5) return nil;
return this;
}
private func EnvCheck_City(object cursor, int x, int y, bool is_current)
{
// There must be buildings around the clonk
var building_count = cursor->ObjectCount(cursor->Find_AtRect(-180,-100,360,200), Find_Func("IsStructure"));
// 3 buildings to start the environment. Just 1 building to sustain it.
if (building_count < 3-2*is_current) return nil;
return this;
}
private func EnvCheck_Lava(object cursor, int x, int y, bool is_current)
{
// Check for lava pixels. First check if the last lava pixel we found is still in place.
var search_range;
if (is_current)
{
if (this.mat_mask[GetMaterial(this.last_x, this.last_y)+1])
if (Distance(this.last_x, this.last_y, x, y) < 140)
return this;
search_range = 140;
}
else
{
search_range = 70;
}
// Now search for lava in search range
var ang = Random(360);
for (; search_range >= 0; search_range -= 10)
{
ang += 200;
var x2 = x + Sin(ang, search_range);
var y2 = y + Cos(ang, search_range);
if (this.mat_mask[GetMaterial(x2, y2)+1])
{
// Lava found!
this.last_x = x2;
this.last_y = y2;
return this;
}
}
// No lava found
return nil;
}
private func EnvCheck_Underground(object cursor, int x, int y, bool is_current)
{
// Check for underground: No sky at cursor or above
if (GetMaterial(x,y)<0) return nil;
if (GetMaterial(x,y-30)<0) return nil;
if (GetMaterial(x-10,y-20)<0) return nil;
if (GetMaterial(x+10,y-20)<0) return nil;
return this;
}
private func EnvCheck_Mountains(object cursor, int x, int y, bool is_current)
{
// Check for mountains: Rock materials below
var num_rock;
for (var y2=0; y2<=45; y2+=15)
for (var x2=-75; x2<=75; x2+=15)
num_rock += this.mat_mask[GetMaterial(x+x2,y+y2)+1];
// need 15pts on first check; 5 to sustain
if (num_rock < 15-is_current*10) return nil;
return this;
}
private func EnvCheck_Snow(object cursor, int x, int y, bool is_current)
{
// Must be snowing from above
if (GetPXSCount(this.mat, x-300, y-200, 600, 300) < 20 - is_current*15) return nil;
return this;
}
private func EnvCheck_Night(object cursor, int x, int y, bool is_current)
{
// Night time.
var time = FindObject(Find_ID(Environment_Time));
if (!time || !time->IsNight()) return nil;
return this;
}
private func EnvCheck_Overground(object cursor, int x, int y, bool is_current)
{
// This is the fallback environment
return this;
}
/*-- Proplist --*/
local Name = "$Name$";
local Description = "$Description$";
local Environment;

View File

@ -0,0 +1,2 @@
Name=Ambiente
Description=Regelt die Geraeuschkulisse.

View File

@ -0,0 +1,3 @@
Name=Ambience
Description=Controls environmental sounds and music.

View File

@ -0,0 +1,15 @@
[DefCore]
id=CrystalCommunicator
Version=6,0
Category=C4D_Structure
Width=90
Height=70
Offset=-45,-35
Vertices=2
VertexX=-40,40
VertexY=34,34
VertexFriction=100,100
Mass=300
Components=Ruby=6;Amethyst=6;Metal=6;
Rotate=0
Construction=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

View File

@ -0,0 +1,357 @@
/*--
Crystal communicator
Author: Sven2
Shining structure built from gems and metal
--*/
#include Library_Structure
local top_face, base_face;
public func IsCrystalCommunicator() { return !base_face; }
/* Construction */
public func SetConstructionSiteOverlay(object site, int dir, object stick, object component_obj)
{
// Play component-specific sound for adding stuff to the site
if (component_obj && !component_obj->GetDefFragile()) component_obj->~Hit();
// Construction site graphics by provided metal
var metal_completion = site->ContentsCount(Metal) * 3 / Max(GetComponent(Metal, nil, nil, this), 1);
site->SetGraphics(["Site0", "Site1", "Site2", nil][metal_completion], CrystalCommunicator, 1, GFXOV_MODE_Base);
site->SetGraphics(nil, nil, 2);
// Add graphics of contained gems
UpdateGemOverlays(site, [1, 3, 7, 12][metal_completion]);
return true;
}
public func DoConstructionEffects(object site)
{
// Grab all gems from site
GrabContents(site);
var metal;
while (metal = FindContents(Metal)) metal->RemoveObject();
// Site is done immediately
SetCon(100);
// Create TopFace overlay
top_face = CreateObject(GetID(),0,35,GetOwner());
top_face.Plane = this.Plane + 10;
top_face->SetGraphics("TopFace");
top_face->SetAction("Attach", this);
top_face.base_face = this;
// Transfer gem overlays
this.gem_overlays = site.gem_overlays;
UpdateGemOverlays(this, 13, true);
// Construction done. Remove site.
site->RemoveObject(site);
// Start finals effect
return true;
}
/* Gem overlays */
static const CrystalCommunicator_GemsX = [ 15,440,336,221,121,298,220, 50, 14,333,129, 77],
CrystalCommunicator_GemsY = [255, 75,100, 84, 44,107, 15,130,107,153,149,106],
CrystalCommunicator_GemsZ = [ 5, 3, 4, 0, 4, 0, 5, 2, 3, 1, 1, 4],
CrystalCommunicator_GemCount = 12;
private func UpdateGemOverlays(object obj, int max_overlays, bool refresh_existing)
{
// Add overlays for any gems that have not yet been added
var gem_overlay_index = 3;
if (!obj.gem_overlays) obj.gem_overlays = [];
var n_overlays = GetLength(obj.gem_overlays);
var i;
// Remove overlays of gems that have left
for (i=0; i<n_overlays; ++i)
if (!obj.gem_overlays[i] || obj.gem_overlays[i]->Contained() != obj)
{
obj->SetGraphics(nil, nil, gem_overlay_index+i);
if (obj.top_face) obj.top_face->SetGraphics(nil, nil, gem_overlay_index+i);
obj.gem_overlays[i] = nil;
}
// Add new overlays
for (var gem in FindObjects(Find_Container(obj), Find_Func("GetGemColor")))
{
// Already displayed?
i = GetIndexOf(obj.gem_overlays, gem);
if (i>=0)
{
if (!refresh_existing) continue;
}
else
{
// Find a spot for this gem
i = GetIndexOf(obj.gem_overlays, nil);
if (i<0) i=n_overlays;
// No free space?
if (i == max_overlays) if (refresh_existing) continue; else break;
}
// Add overlay
var gem_gfx = gem.graphics_index;
if (gem_gfx) gem_gfx = Format("%d", gem_gfx+1); else gem_gfx = nil;
var x = CrystalCommunicator_GemsX[i];
var y = CrystalCommunicator_GemsY[i];
var z = CrystalCommunicator_GemsZ[i];
var size = z*100+500;
var off_y;
if (obj == this) off_y = 35000; else off_y = 70000;
var gem_target;
if (obj.top_face && z>=3) gem_target = obj.top_face; else gem_target = obj;
gem_target->SetGraphics(gem_gfx, gem->GetID(), gem_overlay_index+i, GFXOV_MODE_Base);
gem_target->SetObjDrawTransform(size,0,x*200-45000, 0,size,y*200-off_y, gem_overlay_index+i);
if (z<3) gem_target->SetClrModulation(0xffb0b0b0, gem_overlay_index+i);
// Remember in list
obj.gem_overlays[i] = gem;
n_overlays = GetLength(obj.gem_overlays);
}
// Make sure a glitter effect is there
if (!GetEffect("IntGemGlitter", obj)) AddEffect("IntGemGlitter", obj, 1, 12, nil, CrystalCommunicator);
return true;
}
private func FxIntGemGlitterTimer(target)
{
// Glitter at random gem position
if (Random(2))
{
var i = Random(12), gem;
if (gem = target.gem_overlays[i])
{
var x = CrystalCommunicator_GemsX[i]/5 - 45;
var y = CrystalCommunicator_GemsY[i]/5 - 35;
if (target->GetID() == ConstructionSite) y -= 35;
var size = CrystalCommunicator_GemsZ[i]*4 + 10;
var sparkle_fx = GetEffect("Sparkle", gem);
sparkle_fx.Size = PV_KeyFrames(1, 0, 0, 500, size, 1000, 0); // modifying value directly in gem, assuming gem won't leave this structure any more
if (sparkle_fx && sparkle_fx.particles)
target->CreateParticle("MagicRing", x, y, 0, 0, size, sparkle_fx.particles, 1);
}
}
}
/* End sequence */
local ruby_particle, amethyst_particle, beam_particles, gem_particles;
local flash_particle, small_flash_particle, large_flash_particle;
local time;
local send_code, next_send_time, send_code_pos;
public func StartCommunication()
{
// forward to main object
if (base_face) return base_face->StartCommunication();
// Init particles
// Gem particles
beam_particles = CreateArray(CrystalCommunicator_GemCount);
gem_particles = CreateArray(CrystalCommunicator_GemCount);
ruby_particle = new Particles_MagicRing() { R = 0xff, G = 0x00, B = 0x30 };
amethyst_particle = new Particles_MagicRing() { R = 0xa0, G = 0x00, B = 0xff };
for (var i=0; i<CrystalCommunicator_GemCount; ++i)
{
var base;
if (this.gem_overlays && this.gem_overlays[i])
{
if (this.gem_overlays[i]->GetID() == Ruby) base = ruby_particle; else base = amethyst_particle;
}
else
{
if (i%2) base = ruby_particle; else base = amethyst_particle;
}
gem_particles[i] = base;
var x = CrystalCommunicator_GemsX[i]/5 - 45;
beam_particles[i] = CreateCirclingParticle(base, 100, 20, Abs(x), x>0);
}
// Central flash particles
flash_particle = {
Size = PV_KeyFrames(0, 0, 0, 500, 60, 1000, 0),
R = PV_KeyFrames(0, 750, 255, 1000, 0),
G = PV_KeyFrames(0, 300, 255, 1000, 0),
B = PV_KeyFrames(0, 300, 255, 500, 0),
Rotation = PV_Random(0, 360),
Alpha = PV_KeyFrames(0, 0, 255, 750, 100, 1000, 0),
BlitMode = GFX_BLIT_Additive,
Attach = ATTACH_Front | ATTACH_MoveRelative,
};
large_flash_particle = {
Size = PV_KeyFrames(0, 0, 0, 500, 200, 1000, 0),
R = PV_KeyFrames(0, 750, 255, 1000, 0),
G = PV_KeyFrames(0, 300, 255, 1000, 0),
B = PV_KeyFrames(0, 300, 255, 500, 0),
Rotation = PV_Random(0, 360),
Alpha = PV_KeyFrames(0, 0, 255, 750, 100, 1000, 0),
BlitMode = GFX_BLIT_Additive,
Attach = ATTACH_Front | ATTACH_MoveRelative,
};
// Gem flash particle
small_flash_particle = {
Size = PV_KeyFrames(0, 0, 0, 500, 20, 1000, 0),
R = PV_KeyFrames(0, 750, 255, 1000, 0),
G = PV_KeyFrames(0, 300, 255, 1000, 0),
B = PV_KeyFrames(0, 300, 255, 500, 0),
Rotation = PV_Random(0, 360),
Alpha = PV_KeyFrames(0, 0, 255, 750, 100, 1000, 0),
BlitMode = GFX_BLIT_Additive,
Attach = ATTACH_Front | ATTACH_MoveRelative,
};
// Run effects
Sound("CrystalCommCharge");
time = 0;
AddTimer(this.PreActivity, 5);
}
private func PreActivity()
{
// Warmup effects
var i,x,y,z;
for (i=0; i<CrystalCommunicator_GemCount; ++i)
{
x = CrystalCommunicator_GemsX[i]/5 - 45;
y = CrystalCommunicator_GemsY[i]/5 - 35;
z = CrystalCommunicator_GemsZ[i];
var gem_target;
if (top_face && z>=3) gem_target = top_face; else gem_target = this;
if (time < 20 || !Random(3))
{
if (!(time % 5)) gem_target->CreateParticle("StarFlash", x,y, 0,0, 60+Random(10), small_flash_particle, 1);
}
else
gem_target->CreateParticle("StarFlash", x, y, -x, -y, 10, small_flash_particle, 10);
}
if (time == 20) Sound("CrystalCommBoost");
if (time > 50)
{
RemoveTimer(this.PreActivity);
time = 0;
CreateParticle("StarFlash", PV_Random(-12, +12), PV_Random(-12, +12), PV_Random(-10, +10),PV_Random(-10, +10), PV_Random(20, 100), large_flash_particle, 10);
Sound("CrystalCommWumm");
SetAction("Active");
AddTimer(this.Activity, 1);
}
++time;
}
public func StopCommunication()
{
// forward to main object
if (base_face) return base_face->StopCommunication();
// Stop activities
RemoveTimer(this.PreActivity);
RemoveTimer(this.Activity);
SetAction("Idle");
time = 0;
return true;
}
private func Activity()
{
// Send codes
if (send_code)
{
if (next_send_time == time)
{
var send_char = GetChar(send_code, send_code_pos++);
if (!send_char)
{
// All sent.
send_code = nil;
}
else
{
// Next char to send
if (send_char == GetChar("."))
{
Sound("CrystalCommToneA");
next_send_time = time + 13;
}
else
{
Sound("CrystalCommToneB");
next_send_time = time + 27;
}
}
}
if (next_send_time - time > 10)
{
// During tone: Effects
CreateParticle("StarFlash", PV_Random(-3, +3), 0, 0,-30, 500, flash_particle, 1);
}
}
// Effects
// Circulate through gems
var i = time % CrystalCommunicator_GemCount;
var x = CrystalCommunicator_GemsX[i]/5 - 45, y = CrystalCommunicator_GemsY[i]/5 - 35, z = CrystalCommunicator_GemsZ[i];
var gem_target;
if (top_face && z>=3) gem_target = top_face; else gem_target = this;
// Create ring moving upwards
if (Abs(x) > 5) CreateParticle("MagicRing", x, y, 0, -Min(time/20,10), 2000, beam_particles[i], 1);
// Create flash at gem
gem_target->CreateParticle("StarFlash", x, y, 0, 0, 20+Random(10), gem_particles[i], 1);
// Create central flash
if (!(time % 5)) CreateParticle("StarFlash", PV_Random(-6, +6), PV_Random(-6, +6), 0,0, 20+Random(10), flash_particle, 1);
++time;
}
private func CreateCirclingParticle(proplist prototype, int frames_per_cycle, int num_cycles, int rad, bool start_backmove)
{
var a = (rad * 10000000) / (2429 * frames_per_cycle * frames_per_cycle);
var ang0 = (!!start_backmove) * 180;
var particle = {
Prototype = prototype,
Size = PV_Sin(PV_Linear( ang0, 360*num_cycles),5,8),
ForceX = PV_Sin(PV_Linear( ang0+90, ang0+90+360*num_cycles), a, 0),
ForceY = 0,
Attach = ATTACH_Front | ATTACH_MoveRelative,
};
return particle;
}
public func SendCode(string code)
{
send_code = code;
next_send_time = time;
send_code_pos = 0;
return true;
}
/* Definition data */
public func Definition(proplist def)
{
}
local ActMap = {
Attach = {
Prototype = Action,
Name = "Attach",
Procedure = DFA_ATTACH,
Directions = 1,
FacetBase = 1,
Length = 1,
Delay = 0,
NextAction = "Hold"
},
Active = {
Prototype = Action,
Name = "Active",
Procedure = DFA_NONE,
Directions = 1,
FacetBase = 1,
Delay = 0,
Length = 1,
NextAction = "Active",
Sound = "CrystalCommActive",
},
};
local Collectible = false;
local Name = "$Name$";
local Description = "$Description$";
local Touchable = 0;
local Plane = 280;

View File

@ -0,0 +1,2 @@
Name=Kristallkommunikator
Description=Gerät zur Langstreckenkommunikation

View File

@ -0,0 +1,2 @@
Name=Crystal communicator
Description=Device for long range communication.

View File

@ -0,0 +1,5 @@
[DefCore]
id=Goal_BuildCrystalCommunicator
Version=6,0
Category=C4D_StaticBack|C4D_Goal
Picture=0,0,128,128

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

View File

@ -0,0 +1,61 @@
/*--
Build crystal communicator
Author: Sven2
Player must build the crystal communicator
--*/
#include Library_Goal
/*-- Goal interface --*/
// The goal is fulfilled if the communicator has been built
public func IsFulfilled()
{
return ObjectCount(Find_ID(CrystalCommunicator));
}
public func GetDescription(int plr)
{
var message;
if (IsFulfilled())
message = "$MsgGoalFulfilled$";
else
message = "$MsgGoalUnfulfilled$";
return message;
}
// Shows or hides a message window with information.
public func Activate(int plr)
{
// If goal message open -> hide it.
if (GetEffect("GoalMessage", this))
{
CustomMessage("", nil, plr, nil, nil, nil, nil, nil, MSG_HCenter);
RemoveEffect("GoalMessage", this);
return;
}
// Otherwise open a new message.
AddEffect("GoalMessage", this, 100, 0, this);
var message;
if (IsFulfilled())
{
message = "@$MsgGoalFulfilled$";
}
else
{
message = "@$MsgGoalUnfulfilled$";
}
CustomMessage(message, nil, plr, 0, 16 + 64, 0xffffff, GUI_MenuDeco, this, MSG_HCenter);
return;
}
protected func FxGoalMessageStart() {}
//public func GetShortDescription(int plr) { return ""; }
/*-- Proplist --*/
local Name = "$Name$";

View File

@ -0,0 +1,5 @@
Name=Kristallkommunikator bauen
#Goal window
MsgGoalFulfilled=Glückwunsch; der Kristallkommunikator steht.
MsgGoalUnfulfilled=Bringe das nötige Baumaterial zur Baustelle des Kristallkommunikator!

View File

@ -0,0 +1,5 @@
Name=Build crystal communicator
#Goal window
MsgGoalFulfilled=Congratulations, the crystal communicator is done.
MsgGoalUnfulfilled=Find the missing components and bring them to the crystal communicator construction site!

View File

@ -0,0 +1,275 @@
/**
Blue lake
Dynamic map with a big lake containing islands of material
Plus lava basins with gems at the bottom
Parts adapted from Gem Grabbers by Maikel
@authors Sven2
*/
#include Library_Map
// zoomed coordinates for scenario script
static main_island_x, main_island_y;
static goal_platform_x, goal_platform_y;
// set after intro to force map creation
static g_intro_done;
// Called be the engine: draw the complete map here.
public func InitializeMap(proplist map)
{
if (!g_intro_done) return true;
Resize(300,400);
this.sea_y = 50;
this.ground_y = 350;
this.map_zoom = 7;
main_island_x = this.Wdt/2 * this.map_zoom;
main_island_y = this.sea_y * this.map_zoom;
Draw("Water", nil, [0,this.sea_y,this.Wdt,this.Hgt]);
DrawMainIsland(80);
DrawGround();
// Regular resource islands
DrawSecondaryIslands(3, 15, [["Ore", 50], ["Coal", 40]], true);
DrawSecondaryIslands(10, 6, [["Firestone", 70]], false);
DrawSecondaryIslands(3, 8, [["Gold", 40]], true);
// Amethyst islands
var i=0, imod=Random(2);
while (i<3 || GetPixelCount("Amethyst")<15)
{
DrawSecondaryIsland(8, [["Amethyst", 70]], true, [0, this.Wdt-70][(i+imod)%2], 70, this.sea_y+50);
++i;
}
FixLiquidBorders("Earth");
// Ensure that left and right side are always open because they're used for water refill
Draw("Sky", nil, [0,0,1,this.sea_y]);
Draw("Sky", nil, [this.Wdt-1,0,1,this.sea_y]);
Draw("Water", nil, [0,this.sea_y,1,70]);
Draw("Water", nil, [this.Wdt-1,this.sea_y,1,70]);
// Top level of water has sky background
Draw("^Water", Duplicate("Water"), [0,this.sea_y,this.Wdt,11]);
// Return true to tell the engine a map has been successfully created.
return true;
}
// Draws the main island with all basic resources
private func DrawMainIsland(int size)
{
// Shape of the main island. Shape taken from Gem Grabbers.
var island_algo = {Algo = MAPALGO_Polygon};
var x = this.Wdt / 2;
var y = this.sea_y;
island_algo.X = [x-size/3, x-size/2, x-size/3, x-size/6, x+size/6, x+size/3, x+size/2, x+size/3];
island_algo.Y = [y-size/6, y, y+size/3, y+size/6, y+size/6, y+size/3, y, y-size/6];
// Draw the earth patch of the island.
island_algo = {Algo = MAPALGO_Turbulence, Iterations = 4, Op = island_algo};
var island = CreateLayer();
island->Draw("Earth", island_algo);
// Draw goal platform shape
while (island->GetPixel(x,y)) ++x; // Find right side of island at sea level
var platform_algo = {Algo = MAPALGO_Polygon};
platform_algo.X = [x-5,x+14,x+14,x+7,x ,x-5];
platform_algo.Y = [y ,y ,y+ 1,y+2,y+4,y ];
island->Draw("Earth", platform_algo);
// Preserve drawn island shape for border algorithms
var island_shape = island->Duplicate();
// Overlay a set of materials inside the island.
DrawIslandMat("Earth-earth_dry", island, 4, 30, true);
DrawIslandMat("Earth-earth_midSoil", island, 3, 30, true);
DrawIslandMat("Tunnel", island, 3, 10, true);
//DrawIslandMat("Water", island, 4, 8);
//DrawIslandMat("Gold", island, 3, 6);
DrawIslandMat("Ore", island, 6, 18, true);
DrawIslandMat("Coal", island, 6, 18, true);
DrawIslandMat("Firestone", island, 6, 12, true);
// Draw a top border out of sand and top soil.
var sand_border = {Algo = MAPALGO_And, Op = [{Algo = MAPALGO_Border, Op = island_shape, Top = [-1,2]}, {Algo = MAPALGO_RndChecker, Ratio = 50, Wdt = 4, Hgt = 3}]};
var topsoil_border = {Algo = MAPALGO_And, Op = [{Algo = MAPALGO_Border, Op = island_shape, Top = [-1,3]}, {Algo = MAPALGO_RndChecker, Ratio = 40, Wdt = 4, Hgt = 2}]};
island->Draw("Sand", sand_border);
island->Draw("Earth-earth_topSoil", topsoil_border);
// Draw a bottom border out of granite and rock.
var granite_border = {Algo = MAPALGO_Border, Op = island_shape, Bottom = [-4,3]};
island->Draw("Granite", granite_border);
var rock_border = {Algo = MAPALGO_RndChecker, Ratio = 20, Wdt = 2, Hgt = 2};
island->Draw("Rock", {Algo = MAPALGO_And, Op = [granite_border, rock_border]});
island->Draw("Rock-rock_cracked", {Algo = MAPALGO_And, Op = [granite_border, rock_border]});
// Draw goal platform
island->Draw("Sky", nil, [x,y-10,14,10]);
island->Draw("Brick", nil, [x,y,14,2]);
goal_platform_x = (x+7)*this.map_zoom;
goal_platform_y = y *this.map_zoom;
// Draw island onto main map
Blit(island);
return true;
}
// Draws multiple underwater resource islands
private func DrawSecondaryIslands(int n, ...)
{
for (var i=0; i<n; ++i) DrawSecondaryIsland(...);
return true;
}
// Draws underwater resource island
private func DrawSecondaryIsland(int size, array materials, bool has_border, int xmin, int xwdt, int ymin)
{
// Find a free spot underwater
var x,y;
var border = size; // left and right border
if (!xwdt) xwdt = this.Wdt;
if (!ymin) ymin = this.sea_y;
var i_tries = 200;
while (i_tries--)
{
var x = Random(xwdt - border*2) + border + xmin;
var y = Random(this.ground_y - ymin - size) + ymin + size/2;
if (GetPixelCount("Solid", [x-size,y-size,size,size])) continue;
break;
}
// Shape of the resource island
var island_algo = {Algo = MAPALGO_Ellipsis, X=x, Y=y, Wdt=size, Hgt=size};
island_algo = {Algo = MAPALGO_Turbulence, Amplitude = [20,5], Iterations = 3, Op = island_algo};
var island = CreateLayer();
island->Draw("Earth", island_algo);
var island_shape = island->Duplicate();
DrawIslandMat("Earth-earth_dry", island, 4, 30);
DrawIslandMat("Earth-earth_midSoil", island, 3, 30);
// Overlay a set of materials inside the island.
for (var mat in materials)
{
DrawIslandMat(mat[0], island, 3, mat[1], has_border);
}
// Draw a border out of granite and rock.
if (has_border)
{
var island_shape = island->Duplicate();
var granite_border = {Algo = MAPALGO_Border, Op = island_shape, Top = [-2,2]};
island->Draw("Granite", granite_border);
var rock_border = {Algo = MAPALGO_RndChecker, Ratio = 20, Wdt = 2, Hgt = 2};
island->Draw("Rock", {Algo = MAPALGO_And, Op = [granite_border, rock_border]});
island->Draw("Rock-rock_cracked", {Algo = MAPALGO_And, Op = [granite_border, rock_border]});
}
// Draw island onto main map
Blit(island);
return true;
}
private func DrawGround()
{
// Bottom of the sea
var ground_algo = { Algo = MAPALGO_Rect, X=-100, Y=this.ground_y, Wdt=this.Wdt+200, Hgt=this.Hgt-this.ground_y+1000 };
ground_algo = {Algo = MAPALGO_Turbulence, Iterations = 4, Amplitude = [10,100], Scale = 20, Op = ground_algo };
var ground2_algo = { Algo = MAPALGO_Rect, X=-100, Y=this.Hgt-10, Wdt=this.Wdt+200, Hgt=this.Hgt-this.ground_y+1000 };
ground2_algo = {Algo = MAPALGO_Turbulence, Iterations = 2, Amplitude = 10, Scale = 30, Op = ground2_algo };
var ground = CreateLayer();
// Ensure lots of earth
while (true)
{
ground->Draw("Earth", ground_algo);
ground->Draw("Granite", ground2_algo);
if (ground->GetPixelCount("Earth") > 10000) break;
}
ground->Draw("DuroLava", {Algo=MAPALGO_Turbulence, Amplitude=10, Scale=20, Iterations=3, Op={Algo=MAPALGO_And, Op=[ground->Duplicate("Granite"), {Algo = MAPALGO_RndChecker, Ratio=50, Wdt=30, Hgt=2}]}});
// Granite/Rock top border
ground->Draw("Granite", {Algo = MAPALGO_Turbulence, Amplitude = 5, Iterations = 1, Op = {Algo = MAPALGO_Border, Op = ground->Duplicate(), Top= [-2,2]}});
ground->Draw("Rock", {Algo=MAPALGO_And, Op=[ground->Duplicate("Granite"), {Algo = MAPALGO_RndChecker, Ratio = 40, Wdt = 2, Hgt = 2}]});
// Alterations in earth material
DrawIslandMat("Earth-earth_dry", ground, 12, 60, false);
DrawIslandMat("Earth-earth_midSoil", ground, 8, 60, false);
// Gem spots
var gem_spots = CreateLayer();
var earth_mats = CreateMatTexMask("Earth");
var i=0;
while (i<3 || gem_spots->GetPixelCount("Ruby") < 15)
{
var gem_mat = "Ruby";
// Find an earth spot
var pos = {X=Random(this.Wdt), Y=this.Hgt/2+Random(this.Hgt/2)};
ground->FindPosition(pos, "Earth");
// Find center of this earth area
var x=pos.X, y=pos.Y;
var x0=x-1, x1=x+1, y0=y-1, y1=y+1;
while (earth_mats[ground->GetPixel(x,y0)]) --y0;
while (earth_mats[ground->GetPixel(x,y1)]) ++y1;
y=Min((y0+y1)/2, this.Hgt-6);
while (earth_mats[ground->GetPixel(x0,y)]) --x0;
while (earth_mats[ground->GetPixel(x1,y)]) ++x1;
x=(x0+x1)/2;
var size = 9;
// Lava basin here
var lava_algo = {Algo = MAPALGO_Ellipsis, X=x, Y=y, Wdt=size, Hgt=size};
lava_algo = {Algo = MAPALGO_Turbulence, Amplitude = 5, Iterations = 5, Op = lava_algo};
gem_spots->Draw("DuroLava", lava_algo);
// Gems at bottom center
y += 2;
size = 3;
var gem_algo = {Algo = MAPALGO_Ellipsis, X=x, Y=y, Wdt=size, Hgt=size};
gem_algo = {Algo = MAPALGO_Turbulence, Amplitude = 3, Iterations = 1, Op = gem_algo};
gem_spots->Draw(gem_mat, gem_algo);
// Draw to map
ground->Blit(gem_spots);
++i;
}
// Lava basins surrounded by granite
ground->Draw("Rock", {Algo=MAPALGO_And, Op=[{Algo=MAPALGO_Not, Op=gem_spots}, {Algo = MAPALGO_Turbulence, Amplitude = 5, Iterations = 5, Op = {Algo = MAPALGO_Border, Op = gem_spots, Wdt=-4}}]});
ground->Draw("Granite", {Algo = MAPALGO_Border, Op = gem_spots, Wdt=-1});
// Lots of rocks
DrawIslandMat("Rock-rock_cracked", ground, 2, 20, false);
DrawIslandMat("Rock", ground, 2, 20, false);
// And some lava
DrawIslandMat("DuroLava", ground, 2, 20, false);
// Other materials (rare)
DrawIslandMat("Ore", ground, 12, 8, false);
DrawIslandMat("Coal", ground, 12, 8, false);
DrawIslandMat("Gold", ground, 12, 8, false);
DrawIslandMat("Firestone", ground, 12, 8, false);
Blit(ground);
return true;
}
// Draws some material inside an island.
private func DrawIslandMat(string mat, proplist onto_mask, int speck_size, int ratio, has_border)
{
if (!speck_size)
speck_size = 3;
if (!ratio)
ratio = 20;
// Use random checker algorithm to draw patches of the material.
var rnd_checker = {Algo = MAPALGO_RndChecker, Ratio = ratio, Wdt = speck_size, Hgt = speck_size};
rnd_checker = {Algo = MAPALGO_Turbulence, Iterations = 4, Op = rnd_checker};
var algo;
if (has_border)
{
var mask_border = {Algo = MAPALGO_Border, Op = onto_mask, Wdt = 3};
algo = {Algo = MAPALGO_And, Op = [{Algo = MAPALGO_Xor, Op = [onto_mask->Duplicate("Earth"), mask_border]}, rnd_checker]};
}
else
{
algo = {Algo = MAPALGO_And, Op = [onto_mask->Duplicate("Earth"), rnd_checker]};
}
onto_mask->Draw(mat, algo);
return true;
}

View File

@ -0,0 +1,57 @@
[Head]
Title=DeepSeaMining
Icon=31
Version=6,0
Difficulty=30
MissionAccess=S2Crash
[Definitions]
Definition1=Objects.ocd
[Game]
Rules=Rule_TeamAccount=1;Rule_BuyAtFlagpole=1;Rule_BaseRespawn=1;
Goals=Goal_BuildCrystalCommunicator=1;
ValueOverloads=Ruby=10;Amethyst=10
[Player1]
Wealth=25
Crew=Clonk=2
Knowledge=Flagpole=1;Foundry=1;WindGenerator=1;SteamEngine=1;Compensator=1;Sawmill=1;ChemicalLab=1;Elevator=1;Pump=1;ToolsWorkshop=1;Basement=1;WallKit=1;GoldBar=1;Loam=1;Metal=1;Axe=1;Barrel=1;Bucket=1;Dynamite=1;Hammer=1;JarOfWinds=1;Pickaxe=1;Pipe=1;Shovel=1;TeleGlove=1;DynamiteBox=1;Lorry=1;
BaseMaterial=Clonk=25;Bread=25;
BaseProduction=Clonk=25;Bread=25;
[Player2]
Wealth=25
Crew=Clonk=2
Knowledge=Flagpole=1;Foundry=1;WindGenerator=1;SteamEngine=1;Compensator=1;Sawmill=1;ChemicalLab=1;Elevator=1;Pump=1;ToolsWorkshop=1;Basement=1;WallKit=1;GoldBar=1;Loam=1;Metal=1;Axe=1;Barrel=1;Bucket=1;Dynamite=1;Hammer=1;JarOfWinds=1;Pickaxe=1;Pipe=1;Shovel=1;TeleGlove=1;DynamiteBox=1;Lorry=1;
BaseMaterial=Clonk=25;Bread=25;
BaseProduction=Clonk=25;Bread=25;
[Player3]
Wealth=25
Crew=Clonk=2
Knowledge=Flagpole=1;Foundry=1;WindGenerator=1;SteamEngine=1;Compensator=1;Sawmill=1;ChemicalLab=1;Elevator=1;Pump=1;ToolsWorkshop=1;Basement=1;WallKit=1;GoldBar=1;Loam=1;Metal=1;Axe=1;Barrel=1;Bucket=1;Dynamite=1;Hammer=1;JarOfWinds=1;Pickaxe=1;Pipe=1;Shovel=1;TeleGlove=1;DynamiteBox=1;Lorry=1;
BaseMaterial=Clonk=25;Bread=25;
BaseProduction=Clonk=25;Bread=25;
[Player4]
Wealth=25
Crew=Clonk=2
Knowledge=Flagpole=1;Foundry=1;WindGenerator=1;SteamEngine=1;Compensator=1;Sawmill=1;ChemicalLab=1;Elevator=1;Pump=1;ToolsWorkshop=1;Basement=1;WallKit=1;GoldBar=1;Loam=1;Metal=1;Axe=1;Barrel=1;Bucket=1;Dynamite=1;Hammer=1;JarOfWinds=1;Pickaxe=1;Pipe=1;Shovel=1;TeleGlove=1;DynamiteBox=1;Lorry=1;
BaseMaterial=Clonk=25;Bread=25;
BaseProduction=Clonk=25;Bread=25;
[Landscape]
Sky=Clouds2
TopOpen=1
BottomOpen=0
AutoScanSideOpen=1
MapWidth=300
MapHeight=400
MapZoom=7
[Weather]
Climate=0
StartSeason=0
YearSpeed=0
Wind=0,100,-100,100

View File

@ -0,0 +1,300 @@
/**
Deep Sea Mining
Mine gems buried deeply below the ocean.
@authors Sven2
*/
// set in Map.c
static main_island_x, main_island_y;
static goal_platform_x, goal_platform_y;
static const SCEN_TEST = false;
static g_is_initialized, g_is_in_intro, g_intro_done, npc_tuesday, g_tuesday_pos;
protected func PostIntroInitialize()
{
// Construction site on goal platform
var goal_site = CreateObject(ConstructionSite, goal_platform_x+10, goal_platform_y+3);
goal_site->Set(CrystalCommunicator);
goal_site->MakeUncancellable();
if (SCEN_TEST)
{
for (var i=0; i<6; ++i)
{
goal_site->CreateObject(Metal,-20);
goal_site->CreateObject(Ruby,0);
goal_site->CreateObject(Amethyst,20);
}
goal_site->CreateContents(Metal,6);
goal_site->CreateContents(Ruby,6);
goal_site->CreateContents(Amethyst,5);
}
// Initialize different parts of the scenario.
InitEnvironment();
InitVegetation();
InitAnimals();
InitMainIsland();
// NPC
g_tuesday_pos = FindMainIslandPosition(0, 100, true);
npc_tuesday = CreateObject(Clonk, g_tuesday_pos[0]+20, g_tuesday_pos[1]-10);
npc_tuesday->SetDir(DIR_Left);
npc_tuesday->SetColor(0x804000);
npc_tuesday->SetName("$Tuesday$");
return true;
}
func DoInit(int first_player)
{
StartSequence("Intro", 0, GetCrew(first_player));
return true;
}
protected func InitializePlayer(int plr)
{
// intro has its own initialization
if (g_is_in_intro) return true;
// Harsh zoom range
SetPlayerZoomByViewRange(plr, 500, 350, PLRZOOM_LimitMax);
SetPlayerZoomByViewRange(plr, 500, 350, PLRZOOM_Direct);
SetPlayerViewLock(plr, true);
// Intro
if (!g_is_initialized) g_is_initialized = DoInit(plr);
if (!g_intro_done) return true;
// Position and materials
var i, crew;
for (i = 0; crew = GetCrew(plr, i); ++i)
{
var pos = FindMainIslandPosition();
crew->SetPosition(pos[0], pos[1] - 11);
crew->CreateContents(Shovel);
if (SCEN_TEST)
{
var cs = FindObject(Find_ID(ConstructionSite));
crew->SetPosition(cs->GetX(), cs->GetY()-20);
}
}
// Claim ownership of unowned structures
for (var structure in FindObjects(Find_Or(Find_Category(C4D_Structure), Find_Func("IsFlagpole")), Find_Owner(NO_OWNER)))
{
structure->SetOwner(plr);
structure->~RefreshOwnershipOfSurrounding();
}
// Should be done in OnOwnerChanged? It doesn't happen ATM.
RedrawAllFlagRadiuses();
return;
}
// Initializes environment and disasters.
private func InitEnvironment()
{
// Water refill from sides
var initial_water_level = 0;
while (GetMaterial(0,initial_water_level) != Material("Water")) ++initial_water_level;
ScheduleCall(nil, this.EnsureWaterLevel, 20, 999999999, initial_water_level);
// Set a certain parallax.
SetSkyParallax(0, 20, 20);
// Ambience sounds
CreateObject(Ambience);
// No disasters for now
//Meteor->SetChance(5); Cloud->SetLightning(16);
return;
}
// Ensures that the sea doesn't disappear
func EnsureWaterLevel(int level, bool no_recursion)
{
var water_mat = Material("Water");
if (GetMaterial(0,level) != water_mat) CastPXS("Water", 100, 20, 0,level, 90, 10);
if (GetMaterial(LandscapeWidth()-1,level) != water_mat) CastPXS("Water", 100, 20, LandscapeWidth()-1,level, 270, 10);
// Extra insertion at a lower level so it's not easy to block off
if (!no_recursion && !Random(3)) EnsureWaterLevel(level + 50 + Random(450), true);
return true;
}
private func InitVegetation()
{
// Grass on starting island.
PlaceGrass(85);
// Place some cocont trees all around the main island
for (var i = 0; i < 10 + Random(8); i++)
PlaceVegetation(Tree_Coconut, 0, 0, LandscapeWidth(), LandscapeHeight(), 1000 * (61 + Random(40)));
// Create an effect to make sure there will always grow some new trees.
ScheduleCall(nil, this.EnsureTrees, 100, 999999999);
// Some objects in the earth.
PlaceObjects(Rock, 10 + Random(10),"Earth");
PlaceObjects(Firestone, 35 + Random(5), "Earth");
PlaceObjects(Loam, 25 + Random(5), "Earth");
// Underwater vegetation
Seaweed->Place(20);
Coral->Place(30);
return;
}
// Ensures that there will always grow some trees on the main island.
func EnsureTrees()
{
var wdt = LandscapeWidth();
var hgt = LandscapeHeight();
// Place a tree if there are less than eight trees, with increasing likelihood for lower amounts of trees.
var nr_trees = ObjectCount(Find_Func("IsTree"), Find_Func("IsStanding"));
if (Random(9) >= nr_trees)
if (!Random(20))
PlaceVegetation(Tree_Coconut, main_island_x - 300, main_island_y - 200, 600, 400, 3);
return true;
}
private func InitAnimals()
{
// Place fish in upper ocean area (there tend to be small basins below, where lots of fish could get stuck)
var fish_area = GetFishArea();
Fish->Place(50, fish_area);
Piranha->Place(25, fish_area);
ScheduleCall(nil, this.EnsureAnimals, 237, 999999999);
return true;
}
private func GetFishArea() { return Rectangle(50, main_island_y, LandscapeWidth() - 100, LandscapeHeight()/2 - main_island_y); }
private func EnsureAnimals()
{
if (ObjectCount(Find_ID(Fish), Find_Not(Find_Action("Dead"))) < 50) DoFishSpawn(Fish);
if (ObjectCount(Find_ID(Piranha), Find_Not(Find_Action("Dead"))) < 25) DoFishSpawn(Piranha);
return true;
}
private func DoFishSpawn(fish_type)
{
// Try placement away from Clonks. If a Clonk was nearby, just remove it immediately.
var fish = fish_type->Place(1, GetFishArea());
if (fish)
if (fish->FindObject(fish->Find_Distance(300), Find_ID(Clonk), Find_OCF(OCF_Alive)))
fish->RemoveObject();
return fish;
}
// Initializes the main island according to the material specification.
private func InitMainIsland()
{
var amount = 3;
var pos;
// Always start with a lorry filled with: hammer(x2), axe(x2), wood(x6) and metal(x4).
var lorry_pos = FindMainIslandPosition(0, 80);
var lorry = CreateObject(Lorry, lorry_pos[0], lorry_pos[1] - 8);
lorry->CreateContents(Hammer, 2);
lorry->CreateContents(Axe, 2);
lorry->CreateContents(Wood, 6);
lorry->CreateContents(Metal, 4);
// If more material is specified, create a small settlement: flag(x2) and windmill.
// Also fill lorry a bit more with: pickaxe(x1), dynamite(x4), wood(x4), metal(x2).
if (amount >= 2)
{
pos = FindMainIslandPosition(-120, 20);
CreateObject(Flagpole, pos[0]-7, pos[1]);
var rfp = CreateObject(Flagpole, pos[0]+7, pos[1]);
rfp->SetNeutral(true);
pos = FindMainIslandPosition(120, 20);
CreateObject(Flagpole, pos[0], pos[1]);
pos = FindMainIslandPosition(nil, nil, true);
CreateObject(WindGenerator, pos[0], pos[1]);
lorry->CreateContents(Wood, 4);
lorry->CreateContents(Metal, 2);
lorry->CreateContents(Pickaxe, 1);
lorry->CreateContents(Dynamite, 4);
}
// If still more material is specified, create a larger settlement: sawmill, chemical lab, tools workshop.
// Also fill lorry a bit more with: Barrel (x1), Bucket(x1), Loam(x4), DynamiteBox(x2).
if (amount >= 3)
{
pos = FindMainIslandPosition(nil, nil, true);
CreateObject(Sawmill, pos[0], pos[1]);
pos = FindMainIslandPosition(nil, nil, true);
CreateObject(ChemicalLab, pos[0], pos[1]);
pos = FindMainIslandPosition(nil, nil, true);
CreateObject(ToolsWorkshop, pos[0], pos[1]);
lorry->CreateContents(Barrel, 1);
lorry->CreateContents(Bucket, 1);
lorry->CreateContents(Loam, 4);
lorry->CreateContents(DynamiteBox, 1);
lorry->CreateContents(WallKit, 4);
//lorry->CreateContents(Boompack, 1);
}
return;
}
// Tries to find a position on the main island.
private func FindMainIslandPosition(int xpos, int sep, bool no_struct)
{
if (xpos == nil)
xpos = 0;
if (sep == nil)
sep = 250;
for (var i = 0; i < 100; i++)
{
var x = main_island_x + xpos + Random(sep*2+1)-sep;
var y = main_island_y / 2 - 220;
while (!GBackSolid(x, y) && y < LandscapeHeight()*3/4)
y++;
if (GetMaterial(x,y) == Material("Brick")) continue; // not on goal platform
if (!no_struct || !FindObject(Find_Or(Find_Category(C4D_Structure), Find_Func("IsFlagpole"), Find_ID(WindGenerator)), Find_Distance(60, x, y)))
break;
}
return [x, y];
}
/* Outro */
// Goal fulfilled
public func OnGoalsFulfilled()
{
SetNextMission("Missions.ocf/TreasureHunt.ocs");
GainScenarioAchievement("Done");
GainMissionAccess("S2Sea");
StartSequence("Outro", 0);
// Return true to force goal rule to not call GameOver() yet
return true;
}
// Intro helper
global func Particles_Smoke(...)
{
var p = inherited(...);
if (g_intro_sky_moving)
{
p.ForceX = -300;
p.DampingX = 800;
}
return p;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

View File

@ -0,0 +1,5 @@
[Landscape]
BottomOpen=0
TopOpen=1
MapZoom=20,0,5,20
Sky=Clouds2

View File

@ -0,0 +1 @@
Tuesday=Dienstag

View File

@ -0,0 +1 @@
Tuesday=Tuesday

View File

@ -0,0 +1,48 @@
// NPC Tuesday: Sits on the island and does nothing
// (except giving some hints)
#appendto Dialogue
func Dlg_Tuesday_1(object clonk)
{
MessageBox("$Tuesday1$", clonk, dlg_target);
return true;
}
func Dlg_Tuesday_2(object clonk)
{
var options = [["$TuesdayQCommunicator$", "Dlg_Tuesday_Communicator"], ["$TuesdayQGems$", "Dlg_Tuesday_Gems"], ["$TuesdayQFish$", "Dlg_Tuesday_Fish"], ["$TuesdayQWater$", "Dlg_Tuesday_Water"], ["$TuesdayQBye$", "StopDialogue()"]];
MessageBox("", clonk, clonk, nil, false, options);
SetDialogueProgress(1);
return true;
}
func Dlg_Tuesday_Communicator(object clonk, q)
{
SetDialogueProgress(2);
return MessageBox("$TuesdayACommunicator$", clonk);
}
func Dlg_Tuesday_Gems(object clonk, q)
{
SetDialogueProgress(2);
return MessageBox("$TuesdayAGems$", clonk);
}
func Dlg_Tuesday_Fish(object clonk, q)
{
SetDialogueProgress(2);
return MessageBox("$TuesdayAFish$", clonk);
}
func Dlg_Tuesday_Water(object clonk, q)
{
SetDialogueProgress(10);
return MessageBox("$TuesdayAWater$", clonk);
}
func Dlg_Tuesday_10(object clonk)
{
SetDialogueProgress(2);
return MessageBox("$TuesdayAWater2$", clonk);
}

Some files were not shown because too many files have changed in this diff Show More