Add sound and music ambience object.
Also tagged the existing music as "day". Only enabled in the first three missions for now.lights3
|
@ -1,5 +0,0 @@
|
||||||
[DefCore]
|
|
||||||
id=Ambience
|
|
||||||
Version=6,0
|
|
||||||
Category=C4D_StaticBack | C4D_Rule
|
|
||||||
Picture=0,0,128,128
|
|
Before Width: | Height: | Size: 14 KiB |
|
@ -1,297 +0,0 @@
|
||||||
/**
|
|
||||||
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);
|
|
||||||
exec_counter += !(i%3);
|
|
||||||
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;
|
|
|
@ -1,15 +0,0 @@
|
||||||
[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
|
|
Before Width: | Height: | Size: 136 KiB |
Before Width: | Height: | Size: 39 KiB |
Before Width: | Height: | Size: 64 KiB |
Before Width: | Height: | Size: 106 KiB |
Before Width: | Height: | Size: 112 KiB |
|
@ -1,357 +0,0 @@
|
||||||
/*--
|
|
||||||
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 = CreateObjectAbove(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;
|
|
|
@ -1,2 +0,0 @@
|
||||||
Name=Kristallkommunikator
|
|
||||||
Description=Gerät zur Langstreckenkommunikation
|
|
|
@ -1,2 +0,0 @@
|
||||||
Name=Crystal communicator
|
|
||||||
Description=Device for long range communication.
|
|
|
@ -1,5 +0,0 @@
|
||||||
[DefCore]
|
|
||||||
id=Goal_BuildCrystalCommunicator
|
|
||||||
Version=6,0
|
|
||||||
Category=C4D_StaticBack|C4D_Goal
|
|
||||||
Picture=0,0,128,128
|
|
Before Width: | Height: | Size: 27 KiB |
|
@ -1,61 +0,0 @@
|
||||||
/*--
|
|
||||||
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$";
|
|
|
@ -1,5 +0,0 @@
|
||||||
Name=Kristallkommunikator bauen
|
|
||||||
|
|
||||||
#Goal window
|
|
||||||
MsgGoalFulfilled=Glückwunsch; der Kristallkommunikator steht.
|
|
||||||
MsgGoalUnfulfilled=Bringe das nötige Baumaterial zur Baustelle des Kristallkommunikator!
|
|
|
@ -1,5 +0,0 @@
|
||||||
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!
|
|
|
@ -1,275 +0,0 @@
|
||||||
/**
|
|
||||||
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 && !SCEN_TEST) 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;
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
[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
|
|
|
@ -1,300 +0,0 @@
|
||||||
/**
|
|
||||||
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 = true;
|
|
||||||
|
|
||||||
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 = CreateObjectAbove(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->CreateObjectAbove(Metal,-20);
|
|
||||||
goal_site->CreateObjectAbove(Ruby,0);
|
|
||||||
goal_site->CreateObjectAbove(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 = CreateObjectAbove(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)
|
|
||||||
{
|
|
||||||
if (!SCEN_TEST)
|
|
||||||
StartSequence("Intro", 0, GetCrew(first_player));
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PostIntroInitialize();
|
|
||||||
g_intro_done = true;
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
|
|
||||||
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
|
|
||||||
CreateObjectAbove(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 Shape->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 = CreateObjectAbove(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);
|
|
||||||
CreateObjectAbove(Flagpole, pos[0]-7, pos[1]);
|
|
||||||
var rfp = CreateObjectAbove(Flagpole, pos[0]+7, pos[1]);
|
|
||||||
rfp->SetNeutral(true);
|
|
||||||
pos = FindMainIslandPosition(120, 20);
|
|
||||||
CreateObjectAbove(Flagpole, pos[0], pos[1]);
|
|
||||||
pos = FindMainIslandPosition(nil, nil, true);
|
|
||||||
CreateObjectAbove(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);
|
|
||||||
CreateObjectAbove(Sawmill, pos[0], pos[1]);
|
|
||||||
pos = FindMainIslandPosition(nil, nil, true);
|
|
||||||
CreateObjectAbove(ChemicalLab, pos[0], pos[1]);
|
|
||||||
pos = FindMainIslandPosition(nil, nil, true);
|
|
||||||
CreateObjectAbove(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;
|
|
||||||
}
|
|
Before Width: | Height: | Size: 4.5 KiB |
|
@ -1,5 +0,0 @@
|
||||||
[Landscape]
|
|
||||||
BottomOpen=0
|
|
||||||
TopOpen=1
|
|
||||||
MapZoom=20,0,5,20
|
|
||||||
Sky=Clouds2
|
|
|
@ -1 +0,0 @@
|
||||||
Tuesday=Dienstag
|
|
|
@ -1 +0,0 @@
|
||||||
Tuesday=Tuesday
|
|
|
@ -1,48 +0,0 @@
|
||||||
// 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);
|
|
||||||
}
|
|
|
@ -1,2 +0,0 @@
|
||||||
#appendto Ruby
|
|
||||||
func IsValuable(){}
|
|
|
@ -1,271 +0,0 @@
|
||||||
#appendto Sequence
|
|
||||||
|
|
||||||
static g_intro_sky_moving;
|
|
||||||
static npc_tuesday;
|
|
||||||
|
|
||||||
func Intro_Start()
|
|
||||||
{
|
|
||||||
// Intro starts high up in the clouds
|
|
||||||
LoadScenarioSection("Intro");
|
|
||||||
SetPlayList("skyisland", NO_OWNER, true);
|
|
||||||
SetWind(-100);
|
|
||||||
SetSkyParallax(0, 20, 20, -10, 0);
|
|
||||||
|
|
||||||
this.plane = CreateObjectAbove(Plane, 500, 200);
|
|
||||||
this.plane->SetColor(0xa04000);
|
|
||||||
this.pilot = CreateObjectAbove(Clonk, 100, 100, NO_OWNER);
|
|
||||||
this.pilot->MakeInvincible();
|
|
||||||
this.pilot->MakeNonFlammable();
|
|
||||||
this.pilot->SetSkin(2);
|
|
||||||
this.pilot->Enter(this.plane);
|
|
||||||
this.pilot->SetAction("Walk");
|
|
||||||
|
|
||||||
this.pilot->SetName("Pyrit");
|
|
||||||
this.pilot->SetColor(0xff0000);
|
|
||||||
this.pilot->SetDir(DIR_Left);
|
|
||||||
this.pilot->SetObjectLayer(this.pilot);
|
|
||||||
|
|
||||||
this.plane.FxIntPlaneTimer = this.Intro_PlaneTimer;
|
|
||||||
RemoveEffect("IntPlane", this.plane);
|
|
||||||
AddEffect("IntPlane",this.plane,1,1,this.plane);
|
|
||||||
this.plane->FaceRight();
|
|
||||||
this.plane->StartInstantFlight(90, 0);
|
|
||||||
g_intro_sky_moving = true;
|
|
||||||
|
|
||||||
|
|
||||||
SetViewTarget(this.plane);
|
|
||||||
|
|
||||||
return ScheduleNext(100, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Intro_PlaneTimer(...)
|
|
||||||
{
|
|
||||||
// Plane flight overload: Just move sky and have plane do turbulent movement during initial part of intro
|
|
||||||
var rv = Call(Plane.FxIntPlaneTimer, ...);
|
|
||||||
if (g_intro_sky_moving)
|
|
||||||
{
|
|
||||||
if (!Random(4)) this.rdir = BoundBy((80+Random(21)-GetR())/5,-1,1);
|
|
||||||
SetXDir(); SetYDir(GetR()*2-GetY()+Random(5),10);
|
|
||||||
}
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
func Intro_JoinPlayer(int plr)
|
|
||||||
{
|
|
||||||
if (g_intro_done) return false; // too late for join - just join on island
|
|
||||||
for(var index = 0, crew; crew = GetCrew(plr, index); ++index) crew->Enter(this);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
func Intro_1()
|
|
||||||
{
|
|
||||||
MessageBoxAll("$Intro1$", GetHero(), true); // y clouds?
|
|
||||||
return ScheduleNext(200);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Intro_2()
|
|
||||||
{
|
|
||||||
MessageBoxAll("$Intro2$", this.pilot, true); // cuz u told me
|
|
||||||
return ScheduleNext(300);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Intro_3()
|
|
||||||
{
|
|
||||||
MessageBoxAll("$Intro3$", GetHero(), true); // 2 turbulent
|
|
||||||
return ScheduleNext(200);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Intro_4()
|
|
||||||
{
|
|
||||||
MessageBoxAll("$Intro4$", this.pilot, true); // cuz condensation
|
|
||||||
return ScheduleNext(380);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Intro_5()
|
|
||||||
{
|
|
||||||
MessageBoxAll("$Intro5$", GetHero(), true); // go lower now
|
|
||||||
return ScheduleNext(300);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Intro_6()
|
|
||||||
{
|
|
||||||
MessageBoxAll("$Intro6$", this.pilot, true); // fuk u
|
|
||||||
return ScheduleNext(450);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Intro_7()
|
|
||||||
{
|
|
||||||
MessageBoxAll("$Intro7$", this.pilot, true); // u fly
|
|
||||||
return ScheduleNext(200);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Intro_8()
|
|
||||||
{
|
|
||||||
MessageBoxAll("$Intro8$", GetHero(), true); // ...
|
|
||||||
return ScheduleNext(100);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Intro_9()
|
|
||||||
{
|
|
||||||
MessageBoxAll("$Intro9$", GetHero(), true); // ok
|
|
||||||
return ScheduleNext(150);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Intro_10()
|
|
||||||
{
|
|
||||||
g_intro_sky_moving = false;
|
|
||||||
this.plane.rdir = 0;
|
|
||||||
this.plane->StartInstantFlight(this.plane->GetR(), 15);
|
|
||||||
MessageBoxAll("$Intro10$", GetHero(), true); // aaaah
|
|
||||||
for (var i=0,plr; i<GetPlayerCount(C4PT_User); ++i)
|
|
||||||
{
|
|
||||||
plr = GetPlayerByIndex(i, C4PT_User);
|
|
||||||
for(var index = 0, crew; crew = GetCrew(plr, index); ++index)
|
|
||||||
{
|
|
||||||
crew->Exit();
|
|
||||||
crew->SetPosition(this.plane->GetX()+10, this.plane->GetY());
|
|
||||||
crew->SetAction("Tumble");
|
|
||||||
if (!index) SetPlrView(plr, crew);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SetViewTarget();
|
|
||||||
return ScheduleNext(200, 11);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Intro_11()
|
|
||||||
{
|
|
||||||
g_intro_done = true;
|
|
||||||
LoadScenarioSection("main");
|
|
||||||
SetWind(0);
|
|
||||||
SetSkyParallax(0, 20, 20, 0, 0);
|
|
||||||
GameCall("PostIntroInitialize");
|
|
||||||
for (var i=0,plr; i<GetPlayerCount(C4PT_User); ++i)
|
|
||||||
{
|
|
||||||
plr = GetPlayerByIndex(i, C4PT_User);
|
|
||||||
GameCall("InitializePlayer", plr);
|
|
||||||
for(var index = 0, crew; crew = GetCrew(plr, index); ++index)
|
|
||||||
{
|
|
||||||
crew->SetPosition(g_tuesday_pos[0],-100);
|
|
||||||
crew->SetXDir(-10); crew->SetYDir(-30);
|
|
||||||
if (!index) SetPlrView(plr, crew);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ScheduleNext(200, 20);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Intro_20()
|
|
||||||
{
|
|
||||||
MessageBoxAll("$Intro20$", GetHero(), true); // ouch
|
|
||||||
for (var i=0,plr; i<GetPlayerCount(C4PT_User); ++i)
|
|
||||||
{
|
|
||||||
plr = GetPlayerByIndex(i, C4PT_User);
|
|
||||||
for(var index = 0, crew; crew = GetCrew(plr, index); ++index)
|
|
||||||
{
|
|
||||||
crew->SetCommand("MoveTo", nil, g_tuesday_pos[0]-15+Random(20), g_tuesday_pos[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ScheduleNext(300);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Intro_21()
|
|
||||||
{
|
|
||||||
Dialogue->SetSpeakerDirs(npc_tuesday, GetHero());
|
|
||||||
MessageBoxAll("$Intro21$", npc_tuesday, true); // hi friend
|
|
||||||
return ScheduleNext(300);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Intro_22()
|
|
||||||
{
|
|
||||||
MessageBoxAll("$Intro22$", GetHero(), true); // where is plane?
|
|
||||||
return ScheduleNext(300);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Intro_23()
|
|
||||||
{
|
|
||||||
MessageBoxAll("$Intro23$", npc_tuesday, true); // 2 cloudy 4 plane
|
|
||||||
return ScheduleNext(350);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Intro_24()
|
|
||||||
{
|
|
||||||
MessageBoxAll("$Intro24$", GetHero(), true); // but i need plane
|
|
||||||
return ScheduleNext(250);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Intro_25()
|
|
||||||
{
|
|
||||||
MessageBoxAll("$Intro25$", npc_tuesday, true); // u stay here
|
|
||||||
return ScheduleNext(300);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Intro_26()
|
|
||||||
{
|
|
||||||
MessageBoxAll("$Intro26$", GetHero(), true); // make fire?
|
|
||||||
return ScheduleNext(300);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Intro_27()
|
|
||||||
{
|
|
||||||
MessageBoxAll("$Intro27$", npc_tuesday, true); // fire sux
|
|
||||||
return ScheduleNext(400);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Intro_28()
|
|
||||||
{
|
|
||||||
MessageBoxAll("$Intro28$", npc_tuesday, true); // use communicator
|
|
||||||
return ScheduleNext(300);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Intro_29()
|
|
||||||
{
|
|
||||||
MessageBoxAll("$Intro29$", GetHero(), true); // ok. where?
|
|
||||||
return ScheduleNext(250);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Intro_30()
|
|
||||||
{
|
|
||||||
MessageBoxAll("$Intro30$", npc_tuesday, true); // not built yet
|
|
||||||
return ScheduleNext(450);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Intro_31()
|
|
||||||
{
|
|
||||||
MessageBoxAll("$Intro31$", npc_tuesday, true); // go east and finish it with metal+gems
|
|
||||||
return ScheduleNext(400);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Intro_32()
|
|
||||||
{
|
|
||||||
MessageBoxAll("$Intro32$", GetHero(), true); // where gems?
|
|
||||||
return ScheduleNext(250);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Intro_33()
|
|
||||||
{
|
|
||||||
MessageBoxAll("$Intro33$", npc_tuesday, true); // fish say gems in sea
|
|
||||||
return ScheduleNext(400);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Intro_34()
|
|
||||||
{
|
|
||||||
MessageBoxAll("$Intro34$", GetHero(), true); // fish talk?
|
|
||||||
return ScheduleNext(150);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Intro_35()
|
|
||||||
{
|
|
||||||
MessageBoxAll("$Intro35$", npc_tuesday, true); // coconut talk!
|
|
||||||
return ScheduleNext(200);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Intro_36()
|
|
||||||
{
|
|
||||||
MessageBoxAll("$Intro36$", GetHero(), true); // ok...
|
|
||||||
return ScheduleNext(150);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Intro_37()
|
|
||||||
{
|
|
||||||
npc_tuesday->SetDialogue("Tuesday", true);
|
|
||||||
return Stop();
|
|
||||||
}
|
|
|
@ -1,106 +0,0 @@
|
||||||
#appendto Sequence
|
|
||||||
|
|
||||||
func Outro_Start()
|
|
||||||
{
|
|
||||||
this.communicator = FindObject(Find_Func("IsCrystalCommunicator"));
|
|
||||||
if (!this.communicator) return false; // what?
|
|
||||||
this.hero = this.communicator->FindObject(Find_ID(Clonk), Find_OCF(OCF_Alive), this.communicator->Sort_Distance());
|
|
||||||
SetViewTarget(this.communicator);
|
|
||||||
// Outro
|
|
||||||
ScheduleCall(nil, this.Outro_Fade2Darkness, 15, 32, {});
|
|
||||||
Dialogue->MessageBoxAll("$Outro1$", this.hero, true); // ok turn it on
|
|
||||||
return ScheduleNext(100);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Outro_1()
|
|
||||||
{
|
|
||||||
this.communicator->StartCommunication(); // 250 frames
|
|
||||||
return ScheduleNext(650);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Outro_2()
|
|
||||||
{
|
|
||||||
Dialogue->MessageBoxAll("$Outro2$", this.hero, true); // let's see if it works
|
|
||||||
return ScheduleNext(50);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Outro_3()
|
|
||||||
{
|
|
||||||
this.communicator->SendCode("...---..."); // 159 frames
|
|
||||||
return ScheduleNext(200);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Outro_4()
|
|
||||||
{
|
|
||||||
this.communicator->StopCommunication();
|
|
||||||
MessageBoxAll("$Outro3$", this.hero, true); // i wonder if anyone has heard us
|
|
||||||
this.plane = CreateObjectAbove(Plane, 100, main_island_y-100);
|
|
||||||
this.plane->SetContactDensity(85); // only collision with brick for proper landing
|
|
||||||
this.pilot = CreateObjectAbove(Clonk, 100, 100);
|
|
||||||
this.pilot->MakeInvincible();
|
|
||||||
this.pilot->SetSkin(2);
|
|
||||||
this.pilot->Enter(this.plane);
|
|
||||||
this.pilot->SetAction("Walk");
|
|
||||||
this.pilot->SetName("Pyrit");
|
|
||||||
this.pilot->SetColor(0xff0000);
|
|
||||||
this.pilot->SetDir(DIR_Right);
|
|
||||||
this.plane->FaceRight();
|
|
||||||
this.plane->StartInstantFlight(90, 15);
|
|
||||||
return ScheduleNext(5);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Outro_5()
|
|
||||||
{
|
|
||||||
// Wait for plane to arrive
|
|
||||||
if (this.plane->GetX() < this.communicator->GetX() - 200) return ScheduleSame(5);
|
|
||||||
// Plane in range! Ensure players see it.
|
|
||||||
SetPlayerZoomByViewRange(NO_OWNER, 500, 350, PLRZOOM_Direct | PLRZOOM_LimitMax);
|
|
||||||
MessageBoxAll("$Outro4$", this.pilot, true); // hey, our friends!
|
|
||||||
return ScheduleNext(100);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Outro_6()
|
|
||||||
{
|
|
||||||
MessageBoxAll("$Outro5$", this.hero, true); // we're saved!
|
|
||||||
this.plane->StartInstantFlight(245, 15);
|
|
||||||
this.plane->SetContactDensity(C4M_Solid);
|
|
||||||
return ScheduleNext(60);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Outro_7()
|
|
||||||
{
|
|
||||||
this.plane->StartInstantFlight(280, 5);
|
|
||||||
return ScheduleNext(15);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Outro_8()
|
|
||||||
{
|
|
||||||
this.plane->CancelFlight();
|
|
||||||
return ScheduleNext(40);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Outro_9()
|
|
||||||
{
|
|
||||||
this.pilot->Exit();
|
|
||||||
MessageBoxAll("$Outro6$", this.pilot, true); // hop on everyone!
|
|
||||||
return ScheduleNext(100);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Outro_10()
|
|
||||||
{
|
|
||||||
this.plane->FaceRight();
|
|
||||||
return ScheduleNext(100);
|
|
||||||
}
|
|
||||||
|
|
||||||
func Outro_11()
|
|
||||||
{
|
|
||||||
Sound("Fanfare");
|
|
||||||
return GameOver();
|
|
||||||
}
|
|
||||||
|
|
||||||
func Outro_Fade2Darkness(proplist v)
|
|
||||||
{
|
|
||||||
v.t += 8;
|
|
||||||
var fade_val = Max(0xff-v.t);
|
|
||||||
SetSkyAdjust(RGB(fade_val,fade_val,fade_val));
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
Intro1=Pyrit, warum müssen wir in den Wolken fliegen?
|
|
||||||
Intro2=Du sagtest, wir sollen höher fliegen, nachdem wir fast im Vulkan gelandet waren.
|
|
||||||
Intro3=Es ist schrecklich turbulent hier.
|
|
||||||
Intro4=Das liegt daran, dass die Kondensation des Wassers in den Wolken Wärme freisetzt, die die Luft weiter aufsteigen lässt.
|
|
||||||
Intro5=Danke für den Vortrag. Können wir nun bitte tiefer fliegen?
|
|
||||||
Intro6=Erst ist es zu turbulent wenn ich tief fliege. Nun ist es zu turbulent wenn ich hoch fliege.
|
|
||||||
Intro7=Warum steuerst du das Flugzeug nicht einfach selber?
|
|
||||||
Intro8=...
|
|
||||||
Intro9=Okay. Wir tauschen Plätze!
|
|
||||||
Intro10=Aaaah
|
|
||||||
|
|
||||||
Intro20=Autsch.
|
|
||||||
Intro21=Oh. Ein Freund ist vom Himmel gefallen. Hallo Freund! Mein Name ist Dienstag.
|
|
||||||
Intro22=Verdammt. Hast du unser Flugzeug gesehen? Ich bin versehentlich raus gefallen.
|
|
||||||
Intro23=Der Himmel ist hier stets bewölkt. Wir sehen kein Flugzeug und kein Flugzeug sieht uns.
|
|
||||||
Intro24=Ugh. Aber Pyrit muss uns irgendwie finden.
|
|
||||||
Intro25=Was auf der Insel strandet bleibt auf der Insel. Genau wie ich.
|
|
||||||
Intro26=Könnten wir nicht ein Feuer machen oder so?
|
|
||||||
Intro27=Feuer? Das wird nicht helfen. Kokosnussholz brennt schlecht und das Feuer würde durch die Wolken eh keiner sehen.
|
|
||||||
Intro28=Aber...wir könnten meinen <c ffff00>Kristallkommunikator</c> benutzen!
|
|
||||||
Intro29=Klingt gut. Wo steht der?
|
|
||||||
Intro30=Ich bin glücklich auf meiner Insel. Warum sollte ich ein Kommunikationsgerät bauen? Ich habe die Pläne fertig, aber mich nie bemüht es auch zu bauen.
|
|
||||||
Intro31=Die Baustelle und die Pläne befinden sich am Östlichen Ende dieser Insel. Du brauchst nur etwas Metall und ein paar Edelsteine.
|
|
||||||
Intro32=Metall klingt einfach. Aber wo finde ich Edelsteine?
|
|
||||||
Intro33=Die Fische sprechen manchmal über glitzernde Edelsteine tief unten im Meer. Vielleicht kannst du die abbauen?
|
|
||||||
Intro34=Fische sprechen mit dir?
|
|
||||||
Intro35=Wenn du nur zuhörst, sprechen sogar die Kokosnüsse!
|
|
||||||
Intro36=Okay...ich schaue mal nach der Baustelle.
|
|
||||||
|
|
||||||
Tuesday1=Hallo, Freund. Wie kann ich dir helfen?
|
|
||||||
TuesdayQCommunicator=Wie benutze ich den Kommunikator?
|
|
||||||
TuesdayACommunicator=Bringe einfach das nötige Material zur Baustelle. Es wird automatisch funktionieren, wenn du es fertig stellst.
|
|
||||||
TuesdayQGems=Wo finde ich Edelsteine?
|
|
||||||
TuesdayAGems=Tauche ins Meer hinein. Die größten Schätze lagern tief unten und sind schwer erreichbar.
|
|
||||||
TuesdayQFish=Kannst du die Fische weg schicken?
|
|
||||||
TuesdayAFish=Ich bin nur ein Zuhörer. Ich belaste die freien Geschöpfe dieser Welt nicht mit unnötigen Verboten.
|
|
||||||
TuesdayQWater=Das wasser ist zu Tief. Wie komme ich an die Edelsteine?
|
|
||||||
TuesdayAWater=Du könntest probieren, Wandbausätze{{WallKit}} in der Werkzeughütte{{ToolsWorkshop}} zu bauen. Wandbausätze können benutzt werden, um stabile Wände auch unter Wasser zu errichten. Diese schützen dich vor den Fischen und schaffen Raum zum Atmen.
|
|
||||||
TuesdayAWater2=Mit Wandbausätzen und einer Pumpe solltest du die Edelsteine erreichen können.
|
|
||||||
TuesdayQBye=Tschüss.
|
|
||||||
|
|
||||||
Outro1=Die Maschine ist fertig. Ob sie wohl funktioniert?
|
|
||||||
Outro2=Das sieht gut aus. Ich sende ein Notsignal...
|
|
||||||
Outro3=Hoffentlich hat uns jemand gehört.
|
|
||||||
Outro4=Hey, sind das nicht unsere gestrandeten Freunde?
|
|
||||||
Outro5=Hurra, wir sind gerettet!
|
|
||||||
Outro6=Alles einsteigen! Wir fliegen zum Goldenen Berg.
|
|
||||||
|
|
|
@ -1,47 +0,0 @@
|
||||||
Intro1=Pyrit, why do we have to fly in the clouds?
|
|
||||||
Intro2=You told me to fly higher after we almost crashed into the volcano.
|
|
||||||
Intro3=It's horribly turbulent in here.
|
|
||||||
Intro4=That's because water condensation in the cloud frees up energy which heats up the air.
|
|
||||||
Intro5=Thanks for the lecture. Now can we please fly lower again?
|
|
||||||
Intro6=First it's too turbulent when i fly low over the volcano and now it's too turbulent when i fly up high in the clouds.
|
|
||||||
Intro7=Why don't you just steer the plane yourself?
|
|
||||||
Intro8=...
|
|
||||||
Intro9=Alright. Let's swap places.
|
|
||||||
Intro10=Aaaah
|
|
||||||
|
|
||||||
Intro20=Ouch.
|
|
||||||
Intro21=Oh, a friend has fallen from the sky. Hello friend! My name is Tuesday.
|
|
||||||
Intro22=Damn. Have you seen our airplane? I accidentally dropped out of it.
|
|
||||||
Intro23=The sky is always cloudy here. We won't see any planes and planes won't see us.
|
|
||||||
Intro24=Ugh. But i need Pyrit to find me somehow.
|
|
||||||
Intro25=What lands on the island stays on the island. Just like me.
|
|
||||||
Intro26=Isn't there any way we could make a fire or something?
|
|
||||||
Intro27=Fire? That will do no good. Coconut wood doesn't burn well and it won't be seen through the clouds.
|
|
||||||
Intro28=But...we could use my <c ffff00>crystal communicator</c>!
|
|
||||||
Intro29=Sounds good. Where is it?
|
|
||||||
Intro30=I'm happy on this island. Why should i build a communication device? I've made plans but I haven't bothered to finish building it.
|
|
||||||
Intro31=The site and plans how to finish it are at the eastern end of this island. It just needs some metal and some gems.
|
|
||||||
Intro32=Metal sounds easy enough? Where can I find the gems?
|
|
||||||
Intro33=The fish sometimes talk about gem reserves deep below the ocean ground. Maybe you can mine those?
|
|
||||||
Intro34=Fish talk to you?
|
|
||||||
Intro35=If you listen carefully, even coconuts talk!
|
|
||||||
Intro36=Okay...i'll see if i can finish this construction.
|
|
||||||
|
|
||||||
Tuesday1=Hello, friend. How can I help you?
|
|
||||||
TuesdayQCommunicator=How do I use the communicator?
|
|
||||||
TuesdayACommunicator=Just bring the necessery materials to the construction site. It should work automatically when completed.
|
|
||||||
TuesdayQGems=Where can I find gems?
|
|
||||||
TuesdayAGems=Try to dive underground.
|
|
||||||
TuesdayQFish=Can you tell the fish to go away?
|
|
||||||
TuesdayAFish=I'm a listener. I do not force restraints onto the free creatures of this world.
|
|
||||||
TuesdayQWater=The water is too deep. How can I reach the gems?
|
|
||||||
TuesdayAWater=You could try and build wall kits{{WallKit}} in the tools workshop{{ToolsWorkshop}}. Wall kits can be used to construct stable walls under water protect you from fish and give some room to breath.
|
|
||||||
TuesdayAWater2=Using wall kits and a pump, you might be able to solve your problems.
|
|
||||||
TuesdayQBye=Bye
|
|
||||||
|
|
||||||
Outro1=The machine is done! I wonder whether it works.
|
|
||||||
Outro2=Looks good. Let's send a rescue signal...
|
|
||||||
Outro3=I wonder if anyone has heard us.
|
|
||||||
Outro4=Hey, isn't that our stranded friends?
|
|
||||||
Outro5=Hooray, we're saved!
|
|
||||||
Outro6=Hop on everyone, we're heading for the Golden Mountain!
|
|
|
@ -1,2 +0,0 @@
|
||||||
DE:AmbienceTest: Tiefseemine
|
|
||||||
US:AmbienceTest: Deep sea mining
|
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
func InitializeObjects()
|
func InitializeObjects()
|
||||||
{
|
{
|
||||||
|
CreateObject(Ambience);
|
||||||
|
|
||||||
CreateObject(Grass, 555, 550);
|
CreateObject(Grass, 555, 550);
|
||||||
CreateObjectAbove(Grass, 533, 550);
|
CreateObjectAbove(Grass, 533, 550);
|
||||||
CreateObjectAbove(Grass, 1306, 706);
|
CreateObjectAbove(Grass, 1306, 706);
|
||||||
|
|
|
@ -33,6 +33,7 @@ protected func PostIntroInitialize()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize different parts of the scenario.
|
// Initialize different parts of the scenario.
|
||||||
|
CreateObject(Ambience);
|
||||||
InitEnvironment();
|
InitEnvironment();
|
||||||
InitVegetation();
|
InitVegetation();
|
||||||
InitAnimals();
|
InitAnimals();
|
||||||
|
|
|
@ -4,6 +4,8 @@ static g_chemical, g_cabin, g_sawmill, g_workshop, g_windmill, g_flagpole, npc_n
|
||||||
|
|
||||||
func InitializeObjects()
|
func InitializeObjects()
|
||||||
{
|
{
|
||||||
|
CreateObject(Ambience);
|
||||||
|
|
||||||
var Rule_BaseRespawn001 = CreateObject(Rule_BaseRespawn);
|
var Rule_BaseRespawn001 = CreateObject(Rule_BaseRespawn);
|
||||||
Rule_BaseRespawn001->SetInventoryTransfer(true);
|
Rule_BaseRespawn001->SetInventoryTransfer(true);
|
||||||
Rule_BaseRespawn001->SetFreeCrew(true);
|
Rule_BaseRespawn001->SetFreeCrew(true);
|
||||||
|
|
|
@ -2,7 +2,7 @@ PlaneNoOil=Das Flugzeug braucht noch Treibstoff. Ich muss irgendwo
|
||||||
|
|
||||||
Intro1=Autsch. Pyrit!
|
Intro1=Autsch. Pyrit!
|
||||||
Intro2=Wie kann der Treibstoff leer sein? Du sagtest doch, ein Fass Öl bringt uns locker an unser Ziel und zurück!
|
Intro2=Wie kann der Treibstoff leer sein? Du sagtest doch, ein Fass Öl bringt uns locker an unser Ziel und zurück!
|
||||||
Intro3=Dachte ich auch. Aber da wusste ich noch nicht, dass ich drei Tage über dem Ozean kreisen und auf einer einsamen Insel suchen müsste.
|
Intro3=Dachte ich auch. Aber da wusste ich noch nicht, dass ich drei Tage über dem Ozean kreisen und nach einer einsamen Insel suchen müsste.
|
||||||
Intro4=Das ist alles deine Schuld. Ich sags ja nur.
|
Intro4=Das ist alles deine Schuld. Ich sags ja nur.
|
||||||
Intro5=Was können wir nun tun?
|
Intro5=Was können wir nun tun?
|
||||||
Intro6=Ich schlage vor du suchst neues Öl und ich repariere derweil das Flugzeug.
|
Intro6=Ich schlage vor du suchst neues Öl und ich repariere derweil das Flugzeug.
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
[DefCore]
|
[DefCore]
|
||||||
id=Ambience
|
id=Ambience
|
||||||
Version=6,0
|
Version=6,0
|
||||||
Category=C4D_StaticBack
|
Category=C4D_StaticBack | C4D_Environment
|
||||||
Width=1
|
Width=1
|
||||||
Height=1
|
Height=1
|
||||||
Offset=-1,-1
|
Offset=-1,-1
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,381 @@
|
||||||
/**
|
/**
|
||||||
Ambience
|
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 player_environments; // array indexed by player number: array of derived environments with per-player data
|
||||||
|
local all_environments; // array of available environments for which it is checked if the player is in. sorted by priority.
|
||||||
|
|
||||||
|
// Initialization
|
||||||
|
protected func Initialize()
|
||||||
|
{
|
||||||
|
// Register default environments (overloadable)
|
||||||
|
this->InitializeEnvironments();
|
||||||
|
// Initial player data
|
||||||
|
player_environments = [];
|
||||||
|
for (var i=0; i<GetPlayerCount(C4PT_User); ++i)
|
||||||
|
InitializePlayer(GetPlayerByIndex(i, C4PT_User));
|
||||||
|
// Periodic execution of ambience events
|
||||||
|
AddTimer(this.Execute, 10);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitializeEnvironments()
|
||||||
|
{
|
||||||
|
// Register all standard environments
|
||||||
|
all_environments = [];
|
||||||
|
|
||||||
|
// Underwater: Clonk is swimming in water
|
||||||
|
var underwater = this.env_underwater = new Environment
|
||||||
|
{
|
||||||
|
Name = "Underwater",
|
||||||
|
CheckPlayer = this.EnvCheck_Underwater,
|
||||||
|
music = "underwater",
|
||||||
|
sound_modifier = UnderwaterModifier,
|
||||||
|
exclusive = true, // Do not player other stuff (such as cave sound) when diving.
|
||||||
|
};
|
||||||
|
|
||||||
|
AddEnvironment(underwater, 1400);
|
||||||
|
|
||||||
|
// City: Clonk is surrounded by buildings
|
||||||
|
var city = this.env_city = new Environment
|
||||||
|
{
|
||||||
|
Name = "City",
|
||||||
|
CheckPlayer = this.EnvCheck_City,
|
||||||
|
};
|
||||||
|
//AddEnvironment(city, 1200); - no music/sound for now
|
||||||
|
|
||||||
|
// Lava: Lava material is nearby
|
||||||
|
var lava = this.env_lava = new Environment
|
||||||
|
{
|
||||||
|
Name = "Lava",
|
||||||
|
CheckPlayer = this.EnvCheck_Lava,
|
||||||
|
min_change_delays = [1, 3], // Easy to miss lava on search.
|
||||||
|
};
|
||||||
|
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;
|
||||||
|
//AddEnvironment(lava, 1000); - no music/sound for now
|
||||||
|
|
||||||
|
// Underground: Clonk in front of tunnel
|
||||||
|
var underground = this.env_underground = new Environment
|
||||||
|
{
|
||||||
|
Name = "Underground",
|
||||||
|
CheckPlayer = this.EnvCheck_Underground,
|
||||||
|
music = "underground",
|
||||||
|
sound_modifier = CaveModifier,
|
||||||
|
};
|
||||||
|
AddEnvironment(underground, 800);
|
||||||
|
|
||||||
|
// Mountains: Overground and lots of rock around
|
||||||
|
var mountains = this.env_mountains = new Environment
|
||||||
|
{
|
||||||
|
Name = "Mountains",
|
||||||
|
CheckPlayer = this.EnvCheck_Mountains,
|
||||||
|
min_change_delay = [3, 3], // Pretty unstable condition
|
||||||
|
};
|
||||||
|
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;
|
||||||
|
//AddEnvironment(mountains, 600); - no music/sound for now
|
||||||
|
|
||||||
|
// Snow: It's snowing around the clonk
|
||||||
|
var snow = this.env_snow = new Environment
|
||||||
|
{
|
||||||
|
Name = "Snow",
|
||||||
|
CheckPlayer = this.EnvCheck_Snow,
|
||||||
|
min_change_delay = [1, 6], // Persist a while after snowing stopped
|
||||||
|
};
|
||||||
|
snow.mat = Material("Snow");
|
||||||
|
//AddEnvironment(snow, 400); - no music/sound for now
|
||||||
|
|
||||||
|
// Night: Sunlight blocked by planet
|
||||||
|
var night = this.env_night = new Environment
|
||||||
|
{
|
||||||
|
Name = "Night",
|
||||||
|
CheckPlayer = this.EnvCheck_Night,
|
||||||
|
music = "night",
|
||||||
|
};
|
||||||
|
AddEnvironment(night, 200);
|
||||||
|
|
||||||
|
// Day: Default environment
|
||||||
|
var day = this.env_day = new Environment
|
||||||
|
{
|
||||||
|
Name = "Day",
|
||||||
|
CheckPlayer = this.EnvCheck_Day,
|
||||||
|
music = "day",
|
||||||
|
};
|
||||||
|
AddEnvironment(day, 0);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private func Execute()
|
||||||
|
{
|
||||||
|
// Per-player execution every third timer (~.8 seconds)
|
||||||
|
var i=GetPlayerCount(C4PT_User), plr;
|
||||||
|
exec_counter += !(i%3);
|
||||||
|
while (i--) if (!(++exec_counter % 3))
|
||||||
|
{
|
||||||
|
plr = GetPlayerByIndex(i, C4PT_User);
|
||||||
|
ExecutePlayer(plr, player_environments[plr]);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private func ExecutePlayer(int plr, array environments)
|
||||||
|
{
|
||||||
|
var cursor = GetCursor(plr);
|
||||||
|
// Update active state of all player environments
|
||||||
|
if (cursor)
|
||||||
|
{
|
||||||
|
var x = cursor->GetX(), y = cursor->GetY();
|
||||||
|
for (var env in environments)
|
||||||
|
{
|
||||||
|
var was_active = env.is_active;
|
||||||
|
var is_active = env->CheckPlayer(cursor, x, y, was_active);
|
||||||
|
if (is_active == was_active)
|
||||||
|
{
|
||||||
|
// No change. Reset change delays.
|
||||||
|
env.change_delay = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Environment change. The change must persist for a while to become active.
|
||||||
|
if (++env.change_delay > env.min_change_delays[!is_active])
|
||||||
|
{
|
||||||
|
// Waited long enough. Activate or deactivate this environment.
|
||||||
|
env.is_active = is_active;
|
||||||
|
//Log("%s environment: %s set to %v", GetPlayerName(plr), env.Name, is_active);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Sound and music by active environments
|
||||||
|
var has_music = false, sound_modifier = nil;
|
||||||
|
for (var env in environments) if (env.is_active)
|
||||||
|
{
|
||||||
|
// Music!
|
||||||
|
if (env.music && !has_music)
|
||||||
|
{
|
||||||
|
this->SetPlayList(env.music, plr, true, 3000);
|
||||||
|
has_music = true;
|
||||||
|
}
|
||||||
|
// Sound effects like cave reverb etc.
|
||||||
|
if (env.sound_modifier && !sound_modifier) sound_modifier = env.sound_modifier;
|
||||||
|
// Sounds and actions by environment
|
||||||
|
for (var action in env.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]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Does this stop all other environments?
|
||||||
|
if (env.is_exclusive) break;
|
||||||
|
}
|
||||||
|
// Apply or clear global sound modifier
|
||||||
|
SetGlobalSoundModifier(sound_modifier);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitializePlayer(int plr)
|
||||||
|
{
|
||||||
|
if (GetPlayerType(plr) == C4PT_User)
|
||||||
|
{
|
||||||
|
// Every player keeps a copy of the environment list to maintain delays
|
||||||
|
// Start with a large change delay to ensure first execution does set a proper environment
|
||||||
|
var n = GetLength(all_environments);
|
||||||
|
var envs = CreateArray(n);
|
||||||
|
for (var i=0; i < n; ++i)
|
||||||
|
envs[i] = new all_environments[i] { change_delay = 999, is_active = false };
|
||||||
|
player_environments[plr] = envs;
|
||||||
|
// 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
|
||||||
|
player_environments[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.all_environments[GetLength(all_environments)] = new_env;
|
||||||
|
SortArrayByProperty(this.all_environments, "Priority", true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private func Env_AddSound(chance, string snd_name)
|
||||||
|
{
|
||||||
|
return Env_AddAction(chance ?? 50, Global.Sound, snd_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private func Env_AddAction(achance, afn, par0, par1, par2, par3, par4)
|
||||||
|
{
|
||||||
|
// Make sure to not write into prototype proplist.
|
||||||
|
if (this.actions == this.Prototype.actions) this.actions = [];
|
||||||
|
return this.actions[GetLength(this.actions)] = { chance=achance, fn=afn, par=[par0, par1, par2, par3, par4] };
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 false;
|
||||||
|
// For initial change, clonk should also be diving: Check for breath below 95%
|
||||||
|
// Use > instead of >= to ensure 0-breath-clonks can also get the environment
|
||||||
|
if (!is_current && cursor->GetBreath() > cursor.MaxBreath*95/100) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 true;
|
||||||
|
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 true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// No lava found
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 false;
|
||||||
|
if (GetMaterial(x,y-30)<0) return false;
|
||||||
|
if (GetMaterial(x-10,y-20)<0) return false;
|
||||||
|
if (GetMaterial(x+10,y-20)<0) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private func EnvCheck_Day(object cursor, int x, int y, bool is_current)
|
||||||
|
{
|
||||||
|
// This is the fallback environment
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-- Proplist --*/
|
||||||
|
|
||||||
|
local SoundModifier, CaveModifier, UnderwaterModifier;
|
||||||
|
|
||||||
|
func ReleaseSoundModifier() { return ChangeSoundModifier(this, true); }
|
||||||
|
func UpdateSoundModifier() { return ChangeSoundModifier(this, false); } // OpenAL-Soft implementation does not work for all modifiers
|
||||||
|
|
||||||
|
public func Definition(def)
|
||||||
|
{
|
||||||
|
// Base environment
|
||||||
|
def.Environment = {
|
||||||
|
actions = [],
|
||||||
|
min_change_delays = [1, 1],
|
||||||
|
AddSound = def.Env_AddSound,
|
||||||
|
AddAction = def.Env_AddAction,
|
||||||
|
};
|
||||||
|
// Base sound modifier
|
||||||
|
SoundModifier = {
|
||||||
|
Release = Ambience.ReleaseSoundModifier,
|
||||||
|
Update = Ambience.UpdateSoundModifier,
|
||||||
|
};
|
||||||
|
// Modifiers for different ambiences
|
||||||
|
CaveModifier = new SoundModifier {
|
||||||
|
Type = C4SMT_Reverb,
|
||||||
|
Reverb_Late_Reverb_Gain = 300,
|
||||||
|
Reverb_Late_Reverb_Delay = 10,
|
||||||
|
Reverb_Decay_HFRatio = 800,
|
||||||
|
};
|
||||||
|
UnderwaterModifier = nil; // not supported yet
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
local Environment;
|
||||||
|
|
||||||
|
local Name = "$Name$";
|
||||||
|
local Description = "$Description$";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Ambience Objects
|
||||||
Cares about the placement of purely visual objects and handles sound ambience
|
Cares about the placement of purely visual objects and handles sound ambience
|
||||||
The placement uses categories and thus is forward-compatible.
|
The placement uses categories and thus is forward-compatible.
|
||||||
*/
|
*/
|
||||||
|
@ -41,7 +417,6 @@ static const Environment_Attributes =
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// provides a simple interface for creation of environment objects and decoration with standard values
|
// provides a simple interface for creation of environment objects and decoration with standard values
|
||||||
// the objects are placed on a best-effort-basis. That means f.e. objects that rely on water will not be placed when there is no water in the landscape.
|
// the objects are placed on a best-effort-basis. That means f.e. objects that rely on water will not be placed when there is no water in the landscape.
|
||||||
global func CreateEnvironmentObjects(
|
global func CreateEnvironmentObjects(
|
||||||
|
@ -106,23 +481,3 @@ CreateEnvironmentObjects("Temperate", Rectangle(LandscapeWidth()/2, 0, Landscape
|
||||||
p_id->Place(amount_percentage, area);
|
p_id->Place(amount_percentage, area);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sound ambience */
|
|
||||||
|
|
||||||
local SoundModifier, CaveModifier;
|
|
||||||
|
|
||||||
func ReleaseSoundModifier() { return ChangeSoundModifier(this, true); }
|
|
||||||
func UpdateSoundModifier() { return ChangeSoundModifier(this, false); } // do not use
|
|
||||||
|
|
||||||
func Definition()
|
|
||||||
{
|
|
||||||
// Base sound modifier
|
|
||||||
SoundModifier = {
|
|
||||||
Release = Ambience.ReleaseSoundModifier,
|
|
||||||
Update = Ambience.UpdateSoundModifier,
|
|
||||||
};
|
|
||||||
// Modifiers for different ambiences
|
|
||||||
CaveModifier = new SoundModifier {
|
|
||||||
Type = C4SMT_Reverb,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|