forked from Mirrors/openclonk
373 lines
13 KiB
C
373 lines
13 KiB
C
/*--
|
|
ForgottenHeights
|
|
Author: Mimmo_O
|
|
|
|
Last man Standing on sky islands for up to 12 players.
|
|
--*/
|
|
|
|
|
|
static Overcast_air_particles;
|
|
|
|
protected func Initialize()
|
|
{
|
|
// Goal.
|
|
CreateObject(Goal_LastManStanding);
|
|
CreateObject(Rule_KillLogs);
|
|
CreateObject(Rule_Gravestones);
|
|
|
|
//Enviroment.
|
|
Cloud->Place(25);
|
|
SetSkyAdjust(RGBa(250,250,255,128),RGB(200,200,220));
|
|
Sound("Environment::BirdsLoop", true, 100, nil, 1);
|
|
|
|
// Brick edges at horizontal moving bricks.
|
|
var x=[525, 436, 436, 525, 812, 812, 716, 716, 573, 573, 213, 213];
|
|
var y=[692, 677, 692, 677, 653, 668, 500, 485, 500, 485, 677, 692];
|
|
var d=[2, 1, 3, 0, 1, 3, 3, 1, 2, 0, 0, 2];
|
|
for (var i = 0; i < GetLength(x); i++)
|
|
{
|
|
var edge=CreateObjectAbove(BrickEdge, x[i], y[i], NO_OWNER);
|
|
edge->Initialize();
|
|
edge->SetP(d[i]);
|
|
edge->SetPosition(x[i],y[i]);
|
|
edge->PermaEdge();
|
|
}
|
|
|
|
// Vertically moving bricks
|
|
var brick = CreateObjectAbove(MovingBrick, 660, 90);
|
|
brick->SetSize(3);
|
|
brick->MoveVertical(80, 144);
|
|
|
|
var brick = CreateObjectAbove(MovingBrick, 592, 270);
|
|
brick->SetSize(2);
|
|
brick->MoveVertical(264, 344);
|
|
var brick = CreateObjectAbove(MovingBrick, 632, 285);
|
|
brick->SetSize(2);
|
|
brick->MoveVertical(272, 352);
|
|
var brick = CreateObjectAbove(MovingBrick, 672, 300);
|
|
brick->SetSize(2);
|
|
brick->MoveVertical(280, 360);
|
|
|
|
var brick = CreateObjectAbove(MovingBrick, 270, 430);
|
|
brick->SetSize(2);
|
|
brick->MoveVertical(416, 488);
|
|
var brick = CreateObjectAbove(MovingBrick, 310, 440);
|
|
brick->SetSize(2);
|
|
brick->MoveVertical(424, 496);
|
|
var brick = CreateObjectAbove(MovingBrick, 350, 450);
|
|
brick->SetSize(2);
|
|
brick->MoveVertical(432, 504);
|
|
|
|
var brick = CreateObjectAbove(MovingBrick, 932, 240);
|
|
brick->SetSize(4);
|
|
brick->MoveVertical(232, 536);
|
|
|
|
var brick = CreateObjectAbove(MovingBrick, 368, 200);
|
|
brick->SetSize(3);
|
|
brick->MoveVertical(152, 288);
|
|
|
|
var brick = CreateObjectAbove(MovingBrick, 184, 320);
|
|
brick->SetSize(2);
|
|
brick->MoveVertical(240, 368);
|
|
|
|
var brick = CreateObjectAbove(MovingBrick, 498, 560);
|
|
brick->SetSize(2);
|
|
brick->MoveVertical(480, 680);
|
|
DrawMaterialQuad("Tunnel-Brickback", 478, 478, 497, 478, 497, 552, 478, 552);
|
|
DrawMaterialQuad("Tunnel-Brickback", 478, 670, 497, 670, 497, 680, 478, 680);
|
|
|
|
var brick = CreateObjectAbove(MovingBrick, 170, 600);
|
|
brick->SetSize(2);
|
|
brick->MoveVertical(528, 680);
|
|
DrawMaterialQuad("Tunnel-Brickback", 150, 524, 169, 524, 169, 576, 150, 576);
|
|
DrawMaterialQuad("Tunnel-Brickback", 150, 670, 169, 670, 169, 680, 150, 680);
|
|
|
|
// Horizontally moving bricks.
|
|
var brick = CreateObjectAbove(MovingBrick, 600, 496);
|
|
brick->SetSize(4);
|
|
brick->MoveHorizontal(552, 736);
|
|
|
|
var brick = CreateObjectAbove(MovingBrick, 656, 688);
|
|
brick->SetSize(3);
|
|
brick->MoveHorizontal(504, 668);
|
|
var brick = CreateObjectAbove(MovingBrick, 688, 664);
|
|
brick->SetSize(3);
|
|
brick->MoveHorizontal(668, 832);
|
|
|
|
var brick = CreateObjectAbove(MovingBrick, 320, 688);
|
|
brick->SetSize(3);
|
|
brick->MoveHorizontal(192, 456);
|
|
|
|
// Chests with weapons.
|
|
var chest;
|
|
chest = CreateObjectAbove(Chest, 764, 128, NO_OWNER);
|
|
chest->MakeInvincible();
|
|
AddEffect("FillChest", chest, 100, 72);
|
|
chest = CreateObjectAbove(Chest, 732, 336, NO_OWNER);
|
|
chest->MakeInvincible();
|
|
AddEffect("FillChest", chest, 100, 72);
|
|
chest = CreateObjectAbove(Chest, 116, 400, NO_OWNER);
|
|
chest->MakeInvincible();
|
|
AddEffect("FillChest", chest, 100, 72);
|
|
chest = CreateObjectAbove(Chest, 272, 152, NO_OWNER);
|
|
chest->MakeInvincible();
|
|
AddEffect("FillChest", chest, 100, 72);
|
|
chest = CreateObjectAbove(Chest, 424, 480, NO_OWNER);
|
|
chest->MakeInvincible();
|
|
AddEffect("FillChest", chest, 100, 72);
|
|
chest = CreateObjectAbove(Chest, 872, 520, NO_OWNER);
|
|
chest->MakeInvincible();
|
|
AddEffect("FillChest", chest, 100, 72);
|
|
chest = CreateObjectAbove(Chest, 72, 208, NO_OWNER);
|
|
chest->MakeInvincible();
|
|
AddEffect("FillChest", chest, 100, 72);
|
|
|
|
// Some columns as decoration.
|
|
CreateObjectAbove(Column, 736, 480, NO_OWNER);
|
|
CreateObjectAbove(Column, 860, 392, NO_OWNER);
|
|
CreateObjectAbove(Column, 420, 280, NO_OWNER);
|
|
CreateObjectAbove(Column, 200, 144, NO_OWNER);
|
|
CreateObjectAbove(Column, 556, 480, NO_OWNER);
|
|
CreateObjectAbove(Column, 452, 672, NO_OWNER);
|
|
CreateObjectAbove(Column, 192, 672, NO_OWNER);
|
|
|
|
// Grass as decoration.
|
|
var x=[813, 820, 856, 833, 827, 838, 844, 869, 872, 882, 853, 861, 506, 466, 527, 524, 514, 510, 517, 502, 436, 437, 441, 448, 457, 463, 177, 139, 121, 126, 199, 190, 181, 213, 206, 133, 147, 196, 104, 175, 116, 108, 126, 135, 155, 201, 195, 188, 43, 52, 58, 406, 410, 551, 554, 550, 547, 538, 723, 838, 802, 808, 836, 690, 781, 787, 745, 869, 861, 825, 829, 849, 720, 910, 908, 901, 795, 803, 819, 875, 855, 830, 813, 869, 894, 886, 844, 796, 789, 787, 729, 764, 779, 770, 755, 749, 741, 574, 533, 574, 566, 559, 546, 426, 429, 414, 407, 397, 390, 387, 380, 376, 218, 210, 97, 104, 118, 123, 131, 139, 144, 154, 212, 194, 209, 205, 198, 188, 181, 174, 216, 221, 291, 313, 298, 305, 307, 296, 301, 284, 269, 103, 84, 132, 124, 148, 146, 140, 118, 107, 91, 332, 330, 328, 314, 298, 281, 184, 236, 227, 213, 268, 292, 307, 315, 322, 365, 362, 370, 378, 578, 582, 589, 731, 734, 740, 759, 773, 787, 833, 826, 806, 818, 832, 842, 864, 851, 887, 892, 906, 877, 732, 729, 709, 704, 757, 769, 717, 892, 899, 922, 907, 857, 842, 832];
|
|
var y=[648, 646, 645, 634, 636, 629, 623, 628, 633, 640, 620, 621, 668, 669, 673, 666, 655, 648, 660, 643, 675, 664, 658, 653, 646, 646, 669, 655, 673, 662, 661, 653, 652, 672, 670, 660, 645, 500, 518, 493, 508, 516, 499, 500, 484, 519, 517, 493, 207, 205, 204, 283, 277, 282, 289, 275, 268, 259, 127, 137, 258, 254, 223, 336, 343, 331, 333, 389, 374, 394, 387, 372, 479, 522, 513, 508, 484, 486, 484, 498, 474, 483, 477, 493, 500, 500, 469, 472, 469, 464, 476, 468, 460, 462, 467, 468, 469, 482, 453, 475, 470, 468, 460, 460, 451, 461, 460, 460, 462, 469, 477, 483, 412, 405, 403, 398, 382, 377, 373, 374, 373, 373, 398, 376, 389, 384, 381, 373, 372, 372, 235, 229, 232, 272, 271, 270, 255, 243, 250, 226, 220, 191, 192, 207, 204, 223, 216, 213, 193, 188, 187, 126, 119, 147, 140, 121, 131, 141, 131, 132, 125, 131, 124, 116, 116, 116, 88, 93, 84, 75, 77, 84, 92, 116, 112, 108, 107, 108, 108, 131, 111, 108, 107, 204, 196, 197, 188, 193, 196, 212, 179, 318, 316, 310, 316, 317, 323, 307, 372, 369, 367, 363, 372, 372, 379];
|
|
var r=[-50, 0, 0, -50, 0, -50, -30, 90, 50, 60, 0, 0, 0, 0, 60, 60, 60, 45, 0, 0, -45, -45, -45, 0, 0, 0, 0, -45, -45, -45, 0, 0, 0, 45, 0, 0, 0, 85, -35, 0, 0, 0, 0, 0, 0, 35, 0, 0, -35, 0, 0, -85, 0, 45, 95, 95, 95, 0, -45, 45, -45, 0, -45, -45, 45, 95, 0, 0, 0, -35, -95, 0, -35, 75, 75, 0, 45, 0, 90, 90, 60, 0, 0, 0, 0, 0, 0, 60, 0, 60, 0, 0, 0, 0, 0, 0, 0, 45, 90, 90, 0, 0, 0, 0, -90, 0, 0, 0, -40, 0, -40, -40, 40, 30, -30, 0, -30, -30, 0, 0, 0, 0, 90, 40, 40, 40, 0, 0, 0, 0, -40, -20, 50, 50, 50, 0, 50, 50, 50, 0, 0, -40, -40, 50, 0, 90, 50, 0, 50, 0, 0, 90, 55, 55, 0, -35, -35, 0, 0, 0, 0, 0, 0, 0, 0, 0, -55, 0, 0, 0, 55, 0, 0, 0, -35, 0, 0, 0, 0, 35, 35, 0, 0, -35, 0, 0, 0, 35, 0, 0, 0, 0, 0, -35, -45, 0, 0, 0, 0, -45, 45, 0, 10, 0, -50];
|
|
for (var i = 0; i < GetLength(x); i++)
|
|
{
|
|
var grass = CreateObjectAbove(Grass, x[i], y[i] + 5, NO_OWNER);
|
|
grass->SetR(r[i]);
|
|
}
|
|
|
|
// Blue chest with wind bag
|
|
var chest_blue = CreateObjectAbove(Chest, 850, 648, NO_OWNER);
|
|
chest_blue->SetClrModulation(RGB(100,180,255));
|
|
AddEffect("FillBlueChest", chest_blue, 100, 72);
|
|
|
|
// Red chest with club.
|
|
var chest_red = CreateObjectAbove(Chest, 124, 520, NO_OWNER);
|
|
chest_red->SetClrModulation(RGB(255, 100, 100));
|
|
AddEffect("FillRedChest", chest_red, 100, 72);
|
|
|
|
// Wind channel.
|
|
AddEffect("WindChannel", nil, 100, 1);
|
|
|
|
Overcast_air_particles =
|
|
{
|
|
Prototype = Particles_Air(),
|
|
Size = PV_KeyFrames(0, 0, 0, 100, PV_Random(5, 10), 1000, 0),
|
|
OnCollision = PC_Die()
|
|
};
|
|
return;
|
|
}
|
|
|
|
protected func InitializePlayer(int plr)
|
|
{
|
|
// This scenario does not have shadows.
|
|
SetFoW(false, plr);
|
|
return;
|
|
}
|
|
|
|
/*-- Wind channel --*/
|
|
|
|
global func FxWindChannelStart(object target, proplist effect, int temporary)
|
|
{
|
|
if (temporary == 0)
|
|
effect.Divider = 1;
|
|
return 1;
|
|
}
|
|
|
|
global func FxWindChannelTimer(object target, proplist effect)
|
|
{
|
|
// Channel divided into three parts.
|
|
|
|
// First shaft with upward wind.
|
|
for (var obj in FindObjects(Find_InRect(464, 288, 40, 152)))
|
|
{
|
|
var speed = obj->GetYDir(100);
|
|
if (speed < -360)
|
|
continue;
|
|
obj->SetYDir(speed - 36, 100);
|
|
}
|
|
CreateParticle("Air", 464+Random(40), 344+Random(112), RandomX(-1,1), -30, PV_Random(10, 40), Overcast_air_particles);
|
|
|
|
// Divider with random wind.
|
|
if (!Random(100))
|
|
effect.Divider = Random(3);
|
|
for (var obj in FindObjects(Find_InRect(464, 240, 40, 48)))
|
|
{
|
|
if (effect.Divider == 1)
|
|
{
|
|
var speed = obj->GetYDir(100);
|
|
if (speed < -360)
|
|
continue;
|
|
obj->SetYDir(speed - 36, 100);
|
|
}
|
|
if (effect.Divider == 0)
|
|
{
|
|
var speed = obj->GetXDir(100);
|
|
if (speed > -360)
|
|
obj->SetXDir(speed - 20, 100);
|
|
}
|
|
if (effect.Divider == 2)
|
|
{
|
|
var speed = obj->GetXDir(100);
|
|
if (speed < 360)
|
|
obj->SetXDir(speed + 20, 100);
|
|
}
|
|
}
|
|
if (effect.Divider == 1)
|
|
CreateParticle("Air", 464+Random(40), 280+Random(10), RandomX(-1,1), -30, PV_Random(10, 40), Overcast_air_particles);
|
|
if (effect.Divider == 0)
|
|
CreateParticle("Air", 464+Random(40), 280+Random(10), RandomX(-20,-10), -20, PV_Random(10, 40), Overcast_air_particles);
|
|
if (effect.Divider == 2)
|
|
CreateParticle("Air", 464+Random(40), 280+Random(10), RandomX(10,20), -20, PV_Random(10, 40), Overcast_air_particles);
|
|
|
|
// Second shaft with upward wind.
|
|
for (var obj in FindObjects(Find_InRect(464, 96, 40, 144)))
|
|
{
|
|
// Divert at top.
|
|
if (obj->GetY() < 104)
|
|
{
|
|
if (obj->GetX() < 484)
|
|
{
|
|
var speed = obj->GetXDir(100);
|
|
if (speed > -200)
|
|
obj->SetXDir(speed - 16, 100);
|
|
}
|
|
else
|
|
{
|
|
var speed = obj->GetXDir(100);
|
|
if (speed < 200)
|
|
obj->SetXDir(speed + 16, 100);
|
|
}
|
|
//continue;
|
|
}
|
|
var speed = obj->GetYDir(100);
|
|
if (speed < -360)
|
|
continue;
|
|
obj->SetYDir(speed - 36, 100);
|
|
}
|
|
CreateParticle("Air", 464+Random(40), 160+Random(96), RandomX(-1,1), -30, PV_Random(10, 40), Overcast_air_particles);
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*-- Chest contents --*/
|
|
|
|
global func FxFillChestStart(object target, proplist effect, int temporary)
|
|
{
|
|
if (temporary)
|
|
return 1;
|
|
var w_list = [Shield, Javelin, FireballScroll, Bow, Musket, WindScroll, TeleportScroll];
|
|
for (var i = 0; i < 4; i++)
|
|
target->CreateChestContents(w_list[Random(GetLength(w_list))]);
|
|
return 1;
|
|
}
|
|
|
|
global func FxFillChestTimer(object target, proplist effect)
|
|
{
|
|
if (Random(5))
|
|
return 1;
|
|
var w_list = [Balloon, Boompack, IronBomb, Shield, Javelin, Bow, Musket, Boompack, IronBomb, Shield, Javelin, Bow, Musket, TeleportScroll, WindScroll, FireballScroll];
|
|
|
|
if (target->ContentsCount() < 6)
|
|
target->CreateChestContents(w_list[Random(GetLength(w_list))]);
|
|
return 1;
|
|
}
|
|
|
|
global func FxFillBlueChestStart(object target, proplist effect, int temporary)
|
|
{
|
|
if (temporary)
|
|
return 1;
|
|
target->CreateContents(WindBag);
|
|
var w_list = [Firestone, Boompack, Balloon, FireballScroll, WindScroll];
|
|
for (var i = 0; i < 4; i++)
|
|
target->CreateContents(w_list[Random(GetLength(w_list))]);
|
|
return 1;
|
|
}
|
|
|
|
global func FxFillBlueChestTimer(object target, proplist effect)
|
|
{
|
|
if (Random(5))
|
|
return 1;
|
|
var w_list = [Firestone, Boompack, FireballScroll, WindScroll];
|
|
if (target->ContentsCount() < 6)
|
|
target->CreateContents(w_list[Random(GetLength(w_list))]);
|
|
|
|
if (!FindObject(Find_ID(WindBag)))
|
|
target->CreateContents(WindBag);
|
|
return 1;
|
|
}
|
|
|
|
global func FxFillRedChestStart(object target, proplist effect, int temporary)
|
|
{
|
|
if (temporary)
|
|
return 1;
|
|
target->CreateContents(Club);
|
|
var w_list = [Firestone, Boompack, FireballScroll, WindScroll];
|
|
for (var i = 0; i < 4; i++)
|
|
target->CreateContents(w_list[Random(GetLength(w_list))]);
|
|
return 1;
|
|
}
|
|
|
|
global func FxFillRedChestTimer(object target, proplist effect)
|
|
{
|
|
if (Random(5))
|
|
return 1;
|
|
var w_list = [Firestone, Boompack, FireballScroll, WindScroll];
|
|
if (target->ContentsCount() < 6)
|
|
target->CreateContents(w_list[Random(GetLength(w_list))]);
|
|
|
|
if (!FindObject(Find_ID(Club)))
|
|
target->CreateContents(Club);
|
|
|
|
return 1;
|
|
}
|
|
|
|
global func CreateChestContents(id obj_id)
|
|
{
|
|
if (!this)
|
|
return;
|
|
var obj = CreateObjectAbove(obj_id);
|
|
if (obj_id == Bow)
|
|
obj->CreateContents(Arrow);
|
|
if (obj_id == Musket)
|
|
obj->CreateContents(LeadShot);
|
|
obj->Enter(this);
|
|
return;
|
|
}
|
|
|
|
/*-- Player control --*/
|
|
|
|
// GameCall from RelaunchContainer.
|
|
func OnClonkLeftRelaunch(object clonk)
|
|
{
|
|
var pos = GetRandomSpawn();
|
|
clonk->SetPosition(pos[0],pos[1]);
|
|
CreateParticle("Air", pos[0],pos[1], PV_Random(-20, 20), PV_Random(-20, 20), PV_Random(5, 10), Overcast_air_particles, 25);
|
|
return;
|
|
}
|
|
|
|
global func GetRandomSpawn()
|
|
{
|
|
var spawns = [[432,270],[136,382],[200,134],[864,190],[856,382],[840,518],[408,86],[536,470]];
|
|
var rand = Random(GetLength(spawns));
|
|
return spawns[rand];
|
|
}
|
|
|
|
|
|
// Gamecall from LastManStanding goal, on respawning.
|
|
protected func OnPlayerRelaunch(int plr)
|
|
{
|
|
var clonk = GetCrew(plr);
|
|
var relaunch = CreateObjectAbove(RelaunchContainer, LandscapeWidth() / 2, LandscapeHeight() / 2, clonk->GetOwner());
|
|
relaunch->StartRelaunch(clonk);
|
|
return;
|
|
}
|
|
|
|
func KillsToRelaunch() { return 0; }
|
|
func RelaunchWeaponList() { return [Bow, Javelin, Musket, FireballScroll, WindScroll, TeleportScroll]; }
|