Merge branch 'master' of ssh://git.openclonk.org/openclonk

Conflicts:
	src/editor/C4ConsoleQtPropListViewer.cpp
alut-include-path
Sven Eberhardt 2017-05-07 15:16:01 -04:00
commit 94669cebe4
361 changed files with 6566 additions and 2499 deletions

View File

@ -1 +1,2 @@
node: $Format:%H$
date: $Format:%ci$

View File

@ -721,6 +721,8 @@ set(OC_CLONK_SOURCES
src/platform/PlatformAbstraction.cpp
src/platform/PlatformAbstraction.h
src/platform/StdSync.h
src/player/C4Achievement.cpp
src/player/C4Achievement.h
src/player/C4Player.cpp
src/player/C4Player.h
src/player/C4PlayerList.cpp
@ -1512,12 +1514,16 @@ foreach(group ${OC_C4GROUPS})
endif()
endforeach()
if(NOT APPLE)
# group files (game data)
add_custom_target(groups DEPENDS ${OC_C4GROUPS})
set_property(TARGET groups PROPERTY FOLDER "Setup")
add_dependencies(data groups)
# Install binaries
install(TARGETS c4group DESTINATION bin)
endif()
if(NOT HEADLESS_ONLY)
if(NOT APPLE)
add_custom_target(groups DEPENDS ${OC_C4GROUPS})
set_property(TARGET groups PROPERTY FOLDER "Setup")
add_dependencies(data groups)
# Install new files
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/openclonk.desktop DESTINATION share/applications)
# Update the MIME cache -- this makes the clonk:// protocol handler actually work
@ -1528,7 +1534,6 @@ if(NOT HEADLESS_ONLY)
# Install binaries
install(TARGETS openclonk DESTINATION games)
install(TARGETS c4group DESTINATION bin)
else()
install(TARGETS openclonk
BUNDLE DESTINATION .

View File

@ -28,6 +28,20 @@ function(git_get_changeset_id VAR)
OUTPUT_VARIABLE GIT_STATUS
)
string(REGEX MATCH "^[MADRC ][MD ]" WORKDIR_DIRTY "${GIT_STATUS}")
execute_process(WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND "${GIT_EXECUTABLE}" "rev-parse" "--git-path" "index"
OUTPUT_VARIABLE GIT_INDEX
OUTPUT_STRIP_TRAILING_WHITESPACE
)
set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS
"${GIT_INDEX}"
)
execute_process(WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND "${GIT_EXECUTABLE}" "show" "--format=%ci" "-s" "HEAD"
OUTPUT_VARIABLE GIT_TIMESTAMP
OUTPUT_STRIP_TRAILING_WHITESPACE
)
endif()
endif()
if (NOT C4REVISION)
@ -44,9 +58,17 @@ function(git_get_changeset_id VAR)
string(SUBSTRING "${C4REVISION}" 6 12 C4REVISION)
endif()
unset(revlength)
file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/.git_archival" C4REVISION_TS
LIMIT_COUNT 1
REGEX "date: .+"
)
string(SUBSTRING "${C4REVISION_TS}" 6 -1 GIT_TIMESTAMP)
endif()
if(WORKDIR_DIRTY)
set(C4REVISION "${C4REVISION}+")
set(WORKDIR_DIRTY 1)
endif()
set(${VAR} "${C4REVISION}" PARENT_SCOPE)
set(${VAR}_DIRTY ${WORKDIR_DIRTY} PARENT_SCOPE)
set(${VAR}_TS "${GIT_TIMESTAMP}" PARENT_SCOPE)
endfunction()

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!DOCTYPE funcs
SYSTEM '../../../clonk.dtd'>
<?xml-stylesheet type="text/xsl" href="../../../clonk.xsl"?>
<funcs>
<func>
<title>ParseInt</title>
<category>Script</category>
<subcat>Strings</subcat>
<version>8.0 OC</version>
<syntax>
<rtype>int</rtype>
<params>
<param>
<type>string</type>
<name>value</name>
<desc>string representation of a number to parse</desc>
</param>
</params>
</syntax>
<desc>Parses a string representing a base 10 number into an integer value. If the string does not entirely consist of a base 10 number, optionally signed, <code>nil</code> is returned.</desc>
<examples>
<example>
<code>ParseInt("14")</code>
<text>Returns the integer <code>14</code>.</text>
<code>ParseInt("fourteen")</code>
<text>Returns <code>nil</code>.</text>
</example>
</examples>
</func>
</funcs>

View File

@ -7,9 +7,6 @@
*/
// List for storing the different large caves.
static cave_list;
// Game modes.
static const GAMEMODE_Deathmatch = 0;
static const GAMEMODE_LastManStanding = 1;
@ -19,18 +16,31 @@ protected func Initialize()
{
// Goals and rules.
if (SCENPAR_GameMode == GAMEMODE_Deathmatch)
{
CreateObject(Goal_DeathMatch);
GetRelaunchRule()->SetDefaultRelaunchCount(Max(SCENPAR_NrRelaunchesKills, 0));
}
else if (SCENPAR_GameMode == GAMEMODE_LastManStanding)
{
CreateObject(Goal_LastManStanding);
GetRelaunchRule()->SetDefaultRelaunchCount(Max(SCENPAR_NrRelaunchesKills, 0));
}
else if (SCENPAR_GameMode == GAMEMODE_KingOfTheHill)
{
var goal = CreateObject(Goal_KingOfTheHill, LandscapeWidth() / 2, LandscapeHeight() / 2);
goal->SetRadius(72);
goal->SetPointLimit(Max(SCENPAR_NrRelaunchesKills, 1));
GetRelaunchRule()->SetDefaultRelaunchCount(nil);
}
CreateObject(Rule_KillLogs);
CreateObject(Rule_Gravestones);
GetRelaunchRule()
->SetLastWeaponUse(false)
->SetFreeCrew(true)
->SetRespawnDelay(4);
// Rescale cave coordinates with map zoom and shuffle them.
var mapzoom = GetScenarioVal("MapZoom", "Landscape");
for (var cave in cave_list)
@ -53,13 +63,6 @@ protected func Initialize()
return;
}
// Callback from the last man standing goal.
protected func RelaunchCount()
{
// Relaunch count depends on scenario setting.
return Max(SCENPAR_NrRelaunchesKills, 0);
}
// Callback from the last man standing goal.
protected func KillsToRelaunch()
{
@ -73,46 +76,23 @@ public func WinKillCount()
return Max(SCENPAR_NrRelaunchesKills, 1);
}
// Forward callbacks to OnPlayerRelaunch for KotH goal.
protected func InitializePlayer(int plr)
public func RelaunchPosition(int plr)
{
if (SCENPAR_GameMode == GAMEMODE_KingOfTheHill)
GameCall("OnPlayerRelaunch", plr, false);
return _inherited(plr, ...);
return FindStartCave(plr, GetRelaunchRule()->GetPlayerRelaunchCount(plr) != SCENPAR_NrRelaunchesKills);
}
// Forward callbacks to OnPlayerRelaunch for KotH goal.
protected func RelaunchPlayer(int plr, int killer)
public func OnClonkLeftRelaunch(object clonk, int plr)
{
if (SCENPAR_GameMode == GAMEMODE_KingOfTheHill)
{
var clonk = CreateObjectAbove(Clonk, 0, 0, plr);
clonk->MakeCrewMember(plr);
SetCursor(plr, clonk);
clonk->DoEnergy(100000);
GameCall("OnPlayerRelaunch", plr, true);
}
return _inherited(plr, killer);
}
// Callback from the last man standing and deathmatch goal.
// Takes over the role of initializing the player.
protected func OnPlayerRelaunch(int plr, bool is_relaunch)
{
// Get the only clonk of the player.
var clonk = GetCrew(plr);
// Players start in a random small cave, the cave depends on whether it is a relaunch.
var cave = FindStartCave(plr, is_relaunch);
clonk->SetPosition(cave[0], cave[1]);
// Ensure spawn position is free
for (var i=0; i<4; ++i) BlastFree(cave[0], cave[1], 13);
var cave = [clonk->GetX(), clonk->GetY()];
for (var i = 0; i < 4; ++i)
BlastFree(cave[0], cave[1], 13);
// Players start with a shovel, a pickaxe and two firestones.
clonk->CreateContents(Shovel);
clonk->CreateContents(Pickaxe);
// Better weapons after relaunching.
if (!is_relaunch)
if (GetRelaunchRule()->GetPlayerRelaunchCount(plr) != SCENPAR_NrRelaunchesKills)
{
clonk->CreateContents(Torch);
clonk->CreateContents(Firestone, 2);

View File

@ -10,6 +10,9 @@ protected func Initialize()
{
// Environment
CreateObject(Rule_ObjectFade)->DoFadeTime(10 * 36);
GetRelaunchRule()->SetLastWeaponUse(false);
var time=CreateObject(Time);
time->SetTime();
time->SetCycleSpeed();
@ -151,16 +154,6 @@ protected func InitializePlayer(int plr)
return;
}
// Gamecall from CTF goal, on respawning.
protected func OnPlayerRelaunch(int plr)
{
var clonk = GetCrew(plr);
var relaunch = CreateObjectAbove(RelaunchContainer, clonk->GetX(), clonk->GetY(), clonk->GetOwner());
relaunch->StartRelaunch(clonk);
relaunch->SetRelaunchTime(8, true);
return;
}
func RelaunchWeaponList() { return [Blunderbuss, Sword, Javelin, FrostboltScroll, Shovel]; }
/*-- Chest filler effects --*/

View File

@ -14,17 +14,19 @@ protected func Initialize()
// Goal: Capture the flag, with bases in both hideouts.
var goal = CreateObject(Goal_CaptureTheFlag, 0, 0, NO_OWNER);
goal->SetFlagBase(1, 120, 502);
goal->SetFlagBase(2, LandscapeWidth() - 120, 502);
goal->SetFlagBase(1, 120, 506);
goal->SetFlagBase(2, LandscapeWidth() - 120, 506);
// Rules
CreateObject(Rule_Restart);
var relaunch_rule = GetRelaunchRule();
relaunch_rule->SetAllowPlayerRestart(true);
relaunch_rule->SetRespawnDelay(8);
relaunch_rule->SetLastWeaponUse(false);
CreateObject(Rule_ObjectFade)->DoFadeTime(5 * 36);
CreateObject(Rule_KillLogs);
CreateObject(Rule_Gravestones);
var lwidth = LandscapeWidth();
// Doors and spinwheels.
var gate, wheel;
gate = CreateObjectAbove(StoneDoor, 364, 448, NO_OWNER);
@ -100,16 +102,6 @@ protected func InitializePlayer(int plr)
return;
}
// Gamecall from CTF goal, on respawning.
protected func OnPlayerRelaunch(int plr)
{
var clonk = GetCrew(plr);
var relaunch = CreateObjectAbove(RelaunchContainer, clonk->GetX(), clonk->GetY(), clonk->GetOwner());
relaunch->StartRelaunch(clonk);
relaunch->SetRelaunchTime(8, true);
return;
}
// Game call from RelaunchContainer when a Clonk has left the respawn.
public func OnClonkLeftRelaunch(object clonk)
{

View File

@ -47,7 +47,9 @@ func Initialize()
g_goal = CreateObject(Goal_BeRich);
CreateObject(Rule_BuyAtFlagpole);
CreateObject(Rule_BaseRespawn);
GetRelaunchRule()
->SetBaseRespawn(true)
->SetLastClonkRespawn(true);
CreateObject(Rule_KillLogs);
CreateObject(Rule_TeamAccount);

View File

@ -4,8 +4,7 @@ func InitializeObjects()
{
CreateObject(Rule_KillLogs, 50, 50);
CreateObject(Rule_Gravestones, 50, 50);
CreateObject(Rule_Restart, 50, 50);
CreateObject(Goal_Melee, 50, 50);
ItemSpawn->Create(Firestone,407,389);

View File

@ -7,6 +7,10 @@ static const EDIT_MAP = false; // Set to true to edit map and Objects.c; avoids
func Initialize()
{
if (EDIT_MAP) return true;
GetRelaunchRule()->SetDefaultRelaunchCount(nil);
GetRelaunchRule()->SetRespawnDelay(8);
GetRelaunchRule()->SetLastWeaponUse(false);
GetRelaunchRule()->SetAllowPlayerRestart(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))))
{
@ -105,7 +109,6 @@ func InitializePlayer(int plr)
ScheduleCall(nil, Scenario.IntroMsg, 10, 1);
}
// Initial launch
RelaunchPlayer(plr);
return true;
}
@ -125,56 +128,39 @@ func IntroMsg()
return true;
}
func LaunchPlayer(int plr)
func LaunchPlayer(object clonk, 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);
DigFreeRect(clonk->GetX()-6,clonk->GetY()-10,13,18,true);
// Crew setup
crew.MaxEnergy = 100000;
crew->DoEnergy(1000);
crew->CreateContents(WindBag);
clonk.MaxEnergy = 100000;
clonk->DoEnergy(1000);
clonk->CreateContents(WindBag);
return true;
}
func RelaunchPlayer(int plr)
public func OnPlayerRelaunch(int plr)
{
if (!g_respawn_flags[GetPlayerTeam(plr)])
return EliminatePlayer(plr);
}
public func RelaunchPosition(int iPlr, int iTeam)
{
if(!g_respawn_flags[iTeam]) return;
return [g_respawn_flags[iTeam]->GetX(), g_respawn_flags[iTeam]->GetY()];
}
public func OnClonkLeftRelaunch(object clonk, 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);
}
// Reset available items in spawns
for (var item_spawn in FindObjects(Find_ID(ItemSpawn))) item_spawn->Reset(plr);
// 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());
return LaunchPlayer(clonk, plr);
}
func RelaunchWeaponList() { return [Bow, Sword, Club, Javelin, Blunderbuss, Firestone, IceWallKit]; }

View File

