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.cliquid_container
|
@ -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}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 && !release)
|
||||
if (control == CON_Jump && 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->PlayerControl(player, control, x, y, strength, repeat, release);
|
||||
if (control_extra) return control_extra->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);
|
||||
// ...
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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!
|
||||
|
|
|
@ -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!
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
MsgGoalFulfilled=Eure Gegner sind eliminiert.
|
||||
MsgGoalUnfulfilled=Es sind noch %d Gegner im Spiel.
|
|
@ -0,0 +1,2 @@
|
|||
MsgGoalFulfilled=All opponents eliminated.
|
||||
MsgGoalUnfulfilled=There are still %d opponents in the game.
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
After Width: | Height: | Size: 43 KiB |
|
@ -1,5 +1,5 @@
|
|||
// Max distance for pipe line
|
||||
// Max distance for pipe line.
|
||||
|
||||
#appendto PipeLine
|
||||
|
||||
local LineMaxDistance = 500;
|
||||
local PipeMaxLength = 600;
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
Model by pluto
|
||||
--------------
|
||||
Model, texture and animations.
|
|
@ -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
|
After Width: | Height: | Size: 48 KiB |
|
@ -0,0 +1,3 @@
|
|||
[Particle]
|
||||
Name=Clusterflight
|
||||
Face=0,0,64,64,-32,-32
|
|
@ -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
|
After Width: | Height: | Size: 136 B |
|
@ -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",
|
||||
},
|
||||
};
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 794 KiB |
|
@ -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;
|
|
@ -0,0 +1,2 @@
|
|||
Name=Mooq
|
||||
Description=Süße kleine Kreatur. Mag Lava.
|
|
@ -0,0 +1,2 @@
|
|||
Name=Mooq
|
||||
Description=Cute little creature. Likes lava.
|
|
@ -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$";
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
After Width: | Height: | Size: 1.8 KiB |
|
@ -0,0 +1,3 @@
|
|||
[Particle]
|
||||
Name=Hail
|
||||
Face=0,0,35,35,-17,-17
|
After Width: | Height: | Size: 405 B |
|
@ -0,0 +1,2 @@
|
|||
DE:Regentropfen
|
||||
US:Raindrop
|
|
@ -0,0 +1,3 @@
|
|||
[Particle]
|
||||
Name=Raindrop
|
||||
Face=0,0,32,128,-16,-64
|
After Width: | Height: | Size: 879 B |
|
@ -0,0 +1,3 @@
|
|||
[Particle]
|
||||
Name=RaindropLava
|
||||
Face=0,0,32,128,-16,-64
|
After Width: | Height: | Size: 239 B |
|
@ -0,0 +1,2 @@
|
|||
DE:Regentropfen
|
||||
US:Raindrop
|
|
@ -0,0 +1,3 @@
|
|||
[Particle]
|
||||
Name=RaindropSmall
|
||||
Face=0,0,64,64,-32,-32
|
After Width: | Height: | Size: 3.7 KiB |
|
@ -0,0 +1,2 @@
|
|||
DE:Schneeflocke
|
||||
US:Snow flake
|
|
@ -0,0 +1,3 @@
|
|||
[Particle]
|
||||
Name=RaindropSnow
|
||||
Face=0,0,16,16,-8,-8
|
After Width: | Height: | Size: 3.2 KiB |
|
@ -0,0 +1,2 @@
|
|||
DE:Regentropfen
|
||||
US:Raindrop
|
|
@ -0,0 +1,3 @@
|
|||
[Particle]
|
||||
Name=RaindropSplash
|
||||
Face=0,0,32,32,-16,-16
|
After Width: | Height: | Size: 11 KiB |
|
@ -0,0 +1,2 @@
|
|||
DE:Regentropfen
|
||||
US:Raindrop
|
|
@ -0,0 +1,3 @@
|
|||
[Particle]
|
||||
Name=RaindropSplashLiquid
|
||||
Face=0,0,100,32,-50,-32
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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$";
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|