forked from Mirrors/openclonk
Add MeltingCastle team melee
parent
1ebdc31182
commit
c9d3cd7417
|
@ -0,0 +1,5 @@
|
|||
Schmelzendes Schloss
|
||||
|
||||
Teamwork-Melee in luftiger Hoehe. Es gibt endlos Respawn an der Flagge - bis der Gegner sie in den Abgrund geschleudert hat.
|
||||
|
||||
Ziel: Gegnerische Flagge in den Abgrund sprengen. Danach: Last Team Standing (Bleibe als Letzter am Leben und gewinne)
|
|
@ -0,0 +1,5 @@
|
|||
Melting Castle
|
||||
|
||||
Teamwork-Melee high in the skies. Infinite respawn at the flagpole, until the opposing team (or melting ice) has dropped it down.
|
||||
|
||||
Goal: Blast opponent flag into the abyss. Afterwards, be the last team to have a clonk alive.
|
|
@ -0,0 +1,17 @@
|
|||
[DefCore]
|
||||
id=IceWallKit
|
||||
Version=8,0
|
||||
Category=C4D_Object
|
||||
Width=12
|
||||
Height=4
|
||||
Offset=-6,-2
|
||||
Vertices=3
|
||||
VertexX=-5,5,0
|
||||
VertexY=0,0,0
|
||||
VertexCNAT=1,2,16
|
||||
VertexFriction=30,30,30
|
||||
Value=8
|
||||
Mass=12
|
||||
Components=Ice=2
|
||||
Rotate=1
|
||||
Picture=0,20,64,64
|
Binary file not shown.
After Width: | Height: | Size: 7.9 KiB |
|
@ -0,0 +1,68 @@
|
|||
/* Wall kit */
|
||||
// Modified to draw Ice + not allowed too close to flag
|
||||
|
||||
#include WallKit
|
||||
|
||||
public func ControlUseStop(object clonk, int x, int y, ...)
|
||||
{
|
||||
StopPreview(clonk);
|
||||
if (!IsIceBridgeAllowed(clonk, x, y))
|
||||
{
|
||||
clonk->PlaySoundDoubt();
|
||||
clonk->Message("$NoWall$");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return inherited(clonk, x, y, ...);
|
||||
}
|
||||
}
|
||||
|
||||
private func IsIceBridgeAllowed(object clonk, int x, int y)
|
||||
{
|
||||
var c = Offset2BridgeCoords(clonk, x, y);
|
||||
// Must not intersect a flag
|
||||
// Search from clonk context because that's the coordinate space returned by Offset2BridgeCoords
|
||||
var flag = clonk->FindObject(Find_ID(Goal_Flag), clonk->Find_AtRect(Min(c.x1, c.x2)-5, Min(c.y1, c.y2)-5, Abs(c.x1 - c.x2)+11, Abs(c.y1 - c.y2)+11));
|
||||
return !flag;
|
||||
}
|
||||
|
||||
private func SetPreview(object clonk, int x, int y, ...)
|
||||
{
|
||||
if (!preview) AddTimer(this.UpdateIcePreviewColor, 3);
|
||||
this.ice_last_clonk = clonk;
|
||||
this.ice_last_x = x;
|
||||
this.ice_last_y = y;
|
||||
var r = inherited(clonk, x, y, ...);
|
||||
UpdateIcePreviewColor();
|
||||
return r;
|
||||
}
|
||||
|
||||
private func UpdateIcePreviewColor()
|
||||
{
|
||||
if (preview)
|
||||
{
|
||||
var ok = IsIceBridgeAllowed(this.ice_last_clonk, this.ice_last_x, this.ice_last_y);
|
||||
if (ok)
|
||||
preview->SetColor(0xff80ffff);
|
||||
else
|
||||
preview->SetColor(0xffff0000);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private func StopPreview(object clonk, ...)
|
||||
{
|
||||
RemoveTimer(this.UpdateIcePreviewColor);
|
||||
return inherited(clonk, ...);
|
||||
}
|
||||
|
||||
|
||||
/* Status */
|
||||
|
||||
local Collectible = 1;
|
||||
local Name = "$Name$";
|
||||
local Description = "$Description$";
|
||||
local BridgeLength = 15;
|
||||
local BridgeThickness = 5;
|
||||
local BridgeMaterial = "Ice-ice";
|
|
@ -0,0 +1,3 @@
|
|||
NoWall=Zu dicht an der Flagge.
|
||||
Name=Eisbausatz
|
||||
Description=Mit dem Eisbausatz koennen temporaere Eiswaende errichtet werden. Halte [Benutzen] gedrückt, um eine Vorschau für die Brücke zu erhalten. Lasse los, um die Brücke am gewünschten Ort zu errichten. Kann nicht in unmittelbarer Naehe der Flage genutzt werden.
|
|
@ -0,0 +1,3 @@
|
|||
NoWall=Too close to the flag.
|
||||
Name=Ice wall kit
|
||||
Description=You can create ice walls with the ice wall kit. Hold down the [Use] key to see a preview in the direction you are pointing. Let go to build there. Cannot be used close to the flag.
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
Melting Castle
|
||||
Team melee to melt each others castles
|
||||
|
||||
@authors Sven2
|
||||
*/
|
||||
|
||||
// Only half of the actual map is present in the map file and Objects.c.
|
||||
// Create a mirror for the missing half here.
|
||||
public func InitializeMap(proplist map)
|
||||
{
|
||||
// Not when editing
|
||||
if (EDIT_MAP) return true;
|
||||
// Mirror map
|
||||
var old_map = Duplicate();
|
||||
Resize(this.Wdt*2, this.Hgt);
|
||||
Blit(old_map);
|
||||
Blit({Algo=MAPALGO_Scale, OffX=old_map.Wdt, X=-100, Op=old_map});
|
||||
return true;
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 3.6 KiB |
Binary file not shown.
After Width: | Height: | Size: 3.6 KiB |
|
@ -0,0 +1,20 @@
|
|||
[Material]
|
||||
Name=Ice
|
||||
Shape=TopFlat
|
||||
Density=60
|
||||
Friction=15
|
||||
DigFree=1
|
||||
BlastFree=1
|
||||
Blast2Object=Ice
|
||||
Dig2Object=Ice
|
||||
Dig2ObjectRatio=200
|
||||
Blast2ObjectRatio=220
|
||||
MaxAirSpeed=100
|
||||
MaxSlide=1
|
||||
Corrode=60
|
||||
TempConvStrength=2
|
||||
AboveTempConvert=10
|
||||
AboveTempConvertDir=1
|
||||
AboveTempConvertTo=Water
|
||||
Placement=21
|
||||
TextureOverlay=ice
|
|
@ -0,0 +1,52 @@
|
|||
# Automatically generated texture map
|
||||
# Contains material-texture-combinations added at runtime
|
||||
# Import materials from global file as well
|
||||
OverloadMaterials
|
||||
# Import textures from global file as well
|
||||
OverloadTextures
|
||||
|
||||
10=Tunnel-tunnel
|
||||
11=Tunnel-tunnel
|
||||
12=Tunnel-brickback
|
||||
13=BrickSoft-brick
|
||||
19=DuroLava-lava_red
|
||||
20=Water-water
|
||||
22=Acid-acid
|
||||
23=Lava-lava_red
|
||||
24=DuroLava-lava_red
|
||||
25=Water-water
|
||||
27=Acid-acid
|
||||
28=Lava-lava_red
|
||||
29=Earth-earth
|
||||
30=Earth-earth_root
|
||||
31=Earth-earth_spongy
|
||||
32=Earth-earth
|
||||
33=Ashes-ashes
|
||||
36=Ore-ore
|
||||
37=Ore-ore
|
||||
38=Ore-ore
|
||||
40=Granite-granite
|
||||
41=Granite-granite
|
||||
42=Granite-rock
|
||||
45=Gold-gold
|
||||
50=Rock-rock
|
||||
51=Rock-rock
|
||||
52=Rock-rock
|
||||
53=Firestone-firestone
|
||||
54=Coal-coal
|
||||
55=Sand-sand
|
||||
56=Sand-sand
|
||||
65=Ice-ice
|
||||
66=Ice-ice
|
||||
67=Ice-ice2
|
||||
68=Ice-ice2
|
||||
70=Snow-snow1
|
||||
71=Snow-snow1
|
||||
72=Snow-snow1
|
||||
73=Brick-brick
|
||||
1=Amethyst-amethyst
|
||||
2=Everrock-everrock
|
||||
3=HalfVehicle-none
|
||||
4=Ruby-ruby
|
||||
5=SandDry-sand
|
||||
6=Vehicle-none
|
|
@ -0,0 +1,47 @@
|
|||
/* Automatically created objects file */
|
||||
|
||||
func InitializeObjects()
|
||||
{
|
||||
CreateObject(Rule_KillLogs, 50, 50);
|
||||
|
||||
CreateObject(Rule_Gravestones, 50, 50);
|
||||
|
||||
CreateObject(Goal_Melee, 50, 50);
|
||||
|
||||
ItemSpawn->Create(Firestone,407,389);
|
||||
ItemSpawn->Create(Firestone,423,389);
|
||||
ItemSpawn->Create(PowderKeg,669,261);
|
||||
ItemSpawn->Create(Bread,407,258);
|
||||
ItemSpawn->Create(IronBomb,441,389);
|
||||
|
||||
var Chest001 = CreateObjectAbove(Chest, 1047, 359);
|
||||
|
||||
CreateObjectAbove(Idol, 313, 254);
|
||||
|
||||
var WoodenBridge001 = CreateObjectAbove(WoodenBridge, 1126, 372);
|
||||
WoodenBridge001->SetCategory(C4D_StaticBack);
|
||||
var WoodenBridge002 = CreateObjectAbove(WoodenBridge, 513, 282);
|
||||
WoodenBridge002->SetCategory(C4D_StaticBack);
|
||||
|
||||
CreateObjectAbove(Goal_Flag, 507, 180);
|
||||
|
||||
CreateObjectAbove(Catapult, 728, 431);
|
||||
CreateObjectAbove(Catapult, 627, 269);
|
||||
|
||||
var Cannon001 = CreateObjectAbove(Cannon, 692, 253);
|
||||
Cannon001->SetRDir(3);
|
||||
CreateObjectAbove(Cannon, 511, 179);
|
||||
|
||||
CreateObjectAbove(Airship, 369, 269);
|
||||
|
||||
Chest001->CreateContents(Boompack);
|
||||
|
||||
Chest001->CreateContents(IronBomb, 2);
|
||||
|
||||
Chest001->CreateContents(Bread);
|
||||
|
||||
Chest001->CreateContents(BombArrow);
|
||||
|
||||
Chest001->CreateContents(Bow);
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
[Head]
|
||||
Icon=21
|
||||
Title=MeltingCastle
|
||||
Version=8
|
||||
MaxPlayer=20
|
||||
MinPlayer=2
|
||||
NoInitialize=true
|
||||
|
||||
[Game]
|
||||
Mode=Melee
|
||||
|
||||
[Player1]
|
||||
|
||||
[Player2]
|
||||
|
||||
[Player3]
|
||||
|
||||
[Player4]
|
||||
|
||||
[Landscape]
|
||||
BottomOpen=1
|
||||
MapWidth=64,0,64,10000
|
||||
MapHeight=40,0,40,10000
|
||||
MapZoom=18,0,0,18
|
||||
|
||||
[Weather]
|
||||
Climate=0,10,0,100
|
|
@ -0,0 +1,193 @@
|
|||
/* Melting Castle */
|
||||
|
||||
static g_respawn_flags, g_had_intro_msg;
|
||||
|
||||
static const EDIT_MAP = false; // Set to true to edit map and Objects.c; avoids map resize and object duplication
|
||||
|
||||
func Initialize()
|
||||
{
|
||||
if (EDIT_MAP) return true;
|
||||
// Mirror map objects by moving them to the other side, then re-running object initialization
|
||||
for (var o in FindObjects(Find_NoContainer(), Find_Not(Find_Category(C4D_Goal | C4D_Rule))))
|
||||
{
|
||||
var oid = o->GetID();
|
||||
if (oid == Ambience) continue; // Can't filter by C4D_Environment, because we do want waterfalls and item spawns
|
||||
o->SetPosition(LandscapeWidth() - o->GetX(), o->GetY());
|
||||
// Catapults and cannons should point left on the right island
|
||||
|
||||
if (oid == Catapult)
|
||||
o->TurnLeft();
|
||||
else if (oid == Cannon)
|
||||
o->TurnCannon(DIR_Left, true);
|
||||
}
|
||||
ScenarioObjects->InitializeObjects();
|
||||
// Some adjustments to the bridges
|
||||
for (var bridge in FindObjects(Find_ID(WoodenBridge)))
|
||||
{
|
||||
bridge->SetClrModulation(0xff00ffff);
|
||||
bridge->SetHalfVehicleSolidMask(true);
|
||||
bridge->SetCategory(C4D_Vehicle);
|
||||
bridge->SetVertex(,,-37); // prevent self-stuck
|
||||
}
|
||||
// Item spawns by team
|
||||
for (var item_spawn in FindObjects(Find_ID(ItemSpawn)))
|
||||
{
|
||||
item_spawn->SetTeam(1 + (item_spawn->GetX() > LandscapeWidth()/2));
|
||||
}
|
||||
// Remember flags for respawn
|
||||
g_respawn_flags = CreateArray(3);
|
||||
for (var flag in FindObjects(Find_ID(Goal_Flag)))
|
||||
{
|
||||
flag->DisablePickup(); // Not using CTF goal
|
||||
flag.Destruction = Scenario.OnFlagDestruction;
|
||||
flag.team = 1;
|
||||
flag.Plane = 274; // cannot be moved by airship
|
||||
if (flag->GetX() > LandscapeWidth()/2) ++flag.team;
|
||||
g_respawn_flags[flag.team] = flag;
|
||||
}
|
||||
// Weapon drops timer
|
||||
ScheduleCall(nil, Scenario.DoBalloonDrop, 36*8, 99999);
|
||||
return true;
|
||||
}
|
||||
|
||||
local weapon_list = [ // id, vertex, offx, offy, deployy
|
||||
[Firestone, 0, -3, -6, -18],
|
||||
[IronBomb, 0, 0, -6, -10],
|
||||
[IceWallKit, 2, 0, -5, -10],
|
||||
[DynamiteBox, 0, 3, -5, -10],
|
||||
[BombArrow, 2, 0, -8, -10],
|
||||
[Boompack, 0, 0, 0, 0],
|
||||
[GrenadeLauncher, 3, 0, -4, -10]
|
||||
];
|
||||
|
||||
func DoBalloonDrop()
|
||||
{
|
||||
// Random weapon
|
||||
var wp = Scenario.weapon_list[Random(GetLength(Scenario.weapon_list))];
|
||||
var x = LandscapeWidth()/4 + Random(LandscapeWidth()/2);
|
||||
var y = 0;
|
||||
var balloon = CreateObject(BalloonDeployed, x, y);
|
||||
if (!balloon) return;
|
||||
balloon->SetInflated();
|
||||
var cargo = CreateObject(wp[0]);
|
||||
if (!cargo) return;
|
||||
balloon->SetCargo(cargo, wp[1], wp[2], wp[3], wp[4]);
|
||||
if (wp[0] == GrenadeLauncher) cargo->CreateContents(IronBomb);
|
||||
return balloon;
|
||||
}
|
||||
|
||||
func OnFlagDestruction()
|
||||
{
|
||||
// Callback from flag after it dropped
|
||||
Log("$FlagDownMsg$", ["$TeamLeft$", "$TeamRight$"][this.team-1]);
|
||||
return true;
|
||||
}
|
||||
|
||||
func InitializePlayer(int plr)
|
||||
{
|
||||
// Everything freely visible (to allow aiming with the cannon)
|
||||
SetFoW(false, plr);
|
||||
SetPlayerZoomByViewRange(plr,LandscapeWidth(),LandscapeHeight(),PLRZOOM_LimitMax);
|
||||
SetPlayerViewLock(plr, false);
|
||||
// Acquire base
|
||||
var team = GetPlayerTeam(plr);
|
||||
var flag = g_respawn_flags[team];
|
||||
if (flag && flag->GetOwner() == NO_OWNER) AcquireBase(plr, team);
|
||||
// Intro message. Delayed to be visible to all players.
|
||||
if (!g_had_intro_msg)
|
||||
{
|
||||
g_had_intro_msg = true;
|
||||
ScheduleCall(nil, Scenario.IntroMsg, 10, 1);
|
||||
}
|
||||
// Initial launch
|
||||
RelaunchPlayer(plr);
|
||||
return true;
|
||||
}
|
||||
|
||||
func IntroMsg()
|
||||
{
|
||||
var speaker = FindObject(Find_ID(Goal_Flag));
|
||||
if (speaker)
|
||||
{
|
||||
var c = speaker->GetColor();
|
||||
var n = speaker->GetName();
|
||||
speaker->SetColor(0xffffff);
|
||||
speaker->SetName("$IntroName$");
|
||||
Dialogue->MessageBoxAll("$IntroMsg$", speaker, true);
|
||||
speaker->SetName(n);
|
||||
speaker->SetColor(c);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
func LaunchPlayer(int plr)
|
||||
{
|
||||
// Position at flag
|
||||
var flagpole = g_respawn_flags[GetPlayerTeam(plr)];
|
||||
if (!flagpole) return EliminatePlayer(plr); // Flag lost and clonk died? Game over!
|
||||
var crew = GetCrew(plr), start_x = flagpole->GetX(), start_y = flagpole->GetY();
|
||||
crew->SetPosition(start_x, start_y);
|
||||
// Make sure clonk can move
|
||||
DigFreeRect(start_x-6,start_y-10,13,18,true);
|
||||
// Crew setup
|
||||
crew.MaxEnergy = 100000;
|
||||
crew->DoEnergy(1000);
|
||||
crew->CreateContents(WindBag);
|
||||
return true;
|
||||
}
|
||||
|
||||
func RelaunchPlayer(int plr)
|
||||
{
|
||||
// Find flag for respawn
|
||||
var flagpole = g_respawn_flags[GetPlayerTeam(plr)];
|
||||
if (!flagpole) return EliminatePlayer(plr); // Flag lost and clonk died? Game over!
|
||||
// Player positioning.
|
||||
var start_x = flagpole->GetX(), start_y = flagpole->GetY();
|
||||
// Relaunch: New clonk
|
||||
var crew = GetCrew(plr);
|
||||
var is_relaunch = (!crew || !crew->GetAlive());
|
||||
if (is_relaunch)
|
||||
{
|
||||
crew = CreateObject(Clonk, 10,10, plr);
|
||||
if (!crew) return false; // wat?
|
||||
crew->MakeCrewMember(plr);
|
||||
SetCursor(plr, crew, false);
|
||||
}
|
||||
// Relaunch near current flag pos (will be adjusted on actual relaunch)
|
||||
crew->SetPosition(start_x, start_y);
|
||||
var relaunch = CreateObjectAbove(RelaunchContainer, start_x, start_y, plr);
|
||||
if (relaunch)
|
||||
{
|
||||
relaunch->StartRelaunch(crew);
|
||||
relaunch->SetRelaunchTime(8, is_relaunch);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// GameCall from RelaunchContainer.
|
||||
func OnClonkLeftRelaunch(object clonk)
|
||||
{
|
||||
if (clonk) return LaunchPlayer(clonk->GetOwner());
|
||||
}
|
||||
|
||||
func RelaunchWeaponList() { return [Bow, Sword, Club, Javelin, Musket, Firestone, IceWallKit]; }
|
||||
|
||||
|
||||
func AcquireBase(int plr, int team)
|
||||
{
|
||||
// Change ownership of some stuff in the base to the first player of a team joining
|
||||
// Note that this may be called late into the game in case all players of one team join late into the game
|
||||
var base_x0 = 0;
|
||||
if (team == 2) base_x0 = LandscapeWidth()/2;
|
||||
var base_ids = [Catapult, Cannon, Goal_Flag, Chest];
|
||||
for (var obj in FindObjects(Find_InRect(base_x0, 100, LandscapeWidth()/2, LandscapeHeight()-100), Find_NoContainer(), Find_Owner(NO_OWNER)))
|
||||
{
|
||||
var idobj = obj->GetID();
|
||||
if (GetIndexOf(base_ids, idobj))
|
||||
{
|
||||
obj->SetOwner(plr);
|
||||
if (idobj == Goal_Flag) obj->SetClrModulation(0xff000000 | GetPlayerColor(plr));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
TeamLeft=Rot (links)
|
||||
TeamRight=Gruen (rechts)
|
||||
FlagDownMsg=Team %s hat die Flagge verloren - sie werden nicht mehr wiederbelebt!
|
||||
IntroMsg=Sprengt die gegnerische Flagge in die Lava und eliminiert dann die Gegner!
|
||||
IntroName=Schmelzendes Schloss
|
|
@ -0,0 +1,5 @@
|
|||
TeamLeft=Red (left)
|
||||
TeamRight=Green (right)
|
||||
FlagDownMsg=Team %s lost their flag - they will no longer respawn!
|
||||
IntroMsg=Blast the enemy flag down into the lava to stop them from respawning and then eliminate your opponents!
|
||||
IntroName=Melting Castle
|
|
@ -0,0 +1,13 @@
|
|||
[Teams]
|
||||
LastTeamID=2
|
||||
TeamColors=true
|
||||
|
||||
[Team]
|
||||
id=1
|
||||
Name=$TeamLeft$
|
||||
Color=16711680
|
||||
|
||||
[Team]
|
||||
id=2
|
||||
Name=$TeamRight$
|
||||
Color=65280
|
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
|
@ -0,0 +1,2 @@
|
|||
DE:Schmelzendes Schloss
|
||||
US:Melting Castle
|
Loading…
Reference in New Issue