@ -18,6 +18,7 @@ protected func Initialize()
CreateObject(Rule_ObjectFade)->DoFadeTime(7 * 36);
CreateObject(Rule_KillLogs);
CreateObject(Rule_Gravestones);
GetRelaunchRule()->SetLastWeaponUse(false);
//make lava collapse
CreateObjectAbove(Firestone,625,480);
@ -147,31 +148,9 @@ global func CreateChestContents(id obj_id)
return;
}
protected func InitializePlayer(int plr)
public func RelaunchPosition()
{
return JoinPlayer(plr);
}
// GameCall from RelaunchContainer.
protected func RelaunchPlayer(int plr)
{
var clonk = CreateObjectAbove(Clonk, 0, 0, plr);
clonk->MakeCrewMember(plr);
SetCursor(plr, clonk);
JoinPlayer(plr);
return;
}
protected func JoinPlayer(int plr)
{
var clonk = GetCrew(plr);
clonk->DoEnergy(100000);
var position = [[420,200],[300,440],[130,176],[140,368],[700,192],[670,336],[750,440],[440,392],[45,256]];
var r=Random(GetLength(position));
var x = position[r][0], y = position[r][1];
var relaunch = CreateObjectAbove(RelaunchContainer, x, y, clonk->GetOwner());
relaunch->StartRelaunch(clonk);
return;
return [[420,200],[300,440],[130,176],[140,368],[700,192],[670,336],[750,440],[440,392],[45,256]];
}
func RelaunchWeaponList() { return [Bow, Shield, Sword, Javelin, Blunderbuss, Club]; }

View File

@ -14,6 +14,7 @@ protected func Initialize()
CreateObject(Goal_LastManStanding);
CreateObject(Rule_KillLogs);
CreateObject(Rule_Gravestones);
GetRelaunchRule()->SetLastWeaponUse(false);
//Enviroment.
Cloud->Place(25);
@ -339,27 +340,19 @@ global func CreateChestContents(id obj_id)
// 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);
CreateParticle("Air", clonk->GetX(),clonk->GetY(), PV_Random(-20, 20), PV_Random(-20, 20), PV_Random(5, 10), Overcast_air_particles, 25);
return;
}
public func RelaunchPosition()
{
return [[432,270],[136,382],[200,134],[864,190],[856,382],[840,518],[408,86],[536,470]];
}
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;
return RandomElement(Scenario->RelaunchPosition());
}
func KillsToRelaunch() { return 0; }

View File

@ -12,6 +12,7 @@ protected func Initialize()
CreateObject(Goal_LastManStanding, 0, 0, NO_OWNER);
CreateObject(Rule_KillLogs);
CreateObject(Rule_Gravestones);
GetRelaunchRule()->SetLastWeaponUse(false);
// Chests with weapons.
var chest = CreateObjectAbove(Chest, 108, 248);
@ -82,16 +83,6 @@ protected func InitializePlayer(int plr)
return;
}
// 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;
}
// Refill/fill chests.
global func FxIntFillChestsStart(object target, proplist effect, int temporary, object chest)
{
@ -135,5 +126,10 @@ public func OnClonkLeftRelaunch(object clonk)
return;
}
public func RelaunchPosition()
{
return [LandscapeWidth() / 2, LandscapeHeight() / 2];
}
public func KillsToRelaunch() { return 0; }
public func RelaunchWeaponList() { return [Bow, Shield, Sword, Firestone, Dynamite, Javelin, Blunderbuss]; }

View File

@ -13,6 +13,7 @@ protected func Initialize()
CreateObject(Goal_LastManStanding, 0, 0, NO_OWNER);
CreateObject(Rule_KillLogs);
CreateObject(Rule_Gravestones);
GetRelaunchRule()->SetLastWeaponUse(false);
// Mood.
SetSkyAdjust(RGBa(255, 255, 255, 127), RGB(255, 200, 150));
@ -37,15 +38,6 @@ protected func Initialize()
return;
}
// 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;
}
global func FxRainTimer(object pTarget, effect, int timer)
{

View File

@ -13,6 +13,9 @@ protected func Initialize()
CreateObject(Goal_LastManStanding);
CreateObject(Rule_KillLogs);
CreateObject(Rule_Gravestones);
GetRelaunchRule()
->SetRespawnDelay(3)
->SetLastWeaponUse(false);
// Enviroment.
CreateObject(Rule_ObjectFade)->DoFadeTime(10 * 36);
@ -73,25 +76,21 @@ private func PlaceGras()
return;
}
protected func OnPlayerRelaunch(int plr)
public func RelaunchPosition()
{
var clonk = GetCrew(plr);
clonk->DoEnergy(100000);
var x = RandomX(75,500);
var y=100;
while(!GBackSolid(x,y)) y+=1;
y-=30;
var relaunch = CreateObjectAbove(RelaunchContainer, x, y, clonk->GetOwner());
relaunch->StartRelaunch(clonk);
relaunch->SetRelaunchTime(3);
clonk->CreateContents(TeleGlove);
return;
return [x, y];
}
public func OnClonkLeftRelaunch(object clonk)
{
clonk->CreateParticle("Fire", 0, 0, PV_Random(-20, 20), PV_Random(-40, 5), PV_Random(20, 90), Particles_Glimmer(), 30);
clonk->SetYDir(-5);
clonk->CreateContents(TeleGlove);
return;
}
@ -104,5 +103,4 @@ public func OnClonkDeath(object clonk)
}
// Settings for LMS and DM.
public func RelaunchCount() { return 5; }
public func WinKillCount() { return 5; }

View File

@ -18,6 +18,9 @@ protected func Initialize()
AddEffect("BlessTheKing",goal,100,1,nil);
CreateObject(Rule_KillLogs);
CreateObject(Rule_Gravestones);
GetRelaunchRule()
->SetLastWeaponUse(false)
->SetDefaultRelaunchCount(nil);
//Enviroment.
//SetSkyAdjust(RGBa(250,250,255,128),RGB(200,200,220));
@ -247,29 +250,11 @@ protected func InitializePlayer(int plr)
{
// This scenario does not have shadows.
SetFoW(false, plr);
return JoinPlayer(plr);
}
// GameCall from RelaunchContainer.
protected func RelaunchPlayer(int plr)
public func RelaunchPosition()
{
var clonk = CreateObjectAbove(Clonk, 0, 0, plr);
clonk->MakeCrewMember(plr);
SetCursor(plr, clonk);
JoinPlayer(plr);
return;
}
protected func JoinPlayer(int plr)
{
var clonk = GetCrew(plr);
clonk->DoEnergy(100000);
var position = [[180,150],[310,320],[600,290],[650,180],[790,110],[440,190]];
var r=Random(GetLength(position));
var x = position[r][0], y = position[r][1];
var relaunch = CreateObjectAbove(RelaunchContainer, x, y + 49, clonk->GetOwner());
relaunch->StartRelaunch(clonk);
return;
return [[180,150],[310,300],[600,290],[650,180],[790,110],[440,190]];
}
func KillsToRelaunch() { return 0; }

View File

