Merge remote-tracking branch 'origin/master' into liquid_container

Conflicts will be merged in the next commit:
	planet/Objects.ocd/Items.ocd/Tools.ocd/Pipe.ocd/PipeLine.ocd/Script.c
	planet/Objects.ocd/Items.ocd/Tools.ocd/Pipe.ocd/Script.c
liquid_container
Mark 2016-03-25 17:15:39 +01:00
commit dd7bf3e89e
171 changed files with 3281 additions and 1389 deletions

View File

@ -304,7 +304,7 @@ endif()
# SDL
if(USE_SDL_MAINLOOP)
find_package(SDL2 REQUIRED)
elseif(NOT WIN32)
else()
# for gamepads
find_package(SDL2)
endif()
@ -467,20 +467,14 @@ set(OC_CLONK_SOURCES
src/game/C4FullScreen.h
src/game/C4Game.cpp
src/game/C4Game.h
src/game/C4GameScript.cpp
src/game/C4GameScript.h
src/game/C4GameVersion.h
src/game/C4GraphicsSystem.cpp
src/game/C4GraphicsSystem.h
src/game/C4Physics.h
src/game/C4Viewport.cpp
src/game/C4Viewport.h
src/gamescript/C4Effect.cpp
src/gamescript/C4Effect.h
src/gamescript/C4FindObject.cpp
src/gamescript/C4FindObject.h
src/gamescript/C4GameScript.cpp
src/gamescript/C4GameScript.h
src/gamescript/C4TransferZone.cpp
src/gamescript/C4TransferZone.h
src/graphics/Bitmap256.cpp
src/graphics/Bitmap256.h
src/graphics/C4Draw.cpp
@ -627,6 +621,8 @@ set(OC_CLONK_SOURCES
src/landscape/C4Texture.h
src/landscape/C4TextureShape.cpp
src/landscape/C4TextureShape.h
src/landscape/C4TransferZone.cpp
src/landscape/C4TransferZone.h
src/landscape/C4Weather.cpp
src/landscape/C4Weather.h
src/lib/C4LogBuf.cpp
@ -697,6 +693,8 @@ set(OC_CLONK_SOURCES
src/object/C4Def.h
src/object/C4DefList.cpp
src/object/C4DefList.h
src/object/C4FindObject.cpp
src/object/C4FindObject.h
src/object/C4GameObjects.cpp
src/object/C4GameObjects.h
src/object/C4Id.cpp
@ -910,8 +908,6 @@ elseif(USE_WIN32_WINDOWS)
list(APPEND OC_GUI_SOURCES
src/editor/C4ConsoleWin32.cpp
src/platform/C4WindowWin32.cpp
src/platform/StdJoystick.cpp
src/platform/StdJoystick.h
)
elseif(USE_COCOA)
list(APPEND OC_GUI_SOURCES
@ -1057,6 +1053,8 @@ src/script/C4AulLink.cpp
src/script/C4AulParse.cpp
src/script/C4AulScriptFunc.cpp
src/script/C4AulScriptFunc.h
src/script/C4Effect.cpp
src/script/C4Effect.h
src/script/C4PropList.cpp
src/script/C4PropList.h
src/script/C4Script.cpp
@ -1131,6 +1129,7 @@ target_link_libraries(openclonk-server
${PNG_LIBRARIES}
${JPEG_LIBRARIES}
${EXECINFO_LIBRARY}
${SDL2_LIBRARIES}
${READLINE_LIBRARIES}
${Audio_LIBRARIES}
${GETOPT_LIBRARIES}

View File

@ -17,9 +17,19 @@
# SDL2_LIBRARIES - a list of libraries to link against to use SDL2
# SDL2_FOUND - if false, SDL2 cannot be used
find_path(SDL2_INCLUDE_DIR SDL.h PATH_SUFFIXES SDL2 HINTS ENV SDL2DIR)
find_path(SDL2_INCLUDE_DIR SDL.h
HINTS
$ENV{SDL2DIR}
PATH_SUFFIXES SDL2 include
)
mark_as_advanced(SDL2_INCLUDE_DIR)
find_library(SDL2_LIBRARY SDL2 HINTS ENV SDL2DIR)
find_library(SDL2_LIBRARY
SDL2
HINTS
$ENV{SDL2DIR}
PATH_SUFFIXES lib
)
mark_as_advanced(SDL2_LIBRARY)
include(FindPackageHandleStandardArgs)

View File

@ -101,7 +101,7 @@
<row id="CONNECT">
<col>DFA_CONNECT</col>
<col>Line connections</col>
<col>Only <emlink href="definition/lineconnect.html">line objects</emlink>. Connects <emlink href="script/fn/SetAction.html">target object 1</emlink> and <emlink href="script/fn/SetAction.html">target object 2</emlink>. If property LineMaxDistance is a nonzero integer, the line breaks when the target objects are further apart than the given distance.</col>
<col>Only <emlink href="definition/lineconnect.html">line objects</emlink>. Connects <emlink href="script/fn/SetAction.html">target object 1</emlink> and <emlink href="script/fn/SetAction.html">target object 2</emlink>.</col>
<col>CNAT_None</col>
</row>
<row id="PULL">

View File

@ -188,11 +188,16 @@
<col>object by</col>
<col>Called before the object is hit or punched by another object. By returning <code>true</code>, QueryCatchBlow can reject physical blows.</col>
</row>
<row id="LineBreak">
<literal_col>LineBreak</literal_col>
<row id="OnLineBreak">
<literal_col>OnLineBreak</literal_col>
<col>int cause</col>
<col>When a line object is broken. cause: 0 by movement, 1 because of a missing or incomplete target object.</col>
</row>
<row id="OnLineChange">
<literal_col>OnLineChange</literal_col>
<col>int cause</col>
<col>When a line object is changed, that is when one of it vertices changed its position.</col>
</row>
<row id="BuildNeedsMaterial">
<literal_col>BuildNeedsMaterial</literal_col>
<col>id material_definition, int amount</col>

View File

@ -273,7 +273,7 @@
return true;
}</code>
<text>most commands (except for asynchronous commands in the player menu) call a global script function:</text>
<code>global func PlayerControl(int player, int control, C4ID control_extra, int x, int y, int strength, bool repeated, bool release)</code>
<code>global func PlayerControl(int player, int control, C4ID control_extra, int x, int y, int strength, bool repeated, int state)</code>
<text>For an explanation of the parameters see <funclink>PlayerControl</funclink>. Amongst others, the function receives the calling player in player as well as the command to be executed in control.</text>
<text>As a simple example let's assume that in the global <em>PlayerControls.txt</em> the following command has been defined:</text>
<code>[ControlDefs]
@ -293,11 +293,11 @@
Control=Jump
Priority=50</code>
<text>This defines a Jump key and the corresponding standard mapping on the keyboard for the first player. The following script is used to handle the control:</text>
<code>global func PlayerControl(int player, int control, C4ID control_extra, int x, int y, int strength, bool repeated, bool release)
<code>global func PlayerControl(int player, int control, C4ID control_extra, int x, int y, int strength, bool repeated, int state)
{
// Which command has been issued?
// The constant CON_Jump has been declared automatically through the definition in PlayerControls.txt
if (control == CON_Jump &amp;&amp; !release)
if (control == CON_Jump &amp;&amp; state == CONS_Down)
{
// pressed the jump button. The clonk selected by the player shall jump
var player_clonk = GetCursor(player);
@ -319,17 +319,17 @@
GUIDesc=Going underground
ExtraData=Shovel</code>
<text>Let shovel be the ID of a shovel object. In the global script there could be the following, generic handling for unknown commands, for example:</text>
<code>global func PlayerControl(int player, int control, C4ID control_extra, int x, int y, int strength, bool repeated, bool release)
<code>global func PlayerControl(int player, int control, C4ID control_extra, int x, int y, int strength, bool repeated, int state)
{
// Handling of known controls
// [...]
// control with own handling
if (control_extra) return control_extra-&gt;PlayerControl(player, control, x, y, strength, repeat, release);
if (control_extra) return control_extra-&gt;PlayerControl(player, control, x, y, strength, repeat, state);
// unkown control
return false;
}</code>
<text>And in the script of the shovel:</text>
<code>func PlayerControl(int player, int control, int x, int y, int strength, bool repeated, bool release)
<code>func PlayerControl(int player, int control, int x, int y, int strength, bool repeated, int state)
{
// Handling of known controls
// Control dig directly in the shovel
@ -353,6 +353,7 @@
<li>Mappings can emulate permanent key presses using the <em>Hold</em>/<em>Release</em> flags.</li>
<li><emlink href="playercontrols.xml#Repeat">Key repeats</emlink> are generated.</li>
<li>The held state of the key can be queried in the script via <funclink>GetPlayerControlState</funclink>.</li>
<li>If the command is bound to an analog stick or trigger on a controller, every change in position causes in a call to PlayerControl() with state = CONS_Moved.</li>
</ul>
</text>
<text>A good example for this functionality is a directional command:</text>
@ -362,7 +363,7 @@
GUIDesc=Walk left
Hold=1</code>
<text>In the script the direction is transferred to the Clonk:</text>
<code>global func PlayerControl(int player, int control, C4ID control_extra, int x, int y, int strength, bool repeated, bool release)
<code>global func PlayerControl(int player, int control, C4ID control_extra, int x, int y, int strength, bool repeated, int state)
{
if (control == CON_Left) return UpdateControlDir(player);
// ...

View File

@ -6,7 +6,7 @@
<func>
<title>GetPlayerControlState</title>
<category>Player</category>
<version>5.1 OC</version>
<version>5.1 OC (extended in 8.0 OC)</version>
<syntax>
<rtype>int</rtype>
<params>
@ -20,9 +20,15 @@
<name>control</name>
<desc>Control to query. A CON_* constant should be used here.</desc>
</param>
<param>
<type>bool</type>
<name>analog_strength</name>
<desc>If true: Query current state of an analog control on a gamepad instead of the emulated button state.</desc>
<optional />
</param>
</params>
</syntax>
<desc>Returns the current state of a control for a certain player. The return value is the strength of the control (e.g. for gamepad joysticks). If the control is assigned to a key, a value not equal to 0 means that the key is currently held down by the player.</desc>
<desc>Returns the current state of a control for a certain player. If the control is assigned to a key, a value not equal to 0 means that the key is currently held down by the player. For analog controls on gamepads, the function either queries the current emulated button state (analog_strength = false), or the current position of the stick or trigger (analog_strength = true).</desc>
<examples>
<example>
<code>
@ -36,4 +42,5 @@ if (GetPlayerControlState(GetOwner(), CON_Left) != 0)
</related>
</func>
<author>Zapper</author><date>2015-10</date>
<author>Luchs</author><date>2016-02</date>
</funcs>

View File

@ -0,0 +1,45 @@
<?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>PlayRumble</title>
<category>Player</category>
<version>8.0 OC</version>
<syntax>
<rtype>bool</rtype>
<params>
<param>
<type>int</type>
<name>player</name>
<desc>Number of the player whose controller should rumble. Can be NO_OWNER to make all controllers rumble.</desc>
</param>
<param>
<type>int</type>
<name>strength</name>
<desc>Strength of the rumble, between 0 and 1000.</desc>
</param>
<param>
<type>int</type>
<name>length</name>
<desc>Duration of the rumble in milliseconds.</desc>
</param>
</params>
</syntax>
<desc>Plays a haptic effect on the given player's gamepad. Returns true if all parameters are valid; there is no way to know whether the rumble was actually played.</desc>
<examples>
<example>
<code>
<funclink>ShakeObjects</funclink>(<funclink>LandscapeWidth</funclink>()/2, <funclink>LandscapeHeight</funclink>()/2, <funclink>Distance</funclink>(<funclink>LandscapeWidth</funclink>(), <funclink>LandscapeHeight</funclink>())/2);
PlayRumble(NO_OWNER, 1000, 2000);
</code>
<text>Earthquake: Shakes all Clonks and rumbles all controllers at full strength for two seconds.</text>
</example>
</examples>
<related>
<funclink>StopRumble</funclink>
</related>
</func>
<author>Luchs</author><date>2016-02</date>
</funcs>

View File

@ -0,0 +1,80 @@
<?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>PlayerControl</title>
<category>Callbacks</category>
<version>5.1 OC</version>
<syntax>
<rtype>bool</rtype>
<params>
<param>
<type>int</type>
<name>player</name>
<desc>Number of the player who pressed the control.</desc>
</param>
<param>
<type>int</type>
<name>control</name>
<desc>Number of the pressed control, defined as a CON_ constant via PlayerControls.txt.</desc>
</param>
<param>
<type>id</type>
<name>control_extra</name>
<desc>Optional id defined with ExtraData in PlayerControls.txt.</desc>
</param>
<param>
<type>int</type>
<name>x</name>
<desc>X coordinate for mouse controls.</desc>
</param>
<param>
<type>int</type>
<name>y</name>
<desc>Y coordinate for mouse controls.</desc>
</param>
<param>
<type>int</type>
<name>strength</name>
<desc>Current strength of the control. For key presses: 0 or 100. For analog stick or trigger movement (state = CONS_Moved): 0 to <code>PLRCON_MaxStrength</code>.</desc>
</param>
<param>
<type>bool</type>
<name>repeated</name>
<desc>Whether the call is generated because of a held button.</desc>
</param>
<param>
<type>int</type>
<name>state</name>
<desc>
State of the key press. Possible values:
<table>
<rowh>
<col>Constant</col>
<col>Description</col>
</rowh>
<row>
<literal_col>CONS_Down</literal_col>
<col>Key has been pressed down.</col>
</row>
<row>
<literal_col>CONS_Up</literal_col>
<col>Key has been released. Only generated for held keys.</col>
</row>
<row>
<literal_col>CONS_Moved</literal_col>
<col>An analog control on a gamepad has been moved. Only generated for held keys.</col>
</row>
</table>
</desc>
</param>
</params>
</syntax>
<desc>Called globally for each control command by players. See <emlink href="script/playercontrols.html">Player Controls</emlink>.</desc>
<related><funclink>GetPlayerControlState</funclink></related>
<related><emlink href="playercontrols.html">Player Controls</emlink></related>
</func>
<author>Luchs</author><date>2016-02</date>
</funcs>

View File

@ -0,0 +1,26 @@
<?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>StopRumble</title>
<category>Player</category>
<version>8.0 OC</version>
<syntax>
<rtype>bool</rtype>
<params>
<param>
<type>int</type>
<name>player</name>
<desc>Number of the player whose controller should stop rumbling. Can be NO_OWNER to make all controllers stop.</desc>
</param>
</params>
</syntax>
<desc>Stops a rumble effect that was started with <funclink>PlayRumble</funclink>. Returns true if the given player is valid; there is no way to know whether there was actually a playing rumble effect.</desc>
<related>
<funclink>PlayRumble</funclink>
</related>
</func>
<author>Luchs</author><date>2016-02</date>
</funcs>

View File

@ -7,10 +7,17 @@
static g_player_spawn_positions;
static g_map_width;
static g_no_map, g_seed;
// Called be the engine: draw the complete map here.
public func InitializeMap(proplist map)
{
// Don't draw a map when switching to the empty scenario section.
if (g_no_map) return true;
// Reloading the scenario section also resets the RNG. Call Random() a few times to get a new map each round.
var i = g_seed++;
while (i--) Random(2);
// Map type 0: One big island; more small islands above
// Map type 1: Only many small islands
var t = SCENPAR_MapType;

View File

@ -33,3 +33,31 @@ Default=0
Name=$WeaponsExplosive$
Description=$DescWeaponsExplosive$
Value=1
[ParameterDef]
Name=$Rounds$
Description=$DescRounds$
ID=Rounds
Default=1
[Options]
[Option]
Name=1
Value=1
[Option]
Name=2
Value=2
[Option]
Name=3
Value=3
[Option]
Name=5
Value=5
[Option]
Name=7
Value=7

View File

@ -1,7 +1,61 @@
/* Hot ice */
static g_remaining_rounds, g_winners, g_check_victory_effect;
static g_gameover;
func Initialize()
{
g_remaining_rounds = SCENPAR_Rounds;
g_winners = [];
InitializeRound();
Scoreboard->Init([
// Invisible team column for sorting players under their teams.
{key = "team", title = "", sorted = true, desc = false, default = "", priority = 90},
{key = "wins", title = "Wins", sorted = true, desc = true, default = 0, priority = 100},
{key = "death", title = "", sorted = false, default = "", priority = 0},
]);
}
// Resets the scenario, redrawing the map.
func ResetRound()
{
// Retrieve all Clonks.
var clonks = FindObjects(Find_OCF(OCF_CrewMember));
for (var clonk in clonks)
{
var container = clonk->Contained();
if (container)
{
clonk->Exit();
container->RemoveObject();
}
clonk->SetObjectStatus(C4OS_INACTIVE);
}
// Clear and redraw the map.
g_no_map = true;
LoadScenarioSection("Empty");
g_no_map = false;
LoadScenarioSection("main");
InitializeRound();
// Re-enable the players.
for (var clonk in clonks)
{
clonk->SetObjectStatus(C4OS_NORMAL);
SetCursor(clonk->GetOwner(), clonk);
// Select the first item. This fixes item ordering.
clonk->SetHandItemPos(0, 0);
InitPlayerRound(clonk->GetOwner());
}
}
func InitializeRound()
{
// Checking for victory: Only active after a Clonk dies.
g_check_victory_effect = AddEffect("CheckVictory", nil, 1, 0);
g_player_spawn_index = 0;
ShuffleArray(g_player_spawn_positions);
// Materials: Chests
var i,pos;
var ls_wdt = LandscapeWidth(), ls_hgt = LandscapeHeight();
@ -41,15 +95,37 @@ func Initialize()
if (pos=FindLocation(Loc_InRect(0,ls_hgt/2,ls_wdt,ls_hgt/3), Loc_Solid()))
if (IsFirestoneSpot(pos.x,pos.y))
CreateObjectAbove([Firestone,IronBomb][Random(Random(3))],pos.x,pos.y-1);
// The game starts after a delay to ensure that everyone is ready.
GUI_Clock->CreateCountdown(3);
return true;
}
static g_player_spawn_positions, g_map_width, g_player_spawn_index;
global func ScoreboardTeam(int team) { return team * 100; }
func InitializePlayer(int plr)
{
// Add the player and their team to the scoreboard.
Scoreboard->NewPlayerEntry(plr);
Scoreboard->SetPlayerData(plr, "wins", "");
var team = GetPlayerTeam(plr);
Scoreboard->NewEntry(ScoreboardTeam(team), GetTeamName(team));
Scoreboard->SetData(ScoreboardTeam(team), "team", "", ScoreboardTeam(team));
Scoreboard->SetPlayerData(plr, "team", "", ScoreboardTeam(team) + 1);
return InitPlayerRound(plr);
}
func InitPlayerRound(int plr)
{
// Unmark death on scoreboard.
Scoreboard->SetPlayerData(plr, "death", "");
// everything visible
SetFoW(false, plr);
SetPlayerViewLock(plr, true);
// Player positioning.
var ls_wdt = LandscapeWidth(), ls_hgt = LandscapeHeight();
var crew = GetCrew(plr), start_pos;
@ -86,13 +162,183 @@ func InitializePlayer(int plr)
{
var ammo = launcher->CreateContents(IronBomb);
launcher->AddTimer(Scenario.ReplenishLauncherAmmo, 10);
// Start reloading the launcher during the countdown.
crew->SetHandItemPos(0, crew->GetItemPos(launcher));
// This doesn't play the animation properly - simulate a click instead.
/* crew->StartLoad(launcher); */
crew->StartUseControl(CON_Use, 0, 0, launcher);
crew->StopUseControl(0, 0, launcher);
}
}
crew.MaxEnergy = 100000;
crew->DoEnergy(1000);
// Disable the Clonk during the countdown.
crew->SetCrewEnabled(false);
crew->SetComDir(COMD_Stop);
return true;
}
// Called by the round start countdown.
func OnCountdownFinished()
{
// Re-enable all Clonks.
for (var clonk in FindObjects(Find_OCF(OCF_CrewMember)))
{
clonk->SetCrewEnabled(true);
SetCursor(clonk->GetOwner(), clonk);
}
}
func OnClonkDeath(object clonk)
{
var plr = clonk->GetOwner();
// Mark death on scoreboard.
Scoreboard->SetPlayerData(plr, "death", "{{Scoreboard_Death}}");
// Skip eliminated players, NO_OWNER, etc.
if (GetPlayerName(plr))
{
var crew = CreateObject(Clonk, 0, 0, plr);
crew->MakeCrewMember(plr);
var relaunch = CreateObject(RelaunchContainer, LandscapeWidth() / 2, LandscapeHeight() / 2, plr);
// We just use the relaunch object as a dumb container.
crew->Enter(relaunch);
// Allow scrolling around the landscape.
SetPlayerViewLock(plr, false);
}
// Check for victory after three seconds to allow stalemates.
if (!g_gameover)
g_check_victory_effect.Interval = 36 * 5;
}
// Returns a list of colored player names, for example "Sven2, Maikel, Luchs"
global func GetTeamPlayerNames(int team)
{
var str = "";
for (var i = 0; i < GetPlayerCount(); i++)
{
var plr = GetPlayerByIndex(i);
if (GetPlayerTeam(plr) == team)
{
var comma = "";
if (str != "") comma = ", ";
str = Format("%s%s<c %x>%s</c>", str, comma, GetPlayerColor(plr), GetPlayerName(plr));
}
}
return str;
}
global func FxCheckVictoryTimer(_, proplist effect)
{
var find_living = Find_And(Find_OCF(OCF_CrewMember), Find_NoContainer());
var clonk = FindObject(find_living);
var msg;
if (!clonk)
{
// Stalemate!
msg = "$Stalemate$";
Log(msg);
GameCall("ResetRound");
}
else if (!FindObject(find_living, Find_Hostile(clonk->GetOwner())))
{
// We have a winner!
var team = GetPlayerTeam(clonk->GetOwner());
PushBack(g_winners, team);
// Announce the winning team.
msg = Format("$WinningTeam$", GetTeamPlayerNames(team));
Log(msg);
// Update the scoreboard.
UpdateScoreboardWins(team);
if (--g_remaining_rounds > 0 || GetLeadingTeam() == nil)
{
var msg2 = CurrentRoundStr();
Log(msg2);
msg = Format("%s|%s", msg, msg2);
GameCall("ResetRound");
}
else
{
GameCall("EliminateLosers");
}
}
// Switching scenario sections makes the Log() messages hard to see, so announce them using a message as well.
CustomMessage(msg);
// Go to sleep again.
effect.Interval = 0;
return FX_OK;
}
global func CurrentRoundStr()
{
if (g_remaining_rounds == 1)
return "$LastRound$";
else if (g_remaining_rounds > 1)
return Format("$RemainingRounds$", g_remaining_rounds);
else
return "$Tiebreak$";
}
global func UpdateScoreboardWins(int team)
{
var wins = GetTeamWins(team);
Scoreboard->SetData(ScoreboardTeam(team), "wins", wins, wins);
// We have to update each player as well to make the sorting work.
for (var i = 0; i < GetPlayerCount(); i++)
{
var plr = GetPlayerByIndex(i);
if (GetPlayerTeam(plr) == team)
{
Scoreboard->SetPlayerData(plr, "wins", "", wins);
}
}
}
global func GetTeamWins(int team)
{
var wins = 0;
for (var w in g_winners)
if (w == team)
wins++;
return wins;
}
// Returns the team which won the most rounds, or nil if there is a tie.
global func GetLeadingTeam()
{
var teams = [], winning_team = g_winners[0];
for (var w in g_winners)
{
teams[w] += 1;
if (teams[w] > teams[winning_team])
winning_team = w;
}
// Detect a tie.
for (var i = 0; i < GetLength(teams); i++)
{
if (i != winning_team && teams[i] == teams[winning_team])
return nil;
}
return winning_team;
}
func EliminateLosers()
{
g_gameover = true;
// Determine the winning team.
var winning_team = GetLeadingTeam();
// Eliminate everybody who isn't on the winning team.
for (var i = 0; i < GetPlayerCount(); i++)
{
var plr = GetPlayerByIndex(i);
if (GetPlayerTeam(plr) != winning_team)
EliminatePlayer(plr);
}
// The scenario goal will end the scenario.
}
/* Called periodically in grenade launcher */
func ReplenishLauncherAmmo()
{

View File

@ -10,3 +10,10 @@ WeaponsClassic=Klassisch
DescWeaponsClassic=Bögen, Speere, Keulen und einige Feuersteine
WeaponsExplosive=Explosiv
DescWeaponsExplosive=Nur Granatwerfer mit Endlosmunition
Rounds=Rundenzahl
DescRounds=Mehrere Runden spielen
Stalemate=Unentschieden!
WinningTeam=Gewinner: %s
RemainingRounds=Noch %d Runden.
LastRound=Letzte Runde!
Tiebreak=Entscheidende Runde!

View File

@ -10,3 +10,10 @@ WeaponsClassic=Classic
DescWeaponsClassic=Bows, spears and clubs available in chests
WeaponsExplosive=Explosive
DescWeaponsExplosive=Only grenade lauchers and wind bags available
Rounds=Number of rounds
DescRounds=Play for multiple rounds
Stalemate=Stalemate!
WinningTeam=Winning team: %s
RemainingRounds=%d rounds remaining.
LastRound=Last round!
Tiebreak=Tiebreak!

View File

@ -0,0 +1,17 @@
#appendto Goal_Melee
public func GetDescription(int plr)
{
// Count active enemy clonks.
var hostile_count = ObjectCount(Find_OCF(OCF_CrewMember), Find_NoContainer(), Find_Hostile(plr));
var message;
if (!hostile_count)
message = "$MsgGoalFulfilled$";
else
message = Format("$MsgGoalUnfulfilled$", hostile_count);
// Also report the remaining rounds.
message = Format("%s|%s", message, CurrentRoundStr());
return message;
}

View File

@ -0,0 +1,2 @@
MsgGoalFulfilled=Eure Gegner sind eliminiert.
MsgGoalUnfulfilled=Es sind noch %d Gegner im Spiel.

View File

@ -0,0 +1,2 @@
MsgGoalFulfilled=All opponents eliminated.
MsgGoalUnfulfilled=There are still %d opponents in the game.

View File

@ -58,7 +58,7 @@ protected func UpdateDraw2()
var Length = ObjectDistance(GetActionTarget(0), GetActionTarget(1));
if (GetVertexNum() > 2 || Length > max_distance)
{
LineBreak();
OnLineBreak();
return RemoveObject();
}
@ -150,7 +150,7 @@ public func SetConnectedObjects(obj1, obj2)
obj1->AddCableConnection(this);
}
protected func LineBreak(bool no_msg)
protected func OnLineBreak(bool no_msg)
{
Sound("Objects::Connect");
if (!no_msg)

View File

@ -13,3 +13,6 @@ StartupPlrSelBG.jpg
StartupScenSelBG.jpg)
Loader1.jpg - Nachtfalter
ControllerIcons.png - Nicolae Berbece (http://opengameart.org/content/free-keyboard-and-controllers-prompts-pack)
License: CC0

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

View File

@ -1,5 +1,5 @@
// Max distance for pipe line
// Max distance for pipe line.
#appendto PipeLine
local LineMaxDistance = 500;
local PipeMaxLength = 600;

View File

@ -0,0 +1,3 @@
Model by pluto
--------------
Model, texture and animations.

View File

@ -0,0 +1,19 @@
[DefCore]
id=Mooq
Version=7,0,0,0
Category=C4D_Living
Width=20
Height=12
Offset=-10,-6
Vertices=7
VertexX= 0, 0,0,-5,5,-5, 5
VertexY= 0,-5,5, 1,1,-1,-1
VertexCNAT=0, 4,8, 1,2, 1, 2
VertexFriction=300,300,100,300,300,300,300
Mass=250
NoGet=1
Float=0
StretchGrowth=1
IncompleteActivity=1
Oversize=1
Pathfinder=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

View File

@ -0,0 +1,3 @@
[Particle]
Name=Clusterflight
Face=0,0,64,64,-32,-32

View File

@ -0,0 +1,12 @@
[DefCore]
id=Mooq_Firebomb
Version=7,0,0,0
Category=C4D_Vehicle
Width=5
Height=5
Offset=-3,-3
Value=10
Mass=10
Vertices=1
VertexY=1
VertexFriction=20

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 B

View File

@ -0,0 +1,70 @@
/*-- Firebomb --*/
static const FIREBOMB_DAMAGE = 70;
func Initialize() {
SetAction("Fly");
}
func Hit() {
var dmg = FIREBOMB_DAMAGE;
BlastObjects(GetX(), GetY(), dmg/2, 0, GetOwner() + 1);
BlastObjects(GetX(), GetY(), dmg/2, 0, GetOwner() + 1);
var blast = {
R = 255,
G = 255,
B = 255,
Size = (dmg*13)/20, // /10
Phase = PV_Linear(0, 21),
DampingX = 1000,
DampingY = 1000,
BlitMode = GFX_BLIT_Additive
};
CreateParticle("Blast", 0, 0, 0, 0, 21, blast, 1);
Call("ExplosionEffect", dmg/2, 0, 0, 0);
RemoveObject();
}
func Sparkle() {
if(Contained())
return false;
var clusterflight = {
R = 200 + Random(55),
G = 200 + Random(55),
B = 200 + Random(55),
Alpha = PV_Linear(255, 0), //AlphaFade=4
Size = 16, //40
Phase = PV_Linear(0, 9),
Rotation = PV_Random(360),
DampingX = 1000,
DampingY = 1000,
//Attach = ATTACH_MoveRelative
};
CreateParticle("Clusterflight", 0, 0, RandomX(-2,2),RandomX(-2,2), 36, clusterflight, 1);
}
local BorderBound = C4D_Border_Sides;
/* Act Map */
local ActMap = {
Fly = {
Prototype = Action,
Name = "Fly",
Procedure = nil,
Length = 1,
Delay = 1, // 1
NextAction = "Fly",
FacetBase = 1,
PhaseCall = "Sparkle",
},
};

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 794 KiB

View File

@ -0,0 +1,927 @@
/**
Mooq
Author: jok
*/
// Animations
local turn_angle;
// Color
local color;
// The closest enemy that has been found.
local enemy;
// Closest food that has been found.
local food;
public func Place(int amount, proplist rectangle, proplist settings)
{
var max_tries = 3 * amount;
var loc_area = nil;
if (rectangle) loc_area = Loc_InArea(rectangle);
var animal;
while ((amount > 0) && (--max_tries > 0))
{
// Try to find walkable ground near lava.
var lava_spot = FindLocation(Loc_Material("DuroLava"));
var ground_spot = nil;
if (lava_spot)
{
var lava_rectangle = Shape->Rectangle(lava_spot.x - 200, lava_spot.y - 200, 400, 400);
// Make sure the position is inside the required target rectangle.
lava_rectangle = Shape->Intersect(lava_rectangle, rectangle)->GetBoundingRectangle();
ground_spot = FindLocation(Loc_Wall(CNAT_Bottom), Loc_Or(Loc_Sky(), Loc_Tunnel()), Loc_Space(20, CNAT_Top), Loc_InArea(lava_rectangle));
}
// If no hip and cool spot found, just get some generic spot.
if (!ground_spot) ground_spot = FindLocation(Loc_Wall(CNAT_Bottom), Loc_Or(Loc_Sky(), Loc_Tunnel()), Loc_Space(20, CNAT_Top), loc_area);
if (!ground_spot) continue;
animal = CreateObjectAbove(this, ground_spot.x, ground_spot.y, NO_OWNER);
if (!animal) continue;
if (animal->Stuck())
{
animal->RemoveObject();
continue;
}
--amount;
}
return animal;
}
func Construction()
{
turn_angle = -60;
color = 255;
AddEffect("IntActivity", this, 1, 10, this);
AddTimer("UpdateEnemy", 30);
AddTimer("UpdateFood", 60);
Stop();
CheckTurn(GetDir());
SetTailOnFire();
SetCreatureControlled();
}
func Death()
{
RemoveTimer("UpdateEnemy");
RemoveTimer("UpdateFood");
RemoveEffect("IntActivity", this);
Sound("Animals::Mooq::Die*");
}
func CatchBlow(int damage, object from)
{
Schedule(this, "Sound(\"Animals::Mooq::Hurt*\")", RandomX(5, 20));
}
/* Action Callbacks */
func CheckStuck()
{
// Prevents getting stuck on middle vertex
if(!GetXDir())
if(Abs(GetYDir()) < 5)
if(GBackSolid(0, 3))
SetPosition(GetX(), GetY() - 1);
}
func ClearActivity()
{
this.Activity = nil;
}
func StartSwim()
{
this.Activity = this.ActivitySwimming;
}
func StartWalk()
{
SetTailOnFire();
this.Activity = this.ActivityWalking;
}
func SpitPhase()
{
if(GetActTime() > 45 && GetActTime() < 65)
{
if(!Random(4))
{
var iX, iY;
iX = 5;
if (!GetDir()) iX = -iX;
iY = -4;
Smoke(iX,iY,5);
}
}
if(GetActTime() == 58)
{
var iX, iY, iXDir, iYDir;
iX = 10;
if (!GetDir()) iX = -iX;
iY = -4;
iXDir = 300;
if (!GetDir()) iXDir = -iXDir;
iYDir = -300;
Sound("Animals::Mooq::Spit*");
var obj = CreateContents(Mooq_Firebomb);
obj->Exit(iX, iY);
obj->SetXDir(iXDir,100);
obj->SetYDir(iYDir,100);
}
}
func EatPhase()
{
var actt = GetActTime();
if(actt > 13 && actt < 25)
{
if(!Random(4))
{
var iX, iY;
iX = 5;
if (!GetDir()) iX = -iX;
iY = 4;
Smoke(iX,iY,5);
}
}
if(actt == 22)
{
if (!food) return;
Sound("Animals::Mooq::Munch*");
DoEnergy(food->GetMass());
food->RemoveObject();
}
if(actt > 43 && actt < 55)
{
if(!Random(4))
{
var iX, iY;
iX = 5;
if (!GetDir()) iX = -iX;
iY = 1;
Smoke(iX,iY,5);
}
}
}
/* Activity */
func ActivitySwimming()
{
CheckBreathe();
if(GetMaterial() == Material("Water"))
CheckFossilize();
// Stuck?
if (GetComDir() && !GetXDir() && !GetYDir())
{
DoJump(true);
return Swim(Random(2));
}
// Fossilizing?
if(GetEffect("IntFossilizing", this))
{
var lava_spot = FindLava();
if (lava_spot)
return TaskSwimTo(lava_spot);
}
if (enemy && Random(2)) return TaskSwimTo(enemy);
if (!enemy && food) return TaskSwimTo(food);
if (!Random(6)) return Swim(Random(2));
if (!Random(6)) return DoJump(true);
}
func ActivityWalking()
{
// Stuck?
if (GetComDir() && !GetXDir() && !GetYDir())
{
if(GetDir())
Walk(0);
else
Walk(1);
return DoJump();
}
// Fossilizing?
if(GetEffect("IntFossilizing", this))
{
var lava_spot = FindLava();
if (lava_spot) return TaskWalkTo(lava_spot);
}
// If enemy, hopefully attack!
if (enemy)
{
var distance = ObjectDistance(this, enemy);
if (distance < 50 && Random(2)) return TaskHeadbutt(distance);
if (Inside(distance, 85, 145) && !Random(5)) return TaskSpit();
}
// If no enemy, go to food and eat.
if (!enemy && food) return TaskFood();
// If not walking, randomly idle.
if (GetAction() == "Stand")
{
if (!enemy && !food)
{
// Idle?
if (!Random(15)) return TaskIdle();
}
if (!Random(5)) return Walk(Random(2));
return;
}
if (!Random(5)) return Stop();
if (!Random(5)) return Walk(Random(2));
if (GetAction() == "Walk")
{
if (!Random(5)) return DoJump();
}
// Anticipate holes in the landscape while walking.
}
func FxIntActivityTimer(target, effect, time)
{
if (this.Activity) this->Activity();
if (!GetAlive()) return -1;
return 1;
}
func FxIntActivityDamage(target, effect, dmg)
{
if (dmg > 0) return dmg;
return dmg;
}
/* Tasks */
func TaskIdle()
{
Sound("Animals::Mooq::Snorting*");
if (!Random(3)) return SetAction("IdleSit");
if (!Random(2)) return SetAction("IdleStand");
return SetAction("IdleTailwave");
}
func TaskFood()
{
var distance = ObjectDistance(this, food);
if (distance < 11) return Eat();
return TaskWalkTo(food);
}
func TaskHeadbutt(distance)
{
if (distance < 11) return Headbutt();
return TaskWalkTo(enemy);
}
func TaskSpit()
{
var eX = enemy->GetX();
var iX = GetX();
if (iX < eX)
{
if (GetDir() != DIR_Right) return Turn(DIR_Right);
Stop();
return Spit();
} else {
if (GetDir() != DIR_Left) return Turn(DIR_Left);
Stop();
return Spit();
}
}
func TaskWalkTo(spot)
{
var iX = GetX();
var iY = GetY();
if (GetType(spot) == C4V_C4Object)
{
var sX = spot->GetX();
var sY = spot->GetY();
}
else if (GetType(spot) == C4V_PropList)
{
var sX = spot.x;
var sY = spot.y;
}
else return;
if (iX < sX)
{
if (GetDir() == DIR_Right)
if (iY > sY + 6)
if (Random(2)) if(DoJump())
return true;
return Walk(DIR_Right);
} else {
if (GetDir() == DIR_Left)
if(iY > sY + 6)
if(Random(2)) if(DoJump())
return true;
return Walk(DIR_Left);
}
}
func TaskSwimTo(spot)
{
var iX = GetX();
var iY = GetY();
if (GetType(spot) == C4V_C4Object)
{
var sX = spot->GetX();
var sY = spot->GetY();
}
else if (GetType(spot) == C4V_PropList)
{
var sX = spot.x;
var sY = spot.y;
}
else return;
if (iX < sX)
{
if (GetDir() == DIR_Right)
if(iY > sY)
if(DoJump(true))
return true;
return Swim(DIR_Right);
} else {
if (GetDir() == DIR_Left)
if(iY > sY)
if(DoJump(true))
return true;
return Swim(DIR_Left);
}
}
/* Actions */
func Stop()
{
SetComDir(COMD_Stop);
SetXDir(0);
return SetAction("Stand");
}
func Turn(int dir, bool move)
{
if (dir == nil)
{
if (GetDir() == DIR_Left)
dir = DIR_Right;
else
dir = DIR_Left;
}
if(GetDir() == dir) return;
return CheckTurn(dir, move);
}
func Walk(int dir)
{
if (GetAction() != "Stand" && GetAction() != "Walk") return;
if (GetDir() == dir)
{
SetAction("Walk");
if (GetDir())
return SetComDir(COMD_Right);
else
return SetComDir(COMD_Left);
}
return Turn(dir, true);
}
func Swim(int dir)
{
if (GetAction() != "Swim") return;
if (GetDir() == dir)
{
SetAction("Swim");
if (GetDir())
return SetComDir(COMD_UpRight);
else
return SetComDir(COMD_UpLeft);
}
return Turn(dir, true);
}
func DoJump(bool swimming)
{
if (GetAction() != "Walk" && GetAction() != "Stand" && GetAction() != "Swim") return;
if (swimming)
{
if (GBackSky(0, -2))
SetPosition(GetX(), GetY() - 2);
else
return;
var iX, iY, iXDir, iYDir;
iX = 10;
if (!GetDir()) iX = -iX;
iY = -4;
iXDir = 200;
if (!GetDir()) iXDir = -iXDir;
iYDir = -200;
if (Random(2)) Sound("Animals::Mooq::Snort*");
SetSpeed(iXDir + GetXDir(100), iYDir + GetYDir(100), 100);
return true;
}
if (Random(2)) Sound("Animals::Mooq::Snort*");
return Jump();
}
func Spit()
{
if (GetAction() == "Stand") return SetAction("Spit");
}
func Eat(object food)
{
Stop();
if (GetAction() == "Stand") return SetAction("Eat");
}
func Headbutt()
{
if (GetAction() != "Walk") return;
Punch(enemy, 10);
return SetAction("Headbutt");
}
/* FindEnemy */
func UpdateEnemy()
{
// Already disposed of the last one?
if (enemy && !enemy->GetAlive()) enemy = nil;
// Last one too far away now?
if (enemy && ObjectDistance(this, enemy) > 250) enemy = nil;
// Slid in water?
if (enemy && enemy->GBackLiquid()) enemy = nil;
var x = GetX();
var y = GetY();
for (var obj in FindObjects(Find_Distance(200), Find_OCF(OCF_Alive), Find_Hostile(GetOwner()), Sort_Distance()))
{
if (!PathFree(x, y, obj->GetX(), obj->GetY())) continue;
if (obj->GBackLiquid()) continue;
enemy = obj;
return;
}
}
/* FindFood */
func UpdateFood()
{
// Need food?
if (GetEnergy() >= MaxEnergy/1000) return food = nil;
// Last one too far away now?
if (food && ObjectDistance(this, food) > 150) food = nil;
// Slid in water?
if (food && food->GBackLiquid()) food = nil;
var x = GetX();
var y = GetY();
var Find_FoodIDs = Find_Or(Find_ID(Rock), Find_ID(Coal), Find_ID(Ore));
for (var obj in FindObjects(Find_Distance(100), Find_FoodIDs, Sort_Distance()))
{
if (!PathFree(x, y, obj->GetX(), obj->GetY())) continue;
if (obj->GBackLiquid()) continue;
food = obj;
return;
}
}
/* FindLava */
func FindLava()
{
var lava_spot = FindLocation(Loc_Material("DuroLava"), Loc_Space(20));
if (lava_spot) return lava_spot;
var lava_spot = FindLocation(Loc_Material("Lava"), Loc_Space(20));
if (lava_spot) return lava_spot;
return;
}
/* Turning */
func CheckTurn(int dir, bool move)
{
if (!GetEffect("IntTurning", this))
{
SetDir(dir);
AddEffect("IntTurning", this, 1, 1, this, nil, move);
return true;
}
return false;
}
func FxIntTurningStart(object target, effect fx, temp, move)
{
fx.mvmn = move;
if (!InLiquid())
{
Stop();
SetAction("Turn");
} else {
SetComDir(COMD_Stop);
SetXDir(0);
SetAction("SwimTurn");
}
if (temp) return true;
}
func FxIntTurningTimer(object target, effect fx, int time)
{
if (GetDir() == DIR_Left)
turn_angle += 15;
else
turn_angle -= 15;
if (turn_angle < -60 || turn_angle > 180)
{
turn_angle = BoundBy(turn_angle, -60, 180);
this.MeshTransformation = Trans_Rotate(turn_angle + 180 + 30,0,1,0);
return -1;
}
this.MeshTransformation = Trans_Rotate(turn_angle + 180 + 30,0,1,0);
return 1;
}
func FxIntTurningStop(object target, effect fx, temp)
{
if (fx.mvmn)
{
if (!InLiquid())
{
if (GetDir()) SetComDir(COMD_Right);
else SetComDir(COMD_Left);
return SetAction("Walk");
}
if (GetDir()) SetComDir(COMD_UpRight);
else SetComDir(COMD_UpLeft);
return SetAction("Swim");
}
}
/* Breathing */
func CheckBreathe()
{
if (!GetEffect("IntBreathing", this)) AddEffect("IntBreathing", this, 1, 1, this, nil);
}
func FxIntBreathingStart(object target, effect fx, temp)
{
if (temp) return true;
}
func FxIntBreathingTimer(object target, effect fx, int time)
{
DoBreath(MaxBreath - GetBreath());
if (!InLiquid()) return -1;
return 1;
}
/* Fossilizing */
func CheckFossilize()
{
if (!GetEffect("IntFossilizing", this))
// Ca. 60 seconds till death without lava
AddEffect("IntFossilizing", this, 1, 11, this, nil);
}
func FxIntFossilizingStart(object target, effect fx, temp)
{
if (temp) return true;
}
func FxIntFossilizingTimer(object target, effect fx, int time)
{
if (GetMaterial() == Material("DuroLava") || GetMaterial() == Material("Lava"))
{
color++;
if (Speed < MaxSpeed) Speed += Random(2);
if (JumpSpeed < MaxJumpSpeed)
{
JumpSpeed += Random(3);
if(JumpSpeed > MaxJumpSpeed) JumpSpeed = MaxJumpSpeed;
}
} else {
color--;
if (Speed > 0) Speed -= Random(2);
if (JumpSpeed > 0)
{
JumpSpeed -= Random(3);
if(JumpSpeed < 0) JumpSpeed = 0;
}
}
if (color < 45 || color > 255)
{
color = BoundBy(color, 45, 255);
SetClrModulation(RGBa(color, color, color, 255));
return -1;
}
SetClrModulation(RGBa(color, color, color, 255));
return 1;
}
func FxIntFossilizingStop(object target, effect fx, temp)
{
if (GetMaterial() == Material("DuroLava") || GetMaterial() == Material("Lava")) return SetAction("Swim");
else return Kill();
}
/* Burning Tail */
func SetTailOnFire()
{
if (!GetEffect("IntTailBurning", this))
AddEffect("IntTailBurning", this, 1, 2, this, nil);
}
func FxIntTailBurningStart(object target, effect fx, temp)
{
fx.fire = {
R = 200 + Random(55),
G = 200 + Random(55),
B = 200 + Random(55),
Alpha = PV_Linear(255, 0),
Size = 4,
Phase = PV_Linear(0, 9),
DampingX = 1000,
DampingY = 1000,
Attach = ATTACH_MoveRelative
};
if (temp) return true;
}
func FxIntTailBurningTimer(object target, effect fx, int time)
{
if (!GetAlive() || InLiquid())
{
var level;
level = 5 ?? 10;
var particles = Particles_Smoke();
particles.Size = PV_Linear(PV_Random(level/2, level), PV_Random(2 * level, 3 * level));
var pos = [3, -1, 0];
var dir = [PV_Random(-level/3, level/3), PV_Random(-level/2, -level/3), 0];
CreateParticleAtBone("Smoke", "tail_3", pos, dir, PV_Random(level * 2, level * 10), particles, BoundBy(level/5, 3, 20));
return -1;
}
var pos = [3, -1, 0];
var dir = [0, 0, 0];
CreateParticleAtBone("Fire", "tail_3", pos, dir, 5, fx.fire, 1);
return 1;
}
/* ActMap */
local ActMap = {
Walk = {
Prototype = Action,
Name = "Walk",
Procedure = DFA_WALK,
Speed = Speed,
Accel = 4,
Decel = 22,
Directions = 2,
FlipDir = 0,
Length = 12,
Delay = 1,
Animation = "Walk",
StartCall = "StartWalk",
InLiquidAction = "Swim",
},
Swim = {
Prototype = Action,
Name = "Swim",
Procedure = DFA_SWIM,
Speed = Speed,
Accel = 16,
Decel = 22,
Directions = 2,
FlipDir = 0,
Length = 12,
Delay = 1,
Animation = "Swim",
StartCall = "StartSwim",
},
Jump = {
Prototype = Action,
Name = "Jump",
Procedure = DFA_FLIGHT,
Speed = 200,
Accel = 14,
Directions = 2,
FlipDir = 0,
Length = 20,
Delay = 1,
Animation = "Jump",
NextAction = "Hold",
PhaseCall = "CheckStuck",
StartCall = "ClearActivity",
InLiquidAction = "Swim",
},
Dead = {
Prototype = Action,
Name = "Dead",
Directions = 2,
FlipDir = 0,
Length = 30,
Delay = 1,
Animation = "Death",
NextAction = "Hold",
StartCall = "ClearActivity",
NoOtherAction = 1,
ObjectDisabled = 1,
},
Stand = {
Prototype = Action,
Name = "Stand",
Procedure = DFA_WALK, //DFA_THROW
Directions = 2,
FlipDir = 0,
Length = 90,
Delay = 1,
Animation = "Stand",
NextAction = "Stand",
StartCall = "StartWalk",
InLiquidAction = "Swim",
},
Turn = {
Prototype = Action,
Name = "Turn",
Procedure = DFA_THROW,
Directions = 2,
FlipDir = 0,
Length = 16,
Delay = 1,
Animation = "Walk",
NextAction = "Stand",
StartCall = "ClearActivity",
},
SwimTurn = {
Prototype = Action,
Name = "SwimTurn",
Procedure = DFA_THROW,
Directions = 2,
FlipDir = 0,
Length = 16,
Delay = 1,
Animation = "Swim",
NextAction = "Swim",
StartCall = "ClearActivity",
},
Spit = {
Prototype = Action,
Name = "Spit",
Procedure = DFA_THROW,
Directions = 2,
FlipDir = 0,
Length = 90,
Delay = 1,
Animation = "SitMouthOpen",
NextAction = "Stand",
PhaseCall = "SpitPhase",
StartCall = "ClearActivity",
InLiquidAction = "Swim",
},
Eat = {
Prototype = Action,
Name = "Eat",
Procedure = DFA_NONE,
Directions = 2,
Length = 60,
Delay = 1,
Animation = "Eat",
PhaseCall = "EatPhase",
StartCall = "ClearActivity",
NextAction = "Stand",
InLiquidAction = "Swim",
Attach=CNAT_Bottom,
},
Headbutt = {
Prototype = Action,
Name = "Headbutt",
Procedure = DFA_THROW,
Directions = 2,
FlipDir = 0,
Length = 12,
Delay = 1,
Animation = "Headbutt",
StartCall = "ClearActivity",
NextAction = "Stand",
InLiquidAction = "Swim",
},
IdleStand = {
Prototype = Action,
Name = "IdleStand",
Procedure = DFA_THROW,
Directions = 2,
FlipDir = 0,
Length = 32,
Delay = 1,
Animation = "IdleStand",
NextAction = "Stand",
InLiquidAction = "Swim",
StartCall = "ClearActivity",
},
IdleSit = {
Prototype = Action,
Name = "IdleSit",
Procedure = DFA_THROW,
Directions = 2,
FlipDir = 0,
Length = 64,
Delay = 1,
Animation = "IdleSit",
NextAction = "Stand",
InLiquidAction = "Swim",
StartCall = "ClearActivity",
},
IdleTailwave = {
Prototype = Action,
Name = "IdleTailwave",
Procedure = DFA_THROW,
Directions = 2,
FlipDir = 0,
Length = 16,
Delay = 1,
Animation = "IdleTailwave",
NextAction = "Stand",
InLiquidAction = "Swim",
StartCall = "ClearActivity",
},
};
local Name = "$Name$";
local Description = "$Description$";
local MaxEnergy = 250000;
local MaxBreath = 720; // Mooq can breathe for 20 seconds under water. // But it haz special effects ignoring MaxBreath.
local MaxSpeed = 100;
local Speed = MaxSpeed;
local MaxJumpSpeed = 300;
local JumpSpeed = MaxJumpSpeed;
local NoBurnDecay = 1;
local BorderBound = C4D_Border_Sides;
local ContactCalls = true;

View File

@ -0,0 +1,2 @@
Name=Mooq
Description=Süße kleine Kreatur. Mag Lava.

View File

@ -0,0 +1,2 @@
Name=Mooq
Description=Cute little creature. Likes lava.

View File

@ -79,7 +79,7 @@ private func UpdateVision()
private func BiteEffect()
{
Sound("Animals::Fish::Munch*", nil, nil, nil, nil, nil, 100);
Sound("Animals::Fish::Munch*", {pitch = 100});
}
local Name = "$Name$";

View File

@ -61,6 +61,14 @@ public func FxIntActivityTimer(object target, proplist effect, int time)
if (Contained())
return FX_OK;
// Start digging if stuck.
if (Stuck())
{
SetAction("Dig");
SetDigDirection(Random(2) * 2 - 1, Random(2) * 2 - 1);
return FX_OK;
}
// Actions when standing.
if (IsStanding())
{
@ -115,6 +123,10 @@ public func FxIntActivityTimer(object target, proplist effect, int time)
// Actions on digging.
if (IsDigging())
{
// If the wipf if stuck while digging digfree the full wipf's shape.
if (Stuck())
DigFree(GetX(), GetY(), 8);
// Change digging direction.
if (!Random(3))
{

View File

@ -170,7 +170,7 @@ private func CheckTurn()
private func AngryBuzz()
{
Sound("Animals::Zap::Zap?", nil,nil,nil,nil, nil, -Random(100));
Sound("Animals::Zap::Zap?", {pitch = -Random(100)});
}
/*-- Saving --*/
@ -248,4 +248,4 @@ local MaxBreath = 250;
local Placement = 2;
local NoBurnDecay = 1;
local BorderBound = C4D_Border_Sides | C4D_Border_Top | C4D_Border_Bottom;
local ContactCalls = true;
local ContactCalls = true;

View File

@ -11,14 +11,25 @@ local current_objects;
// Overload contents callback for the interaction menu.
public func Contents(int index)
{
RefreshIfNecessary();
if (index < 0 || index >= GetLength(current_objects)) return nil;
return current_objects[index];
}
public func ContentsCount()
{
RefreshIfNecessary();
return GetLength(current_objects);
}
private func RefreshIfNecessary()
{
if (last_search_frame != FrameCounter())
{
current_objects = GetPossibleObjects();
last_search_frame = FrameCounter();
}
if (index < 0 || index >= GetLength(current_objects)) return nil;
return current_objects[index];
}
private func GetPossibleObjects(id limit_definition)

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -0,0 +1,3 @@
[Particle]
Name=Hail
Face=0,0,35,35,-17,-17

Binary file not shown.

After

Width:  |  Height:  |  Size: 405 B

View File

@ -0,0 +1,2 @@
DE:Regentropfen
US:Raindrop

View File

@ -0,0 +1,3 @@
[Particle]
Name=Raindrop
Face=0,0,32,128,-16,-64

Binary file not shown.

After

Width:  |  Height:  |  Size: 879 B

View File

@ -0,0 +1,3 @@
[Particle]
Name=RaindropLava
Face=0,0,32,128,-16,-64

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 B

View File

@ -0,0 +1,2 @@
DE:Regentropfen
US:Raindrop

View File

@ -0,0 +1,3 @@
[Particle]
Name=RaindropSmall
Face=0,0,64,64,-32,-32

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -0,0 +1,2 @@
DE:Schneeflocke
US:Snow flake

View File

@ -0,0 +1,3 @@
[Particle]
Name=RaindropSnow
Face=0,0,16,16,-8,-8

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

@ -0,0 +1,2 @@
DE:Regentropfen
US:Raindrop

View File

@ -0,0 +1,3 @@
[Particle]
Name=RaindropSplash
Face=0,0,32,32,-16,-16

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -0,0 +1,2 @@
DE:Regentropfen
US:Raindrop

View File

@ -0,0 +1,3 @@
[Particle]
Name=RaindropSplashLiquid
Face=0,0,100,32,-50,-32

View File

@ -26,6 +26,7 @@ local rain_amount; // Precipitation amount from scenario or other.
local rain_max; // Max rain the cloud can hold.
local rain_mat_freeze_temp; // Freezing temperature of current rain material.
local rain_mat_frozen; // Material currently frozen to.
local rain_visual_strength; // Amount of rain particles
local cloud_shade; // Cloud shade.
local cloud_alpha; // Cloud alpha.
@ -43,6 +44,7 @@ protected func Initialize()
// Default values for rain.
rain = 0;
rain_max = 960;
rain_visual_strength = 10;
// Cloud defaults
lightning_chance = 0;
@ -138,6 +140,22 @@ public func SetRain(int to_rain)
return;
}
// Sets the strength of the visual particle rain.
// Also an id call: Changes all clouds to this settings.
public func SetVisualRainStrength(int to)
{
// Called to proplist: change all clouds.
if (this == Cloud)
{
for (var cloud in FindObjects(Find_ID(Cloud)))
cloud->SetVisualRainStrength(to);
}
else
{
rain_visual_strength = to;
}
}
// Changes the color of this cloud.
// Also an id call: Changes all clouds to this settings.
@ -180,6 +198,19 @@ protected func FxProcessCloudTimer()
// Change mode, reset timer.
mode = (mode + 1) % 3;
mode_time = 480 + RandomX(-90, 90);
// Start or stop the rain sound.
// TODO: Sound should play where the rain hits the ground, not where the cloud is.
if (mode == CLOUD_ModeRaining)
{
var mat = RainMat();
if (mat == "Water" || mat == "Acid")
Sound("Liquids::StereoRain", false, 80, nil, +1, 1000);
}
else
{
Sound("Liquids::StereoRain",,,, -1);
}
}
// Process modes.
/*if (mode == CLOUD_ModeIdle)
@ -249,28 +280,138 @@ private func Precipitation()
return;
}
// Check if liquid is maybe in frozen form.
private func RainMat()
{
if (rain_mat_freeze_temp != nil && GetTemperature() < rain_mat_freeze_temp)
return rain_mat_frozen;
else
return rain_mat;
}
local last_raindrop_color = nil;
local particle_cache;
// Raindrop somewhere from the cloud.
private func RainDrop()
{
// Find Random Position.
var con = GetCon();
var wdt = GetDefWidth() * con / 500;
var hgt = GetDefHeight() * con / 700;
var x = RandomX(-wdt, wdt);
var y = RandomX(-hgt, hgt);
if (!GBackSky(x, y))
return false;
// Check if liquid is maybe in frozen form.
var mat;
if (rain_mat_freeze_temp != nil && GetTemperature() < rain_mat_freeze_temp)
mat = rain_mat_frozen;
var mat = RainMat();
var particle_name = "Raindrop";
var color = GetMaterialColor(mat);
if (color != last_raindrop_color)
{
particle_cache = {};
last_raindrop_color = color;
}
if (mat == "Lava" || mat == "DuroLava")
particle_name = "RaindropLava";
if (mat == "Snow")
particle_cache.snow = particle_cache.snow ?? Particles_Snow(color);
else
mat = rain_mat;
// Create rain drop.
CastPXS(mat, 1, 1, x, y);
particle_cache.rain = particle_cache.rain ?? Particles_Rain(color);
var count = Max(rain_visual_strength, 1);
for (var i = 0; i < count; i++)
{
var x = RandomX(-wdt, wdt);
var y = RandomX(-hgt, hgt);
var xdir = RandomX(GetWind(0,0,1)-5, GetWind(0,0,1)+5)/5;
var ydir = 30;
if (!GBackSky(x, y))
continue;
if(mat == "Ice")
{
// Ice (-> hail) falls faster.
xdir *= 4;
ydir *= 4;
}
// Snow is special.
if(mat == "Snow")
{
CreateParticle("RaindropSnow", x, y, xdir, 10, PV_Random(2000, 3000), particle_cache.snow, 0);
if (!i)
CastPXS(mat, 1, 0, x, y);
continue;
}
var particle = new particle_cache.rain {};
if(Random(2))
particle.Attach = ATTACH_Back;
CreateParticle(particle_name, x, y, xdir, ydir, PV_Random(200, 300), particle, 0);
// Splash.
if (!i)
{
var hit = SimFlight(x, y, xdir, ydir, 25 /* Liquid */, nil, nil, 3);
var x_final = hit[0], y_final = hit[1], time_passed = hit[4];
if (time_passed > 0)
{
ScheduleCall(this, "DropHit", time_passed, 0, mat, color, x_final, y_final);
}
}
}
return true;
}
// Checks whether the given material might smoke when in contact with water.
private func SmokeyMaterial(string material_name)
{
var mat = Material(material_name);
return GetMaterialVal("Corrosive", "Material", mat) || GetMaterialVal("Incendiary", "Material", mat);
}
private func DropHit(string material_name, int color, int x_orig, int y_orig)
{
// Adjust position so that it's in the air.
var x = AbsX(x_orig), y = AbsY(y_orig);
while (GBackSemiSolid(x, y - 1)) y--;
InsertMaterial(Material(material_name), x, y - 1);
// Some materials cast smoke when hitting water.
if (GetMaterial(x,y) == Material("Water") && SmokeyMaterial(material_name))
{
Smoke(x, y, 3, RGB(150,160,150));
}
// Liquid? liquid splash!
else if(GBackLiquid(x,y))
{
particle_cache.splash_water = particle_cache.splash_water ?? Particles_SplashWater(color);
CreateParticle("RaindropSplashLiquid", x, y - 3, 0, 0, 20, particle_cache.splash_water);
}
// Solid? normal splash!
else
{
if( (material_name == "Acid" && GetMaterial(x,y) == Material("Earth")) || material_name == "Lava" || material_name == "DuroLava")
Smoke(x, y, 3, RGB(150,160,150));
CreateParticle("RaindropSplash", x, y-1, 0, 0, 5, Particles_Splash(color), 0);
if(material_name == "Ice")
{
particle_cache.hail = particle_cache.hail ?? Particles_Hail(color);
CreateParticle("Hail", x, y, RandomX(-2,2), -Random(10), PV_Random(300, 300), particle_cache.hail, 0);
}
else
{
particle_cache.small_rain = particle_cache.small_rain ?? Particles_RainSmall(color);
CreateParticle("RaindropSmall", x, y, RandomX(-4, 4), -Random(10), PV_Random(300, 300), particle_cache.small_rain, 0);
}
}
}
private func GetMaterialColor(string name)
{
// A Material's color is actually defined by its texture.
var texture = GetMaterialVal("TextureOverlay", "Material", Material(name));
return GetAverageTextureColor(texture);
}
// Launches possibly one thunder strike from the cloud.
private func ThunderStrike()
{

View File

@ -1105,6 +1105,35 @@ func FxIntRefreshContentsMenuTimer(target, effect, time)
}
}
// Add a contents counter on top.
var contents_count_bar =
{
BackgroundColor = RGBa(0, 0, 0, 100),
Priority = -1,
Bottom = "1em",
text =
{
Priority = 2,
Style = GUI_TextRight | GUI_TextVCenter
}
};
if (effect.obj.MaxContentsCount)
{
var count = effect.obj->ContentsCount();
var max = effect.obj.MaxContentsCount;
contents_count_bar.text.Text = Format("<c eeeeee>%3d / %3d</c>", count, max);
contents_count_bar.bar =
{
Priority = 1,
BackgroundColor = RGBa(0, 255, 0, 50),
Right = ToPercentString(1000 * count / max, 10)
};
}
else contents_count_bar.text.Text = Format("<c eeeeee>%3d</c>", effect.obj->ContentsCount());
PushBack(inventory, {symbol = nil, text = nil, custom = contents_count_bar});
// Check if nothing changed. If so, we don't need to update.
if (GetLength(inventory) == GetLength(effect.last_inventory))
{

View File

@ -233,11 +233,14 @@ public func GetInventoryIconOverlay()
{
Bottom = "0.75em", Margin = ["0.1em", "0.25em"],
BackgroundColor = RGB(0, 0, 0),
inner =
margin =
{
Margin = "0.05em",
BackgroundColor = RGB(200, 150, 0),
Right = Format("%d%%", percentage),
bar =
{
BackgroundColor = RGB(200, 150, 0),
Right = Format("%d%%", percentage),
}
}
};

View File

@ -151,7 +151,7 @@ public func ControlUseStart(object clonk, int iX, int iY)
PlayWeaponAnimation(clonk, animation, 10, Anim_Linear(0, 0, clonk->GetAnimationLength(animation), StrikingLength, ANIM_Remove), Anim_Const(1000));
clonk->UpdateAttach();
Sound("Objects::Weapons::WeaponSwing?", nil, nil, nil, nil, nil, -Random(10));
Sound("Objects::Weapons::WeaponSwing?", {pitch = -Random(10)});
magic_number=((magic_number+1)%10) + (ObjectNumber()*10);
StartWeaponHitCheckEffect(clonk, StrikingLength, 1);

View File

@ -142,7 +142,7 @@ protected func DoSwing(object clonk, int ix, int iy)
spark.OnCollision = PC_Bounce();
}
CreateParticle("StarSpark", x2*9/10,y2*9/10, PV_Random(-30, 30), PV_Random(-30, 30), PV_Random(10, 50), spark, 30);
Sound(sound, nil, nil, nil, nil, nil, pitch);
Sound(sound, {pitch = pitch});
}
// Do blastfree after landscape checks are made. Otherwise, mat always returns as "tunnel"

View File

@ -37,7 +37,7 @@ public func ControlUseStart(object clonk, int x, int y)
clonk->PlayAnimation(animation, CLONK_ANIM_SLOT_Arms, Anim_Linear(0, 0, clonk->GetAnimationLength(animation), length, ANIM_Remove), Anim_Const(1000));
clonk->UpdateAttach();
Sound("Objects::Weapons::WeaponSwing?", nil, nil, nil, nil, nil, 100);
Sound("Objects::Weapons::WeaponSwing?", {pitch = 100});
// Search for harvestable plants
var crop = FindObject(Find_AtRect(AbsX(clonk->GetX()-8), AbsY(clonk->GetY()-10), 16,20), Find_NoContainer(), Find_Func("SickleHarvesting"), Find_Func("IsHarvestable"));
@ -57,4 +57,4 @@ func Definition(def) {
local Collectible = 1;
local Name = "$Name$";
local Description = "$Description$";
local Description = "$Description$";

View File

@ -87,7 +87,7 @@ public func FxIntReloadTimer(object target, proplist effect, int time)
{
if (effect.sound)
{
Sound("Objects::Windbag::Charge", false, nil, nil, -1);
Sound("Objects::Windbag::Charge", {loop_count = -1});
Sound("Objects::Windbag::ChargeStop");
effect.sound = false;
}
@ -104,7 +104,7 @@ public func FxIntReloadTimer(object target, proplist effect, int time)
{
if (!effect.sound)
{
Sound("Objects::Windbag::Charge", false, nil, nil, 1);
Sound("Objects::Windbag::Charge", {loop_count = 1});
effect.sound = true;
}
@ -127,7 +127,7 @@ public func FxIntReloadStop(object target, proplist effect, int reason, bool tem
return FX_OK;
if (effect.sound)
{
Sound("Objects::Windbag::Charge", false, nil, nil, -1);
Sound("Objects::Windbag::Charge", {loop_count = -1});
Sound("Objects::Windbag::ChargeStop");
}
return FX_OK;

View File

@ -117,7 +117,7 @@ public func FinishedAiming(object clonk, int angle)
// aaaand, a cooldown
AddEffect("ClubWeaponCooldown", clonk, 1, 5, this);
Sound("Objects::Weapons::WeaponSwing?", nil, nil, nil, nil, nil, -50);
Sound("Objects::Weapons::WeaponSwing?", {pitch = -50});
return true;
}
@ -235,7 +235,7 @@ func DoStrike(clonk, angle)
if (found)
{
RemoveEffect("DuringClubShoot", clonk);
Sound("Hits::Materials::Wood::WoodHit?", nil, nil, nil, nil, nil, -10);
Sound("Hits::Materials::Wood::WoodHit?", {pitch = -10});
}
}
@ -250,4 +250,4 @@ func Definition(def)
local Collectible = 1;
local Name = "$Name$";
local Description = "$Description$";
local ForceFreeHands = true;
local ForceFreeHands = true;

View File

@ -28,6 +28,12 @@ protected func Construction()
return _inherited(...);
}
// This object is a structure.
public func IsStructure() { return true; }
/*-- Damage Handling --*/
public func GetHitPoints()
{
return this.HitPoints;
@ -45,18 +51,44 @@ public func Damage(int change, int cause, int cause_plr)
{
if (GetDamage() >= this.HitPoints)
{
// Remove contents from the building depending on the type of damage.
EjectContentsOnDestruction(cause, cause_plr);
// Destruction callback is made by the engine.
return RemoveObject();
}
// Update all interaction menus with the new hitpoints.
UpdateInteractionMenus(this.GetDamageMenuEntries);
}
return _inherited(change, cause, cause_plr, ...);
}
// This object is a structure.
public func IsStructure() { return true; }
private func EjectContentsOnDestruction(int cause, int by_player)
{
// Exit all objects in this structure.
for (obj in FindObjects(Find_Container(this)))
{
// For a non-blast destruction just place the objects at the bottom of the structure.
var angle = Random(360);
var x = RandomX(GetLeft(), GetRight());
var y = GetBottom();
var dx = 0;
var dy = 0;
var dr = 0;
// Scatter objects around if the destruction is caused by a blast.
if (cause == FX_Call_DmgBlast)
{
var speed = RandomX(3, 4);
x = RandomX(-4, 4);
y = RandomX(-4, 4);
dx = Cos(angle, speed);
dy = Sin(angle, speed);
dr = RandomX(-20, 20);
}
obj->Exit(x, y, Random(360), dx, dy, dr);
obj->SetController(by_player);
}
return;
}
/*-- Basement Handling --*/
@ -315,7 +347,7 @@ public func OnRepairSelected(id symbol, string action, object cursor)
if (!hammer)
{
PlayerMessage(cursor->GetOwner(), "$YouNeedAHammer$");
Sound("UI::Click2", nil, nil, cursor->GetOwner());
Sound("UI::Click2", {player = cursor->GetOwner()});
return;
}
@ -340,7 +372,7 @@ public func OnRepairSelected(id symbol, string action, object cursor)
if (total_repair_value == 0)
{
PlayerMessage(cursor->GetOwner(), "$YouNeedMaterials$");
Sound("UI::Click2", nil, nil, cursor->GetOwner());
Sound("UI::Click2", {player = cursor->GetOwner()});
return;
}

View File

@ -80,14 +80,14 @@ func DoBuy(id item, int for_player, int wealth_player, object buyer, bool buy_al
{
if(show_errors)
{
Sound("UI::Error", nil, nil, for_player + 1);
Sound("UI::Error", {player = for_player + 1});
PlayerMessage(for_player, "$MsgNotEnoughWealth$");
}
break;
}
// Take the cash
DoWealth(wealth_player, -price);
Sound("UI::UnCash", nil, nil, for_player + 1); // TODO: get sound
Sound("UI::UnCash", {player = for_player + 1}); // TODO: get sound
// Decrease the base material, allow runtime overload
this->ChangeBuyableAmount(wealth_player, item, -1);
// Deliver the object
@ -113,7 +113,7 @@ func DoSell(object obj, int wealth_player)
// Give the player the cash
DoWealth(wealth_player, this->GetSellValue(obj));
Sound("UI::Cash", nil, nil, wealth_player + 1);
Sound("UI::Cash", {player = wealth_player + 1});
// OnSale callback to object e.g. for goal updates
obj->~OnSale(wealth_player, this);

View File

@ -29,26 +29,26 @@ public func OnProductionStart(id product)
{
AddEffect("Working", this, 100, 1, this);
hold_production = false;
Sound("Liquids::Boiling", false, nil, nil, 1);
Sound("Liquids::Boiling", {loop_count = 1});
}
public func OnProductionHold(id product)
{
hold_production = true;
Sound("Liquids::Boiling", false, nil, nil, -1);
Sound("Liquids::Boiling", {loop_count = -1});
Sound("Fire::Blowout");
}
public func OnProductionContinued(id product)
{
hold_production = false;
Sound("Liquids::Boiling", false, nil, nil, 1);
Sound("Liquids::Boiling", {loop_count = 1});
}
public func OnProductionFinish(id product)
{
RemoveEffect("Working", this);
Sound("Liquids::Boiling", false, nil, nil, -1);
Sound("Liquids::Boiling", {loop_count = -1});
}
protected func FxWorkingTimer()

View File

@ -639,7 +639,7 @@ public func ControlUseStart(object clonk, int x, int y)
if (IsSlave())
return Control2Master("ControlUseStart", clonk, x, y);
MoveTo(GetY() + y, 0, nil, true);
Sound("UI::Click", nil, nil, clonk->GetOwner());
Sound("UI::Click", {player = clonk->GetOwner()});
// Do not trigger a UseStop-callback.
return false;
}
@ -669,7 +669,7 @@ public func ControlUp(object clonk)
// what is that player even doing
if (GetY() <= elevator->GetY() + 20)
{
Sound("UI::Click", nil, nil, clonk->GetOwner());
Sound("UI::Click", {player = clonk->GetOwner()});
return true;
}

View File

@ -144,7 +144,7 @@ public func StartEngine(int direction, bool silent)
if (!silent)
{
Sound("Structures::Elevator::Start", nil, nil, nil, nil, 400);
Sound("Structures::Elevator::Start", {custom_falloff_distance = 400});
ScheduleCall(this, "EngineLoop", 34);
}
if (wheel_anim == nil) // If for some reason the animation has stopped
@ -169,16 +169,16 @@ public func StartEngine(int direction, bool silent)
public func EngineLoop()
{
Sound("Structures::Elevator::Moving", nil, nil, nil, 1, 400);
Sound("Structures::Elevator::Moving", {loop_count = 1, custom_falloff_distance = 400});
}
public func StopEngine(bool silent)
{
if (!silent)
{
Sound("Structures::Elevator::Moving", nil, nil, nil, -1);
Sound("Structures::Elevator::Moving", {loop_count = -1});
ClearScheduleCall(this, "EngineLoop");
Sound("Structures::Elevator::Stop", nil, nil, nil, nil, 400);
Sound("Structures::Elevator::Stop", {custom_falloff_distance = 400});
}
if (wheel_anim == nil) return;
@ -326,4 +326,4 @@ local Name = "$Name$";
local Description = "$Description$";
local BlastIncinerate = 100;
local HitPoints = 70;
local Plane = 249;
local Plane = 249;

View File

@ -244,8 +244,8 @@ private func SpinOn(int diff)
rotate = 0;
SetMeshMaterial("SawmillBlade.Spin", 2);
running = true;
Sound("Structures::SawmillRipcut", nil, nil, nil, +1);
Sound("Sawmill::EngineLoop", nil, nil, nil, +1);
Sound("Structures::SawmillRipcut", {loop_count = +1});
Sound("Sawmill::EngineLoop", {loop_count = +1});
}
SetProperty("MeshTransformation", Trans_Mul(Trans_Rotate(-20, 0, 1, 0), Trans_Rotate(rotate, 1, 0, 0)));
@ -260,14 +260,14 @@ private func SpinOff(int call)
running = false;
spin = 50;
SetMeshMaterial("SawmillBlade", 2);
Sound("Structures::SawmillRipcut", nil, nil, nil, -1);
Sound("Structures::SawmillRipcut", {loop_count = -1});
SetProperty("MeshTransformation", Trans_Rotate(-20, 0, 1, 0));
}
if (call == 1) spin = 75;
if (call == 2)
{
spin = 100;
Sound("Sawmill::EngineLoop", nil, nil, nil, -1);
Sound("Sawmill::EngineLoop", {loop_count = -1});
Sound("Sawmill::EngineStop");
}
if (call == 3) spin = 150;

View File

@ -107,7 +107,7 @@ public func OnPowerProductionStop(int amount)
// Start call from working action.
protected func WorkStart()
{
Sound("Structures::SteamEngine", false, nil, nil, 1);
Sound("Structures::SteamEngine", {loop_count = 1});
return;
}
@ -141,7 +141,7 @@ protected func WorkStop()
protected func WorkAbort()
{
// Sound can be safely stopped here since this action will always end with an abort call.
Sound("Structures::SteamEngine", false, nil, nil, -1);
Sound("Structures::SteamEngine", {loop_count = -1});
return;
}

View File

@ -116,7 +116,7 @@ public func Wind2Turn()
wheel->SetRDir(current_wind * 90, MinRevolutionTime());
// Make some sounds.
if (Abs(current_wind) >= 10 && Random(15 - Abs(current_wind / 10)) < 5)
Sound(["Hits::Materials::Wood::WoodCreak?","Structures::HingeCreak?"][Random(2)], false, nil, nil, nil, 75);
Sound(["Hits::Materials::Wood::WoodCreak?","Structures::HingeCreak?"][Random(2)], {custom_falloff_distance = 75});
return;
}

View File

@ -113,7 +113,7 @@ public func FxIntAirshipMovementTimer(object target, proplist effect, int time)
{
// Fade pitch from -45 to 0
enginesound += 5;
Sound("Structures::FanLoop",nil,nil,nil, 1, 0, enginesound - 50);
Sound("Structures::FanLoop", {loop_count = 1, pitch = enginesound - 50});
}
}
else if(enginesound)
@ -121,9 +121,9 @@ public func FxIntAirshipMovementTimer(object target, proplist effect, int time)
// Fade pitch from 0 to minimum -45, then turn off
enginesound = Max(enginesound - 10);
if (enginesound)
Sound("Structures::FanLoop", nil, nil, nil, 1, 0, enginesound - 50);
Sound("Structures::FanLoop", {loop_count = 1, pitch = enginesound - 50});
else
Sound("Structures::FanLoop", nil, nil, nil, -1);
Sound("Structures::FanLoop", {loop_count = -1});
}
// Wind movement if in the air

View File

@ -220,12 +220,12 @@ public func TurnWheels()
if (Abs(GetXDir()) > 1 && !wheel_sound)
{
if (!wheel_sound)
Sound("Structures::WheelsTurn", false, nil, nil, 1);
Sound("Structures::WheelsTurn", {loop_count = 1});
wheel_sound = true;
}
else if (wheel_sound && !GetXDir())
{
Sound("Structures::WheelsTurn", false, nil, nil, -1);
Sound("Structures::WheelsTurn", {loop_count = -1});
wheel_sound = false;
}
}