@ -18,6 +18,7 @@ public func SaveScenarioObject(props)
var pos = GetHandlePosition();
if (pos) props->AddCall("Handle", this, "SetSwitchDir", (pos>0)-(pos<0));
}
if (left_action || right_action) props->AddCall("Action", this, "SetActions", left_action, right_action);
return true;
}
@ -27,6 +28,13 @@ public func SetTarget(object trg)
return true;
}
public func SetActions(new_left_action, new_right_action)
{
left_action = new_left_action;
right_action = new_right_action;
return true;
}
public func ConnectNearestDoor()
{
// EditCursor helper command: Connect to nearest door. Return connected door.
@ -65,7 +73,7 @@ public func ControlRight(object clonk)
private func ControlSwitchDir(object clonk, int dir)
{
if (!target || !handle)
if (!handle || (!target && !right_action && !left_action))
{
Sound("Structures::SwitchStuck");
Message("$MsgStuck$");
@ -120,7 +128,11 @@ public func SetR(int to_r)
private func SwitchingTimer(int dir)
{
if (!handle || !target) { Sound("Structures::SwitchStuck"); return SetAction("Idle"); }
if (!handle || (!target && !right_action && !left_action))
{
Sound("Structures::SwitchStuck");
return SetAction("Idle");
}
var handle_pos = GetHandlePosition();
var handle_pos_new = BoundBy(handle_pos + HandleSpeed * dir, -MaxHandleAngle, +MaxHandleAngle);
if (!handle_pos_new) handle_pos_new = dir; // avoid direct central position, so player cannot force the same direction twice
@ -139,10 +151,11 @@ private func SwitchingTimer(int dir)
private func DoSwitchFlip(object clonk, int dir)
{
// Perform action associated to this switch
if (target)
if (dir>0)
if (dir > 0)
{
// Open/close should be aligned to vertical component of direction
if (target)
{
// Open/close should be aligned to vertical component of direction
if (GetR() < 0)
{
target->~OpenDoor(this);
@ -151,12 +164,16 @@ private func DoSwitchFlip(object clonk, int dir)
{
target->~CloseDoor(this);
}
// Action last; it may delete the door/clonk/etc.
}
// Action last; it may delete the door/clonk/etc.
if (right_action)
UserAction->EvaluateAction(right_action, this, clonk);
}
else
{
// Open/close should be aligned to vertical component of direction
}
else
{
// Open/close should be aligned to vertical component of direction
if (target)
{
if (GetR() < 0)
{
target->~CloseDoor(this);
@ -165,8 +182,11 @@ private func DoSwitchFlip(object clonk, int dir)
{
target->~OpenDoor(this);
}
UserAction->EvaluateAction(left_action, this, clonk);
}
// Action last; it may delete the door/clonk/etc.
if (left_action)
UserAction->EvaluateAction(left_action, this, clonk);
}
return false;
}

View File

@ -0,0 +1,7 @@
[DefCore]
id=Deco_TunnelSupport
Version=8,0
Category=C4D_StaticBack
Width=30
Height=30
Offset=-15,-15

View File

@ -0,0 +1,21 @@
material TunnelSupport
{
receive_shadows on
technique
{
pass
{
ambient 1.0 1.0 1.0 1.0
diffuse 0.800000011920929 0.800000011920929 0.800000011920929 1.0
specular 0.2638509273529053 0.2638509273529053 0.2638509273529053 1.0 5.0
emissive 0.0 0.0 0.0 1.0
texture_unit
{
texture TunnelSupport.png
tex_address_mode wrap
filtering trilinear
}
}
}
}

View File

@ -0,0 +1,43 @@
/**
Tunnel support
Purely for decoration
@authors: Clonkonaut, Ringwaul (Graphics)
*/
local extension = 0;
func Construction()
{
SetProperty("MeshTransformation", Trans_Rotate(RandomX(75, 105), 0,1,0));
}
// Stretch the support beams
// 0 equals standard height (~30 pixels)
// 100 is about 85 pixels
public func Extend(int percentage)
{
percentage = BoundBy(percentage, 0, 100);
extension = percentage;
var height = 30 + (55 * percentage / 100);
percentage = 2500 * percentage / 100;
PlayAnimation("extend", 1, Anim_Const(percentage));
SetShape(-15, -15 + (30 - height), 30, height);
}
public func SaveScenarioObject(props)
{
if (!inherited(props, ...))
return false;
props->AddCall("Extension", this, "Extend", extension);
return true;
}
/*-- Properties --*/
local Name = "$Name$";
local Plane = 701;

View File

@ -0,0 +1 @@
Name=Tunnelstütze

View File

@ -0,0 +1 @@
Name=Tunnel support

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

View File

@ -46,7 +46,7 @@ func InitializePlayer(int plr, int iX, int iY, object pBase, int iTeam)
{
g_relaunchs = [];
g_scores = [];
Scoreboard->Init([{key = "relaunchs", title = Rule_Restart, sorted = true, desc = true, default = "", priority = 75},
Scoreboard->Init([{key = "relaunchs", title = Rule_Relaunch, sorted = true, desc = true, default = "", priority = 75},
{key = "score", title = Nugget, sorted = true, desc = true, default = "0", priority = 100}]);
}
for (var stonedoor in FindObjects(Find_ID(StoneDoor), Find_Owner(NO_OWNER))) stonedoor->SetOwner(plr);

View File

@ -15,7 +15,11 @@ protected func Initialize()
// Rules.
CreateObject(Rule_BuyAtFlagpole);
CreateObject(Rule_BaseRespawn);
var relaunch_rule = GetRelaunchRule();
relaunch_rule->SetBaseRespawn(true);
relaunch_rule->SetFreeCrew(false);
relaunch_rule->SetLastClonkRespawn(true);
relaunch_rule->SetInitialRelaunch(false);
CreateObject(Rule_TeamAccount);
CreateObject(Rule_NoFriendlyFire);
CreateObject(Rule_Gravestones)->SetFadeOut(3 * 36);

View File

@ -45,7 +45,7 @@ func InitializePlayer(int plr, int iX, int iY, object pBase, int iTeam)
{
g_relaunchs = [];
g_scores = [];
Scoreboard->Init([{key = "relaunchs", title = Rule_Restart, sorted = true, desc = true, default = "", priority = 75},
Scoreboard->Init([{key = "relaunchs", title = Rule_Relaunch, sorted = true, desc = true, default = "", priority = 75},
{key = "score", title = Nugget, sorted = true, desc = true, default = "0", priority = 100}]);
}
g_relaunchs[plr] = MAX_RELAUNCH;

View File

@ -1,15 +0,0 @@
[DefCore]
id=Hatch
Version=6,0
Category=C4D_Structure
Width=26
Height=26
Offset=-13,-13
Vertices=5
VertexX=0,-12,12,-10,10
VertexY=0,0,0,6,6
VertexFriction=100,100,100,100,100
VertexCNAT=64,1,2,1,2
SolidMask=0,0,20,20,0,0
Construction=1
Mass=10

Binary file not shown.

Before

Width:  |  Height:  |  Size: 272 B

View File

@ -1,7 +0,0 @@
[DefCore]
id=Hatch_Graphic
Version=6,0
Width=26
Height=26
Offset=-13,-13
Category=C4D_Structure

View File

@ -1,45 +0,0 @@
//Hatch Graphic
local hatch_anim;
local parent;
protected func Initialize()
{
SetProperty("MeshTransformation", Trans_Mul(Trans_Translate(0,-10000), Trans_Rotate(-10,0,1,0), Trans_Rotate(-8,1,0,0)));
}
public func SetHatchParent(object hatch)
{
parent = hatch;
}
func Anim(string anim_name)
{
var animstart = 0;
if(hatch_anim)
{
if(GetAnimationPosition(hatch_anim) != GetAnimationLength(anim_name))
{
animstart = GetAnimationLength(anim_name) - GetAnimationPosition(hatch_anim);
}
}
StopAnimation(hatch_anim);
hatch_anim = PlayAnimation(anim_name, 5, Anim_Linear(animstart, 0, GetAnimationLength(anim_name), 14, ANIM_Hold));
}
local ActMap = {
Attach = {
Prototype = Action,
Name = "Attach",
Procedure = DFA_ATTACH,
Directions = 1,
X = 0,
Y = 0,
Wdt = 26,
Hgt = 26,
NextAction = "Attach",
},
};
local Plane = 100;

View File

@ -1,58 +0,0 @@
/*
Hatch
Author: Ringwaul
*/
local graphic;
protected func Initialize()
{
SetAction("Hatch");
graphic = CreateObjectAbove(Hatch_Graphic);
graphic->SetAction("Attach", this);
graphic->SetHatchParent(this);
return 1;
}
func ControlUp(object clonk)
{
if(GetPhase() != 0)
{
graphic->Anim("Close");
SetPhase(0);
SetSolidMask(0,0,26,26,0,0);
}
}
func ControlDown(object clonk)
{
if(GetPhase() != 1)
{
graphic->Anim("Open");
SetPhase(1);
SetSolidMask(26,0,26,26,0,0);
}
}
protected func Definition(def)
{
SetProperty("PictureTransformation", Trans_Mul(Trans_Translate(0,-3000,-5000), Trans_Rotate(-30,1,0,0), Trans_Rotate(30,0,1,0), Trans_Translate(1000,1,0)),def);
}
local Name = "$Name$";
local Touchable = 2;
local ActMap = {
Hatch = {
Prototype = Action,
Name = "Hatch",
Procedure = DFA_NONE,
Directions = 1,
FlipDir = 0,
Length = 2,
Delay = 0,
X = 0,
Y = 0,
Wdt = 1,
Hgt = 1,
},
};

View File

@ -1 +0,0 @@
Name=Hatch

View File

@ -1 +0,0 @@
Name=Hatch

View File

@ -9,14 +9,8 @@ func InitializeObjects()
var BoilingLava001 = CreateObject(BoilingLava);
BoilingLava001->SetIntensity(25);
var Rule_BaseRespawn001 = CreateObject(Rule_BaseRespawn);
Rule_BaseRespawn001->SetInventoryTransfer(true);
Rule_BaseRespawn001->SetFreeCrew(true);
CreateObject(Rule_TeamAccount);
CreateObject(Rule_Restart);
CreateObjectAbove(Tree_Coniferous, 380, 877);
var Tree_Coniferous2001 = CreateObjectAbove(Tree_Coniferous2, 562, 563);

View File

@ -53,6 +53,14 @@ func DoInit(int first_player)
// Start intro if not yet started
StartSequence("Intro", 0, GetCrew(first_player));
GetRelaunchRule()
->SetInventoryTransfer(true)
->SetLastClonkRespawn(true)
->SetFreeCrew(true)
->SetAllowPlayerRestart(true)
->SetBaseRespawn(true)
->SetRespawnDelay(0);
return true;
}

View File

@ -11,9 +11,6 @@ func InitializeObjects()
var Grass003 = CreateObjectAbove(Grass, 228, 1180);
Grass003->SetClrModulation(0xffa08060);
var Rule_BaseRespawn001 = CreateObject(Rule_BaseRespawn);
Rule_BaseRespawn001->SetInventoryTransfer(true);
Rule_BaseRespawn001->SetFreeCrew(true);
var Tree_Coniferous_Burned001 = CreateObject(Tree_Coniferous_Burned, 17, 1097);
Tree_Coniferous_Burned001->SetR(10);
@ -543,7 +540,5 @@ func InitializeObjects()
CreateObject(Rule_Gravestones);
CreateObject(Rule_Restart);
return true;
}

View File

@ -11,7 +11,7 @@ Definition1=Objects.ocd
Definition2=Decoration.ocd
[Game]
Rules=Rule_TeamAccount=1;Rule_NoPowerNeed=1;Rule_BaseRespawn=1;
Rules=Rule_TeamAccount=1;Rule_NoPowerNeed=1;
[Player1]
Knowledge=ToolsWorkshop=1;Foundry=1;Flagpole=1;Elevator=1;Armory=1;ChemicalLab=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;ToolsWorkshop_SplitFirestone=1;Barrel=1;Dynamite=1;DynamiteBox=1;Loam=1;Bucket=1;Sword=1;Metal=1;GoldBar=1;Balloon=1;Boompack=1;GrappleBow=1;JarOfWinds=1;Pipe=1;Pump=1;PowderKeg=1;Ropeladder=1;Bow=1;Arrow=1;Club=1;IronBomb=1;Javelin=1;Shield=1;InventorsLab=1;Sawmill=1;BombArrow=1;FireArrow=1;GrenadeLauncher=1;Torch=1;WoodenBridge=1;Basement=1;

View File

@ -11,6 +11,15 @@ static npc_pyrit;
private func DoInit(int first_player)
{
var relaunch_rule = GetRelaunchRule();
relaunch_rule->SetInventoryTransfer(true);
relaunch_rule->SetFreeCrew(true);
relaunch_rule->SetRespawnDelay(1);
relaunch_rule->SetBaseRespawn(true);
relaunch_rule->SetDefaultRelaunchCount(nil);
relaunch_rule->SetAllowPlayerRestart(true);
relaunch_rule->SetLastClonkRespawn(true);
relaunch_rule->SetInitialRelaunch(false);
// Message when first player enters shroom area
ScheduleCall(nil, Scenario.ShroomCaveCheck, 21, 0xffffff);
// Scorching village
@ -115,4 +124,4 @@ public func OnGoalsFulfilled()
GainScenarioAchievement("Done");
GainMissionAccess("S2Castle");
return false;
}
}

View File

@ -2,7 +2,7 @@ MsgEncounterCave=Ein Eindringling klaut unser Gold! Schnappt ihn!
MsgEncounterOutpost=Halt, im Namen des Königs!
MsgEncounterKing=Ah, %s. Ich habe Euch bereits erwartet.
MsgEncounterShrooms=Was ist steht denn da Feines in dieser Höhle? Vielleicht kommen wir damit ja ins Schloss hinein.
NameHorax=Horax
NameHorax=Hörx
DeathOfHorst=Er hinterlässt Frau und zwei Kinder.
DeathOfHanniball=Sein Lachen wird vermisst werden.
DeathOfTwonky=Ein vielversprechender, junger Filmstar.

View File

@ -2,7 +2,7 @@ MsgEncounterCave=An intruder tries to steal our gold. Catch him!
MsgEncounterOutpost=Stop, in the name of the king!
MsgEncounterKing=Ah, %s. I have been awaiting you.
MsgEncounterShrooms=What is this in the cave? Fireworks? Maybe we can use them to get into the castle.
NameHorax=Hörx
NameHorax=Harx
DeathOfHorst=He left a wife and two children.
DeathOfHanniball=His laughter will be missed.
DeathOfTwonky=A promising young movie star.

View File

@ -11,7 +11,7 @@ Definition2=Decoration.ocd\Misc.ocd\Hat.ocd
Definition3=Decoration.ocd\Clonk.ocd\AltSkins.ocd
[Game]
Rules=Rule_TeamAccount=1;Rule_BuyAtFlagpole=1;Rule_BaseRespawn=1;Rule_Restart=1;
Rules=Rule_TeamAccount=1;Rule_BuyAtFlagpole=1;
Goals=Goal_BuildCrystalCommunicator=1;
ValueOverloads=Ruby=10;Amethyst=10

View File

@ -33,12 +33,15 @@ protected func PostIntroInitialize()
}
// Rules
var respawn_rule = FindObject(Find_ID(Rule_BaseRespawn));
if (respawn_rule)
{
respawn_rule->SetInventoryTransfer(true);
respawn_rule->SetFreeCrew(true);
}
var relaunch_rule = GetRelaunchRule();
relaunch_rule->SetInventoryTransfer(true);
relaunch_rule->SetFreeCrew(true);
relaunch_rule->SetRespawnDelay(1);
relaunch_rule->SetBaseRespawn(true);
relaunch_rule->SetDefaultRelaunchCount(nil);
relaunch_rule->SetAllowPlayerRestart(true);
relaunch_rule->SetLastClonkRespawn(true);
relaunch_rule->SetInitialRelaunch(false);
// Initialize different parts of the scenario.
InitializeAmbience();
@ -311,4 +314,4 @@ global func Particles_Smoke(...)
p.DampingX = 800;
}
return p;
}
}

View File

@ -14,6 +14,14 @@ func Initialize()
if (loc = FindLocation(Loc_InRect(0,80*8,40*8,20*8), Loc_Material("Earth")))
CreateObjectAbove(Rock, loc.x, loc.y+3);
SetSkyParallax(1, 20,20, 0,0, nil, nil);
var relaunch_rule = GetRelaunchRule();
relaunch_rule->SetInventoryTransfer(true);
relaunch_rule->SetFreeCrew(true);
relaunch_rule->SetRespawnDelay(1);
relaunch_rule->SetBaseRespawn(false);
relaunch_rule->SetDefaultRelaunchCount(nil);
relaunch_rule->SetAllowPlayerRestart(true);
relaunch_rule->SetLastClonkRespawn(true);
}
static g_was_player_init;
@ -26,50 +34,52 @@ func InitializePlayer(int plr)
InitBase(plr);
g_was_player_init = true;
}
// Position and materials
JoinPlayer(plr);
// Position.
var clonk = GetCrew(plr);
var pos = RelaunchPosition();
clonk->SetPosition(pos[0], pos[1]);
return true;
}
private func InitBase(int owner)
{
// Create standard base owned by player
var y=90*8, x=40*8;
var flag = CreateObjectAbove(Flagpole, x+85,y, owner);
var y = 90 * 8, x=40 * 8;
CreateObjectAbove(Flagpole, x+85,y, owner);
var hut = CreateObjectAbove(ToolsWorkshop, x+45,y, owner);
if (hut)
{
hut->CreateContents(Shovel, 1);
hut->CreateContents(Loam, 1);
}
for (var i=0; i<3; ++i) CreateObjectAbove(Boompack, x+20+i*5+Random(4),y, owner);
for (var i = 0; i < 3; ++i)
CreateObjectAbove(Boompack, x+20+i*5+Random(4),y, owner);
return true;
}
func RelaunchPlayer(int plr)
public func RelaunchPlayer(int plr)
{
var clonk = CreateObjectAbove(Clonk, 50, 1000, plr);
clonk->MakeCrewMember(plr);
SetCursor(plr, clonk);
JoinPlayer(plr);
return true;
}
func JoinPlayer(int plr)
public func OnPlayerRelaunch(int plr, bool is_relaunch)
{
var i, crew;
for (i=0; crew=GetCrew(plr,i); ++i)
if (!is_relaunch)
{
crew->SetPosition(40*8+Random(40), 90*8-10);
if (!i)
{
crew->CreateContents(GrappleBow, 2);
crew->CreateContents(WindBag);
crew->CreateContents(TeleGlove);
crew->CreateContents(Dynamite, 2);
}
var clonk = GetCrew(plr);
clonk->CreateContents(GrappleBow, 2);
clonk->CreateContents(WindBag);
clonk->CreateContents(TeleGlove);
clonk->CreateContents(Dynamite, 2);
}
return true;
}
public func RelaunchPosition()
{
return [40 * 8 + Random(40), 90 * 8 - 10];
}
func OnGoalsFulfilled()

View File

@ -7,17 +7,11 @@ func InitializeObjects()
var Time001 = CreateObject(Time);
Time001->SetTime(600);
Time001->SetCycleSpeed(20);
var Rule_BaseRespawn001 = CreateObject(Rule_BaseRespawn);
Rule_BaseRespawn001->SetInventoryTransfer(true);
Rule_BaseRespawn001->SetFreeCrew(true);
CreateObject(Rule_NoPowerNeed);
CreateObject(Rule_TeamAccount);
CreateObject(Rule_Restart);
CreateObjectAbove(EnvPack_Scarecrow, 1218, 440);
CreateObjectAbove(EnvPack_Guidepost, 835, 369);

View File

@ -10,7 +10,7 @@ Definition2=Decoration.ocd
[Game]
Goals=Goal_Raid=1
Rules=Rule_TeamAccount=1;Rule_NoPowerNeed=1;Rule_BaseRespawn=1;
Rules=Rule_TeamAccount=1;Rule_NoPowerNeed=1;
[Player1]
Knowledge=Foundry=1;ToolsWorkshop=1;WindGenerator=1;Flagpole=1;Sawmill=1;Elevator=1;ChemicalLab=1;Lorry=1;Pickaxe=1;Axe=1;Hammer=1;Shovel=1;Barrel=1;Dynamite=1;DynamiteBox=1;Loam=1;Bucket=1;GoldBar=1;Metal=1;Pipe=1;WallKit=1;WindGenerator=1;

View File

@ -26,6 +26,15 @@ static g_is_initialized, // intro started
func Initialize()
{
var relaunch_rule = GetRelaunchRule();
relaunch_rule->SetInventoryTransfer(true);
relaunch_rule->SetFreeCrew(true);
relaunch_rule->SetRespawnDelay(1);
relaunch_rule->SetBaseRespawn(true);
relaunch_rule->SetDefaultRelaunchCount(nil);
relaunch_rule->SetAllowPlayerRestart(true);
relaunch_rule->SetLastClonkRespawn(true);
relaunch_rule->SetInitialRelaunch(false);
npc_newton->SetAlternativeSkin("MaleBlackHair");
npc_pyrit->SetAlternativeSkin("MaleBrownHair");
npc_woody->SetAlternativeSkin("Youngster");

View File

@ -32,16 +32,10 @@ func InitializeObjects()
Column001->SetMeshMaterial("AncientColumn", 0);
Column001.Plane = 50;
var Rule_BaseRespawn001 = CreateObject(Rule_BaseRespawn);
Rule_BaseRespawn001->SetInventoryTransfer(true);
Rule_BaseRespawn001->SetFreeCrew(true);
CreateObject(Rule_TeamAccount);
CreateObject(Rule_NoPowerNeed);
CreateObject(Rule_Restart);
var LargeCaveMushroom001 = CreateObjectAbove(LargeCaveMushroom, 1308, 1038);
LargeCaveMushroom001->SetClrModulation(0xffe4effc);
var LargeCaveMushroom002 = CreateObjectAbove(LargeCaveMushroom, 1345, 1028);

View File

@ -10,7 +10,7 @@ MissionAccess=S2Sea
Definition2=Decoration.ocd
[Game]
Rules=Rule_TeamAccount=1;Rule_NoPowerNeed=1;Rule_BaseRespawn=1;
Rules=Rule_TeamAccount=1;Rule_NoPowerNeed=1;
[Player1]
Knowledge=ToolsWorkshop=1;Foundry=1;Flagpole=1;Elevator=1;Armory=1;ChemicalLab=1;Lorry=1;Pickaxe=1;Shovel=1;ToolsWorkshop_SplitFirestone=1;Barrel=1;Dynamite=1;DynamiteBox=1;Loam=1;Bucket=1;Sword=1;Metal=1;Balloon=1;Boompack=1;GrappleBow=1;JarOfWinds=1;Pipe=1;Pump=1;PowderKeg=1;Ropeladder=1;Bow=1;Arrow=1;Club=1;IronBomb=1;Javelin=1;Shield=1;Catapult=1;WallKit=1;WoodenBridge=1;Basement=1;

View File

@ -15,6 +15,15 @@ static npc_pyrit;
func DoInit(int first_player)
{
var relaunch_rule = GetRelaunchRule();
relaunch_rule->SetInventoryTransfer(true);
relaunch_rule->SetFreeCrew(true);
relaunch_rule->SetRespawnDelay(1);
relaunch_rule->SetBaseRespawn(true);
relaunch_rule->SetDefaultRelaunchCount(nil);
relaunch_rule->SetAllowPlayerRestart(true);
relaunch_rule->SetLastClonkRespawn(true);
relaunch_rule->SetInitialRelaunch(false);
ClearFreeRect(530,1135, 50,2);
if (g_last_stone_door) g_last_stone_door->DoDamage(170 - g_last_stone_door->GetDamage());
if (g_golden_idol)
@ -174,5 +183,4 @@ func OnInvincibleDamage(object damaged_target)
}
}
return true;
}
}

View File

@ -0,0 +1,18 @@
[DefCore]
id=LavaCore
Version=8,0
Category=C4D_Living
Height=40
Width=40
Offset=-20,-20
Vertices=9
VertexX=0,-19,19, 0, 0,-14, 14,-14,14
VertexY=0, 0, 0,-19,19,-14,-14, 14,14
VertexFriction=1,50,50,50,50,50,50,50,50
VertexCNAT=16,1,2,4,8,5,6,9,10
Mass=80
StretchGrowth=1
Oversize=1
IncompleteActivity=1
NoBreath=1
Float=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB

View File

@ -0,0 +1,14 @@
[DefCore]
id=LavaCoreShell
Version=8,0
Category=C4D_None
Width=56
Height=56
Offset=-28,-28
Vertices=1
VertexX=0
VertexY=0
SolidMask=0,0,4,8,24,24
Rotate=1
NoStabilize=1
HideInCreator=true

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

View File

@ -0,0 +1,54 @@
material LavaShellMat
{
receive_shadows off
technique 0
{
pass 0
{
ambient 0.500000 0.500000 0.500000 1.000000
diffuse 0.800000 0.316192 0.800000 1.000000
specular 0.500000 0.500000 0.500000 1.000000 12.500000
emissive 0.000000 0.000000 0.000000 1.000000
scene_blend alpha_blend
depth_write off
texture_unit
{
texture LavaCoreShell.png
tex_address_mode wrap
filtering trilinear
colour_op_ex source1 src_texture src_texture
}
}
}
}
material LavaShellStoneMat
{
receive_shadows off
technique 0
{
pass 0
{
ambient 0.500000 0.500000 0.500000 1.000000
diffuse 0.800000 0.316192 0.800000 1.000000
specular 0.500000 0.500000 0.500000 1.000000 12.500000
emissive 0.000000 0.000000 0.000000 1.000000
scene_blend alpha_blend
depth_write off
texture_unit
{
texture LavaCoreShellStone.png
tex_address_mode wrap
filtering trilinear
colour_op_ex source1 src_texture src_texture
}
}
}
}

View File