View File

@ -98,7 +98,10 @@ public func FxIntroControlAirshipStop(object target, proplist effect, int reason
if (temp)
return FX_OK;
if (effect.airship)
{
effect.airship->SetContactDensity(C4M_Solid);
effect.airship->SetSolidMask();
}
if (effect.host)
{
effect.host->SetCommand("UnGrab");

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -16,7 +16,9 @@ ala - Fire/Spark1&2&3, Objects/Weapons/Musket/Click1&2&3, Clonk/Acti
Clonk/Skin/Steampunk:
Confirm1&2&3&4, Decline1&2&4, Die1&2&3, Doubt1&2&3&4&5, Hurt1&2&3&4&5&6, Laughter1&2&3, Scream1, Shock1&2&4, Singing1&2
Animals/Bat:
Chirp, Flutter1&2&3, Noise1&2&3
Chirp, Flutter1&2&3, Noise1&2&3
Animals/Mooq:
Die1-5, DieFat, Hurt1-2, Munch1-4, Snort1-3, Snorting1-2, Spit1-2
K-Pone - Objects/Pickaxe/ClangHard1
Ringwaul - Monster/Growl1-3, Monster/Die, Wipf/Snuff1-2, Wipf/Aroof, Wipf/Whine, Chest/Open, Chest/Close
Winbag/Charge, Winbag/ChargeStop, Winbag/Gust, Pickaxe/Clang1-3

View File

@ -103,7 +103,7 @@ global func ShuffleArray(array arr)
while (--len >= 0)
{
var i = Random(len);
var i = Random(len + 1);
arr[len] = working[i];
working[i] = working[len];
}

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