@ -0,0 +1,54 @@
/**
LavaCore Shell
Protects the lava core and provides a solidmask for the clonk to walk on.
@author Win, Maikel
*/
local size;
public func InitAttach(object parent)
{
SetAction("Attach", parent);
SetSize(BoundBy(parent->GetCon(), parent.SizeLimitMin, parent.SizeLimitMax));
return;
}
public func SetSize(int size)
{
// Rotate core to solidmask.
var r = -70;
var fsin = Sin(r, 10 * size), fcos = Cos(r, 10 * size);
SetObjDrawTransform(+fcos, +fsin, 0, -fsin, +fcos, 0);
// Update solid mask.
var solid_size = 2 * ((size * 20 / 100 + 2) / 2) + 4;
solid_size = BoundBy(solid_size, 4, 28);
var solid_x = (1 + solid_size / 2) * (solid_size - 4);
SetSolidMask(solid_x, 0, solid_size * 2, solid_size * 2, 28 - solid_size, 28 - solid_size);
return;
}
/*-- Saving --*/
public func SaveScenarioObject() { return false; }
/*-- Properties --*/
local Name = "$Name$";
local Description = "$Description$";
local Plane = 425;
local ActMap = {
Attach = {
Prototype = Action,
Name = "Attach",
Procedure = DFA_ATTACH,
Length = 1,
Delay = 0,
FacetBase = 1,
NextAction = "Attach",
}
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -0,0 +1,2 @@
Name=Lavacore Shell
Description=Protects the lava core.

View File

@ -0,0 +1,2 @@
Name=Lavacore Shell
Description=Protects the lava core.

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

View File

@ -0,0 +1,63 @@
material LavaCoreMat: NormalMap
{
receive_shadows off
technique 0
{
pass 0
{
cull_hardware none
ambient 0.500000 0.500000 0.500000 1.000000
diffuse 1.000000 1.000000 1.000000 1.000000
specular 0.500000 0.500000 0.500000 1.000000 12.500000
scene_blend alpha_blend
depth_write off
texture_unit base
{
texture LavaCore.png
tex_address_mode wrap
filtering trilinear
}
texture_unit normal
{
texture LavaCoreNormals.png
tex_address_mode wrap
}
}
}
}
material LavaCoreStoneMat: NormalMap
{
receive_shadows off
technique 0
{
pass 0
{
cull_hardware none
ambient 0.500000 0.500000 0.500000 1.000000
diffuse 1.000000 1.000000 1.000000 1.000000
specular 0.500000 0.500000 0.500000 1.000000 12.500000
scene_blend alpha_blend
depth_write off
texture_unit base
{
texture LavaCoreStone.png
tex_address_mode wrap
filtering trilinear
}
texture_unit normal
{
texture LavaCoreNormals.png
tex_address_mode wrap
}
}
}
}

View File

@ -0,0 +1,420 @@
/**
LavaCore
The lava high life. Moves rythmically, spews lava, acts as platform for clonks.
@author Win, Maikel
*/
#include Library_Animal
// The outer shell of the core.
local shell;
local fx_behavior;
public func Construction()
{
shell = CreateObjectAbove(LavaCoreShell);
shell->InitAttach(this);
this.MaxSize = RandomX(40, 50);
// Add a reproduction timer (from the animal library).
AddReproductionEffect();
// Add an effect to control the lava core.
fx_behavior = CreateEffect(FxCoreBehavior, 100, 1);
return;
}
public func Initialize()
{
if (shell)
shell->SetSize(GetCon());
return;
}
public func Place(int amount, proplist rectangle, proplist settings)
{
var max_tries = 5 * amount;
var loc_area = nil;
if (rectangle) loc_area = Loc_InArea(rectangle);
var size_range = nil;
if (settings)
size_range = settings.size_range;
var cores = [];
while ((amount > 0) && (--max_tries > 0))
{
var spot = FindLocation(Loc_Material("Lava"), Loc_Space(20), loc_area);
if(!Random(2))
spot = FindLocation(Loc_Material("DuroLava"), Loc_Space(20), loc_area);
if (!spot) continue;
var core = CreateObjectAbove(this, spot.x, spot.y, NO_OWNER);
if (!core) continue;
if (settings.size_range)
{
var size = RandomX(settings.size_range[0], settings.size_range[1]);
core.MaxSize = BoundBy(size, core.SizeLimitMin, core.SizeLimitMax);
core->SetCon(core.MaxSize);
}
if (core->Stuck())
{
core->RemoveObject();
continue;
}
--amount;
PushBack(cores, core);
}
return cores;
}
public func SetCon(int new_size)
{
if (shell)
shell->SetSize(new_size);
return _inherited(new_size, ...);
}
public func DoCon(int add_size)
{
if (shell)
shell->SetSize(GetCon() + add_size);
return _inherited(add_size, ...);
}
public func Destruction()
{
if (shell)
shell->RemoveObject();
return;
}
/*-- Core Behaviour --*/
local FxCoreBehavior = new Effect
{
Construction = func()
{
this.fossilized = false;
this.move_vector = [0, 0];
this.movement_step = 72;
this.frames_per_attack = 9;
this.evading_core = 0;
// Change time to have cores perform actions at different times.
this.Time = Random(this.movement_step);
// Make core swim and able to move.
Target->SetAction("Swim");
Target->SetComDir(COMD_None);
return;
},
Timer = func(int time)
{
// Check if fossilized and change state.
this->CheckFossilized(time);
if (this.fossilized)
return FX_OK;
// Do growth.
this->DoGrowth(time);
// Attack prey if possible.
if ((time % this.frames_per_attack) == 0)
this->AttackPrey(time);
// Do movement.
this->DoMovement(time);
return FX_OK;
},
CheckFossilized = func(int time)
{
if (this.fossilized && !Random(120))
{
Target->Revive();
this.fossilized = false;
}
// Fossilize more ofen at surface.
if (!this.fossilized && (!Random(160) || (!Random(100) && !Target->GBackLiquid(0, -6))))
{
Target->Fossilize();
this.fossilized = true;
}
return;
},
AttackPrey = func(int time)
{
// Only if fully grown and not fossilized.
if (Target->GetCon() < Target.MaxSize || this.fossilized)
return;
// Shoot a bubble at a nearby prey if the path is free, sometimes randomly shoot a bubble.
var prey = Target->FindObject(Find_OCF(OCF_Alive), Target->Find_Distance(100), Target->Find_PathFree(), Find_Not(Find_ID(LavaCore)));
if (!prey && Random(60))
return;
var angle = Random(360);
if (prey)
angle = Angle(Target->GetX(), Target->GetY(), prey->GetX(), prey->GetY());
var test_x = Sin(angle, Target->GetCon() / 4);
var test_y = -Cos(angle, Target->GetCon() / 4);
if (!PathFree(Target->GetX(), Target->GetY(), Target->GetX() + test_x, Target->GetY() + test_y))
return;
var bubble = Target->CreateObject(BoilingLava_Bubble);
bubble->SetVelocity(angle, RandomX(30, 40));
bubble->DoCon(RandomX(10, 35));
},
DoGrowth = func(int time)
{
if (Target->GetCon() >= Target.MaxSize)
return;
// Only grow in lava.
var mat = MaterialName(Target->GetMaterial(0, 5));
if (mat == "Lava" || mat == "DuroLava")
if (Target->GetCon() < Target.MaxSize && !Random(45))
Target->DoCon(1);
return;
},
DoMovement = func(int time)
{
// Only perform movement if swimming.
if (Target->GetAction() != "Swim")
return;
var forced = false;
var speed = Target.MovementSpeed;
// Evade other cores. This will keep them evenly spread.
var cnat = Target->GetContact(-1);
if (!Target->InLiquid())
{
//Log("[%d]%v out of liquid", FrameCounter(), Target);
cnat = cnat | CNAT_Top;
}
var other_core = Target->FindObject(Find_ID(LavaCore), Find_Exclude(Target), Target->Find_Distance(20 + Target.MaxSize));
// Check for contact.
if (cnat & (CNAT_Left | CNAT_Right | CNAT_Top | CNAT_Bottom) && this.evading_move <= 0)
{
this.move_vector = [RandomX(-1, 1), RandomX(-1, 1)];
if ((cnat & CNAT_Left) && !(cnat & CNAT_Right))
this.move_vector[0] = 1;
if ((cnat & CNAT_Right) && !(cnat & CNAT_Left))
this.move_vector[0] = -1;
if ((cnat & CNAT_Top) && !(cnat & CNAT_Bottom))
this.move_vector[1] = 1;
if ((cnat & CNAT_Bottom) && !(cnat & CNAT_Top))
this.move_vector[1] = -1;
//Log("[%d]%v has contact: %d and move vector %v", FrameCounter(), Target, cnat, this.move_vector);
this.evading_move = 6;
forced = true;
}
// After contact is dealt with we can evade other cores.
else if (other_core && this.evading_move <= 0)
{
//Log("[%d]other core", FrameCounter());
this.move_vector[0] = Sign(Target->GetX() - other_core->GetX());
this.move_vector[1] = Sign(Target->GetY() - other_core->GetY());
this.evading_move = 16;
forced = true;
}
// Otherwise just do random movement.
else
{
this.move_vector[0] = RandomX(-1, 1);
this.move_vector[1] = RandomX(-1, 1);
// Move upwards more often to stay at surface more often.
if (Random(3))
this.move_vector[1] = -1;
}
// Execute the movement.
if ((time % this.movement_step) == 0 || forced)
{
Target->SetXDir(this.move_vector[0] * speed + RandomX(-speed, speed) / 10);
Target->SetYDir(this.move_vector[1] * speed + RandomX(-speed, speed) / 10);
}
if ((time % this.movement_step) == 0 && Target.shell)
Target.shell->SetRDir(5 * (2 * Random(2) - 1));
// Dampen movement over time to make movements seem like impulses.
var xdir = Target->GetXDir(1000);
var ydir = Target->GetYDir(1000);
if (xdir > 0)
Target->SetXDir(xdir - 3 * speed, 1000);
else
Target->SetXDir(xdir + 3 * speed, 1000);
if (ydir > 0)
Target->SetYDir(ydir - 3 * speed, 1000);
else
Target->SetYDir(ydir + 3 * speed, 1000);
this.evading_move--;
return;
},
IsFossilized = func()
{
return this.fossilized;
}
};
public func StartNonSwim()
{
if (GBackLiquid())
{
SetAction("Swim");
return;
}
return;
}
/*-- Reproduction --*/
private func ReproductionCondition()
{
return GetAlive() && GetCon() >= this.MaxSize;
}
private func SpecialReproductionCondition()
{
if (fx_behavior)
return !fx_behavior->IsFossilized();
return false;
}
public func Birth(object parent)
{
SetCon(BoundBy(GetCon(), this.SizeLimitMin, this.SizeLimitMax));
if (shell)
shell->SetSize(GetCon());
return;
}
/*-- Core State --*/
// Explode on death.
public func Death()
{
if (shell)
shell->RemoveObject();
Explode(BoundBy(GetCon() / 2, 20, 90));
return;
}
// Turns the core into a fossil.
public func Fossilize()
{
Sound("Animals::LavaCore::Fossilize", {volume = GetCon()});
SetComDir(COMD_Stop);
SetMeshMaterial("LavaCoreStoneMat");
if (shell)
{
shell->SetMeshMaterial("LavaShellStoneMat");
shell->SetRDir(0);
}
return;
}
// Turns the fossil into a core again.
public func Revive()
{
SetAction("Swim");
SetComDir(COMD_None);
SetMeshMaterial("LavaCoreMat");
if (shell)
shell->SetMeshMaterial("LavaShellMat");
return;
}
/*-- Saving --*/
public func SaveScenarioObject(proplist props)
{
if (!inherited(props, ...))
return false;
// Avoid saving some stuff that's reinitialized anyway.
props->Remove("MeshMaterial");
return true;
}
/*-- Properties --*/
local Name = "$Name$";
local Description = "$Description$";
local Plane = 424;
local CorrosionResist = true;
local MaxEnergy = 100000;
local ContactCalls = true;
local SizeLimitMin = 15; // Min size of all cores.
local SizeLimitMax = 100; // Max size of all cores.
local MaxSize = 50; // To which size this core will grow.
local MovementSpeed = 20;
local ActMap = {
Swim = {
Prototype = Action,
Name = "Swim",
Procedure = DFA_SWIM,
Speed = 100,
Accel = 16,
Decel = 16,
Length = 1,
Delay = 0,
FacetBase = 1,
NextAction = "Swim"
},
Walk = {
Prototype = Action,
Name = "Walk",
Procedure = DFA_WALK,
Speed = 100,
Accel = 16,
Decel = 16,
Length = 1,
Delay = 0,
FacetBase = 1,
NextAction = "Walk",
StartCall = "StartNonSwim",
InLiquidAction = "Swim",
},
Jump = {
Prototype = Action,
Name = "Jump",
Procedure = DFA_FLIGHT,
Speed = 100,
Accel = 16,
Decel = 16,
Length = 1,
Delay = 0,
FacetBase = 1,
NextAction = "Jump",
StartCall = "StartNonSwim",
InLiquidAction = "Swim"
},
Dead = {
Prototype = Action,
Name = "Dead",
Procedure = DFA_NONE,
Speed = 10,
Length = 1,
Delay = 0,
FacetBase=1,
Directions = 2,
FlipDir = 1,
NextAction = "Hold",
NoOtherAction = 1,
ObjectDisabled = 1
}
};

View File

@ -0,0 +1,2 @@
Name=Lavakern
Description=The lava high life. Has a hard shell on which a clonk may stand, but dangerous due to spitting out lava.

View File

@ -0,0 +1,2 @@
Name=Lavacore
Description=The lava high life. Has a hard shell on which a clonk may stand, but dangerous due to spitting out lava.

View File

@ -19,6 +19,12 @@ protected func Initialize()
{
score_list = [];
var relaunch_rule = GetRelaunchRule();
relaunch_rule->SetRespawnDelay(0);
relaunch_rule->SetDefaultRelaunchCount(nil);
relaunch_rule->SetAllowPlayerRestart(true);
relaunch_rule.FindRelaunchPos = GetID().FindRelaunchPos;
// init scoreboard
Scoreboard->Init(
[
@ -41,9 +47,9 @@ private func GetScoreGoal()
public func SetFlagBase(int team, int x, int y)
{
var base = CreateObject(Goal_FlagBase, x, y, NO_OWNER);
var base = CreateObjectAbove(Goal_FlagBase, x, y, NO_OWNER);
base->SetTeam(team);
var flag = CreateObject(Goal_Flag, x, y, NO_OWNER);
var flag = CreateObjectAbove(Goal_Flag, x, y, NO_OWNER);
flag->SetAction("AttachBase", base);
flag->SetTeam(team);
return;
@ -75,43 +81,24 @@ private func EliminateOthers(int win_team)
protected func InitializePlayer(int plr, int x, int y, object base, int team)
{
// Join new clonk.
JoinPlayer(plr);
GetRelaunchRule()->DoRelaunch(plr, nil, FindRelaunchPos(plr), true);
// make scoreboard entry for team
Scoreboard->NewEntry(ScoreboardTeamID(team), GetTaggedTeamName(team));
// Broadcast to scenario.
GameCall("OnPlayerRelaunch", plr, false);
return _inherited(plr, x, y, base, team, ...);
}
protected func RelaunchPlayer(int plr)
public func FindRelaunchPos(int plr)
{
// New clonk.
var clonk = CreateObjectAbove(Clonk, 0, 0, plr);
clonk->MakeCrewMember(plr);
SetCursor(plr, clonk);
// Join new clonk.
JoinPlayer(plr);
// Broadcast to scenario.
GameCall("OnPlayerRelaunch", plr, true);
return _inherited(plr, ...);
}
private func JoinPlayer(int plr)
{
var clonk = GetCrew(plr);
clonk->DoEnergy(100000);
var team = GetPlayerTeam(plr);
var base = FindObject(Find_ID(Goal_FlagBase), Find_Func("FindTeam", team));
if (base)
clonk->SetPosition(base->GetX(), base->GetY() - 10);
return;
return [base->GetX(), base->GetY() - 10];
return nil;
}
protected func RemovePlayer(int plr)
{
return _inherited(plr, ...);
}

View File

@ -23,66 +23,19 @@ func Initialize()
}
maxkills = GameCall("WinKillCount");
if(maxkills == nil || maxkills < 1) maxkills = 4;
GetRelaunchRule()->SetDefaultRelaunchCount(nil);
return _inherited(...);
}
protected func InitializePlayer(int plr)
{
// Join plr.
JoinPlayer(plr);
// Scenario script callback.
GameCall("OnPlayerRelaunch", plr, false);
return _inherited(plr, ...);
}
protected func RelaunchPlayer(int plr, int killer)
{
_inherited(plr, killer, ...);
var clonk = CreateObjectAbove(Clonk, 0, 0, plr);
clonk->MakeCrewMember(plr);
SetCursor(plr, clonk);
JoinPlayer(plr);
// Scenario script callback.
GameCall("OnPlayerRelaunch", plr, true);
// Show scoreboard for a while
DoScoreboardShow(1, plr + 1);
Schedule(this,Format("DoScoreboardShow(-1, %d)", plr + 1), 35 * ShowBoardTime);
NotifyHUD();
return;
}
protected func JoinPlayer(int plr)
{
var clonk = GetCrew(plr);
clonk->DoEnergy(100000);
var pos = FindRelaunchPos(plr);
clonk->SetPosition(pos[0], pos[1]);
return;
}
private func FindRelaunchPos(int plr)
{
var tx, ty; // Test position.
for (var i = 0; i < 500; i++)
{
tx = Random(LandscapeWidth());
ty = Random(LandscapeHeight());
if (GBackSemiSolid(AbsX(tx), AbsY(ty)))
continue;
if (GBackSemiSolid(AbsX(tx+5), AbsY(ty+10)))
continue;
if (GBackSemiSolid(AbsX(tx+5), AbsY(ty-10)))
continue;
if (GBackSemiSolid(AbsX(tx-5), AbsY(ty+10)))
continue;
if (GBackSemiSolid(AbsX(tx-5), AbsY(ty-10)))
continue;
// Succes.
return [tx, ty];
}
return nil;
}
public func IsFulfilled()
{
// Check whether someone has reached the limit.
@ -94,7 +47,7 @@ public func IsFulfilled()
// Otherwise just check if there are no enemies
return Goal_Melee->IsFulfilled();
// Eliminate all players, that are not in a team with one of the winners
for (var i = 0; i < GetPlayerCount(); i++)
for (var i = 0; i < GetPlayerCount(); i++)
{
var plr = GetPlayerByIndex(i);
if (winner == plr)
@ -117,7 +70,7 @@ public func GetDescription(int plr)
{
var score = GetRelativeScore(plr);
if (score.kills > 0)
return Format("$MsgAhead$", score.kills, GetPlayerName(score.best));
return Format("$MsgAhead$", score.kills, GetPlayerName(score.best));
else if (score.kills < 0)
return Format("$MsgBehind$", -score.kills, GetPlayerName(score.best));
else if (score.best == plr)
@ -136,7 +89,7 @@ public func Activate(int byplr)
else
{
var score = GetRelativeScore(byplr);
if(score.kills > 0) MessageWindow(Format("$MsgAhead$", score.kills, GetPlayerName(score.best)), byplr);
if(score.kills > 0) MessageWindow(Format("$MsgAhead$", score.kills, GetPlayerName(score.best)), byplr);
else if(score.kills < 0) MessageWindow(Format("$MsgBehind$", -score.kills,GetPlayerName(score.best)), byplr);
else if(score.best == byplr) MessageWindow(Format("$MsgYouAreBest$", score.kills), byplr);
else MessageWindow(Format("$MsgEqual$", GetPlayerName(score.best)), byplr);

View File

@ -1,3 +0,0 @@
Name=Relaunch container
MsgRelaunch=You will be relaunched in %d seconds.
MsgWeapon=You have %d seconds to choose a weapon.

View File

@ -1,3 +0,0 @@
Name=Relaunch container
MsgRelaunch=You will relaunch in %d seconds.
MsgWeapon=You have %d seconds to choose a weapon.

View File

@ -4,8 +4,6 @@
Premade goal for simple melees with relaunches.
Callbacks made to scenario script:
* OnPlayerRelaunch(int plr) made when the player is relaunched and at game start plr init.
* RelaunchCount() should return the number of relaunches.
* KillsToRelaunch() should return how many kills will earn the player an extra relaunch.
--*/
@ -19,7 +17,6 @@
#include Scoreboard_Relaunch
// Some rule default values
local DefaultRelaunchCount = 5; // Number of relaunches.
local DefaultKillsToRelaunch = 4; // Number of kills one needs to make before gaining a relaunch.
local ShowBoardTime = 5; // Duration in seconds the scoreboard will be shown to a player on an event.
@ -33,14 +30,6 @@ protected func Initialize()
/*-- Scenario callbacks --*/
private func RelaunchCount()
{
var relaunch_cnt = GameCall("RelaunchCount");
if (relaunch_cnt != nil)
return relaunch_cnt;
return DefaultRelaunchCount;
}
private func KillsToRelaunch()
{
var kills_to_relaunch = GameCall("KillsToRelaunch");
@ -53,21 +42,12 @@ private func KillsToRelaunch()
protected func InitializePlayer(int plr)
{
// First process relaunches, etc.
_inherited(plr, ...);
// Join plr.
JoinPlayer(plr);
// Scenario script callback.
GameCall("OnPlayerRelaunch", plr, false);
return;
}
protected func RelaunchPlayer(int plr, int killer)
{
_inherited(plr, killer, ...);
if (GetRelaunchCount(plr) < 0)
return EliminatePlayer(plr);
// the kill logs rule cares about logging the respawn
// ..
@ -78,54 +58,15 @@ protected func RelaunchPlayer(int plr, int killer)
if (!(GetPlayerTeam(killer) && GetPlayerTeam(killer) == GetPlayerTeam(plr)))
if (KillsToRelaunch() && !(GetKillCount(killer) % KillsToRelaunch()) && GetKillCount(killer))
{
DoRelaunchCount(killer, 1);
GetRelaunchRule()->DoPlayerRelaunchCount(killer, 1);
Log("$MsgRelaunchGained$", GetPlayerName(killer));
}
var clonk = CreateObjectAbove(Clonk, 0, 0, plr);
clonk->MakeCrewMember(plr);
SetCursor(plr, clonk);
JoinPlayer(plr);
// Scenario script callback.
GameCall("OnPlayerRelaunch", plr, true);
// Show scoreboard for a while.
DoScoreboardShow(1, plr + 1);
Schedule(this,Format("DoScoreboardShow(-1, %d)", plr + 1), 35 * ShowBoardTime);
return;
}
protected func JoinPlayer(int plr)
{
var clonk = GetCrew(plr);
clonk->DoEnergy(100000);
var pos = FindRelaunchPos(plr);
clonk->SetPosition(pos[0], pos[1]);
return;
}
private func FindRelaunchPos(int plr)
{
var tx, ty; // Test position.
for (var i = 0; i < 500; i++)
{
tx = Random(LandscapeWidth());
ty = Random(LandscapeHeight());
if (GBackSemiSolid(AbsX(tx), AbsY(ty)))
continue;
if (GBackSemiSolid(AbsX(tx+5), AbsY(ty+10)))
continue;
if (GBackSemiSolid(AbsX(tx+5), AbsY(ty-10)))
continue;
if (GBackSemiSolid(AbsX(tx-5), AbsY(ty+10)))
continue;
if (GBackSemiSolid(AbsX(tx-5), AbsY(ty-10)))
continue;
// Succes.
return [tx, ty];
}
return nil;
}
protected func RemovePlayer(int plr)
{
return _inherited(plr, ...);

View File

@ -56,8 +56,9 @@ protected func Initialize(...)
private func EnsureRestartRule()
{
if (!ObjectCount(Find_ID(Rule_Restart)))
CreateObject(Rule_Restart, Min(64, LandscapeWidth()-GetX()-32), 0, NO_OWNER);
var relaunch = GetRelaunchRule();
relaunch->SetAllowPlayerRestart(true);
relaunch->SetPerformRestart(false);
return true;
}
@ -440,7 +441,7 @@ protected func OnClonkDeath(object clonk, int killed_by)
JoinPlayer(plr);
// Transfer contents if active.
if (transfer_contents)
Rule_BaseRespawn->TransferInventory(clonk, new_clonk);
GetRelaunchRule()->TransferInventory(clonk, new_clonk);
// Scenario script callback.
GameCall("OnPlayerRespawn", plr, FindRespawnCP(plr));
// Log message.
@ -448,7 +449,8 @@ protected func OnClonkDeath(object clonk, int killed_by)
// Respawn actions
var cp = FindRespawnCP(plr);
UserAction->EvaluateAction(on_respawn, this, clonk, plr);
if (cp) cp->OnPlayerRespawn(new_clonk, plr);
if (cp)
cp->OnPlayerRespawn(new_clonk, plr);
return;
}
@ -472,7 +474,8 @@ protected func JoinPlayer(int plr)
private func FindRespawnCP(int plr)
{
var respawn_cp = respawn_list[plr];
if (!respawn_cp) respawn_cp = respawn_list[plr] = cp_list[0];
if (!respawn_cp)
respawn_cp = respawn_list[plr] = cp_list[0];
return respawn_cp;
}
@ -498,10 +501,7 @@ public func SaveScenarioObject(props)
{
if (!inherited(props, ...))
return false;
// Force dependency on restart rule.
var restart_rule = FindObject(Find_ID(Rule_Restart));
if (restart_rule)
restart_rule->MakeScenarioSaveName();
props->AddCall("Goal", this, "EnsureRestartRule");
if (no_respawn_handling)
props->AddCall("Goal", this, "DisableRespawnHandling");
if (transfer_contents)
@ -551,19 +551,19 @@ private func UpdateScoreboard(int plr)
/*-- Direction indication --*/
// Effect for direction indication for the clonk.
protected func FxIntDirNextCPStart(object target, effect)
protected func FxIntDirNextCPStart(object target, effect fx)
{
var arrow = CreateObjectAbove(GUI_GoalArrow, 0, 0, target->GetOwner());
arrow->SetAction("Show", target);
effect.arrow = arrow;
fx.arrow = arrow;
return FX_OK;
}
protected func FxIntDirNextCPTimer(object target, effect)
protected func FxIntDirNextCPTimer(object target, effect fx)
{
var plr = target->GetOwner();
var team = GetPlayerTeam(plr);
var arrow = effect.arrow;
var arrow = fx.arrow;
// Find nearest CP.
var nextcp;
for (var cp in FindObjects(Find_ID(ParkourCheckpoint), Find_Func("FindCPMode", PARKOUR_CP_Check | PARKOUR_CP_Finish), Sort_Distance(target->GetX() - GetX(), target->GetY() - GetY())))
@ -608,9 +608,9 @@ protected func FxIntDirNextCPTimer(object target, effect)
return FX_OK;
}
protected func FxIntDirNextCPStop(object target, effect)
protected func FxIntDirNextCPStop(object target, effect fx)
{
effect.arrow->RemoveObject();
fx.arrow->RemoveObject();
return;
}

View File

@ -820,35 +820,41 @@ func OnMenuEntryHover(proplist menu_info, int entry_index, int player)
if (!info.menu.callback_target || !info.menu.callback_hover)
{
var text = Format("%s:|%s", info.entry.symbol->GetName(), info.entry.symbol.Description);
var obj = nil;
if (info.entry.extra_data && info.entry.extra_data.objects)
{
for (var possible in info.entry.extra_data.objects)
{
if (possible == nil) continue;
obj = possible;
break;
}
}
// For contents menus, we can sometimes present additional information about objects.
if (info.menu.flag == InteractionMenu_Contents && obj)
if (info.menu.flag == InteractionMenu_Contents)
{
var additional = nil;
if (obj->Contents())
// Get the first valid object of the clicked stack.
var obj = nil;
if (info.entry.extra_data && info.entry.extra_data.objects)
{
additional = "$Contains$ ";
var i = 0, count = obj->ContentsCount();
// This currently justs lists contents one after the other.
// Items are not stacked, which should be enough for everything we have ingame right now. If this is filed into the bugtracker at some point, fix here.
for (;i < count;++i)
for (var possible in info.entry.extra_data.objects)
{
if (i > 0)
additional = Format("%s, ", additional);
additional = Format("%s%s", additional, obj->Contents(i)->GetName());
if (possible == nil) continue;
obj = possible;
break;
}
}
if (additional != nil)
text = Format("%s||%s", text, additional);
// ..and use that object to fetch some more information.
if (obj)
{
var additional = nil;
if (obj->Contents())
{
additional = "$Contains$ ";
var i = 0, count = obj->ContentsCount();
// This currently justs lists contents one after the other.
// Items are not stacked, which should be enough for everything we have ingame right now. If this is filed into the bugtracker at some point, fix here.
for (;i < count;++i)
{
if (i > 0)
additional = Format("%s, ", additional);
additional = Format("%s%s", additional, obj->Contents(i)->GetName());
}
}
if (additional != nil)
text = Format("%s||%s", text, additional);
}
}
GuiUpdateText(text, current_main_menu_id, 1, current_description_box.desc_target);

View File

@ -42,18 +42,38 @@ func PlayBarrelHitSound()
Sound("Hits::Materials::Wood::DullWoodHit?");
}
func Collection2(object item)
public func Collection2(object item)
{
UpdateLiquidContainer();
return _inherited(item, ...);
}
func Ejection(object item)
public func Ejection(object item)
{
UpdateLiquidContainer();
return _inherited(item, ...);
}
public func ContentsDestruction(object item)
{
ScheduleCall(this, "UpdateLiquidContainer", 1);
return _inherited(item, ...);
}
public func RemoveLiquid(liquid_name, int amount, object destination)
{
var res = _inherited(liquid_name, amount, destination, ...);
UpdateLiquidContainer();
return res;
}
public func PutLiquid(liquid_name, int amount, object source)
{
var res = _inherited(liquid_name, amount, source, ...);
UpdateLiquidContainer();
return res;
}
/*-- Callbacks --*/
public func CollectFromStack(object item)

View File

@ -228,6 +228,11 @@ public func GetCarryTransform()
return Trans_Rotate(90, 1, 0, 0);
}
public func OnRelaunchCreation()
{
CreateContents(LeadBullet);
}
public func Definition(def)
{
SetProperty("PictureTransformation", Trans_Mul(Trans_Translate(1500, 0, -1500), Trans_Rotate(170, 0, 1, 0), Trans_Rotate(30, 0, 0, 1)), def);

View File

@ -232,6 +232,12 @@ public func GetCarrySpecial(clonk)
if(fAiming) return "pos_hand2";
}
public func OnRelaunchCreation()
{
CreateContents(Arrow);
}
func Definition(def)
{
def.PictureTransformation = Trans_Mul(Trans_Translate(-4000,-2000,4000),Trans_Rotate(180,0,1,0),Trans_Rotate(-45,0,0,1));

View File

@ -247,6 +247,12 @@ public func GetCarryTransform(object clonk, bool idle, bool nohand, bool second_
return Trans_Mul(Trans_Rotate(90,1,0,0), Trans_Rotate(-10,0,0,1));
}
public func OnRelaunchCreation()
{
CreateContents(IronBomb);
}
func Definition(def)
{
def.PictureTransformation = Trans_Mul(Trans_Translate(-3000, 1000, 1500),Trans_Rotate(170,0,1,0),Trans_Rotate(30,0,0,1));

View File

@ -27,7 +27,7 @@ private func AddReproductionEffect()
private func RemoveReproductionEffect()
{
return RemoveEffect("IntReproduction");
return RemoveEffect("IntReproduction", this);
}

View File

@ -10,24 +10,14 @@
* RemovePlayer(int plr);
--*/
local score_relaunch_list; // Here the relaunch count of all players is stored, access through plrid.
// Overload this.
public func RelaunchCount()
{
return 5;
}
/*-- Callbacks --*/
protected func Initialize()
{
// Make sure it is a list.
score_relaunch_list = [];
// init scoreboard
// init scoreboard, uses the condition of Scoreboard_Deaths too
Scoreboard->Init(
if (GetRelaunchRule()->HasUnlimitedRelaunches()) return;
Scoreboard->Init(
[{key = "relaunches", title = Scoreboard_Relaunch, sorted = true, desc = true, default = "", priority = 75, conditional = Scoreboard_Death.ScoreboardCondition}]
);
return _inherited(...);
@ -35,20 +25,16 @@ protected func Initialize()
protected func InitializePlayer(int plr)
{
var plrid = GetPlayerID(plr);
// create scoreboard entry
score_relaunch_list[plrid] = RelaunchCount();
if (GetRelaunchRule()->HasUnlimitedRelaunches()) return;
Scoreboard->NewPlayerEntry(plr);
Scoreboard->SetPlayerData(plr, "relaunches", score_relaunch_list[plrid]);
Scoreboard->SetPlayerData(plr, "relaunches", GetRelaunchRule()->GetPlayerRelaunchCount(plr));
return _inherited(plr, ...);
}
protected func RelaunchPlayer(int plr, int killer)
{
var plrid = GetPlayerID(plr);
// Modify scoreboard relaunch count entry for this player.
score_relaunch_list[plrid]--;
Scoreboard->SetPlayerData(plr, "relaunches", score_relaunch_list[plrid]);
if (GetRelaunchRule()->HasUnlimitedRelaunches()) return;
Scoreboard->SetPlayerData(plr, "relaunches", GetRelaunchRule()->GetPlayerRelaunchCount(plr));
return _inherited(plr, killer, ...);
}
@ -59,26 +45,6 @@ protected func RemovePlayer(int plr)
/*-- Misc --*/
public func SetRelaunchCount(int plr, int value)
{
var plrid = GetPlayerID(plr);
score_relaunch_list[plrid] = value;
Scoreboard->SetPlayerData(plr, "relaunches", score_relaunch_list[plrid]);
return;
}
public func GetRelaunchCount(int plr)
{
var plrid = GetPlayerID(plr);
return score_relaunch_list[plrid];
}
public func DoRelaunchCount(int plr, int value)
{
var plrid = GetPlayerID(plr);
score_relaunch_list[plrid] += value;
Scoreboard->SetPlayerData(plr, "relaunches", score_relaunch_list[plrid]);
return;
}
local Name = "Scoreboard Relaunches";

View File

@ -1,185 +1,10 @@
/**
Base Respawn
If neutral flagpoles are available, respawn there (for free). Otherwise, respawn
at the nearest base if sufficient clonks and clunkers are available.
TODO: make more general for all kinds of available crew members.
@author Maikel, Sven2
*/
/* Converts itself to the Rule_Relaunch rule. */
// Determines whether the inventory of the crew member is transfered upon respawn.
local inventory_transfer = false;
// Determines whether a crew member needs to be bought.
local free_crew = false;
// Delay between clonk death and respawn (in seconds)
local respawn_delay = 2;
protected func Initialize()
protected func Construction()
{
ScheduleCall(this, this.CheckDescription, 1, 1);
return true;
}
private func CheckDescription()
{
// If neutral flagpoles exist, update name and description.
if (ObjectCount(Find_ID(Flagpole), Find_Func("IsNeutral")))
{
SetName("$Name2$");
this.Description = "$Description2$";
}
return true;
}
public func SetInventoryTransfer(bool transfer)
{
inventory_transfer = transfer;
return true;
}
public func GetInventoryTransfer()
{
return inventory_transfer;
}
public func SetFreeCrew(bool free)
{
free_crew = free;
return true;
}
public func GetFreeCrew()
{
return free_crew;
}
protected func OnClonkDeath(object clonk)
{
var plr = clonk->GetOwner();
// Skip eliminated players, NO_OWNER, etc.
if (!GetPlayerName(plr))
return true;
// Only respawn a clonk if it is the last crew member.
if (GetCrewCount(plr) >= 1)
return true;
// Get the bases at which the clonk can possibly respawn.
var bases = GetBases(clonk), crew;
for (var base in bases)
{
if (!base)
continue;
// If free crew just create a clonk at the base.
if (free_crew)
{
crew = CreateObjectAbove(Clonk, base->GetX() - GetX(), base->GetY() + base->GetDefHeight() / 2 - GetY(), plr);
crew->MakeCrewMember(plr);
SetCursor(plr, crew);
// Transfer inventory if turned on.
if (inventory_transfer) TransferInventory(clonk, crew);
break;
}
// Try to buy a crew member at the base.
var pay_plr = base->GetOwner();
// Payment in neutral bases by clonk owner.
if (pay_plr == NO_OWNER)
pay_plr = plr;
crew = base->~DoBuy(Clonk, plr, pay_plr, clonk);
if (crew)
{
crew->Exit(0, base->GetDefHeight() / 2);
SetCursor(plr, crew);
// Transfer inventory if turned on.
if (inventory_transfer) TransferInventory(clonk, crew);
break;
}
}
// Respawn delay (+Weapon choice if desired by scenario)
if (crew && respawn_delay)
{
crew->SetCrewEnabled(false); // will be re-set by relauncher
var relaunch = CreateObject(RelaunchContainer, crew->GetX() - GetX(), crew->GetY() - GetY(), plr);
relaunch->SetRelaunchTime(respawn_delay, false);
relaunch->StartRelaunch(crew);
// But keep view on old corpse because the death might be exciting!
// And sometimes you want to know why you died (just like in real-life!)
var light = CreateLight(clonk->GetX() - GetX(), clonk->GetY() - GetY(), 100, Fx_Light.LGT_Temp, plr, 20, respawn_delay*36);
SetCursor(plr, nil);
SetPlrView(plr, light);
}
return true;
}
private func TransferInventory(object from, object to)
{
// Drop some items that cannot be transferred (such as connected pipes and dynamite igniters)
var i = from->ContentsCount(), contents;
while (i--)
if (contents = from->Contents(i))
if (contents->~IsDroppedOnDeath(from))
{
contents->Exit();
}
else
{
// The new clonk doesn't burn. To be consistent, also extinguish contents
contents->Extinguish();
}
return to->GrabContents(from);
}
private func GetBases(object clonk)
{
var plr = clonk->GetOwner();
// Neutral flagpoles are preferred respawn points, because they are used as the only respawn points in missions.
var bases = clonk->FindObjects(Find_ID(Flagpole), Find_Func("IsNeutral"), clonk->Sort_Distance());
// If there are no neutral flagpoles, find closest base owned by the player (or team) and try to buy a clonk.
if (GetLength(bases) <= 0)
bases = clonk->FindObjects(Find_Func("IsBaseBuilding"), Find_Allied(plr), clonk->Sort_Distance());
return bases;
}
protected func Activate(int byplr)
{
MessageWindow(this.Description, byplr);
return true;
}
/*-- Scenario saving --*/
public func SaveScenarioObject(props, ...)
{
if (!inherited(props, ...))
return false;
// Custom properties
props->Remove("Name"); // updated by initialization
props->Remove("Description"); // updated by initialization
if (inventory_transfer)
props->AddCall("InvenctoryTransfer", this, "SetInventoryTransfer", inventory_transfer);
if (free_crew)
props->AddCall("FreeCrew", this, "SetFreeCrew", free_crew);
return true;
}
/* Editor */
public func Definition(def)
{
if (!def.EditorProps) def.EditorProps = {};
def.EditorProps.inventory_transfer = { Name="$InventoryTransfer$", EditorHelp="$InventoryTransferHelp$", Type="bool", Set="SetInventoryTransfer" };
def.EditorProps.free_crew = { Name="$FreeCrew$", EditorHelp="$FreeCrewHelp$", Type="bool", Set="SetFreeCrew" };
}
/*-- Proplist --*/
local Name = "$Name$";
local Description = "$Description$";
local Visibility = VIS_Editor;
local EditorPlacementLimit = 1; // Rules are to be placed only once
var relaunch_rule = GetRelaunchRule();
relaunch_rule->SetBaseRespawn(true);
relaunch_rule->SetFreeCrew(false);
relaunch_rule->SetLastClonkRespawn(true);
return RemoveObject();
}

View File

@ -1,8 +0,0 @@
Name=Basis Neustart
Name2=Neustart am Flaggenmast
Description=Du wirst in der nächstliegenden Basis wiederbelebt, wenn ausreichend Clonks und Clunker vorhanden sind.
Description2=Du wirst am nächstliegenden Flaggenmast wiederbelebt.
InventoryTransfer=Inventar behalten
InventoryTransferHelp=Ob das Inventar sterbender Clonks beim Respawn zum neuen Clonk teleportiert werden soll.
FreeCrew=Kostenloser Respawn
FreeCrewHelp=Ob man die Clonks umsonst bekommt.

View File

@ -1,8 +0,0 @@
Name=Base Respawn
Name2=Respawn at flagpole
Description=You respawn at the nearest base if sufficient clonks and clunkers are available.
Description2=You respawn at the nearest respawn flagpole.
InventoryTransfer=Keep inventory
InventoryTransferHelp=Whether the inventory of dying clonks is beamed to the newly respawned clonk.
FreeCrew=Free respawn
FreeCrewHelp=Whether respawning clonks are free. If not set, respawn happens only if the player has sufficient gold and clonks available for sale.

View File

@ -42,16 +42,7 @@ func OnClonkDeathEx(object clonk, int plr, int killed_by)
log=Format(Translate(Format("Teamkill%d", which_one)), GetTaggedPlayerName(plr), name, GetTaggedPlayerName(killed_by));
else log=Format(Translate(Format("KilledByPlayer%d", which_one)), GetTaggedPlayerName(plr), name, GetTaggedPlayerName(killed_by));
// okay, why is GetRelaunchCount not a global function..?
// and why are the relaunches not stored in a static variable or a singleton that can be accessed somehow..
var relaunches=nil;
for(var goal in FindObjects(Find_Or(Find_Category(C4D_Goal), Find_Category(C4D_Rule))))
{
relaunches = goal->~GetRelaunchCount(plr);
if(relaunches != nil) break;
}
if(relaunches == nil) relaunches=GameCall("GetRelaunchCount", plr);
var relaunches = GetRelaunchRule()->GetPlayerRelaunchCount(plr);
if(relaunches != nil)
{
var msg="";

View File

@ -0,0 +1,7 @@
[DefCore]
id=Rule_Relaunch
Version=8,0
Category=C4D_StaticBack | C4D_Rule
Width=32
Height=32
Offset=-16,-16

View File

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -3,34 +3,28 @@
Author: Maikel
This container holds the clonk after relaunches.
* The time the clonk is held can be specified with SetRelaunchTime(int time);
* The time the clonk is held can be specified by calling GetRelaunchRule()->SetRespawnDelay(int time).
* After that time the clonk is released and OnClonkLeftRelaunch(object clonk) is called in the scenario script.
* Optionally the clonk can choose a weapon if GetRelaunchWeaponList in the scenario script returns a valid id-array.
--*/
local time;
local menu;
local hold;
local has_selected;
local crew;
protected func Initialize()
{
time = 36 * 10;
return;
}
local hold_crew = false;
local relaunch_time = 36 * 10;
// Sets the time, in seconds, the clonk is held in the container.
public func SetRelaunchTime(int to_time, bool to_hold)
{
time = to_time * 36;
hold = to_hold;
relaunch_time = to_time * 36;
hold_crew = to_hold;
return;
}
// Returns the time, in seconds the clonk is held.
public func GetRelaunchTime() { return time / 36; }
public func GetRelaunchTime() { return relaunch_time / 36; }
// Retrieve weapon list from scenario.
private func WeaponList() { return GameCall("RelaunchWeaponList"); }
@ -39,15 +33,14 @@ public func StartRelaunch(object clonk)
{
if (!clonk)
return;
// only 1 clonk can be inside
if(crew)
// Only 1 clonk can be inside.
if (crew)
return;
// save clonk for later use
// Save clonk for later use.
crew = clonk;
clonk->Enter(this);
ScheduleCall(this, "OpenWeaponMenu", 36, 0, clonk);
AddEffect("IntTimeLimit", this, 100, 36, this);
return true;
}
@ -62,49 +55,59 @@ private func OpenWeaponMenu(object clonk)
{
menu = CreateObject(MenuStyle_Default, nil, nil, clonk->GetOwner());
menu->SetPermanent();
menu->SetTitle(Format("$MsgWeapon$", time / 36));
clonk->SetMenu(menu, true);
menu->SetTitle(Format("$MsgWeapon$", relaunch_time / 36));
clonk->SetMenu(menu, true);
if (GetType(GetRelaunchRule().last_used_player_weapons) != C4V_Array)
GetRelaunchRule().last_used_player_weapons = [];
for (var weapon in weapons)
menu->AddItem(weapon, weapon->GetName(), nil, this, "OnWeaponSelected", weapon);
{
if (GetRelaunchRule().last_used_player_weapons[clonk->GetOwner()] != weapon)
{
menu->AddItem(weapon, weapon->GetName(), nil, this, "OnWeaponSelected", weapon);
}
}
menu->Open();
}
}
}
func FxIntTimeLimitTimer(object target, effect, int fxtime)
public func FxIntTimeLimitTimer(object target, effect fx, int fxtime)
{
var clonk = crew;
if (!clonk)
{
RemoveObject();
return -1;
return FX_Execute_Kill;
}
if (fxtime >= time)
if (fxtime >= relaunch_time)
{
if (!has_selected && WeaponList())
GiveWeapon(WeaponList()[Random(GetLength(WeaponList()))]);
GiveWeapon(RandomElement(WeaponList()));
RelaunchClonk();
return -1;
return FX_Execute_Kill;
}
if (menu)
menu->SetTitle(Format("$MsgWeapon$", (time - fxtime) / 36));
menu->SetTitle(Format("$MsgWeapon$", (relaunch_time - fxtime) / 36));
else
PlayerMessage(clonk->GetOwner(), Format("$MsgRelaunch$", (time - fxtime) / 36));
return 1;
PlayerMessage(clonk->GetOwner(), Format("$MsgRelaunch$", (relaunch_time - fxtime) / 36));
return FX_OK;
}
public func OnWeaponSelected(id weapon)
{
if (!crew)
return;
GiveWeapon(weapon);
if (GetRelaunchRule()->GetLastWeaponUse())
GetRelaunchRule().last_used_player_weapons[crew->GetOwner()] = weapon;
has_selected = true;
// Close menu manually, to prevent selecting more weapons.
if (menu)
menu->Close();
if (!hold)
if (!hold_crew)
RelaunchClonk();
return true;
}
@ -112,7 +115,7 @@ public func OnWeaponSelected(id weapon)
private func RelaunchClonk()
{
var clonk = crew;
// When relaunching from disabled state (i.e base respawn), reset view to clonk
// When relaunching from disabled state (i.e base respawn), reset view to clonk.
if (!clonk->GetCrewEnabled())
{
clonk->SetCrewEnabled(true);
@ -120,7 +123,7 @@ private func RelaunchClonk()
SetPlrView(clonk->GetOwner(), clonk);
}
clonk->Exit();
GameCall("OnClonkLeftRelaunch", clonk);
GameCall("OnClonkLeftRelaunch", clonk, clonk->GetOwner());
if (menu)
menu->Close();
PlayerMessage(clonk->GetOwner(), "");
@ -131,14 +134,12 @@ private func RelaunchClonk()
private func GiveWeapon(id weapon_id)
{
var newobj = CreateObjectAbove(weapon_id);
if (weapon_id == Bow)
newobj->CreateContents(Arrow);
if (weapon_id == Blunderbuss)
newobj->CreateContents(LeadBullet);
newobj->~OnRelaunchCreation(crew);
crew->Collect(newobj);
return;
return true;
}
public func SaveScenarioObject() { return false; }
local Name = "$Name$";
/*-- Saving --*/
public func SaveScenarioObject() { return false; }

View File

@ -0,0 +1,2 @@
MsgRelaunch=You will be relaunched in %d seconds.
MsgWeapon=You have %d seconds to choose a weapon.

View File

@ -0,0 +1,2 @@
MsgRelaunch=You will relaunch in %d seconds.
MsgWeapon=You have %d seconds to choose a weapon.

View File

@ -0,0 +1,480 @@
/**
Relaunch Rule
This rule enables and handles relaunches with its various aspects. These are:
* SetInventoryTransfer(bool transfer): inventory of crew is transferred on respawn [default false].
* SetFreeCrew(bool free): whether the crew is free or needs to be bought [default false].
* SetBaseRespawn(bool set): whether to respawn at a nearby base [default false].
* SetLastClonkRespawn(bool b): whether to respawn the last clonk only [default false].
* SetRespawnDelay(int delay): respawn delay in seconds [default 10].
* SetAllowPlayerRestart(bool on): whether a player can select restart in the rule menu.
* SetPerformRestart(bool on): whether this rule actually handles the respawn [default true].
* SetDefaultRelaunchCount(int r): the number of relaunches a player has [default nil == infinte].
* SetInitialRelaunch(bool on): whether a relaunch on round start is done [default true].
The active relaunch rule can be obtained by the global function GetRelaunchRule(). The rule also
keeps track of player's actual number of relaunches which can be modified and accessed by:
* SetPlayerRelaunchCount(int plr, int value): set player relaunch count.
* GetPlayerRelaunchCount(int plr): get player relaunch count.
* DoPlayerRelaunchCount(int plr, int value): add to player relaunch count.
* HasUnlimitedRelaunches(): whether the players have infinite relaunches.
@author Maikel, Sven2, Fulgen
*/
/*-- Settings --*/
// Determines whether the inventory of the crew member is transfered upon respawn.
local inventory_transfer = false;
public func SetInventoryTransfer(bool transfer)
{
inventory_transfer = transfer;
return this;
}
public func GetInventoryTransfer() { return inventory_transfer; }
// Determines whether a crew member needs to be bought.
local free_crew = true;
public func SetFreeCrew(bool free)
{
free_crew = free;
return this;
}
public func GetFreeCrew() { return free_crew; }
// Determines whether the clonk will be respawned at the base.
local respawn_at_base = false;
public func SetBaseRespawn(bool set)
{
respawn_at_base = set;
return this;
}
public func GetBaseRespawn() { return respawn_at_base; }
// Determines whether only the last clonk gets respawned.
local respawn_last_clonk = false;
public func SetLastClonkRespawn(bool b)
{
respawn_last_clonk = b;
return this;
}
public func GetLastClonkRespawn() { return respawn_last_clonk; }
// Determines the amount of time in the relaunch container.
local relaunch_time = 10; // seconds
public func SetRespawnDelay(int delay)
{
relaunch_time = delay;
return this;
}
public func GetRespawnDelay() { return relaunch_time / 36; }
// Determines whether a player can select to restart in a round via the rule menu.
local allow_restart_player = false;
public func SetAllowPlayerRestart(bool on)
{
allow_restart_player = on;
return this;
}
public func GetAllowPlayerRestart() { return allow_restart_player; }
// Determines whether a relaunch is performed by the rule.
local perform_restart = true;
public func SetPerformRestart(bool on)
{
perform_restart = on;
return this;
}
public func GetPerformRestart() { return perform_restart; }
// Determines the default relaunch count.
local default_relaunch_count = nil;
local relaunches = [];
public func SetDefaultRelaunchCount(int r)
{
default_relaunch_count = r;
return this;
}
public func GetDefaultRelaunchCount() { return default_relaunch_count; }
// Determines whether a relaunch is needed on round start.
local initial_relaunch = true;
public func SetInitialRelaunch(bool on)
{
initial_relaunch = on;
return this;
}
public func GetInitialRelaunch() { return initial_relaunch; }
// Determines whether the crew is released after weapon selection.
local hold_crew = false;
public func SetHolding(bool hold)
{
hold_crew = hold;
return this;
}
public func GetHolding() { return hold_crew; }
// Determines whether the player can select the last weapon again.
local disable_last_weapon = false;
local last_used_player_weapons = [];
public func SetLastWeaponUse(bool use)
{
disable_last_weapon = !use;
return this;
}
public func GetLastWeaponUse() { return disable_last_weapon; }
// Not modifiable at the moment.
local respawn_script_players = false;
local clonk_type = Clonk;
/*-- Rule Code --*/
public func Activate(int plr)
{
// Only restart player if enabled unless this is a definition call.
if (this != Rule_Relaunch && !allow_restart_player)
return MessageWindow(this.Description, plr);
// Notify scenario and stop execution if handled by scenario.
if (GameCall("OnPlayerActivatedRestart", plr))
return;
// Remove the player's clonk, including contents.
var clonk = GetCrew(plr);
if (clonk && clonk->GetCrewEnabled())
{
clonk->Kill(clonk, true);
clonk->RemoveObject();
}
return;
}
public func Initialize()
{
ScheduleCall(this, this.CheckDescription, 1, 1);
if (GetScenarioVal("Mode", "Game") == "Melee")
default_relaunch_count = 5;
return;
}
private func CheckDescription()
{
// If neutral flagpoles exist, update name and description.
if(respawn_at_base)
{
if(ObjectCount(Find_ID(Flagpole), Find_Func("IsNeutral")))
{
SetName("$Name2$");
this.Description = "$Description2$";
}
else
{
SetName("$Name3$");
this.Description = "$Description3$";
}
}
else
{
SetName("$Name$");
this.Description = "$Description$";
}
return true;
}
public func InitializePlayer(int plr)
{
_inherited(plr, ...);
relaunches[plr] = default_relaunch_count;
// Check if relaunch is needed.
if (!initial_relaunch || !perform_restart)
return;
// Scenario script callback.
if (GameCall("OnPlayerRelaunch", plr, false))
return;
return DoRelaunch(plr, nil, nil, true);
}
public func OnClonkDeath(object clonk, int killer)
{
if (!clonk || !perform_restart)
return;
var plr = clonk->GetOwner();
if (plr == NO_OWNER || (!respawn_script_players && GetPlayerType(plr) == C4PT_Script)) return;
if (default_relaunch_count != nil)
{
relaunches[plr]--;
if (relaunches[plr] < 0)
{
EliminatePlayer(plr);
return;
}
}
GameCall("OnPlayerRelaunch", plr, true);
return DoRelaunch(plr, clonk, nil);
}
private func RespawnAtBase(int plr, object clonk)
{
var base = GetRelaunchBase(plr, clonk);
if (base)
return [base->GetX(), base->GetY() + base->GetBottom()];
return;
}
private func TransferInventory(object from, object to)
{
if (!from || !to) return;
// Drop some items that cannot be transferred (such as connected pipes and dynamite igniters)
var i = from->ContentsCount(), contents;
while (i--)
{
if (contents = from->Contents(i))
{
if (contents->~IsDroppedOnDeath(from))
{
contents->Exit();
}
else
{
// The new clonk doesn't burn. To be consistent, also extinguish contents
contents->Extinguish();
}
}
}
return to->GrabContents(from);
}
private func GetRelaunchBase(int plr, object clonk)
{
plr = plr ?? clonk->GetOwner();
// Neutral flagpoles are preferred respawn points, because they are used as the only respawn points in missions.
var base = FindObject(Find_ID(Flagpole), Find_Func("IsNeutral"), Sort_Random());
if (clonk)
clonk->FindObject(Find_ID(Flagpole), Find_Func("IsNeutral"), clonk->Sort_Distance());
// If there are no neutral flagpoles, find closest base owned by the player (or team) and try to buy a clonk.
if (!base)
{
base = FindObject(Find_Func("IsBaseBuilding"), Find_Allied(plr), Sort_Random());
if (clonk)
base = clonk->FindObject(Find_Func("IsBaseBuilding"), Find_Allied(plr), clonk->Sort_Distance());
}
return base;
}
public func DoRelaunch(int plr, object clonk, array position, bool no_creation)
{
if (!GetPlayerName(plr))
return;
if (respawn_last_clonk && GetCrewCount(plr) >= 1)
return;
if (respawn_at_base)
position = RespawnAtBase(plr, clonk);
position = position ?? GameCall("RelaunchPosition", plr, GetPlayerTeam(plr));
position = position ?? this->FindRelaunchPos(plr);
var spawn;
// Position array either has the form [x, y] or [[x, y], [x, y], ...].
if (GetType(position) == C4V_Array)
{
if (GetType(position[0]) == C4V_Array)
spawn = position[Random(GetLength(position))];
else
spawn = position;
}
// If no spawn has been found set it to the middle of the landscape, this should not happen.
spawn = spawn ?? [LandscapeWidth() / 2, LandscapeHeight() / 2];
var new_clonk;
if (!no_creation)
{
if (free_crew)
{
new_clonk = CreateObjectAbove(clonk_type, spawn[0], spawn[1], plr);
if (!new_clonk)
return;
new_clonk->MakeCrewMember(plr);
}
else
{
var base = GetRelaunchBase(plr, clonk);
if (!base)
return;
// Try to buy a crew member at the base.
var pay_plr = base->GetOwner();
// Payment in neutral bases by clonk owner.
if (pay_plr == NO_OWNER)
pay_plr = plr;
new_clonk = base->~DoBuy(clonk_type, plr, pay_plr, clonk);
if (new_clonk)
new_clonk->Exit();
}
}
else
{
new_clonk = GetCrew(plr);
if (!new_clonk)
return;
}
if (inventory_transfer)
TransferInventory(clonk, new_clonk);
new_clonk->SetPosition(spawn[0], spawn[1] - new_clonk->GetBottom(), plr);
if (!GetCursor(plr) || GetCursor(plr) == clonk)
SetCursor(plr, new_clonk);
new_clonk->DoEnergy(new_clonk.Energy ?? 100000);
if (relaunch_time)
{
var container = new_clonk->CreateObject(RelaunchContainer, 0, new_clonk->GetBottom(), plr);
container->SetRelaunchTime(relaunch_time, hold_crew);
container->StartRelaunch(new_clonk);
}
return true;
}
protected func FindRelaunchPos(int plr)
{
var loc = FindLocation(Loc_Or(Loc_Sky(), Loc_Tunnel()), Loc_Space(20, CNAT_Top), Loc_Wall(CNAT_Bottom));
if (loc == nil)
return nil;
return [loc.x, loc.y];
}
/*-- Scenario Saving --*/
public func SaveScenarioObject(props, ...)
{
if (!inherited(props, ...))
return false;
// Custom properties
props->Remove("Name"); // updated by initialization
props->Remove("Description"); // updated by initialization
if (inventory_transfer)
props->AddCall("InventoryTransfer", this, "SetInventoryTransfer", inventory_transfer);
if (free_crew)
props->AddCall("FreeCrew", this, "SetFreeCrew", free_crew);
if (respawn_at_base)
props->AddCall("BaseRespawn", this, "SetBaseRespawn", respawn_at_base);
return true;
}
/*-- Globals --*/
// Returns the active relaunch rule, creates one if no exists.
global func GetRelaunchRule()
{
return FindObject(Find_ID(Rule_Relaunch)) || CreateObject(Rule_Relaunch);
}
/*-- Player Relaunches --*/
public func SetPlayerRelaunchCount(int plr, int value)
{
if (HasUnlimitedRelaunches())
return;
relaunches[plr] = value;
Scoreboard->SetPlayerData(plr, "relaunches", relaunches[plr]);
return;
}
public func GetPlayerRelaunchCount(int plr)
{
return relaunches[plr];
}
public func DoPlayerRelaunchCount(int plr, int value)
{
if(HasUnlimitedRelaunches())
return;
relaunches[plr] += value;
Scoreboard->SetPlayerData(plr, "relaunches", relaunches[plr]);
return;
}
public func HasUnlimitedRelaunches()
{
return default_relaunch_count == nil;
}
/*-- Editor --*/
public func Definition(proplist def)
{
if (!def.EditorProps) def.EditorProps = {};
def.EditorProps.inventory_transfer = { Name="$InventoryTransfer$", EditorHelp="$InventoryTransferHelp$", Type="bool", Set="SetInventoryTransfer" };
def.EditorProps.free_crew = { Name="$FreeCrew$", EditorHelp="$FreeCrewHelp$", Type="bool", Set="SetFreeCrew" };
def.EditorProps.respawn_at_base = {
Name = "$RespawnAtBase$",
EditorHelp = "$RespawnAtBaseHelp$",
Type = "bool",
Set = "SetBaseRespawn"
};
def.EditorProps.hold = {
Name = "$Holding$",
EditorHelp = "$HoldingHelp$",
Type = "bool",
Set = "Setholding"
};
def.EditorProps.respawn_delay = {
Name = "$RespawnDelay$",
EditorHelp = "$RespawnDelayHelp$",
Type = "int",
Set = "SetRespawnDelay"
};
def.EditorProps.relaunch_count = {
Name = "$RelaunchCount$",
EditorHelp = "$RelaunchCountHelp$",
Type = "int",
Set = "SetDefaultRelaunchCount"
};
}
/*-- Proplist --*/
local Name = "$Name$";
local Description = "$Description$";
local Visibility = VIS_Editor;
local EditorPlacementLimit = 1; // Rules are to be placed only once

View File

@ -0,0 +1,18 @@
Name=Relaunches
Name2=Neustart am Flaggenmast
Name3=Neustart in der Basis
Description=Du wirst an einem vorgegebenen Ort in der Landschaft wiederbelebt.
Description2=Du wirst am nächstliegenden Flaggenmast wiederbelebt.
Description3=Du wirst in der nächstliegenden Basis wiederbelebt, wenn ausreichend Clonks und Clunker vorhanden sind.
InventoryTransfer=Inventar behalten
InventoryTransferHelp=Ob das Inventar sterbender Clonks beim Respawn zum neuen Clonk teleportiert werden soll.
FreeCrew=Kostenloser Respawn
FreeCrewHelp=Ob man die Clonks umsonst bekommt.
RespawnAtBase=Respawn bei der Basis
RespawnAtBaseHelp=Ob man bei der Basis spawnt.
Holding=Clonk bleibt im Container
HoldingHelp=Ob der Clonk nach Auswahl einer Waffe im Container bleibt.
RespawnDelay=Respawnzeit
RespawnDelayHelp=Zeit, die vom Tod bis zum Respawn vergeht.
RelaunchCount=Anzahl der Relaunches
RelaunchCountHelp=Anzahl der Relaunches, die man erhält. Auf -1 setzen, um unbegrenzte Relaunches zu ermöglichen.

View File

@ -0,0 +1,18 @@
Name=Relaunches
Name2=Respawn at flagpole
Name3=Base respawn
Description=You respawn at a fixed point in the map.
Description2=You respawn at the nearest respawn flagpole.
Description3=You respawn at the nearest base if sufficient clonks and clunkers are available.
InventoryTransfer=Keep inventory
InventoryTransferHelp=Whether the inventory of dying clonks is beamed to the newly respawned clonk.
FreeCrew=Free respawn
FreeCrewHelp=Whether respawning clonks are free. If not set, respawn happens only if the player has sufficient gold and clonks available for sale.
RespawnAtBase=Respawn bei der Basis
RespawnAtBaseHelp=Ob man bei der Basis spawnt.
Holding=Clonks stay in the container
HoldingHelp=Whether respawning clonks stay in the container until the respawn time ends.
RespawnDelay=Respawn delay
RespawnDelayHelp=Time from death to respawning.
RelaunchCount=Relaunch count
RelaunchCountHelp=Amount of relaunches. Set it to -1 to enable infinite relaunches.

View File

@ -1,7 +0,0 @@
[DefCore]
id=Rule_Restart
Version=8,0
Category=C4D_StaticBack|C4D_Rule
Width=32
Height=32
Offset=-16,-16

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -1,39 +0,0 @@
/*-- Restart --*/
local remove_contents;
protected func Initialize()
{
// Contents are removed
remove_contents = true;
return;
}
public func Activate(int plr)
{
// Notify scenario.
if (GameCall("OnPlayerRestart", plr))
return;
// Remove the player's clonk, including contents.
var clonk = GetCrew(plr);
if (clonk && clonk->GetCrewEnabled())
{
// Remove contents only if the Base Respawn Rule isn't there otherwise it will handle inventory
if (!ObjectCount(Find_ID(Rule_BaseRespawn)) && remove_contents)
while (clonk->Contents())
clonk->Contents()->RemoveObject();
clonk->Kill(clonk, true);
clonk->RemoveObject();
}
}
public func SetRemoveContents(bool do_removal)
{
remove_contents = do_removal;
return;
}
local Name = "$Name$";
local Description = "$Description$";
local Visibility = VIS_Editor;
local EditorPlacementLimit = 1; // Rules are to be placed only once

View File

@ -1,2 +0,0 @@
Name=Neu starten
Description=Diese Spielregel erlaubt dem Spieler nochmal von vorne zu beginnen.

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