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

liquid_container
Mark 2016-04-23 11:10:26 +02:00
commit 72c7e4dd87
56 changed files with 3685 additions and 240 deletions

View File

@ -124,7 +124,7 @@ if(MSVC)
# Enable LTCG for release builds
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Ob2 /GL")
set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} /Ob2 /GL")
add_linker_flags(optimized MODULES exe shared static FLAGS /LTCG)
add_linker_flags(optimized MODULES exe shared static FLAGS "/LTCG:incremental")
# Activate edit-and-continue
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /ZI /Gy")
@ -1024,6 +1024,14 @@ src/platform/C4TimeMilliseconds.h
src/zlib/gzio.c
src/zlib/gzio.h
src/zlib/zutil.h
# pcg is a header-only library which we're listing solely so MSVC shows
# the sources in the solution explorer. We could use an INTERFACE library
# but there is no point to that because we don't need it for non-IDE
# generators and support on IDE-targetting generators is nonexistant.
thirdparty/pcg/pcg_extras.hpp
thirdparty/pcg/pcg_random.hpp
thirdparty/pcg/pcg_uint128.hpp
)
target_link_libraries(libmisc ${ZLIB_LIBRARIES})

201
licenses/apache.txt 100644
View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -7,17 +7,10 @@
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

@ -42,9 +42,6 @@ func ResetRound()
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.

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

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

View File

@ -28,8 +28,9 @@ public func SetRider(object clonk)
public func SetInflated()
{
// Skip inflating animation
if (GetAction() == "Inflate") SetAction("Float");
// Skip inflating animation.
if (GetAction() == "Inflate")
SetAction("Float");
}
// Sets a cargo object that is held by the balloon
@ -130,6 +131,8 @@ private func Pack()
RemoveObject();
}
public func RejectWindbagForce() { return true; }
/*-- Controls --*/
@ -151,15 +154,15 @@ public func ControlRight()
public func ControlDown()
{
var effect = GetEffect("ControlFloat", this);
if (effect)
effect.control_dir = 0;
Deflate();
return true;
}
public func ControlJump()
public func ControlUp()
{
Deflate();
var effect = GetEffect("ControlFloat", this);
if (effect)
effect.control_dir = 0;
return true;
}
@ -240,7 +243,7 @@ public func OnProjectileHit(object projectile)
rider->SetKiller(projectile->GetController());
rider->SetAction("Tumble");
}
// Drop anything being transported
// Drop anything being transported.
DropCargo();
// We're done.
RemoveObject();
@ -280,7 +283,7 @@ local ActMap = {
Name = "Deflate",
Procedure = DFA_FLOAT,
Directions = 1,
Length = 20,
Length = 10,
Delay = 1,
PhaseCall = "DeflateEffect",
EndCall = "Pack",

View File

@ -1,2 +1,2 @@
Name=Ballon
Description=Kann den Fall eines Clonks wie ein Fallschirm abbremsen. Benutze den Ballon um deinen Fall abzubremsen.
Description=Wirkt wie ein Fallschirm, Benutze den Ballon während eines Falles um ihn zu aktiveren. While hanging on the balloon use [A] and [D] to steer left and right and [W] to stop. The balloon can be pulled in using [S].

View File

@ -1,2 +1,2 @@
Name=Balloon
Description=Acts like a parachute to slow the fall of your clonk. Press the use key while falling.
Description=Acts like a parachute, press the use key to activate while falling. While hanging on the balloon use [A] and [D] to steer left and right and [W] to stop. The balloon can be pulled in using [S].

View File

@ -172,6 +172,8 @@ public func DoExplode()
public func IsChemicalProduct() { return true; }
public func IsGrenadeLauncherAmmo() { return true; }
public func IsFusing() { return GetAction() == "Fuse"; }
// Drop fusing dynamite on death to prevent explosion directly after respawn
public func IsDroppedOnDeath(object clonk)
{

View File

@ -9,7 +9,7 @@ Vertices=2
VertexX=-3,3
VertexY=0,0
VertexFriction=80,80
Value=12
Value=16
Mass=10
Components=Wood=2;Metal=1;Rope=1;
Rotate=1

View File

@ -16,14 +16,16 @@ public func GetRope() { return rope; }
public func New(object new_clonk, object new_rope)
{
SetObjDrawTransform(0, 1, 0, 0, 0, 0, 0); // Hide
// Hook graphics are handled by rope.
this.Visibility = VIS_None;
clonk = new_clonk;
rope = new_rope;
}
public func Launch(int angle, int str, object shooter, object bow)
{
SetObjDrawTransform(0, 1, 0, 0, 0, 0, 0); // Hide
// Hook graphics are handled by rope.
this.Visibility = VIS_None;
Exit();
pull = false;

View File

@ -212,13 +212,15 @@ public func UpdateLines()
if (i == 1)
{
lib_rope_segments[i]->SetGraphics(nil, GrappleHook);
lib_rope_segments[i].MeshTransformation = Trans_Mul(Trans_Translate(1500, 0, 0), Trans_Scale(1500));
lib_rope_segments[i].MeshTransformation = Trans_Mul(Trans_Translate(0, -7000, 0), Trans_Scale(1500), Trans_Rotate(angle, 0, 0, 1));
point[0] += -Cos(diffangle, 15 * LIB_ROPE_Precision / 10) + Sin(diffangle, 4 * LIB_ROPE_Precision);
point[1] += -Cos(diffangle, 4 * LIB_ROPE_Precision) - Sin(diffangle, 15 * LIB_ROPE_Precision / 10);
length = 1000;
}
SetLineTransform(lib_rope_segments[i], -diffangle, point[0] * 10 - GetPartX(i) * 1000, point[1] * 10 - GetPartY(i) * 1000, length);
// Only apply line transform to the rope segments and not to the hook.
if (i != 1)
SetLineTransform(lib_rope_segments[i], -diffangle, point[0] * 10 - GetPartX(i) * 1000, point[1] * 10 - GetPartY(i) * 1000, length);
// Remember the angle.
oldangle = angle;

View File

@ -42,11 +42,36 @@ public func ControlUseCancel(object clonk, int x, int y)
private func CreateBridge(object clonk, int x, int y)
{
// Get the bridge coordinates.
var c = Offset2BridgeCoords(clonk, x, y);
x = clonk->GetX();
y = clonk->GetY();
// Get living objects near the bridge which are not stuck yet.
var non_stuck_living = clonk->FindObjects(Find_OCF(OCF_Alive), Find_Distance(this.BridgeLength + 8, (c.x1 + c.x2) / 2, (c.y1 + c.y2) / 2));
for (var index = GetLength(non_stuck_living) - 1; index >= 0; index--)
if (non_stuck_living[index]->Stuck())
RemoveArrayIndex(non_stuck_living, index);
// Construct the bridge.
DrawMaterialQuad(BridgeMaterial, x + c.x1 - c.dxm, y + c.y1 - c.dym, x + c.x1 + c.dxp, y + c.y1 + c.dyp, x + c.x2 + c.dxp, y + c.y2 + c.dyp, x + c.x2 - c.dxm, y + c.y2 - c.dym, DMQ_Bridge);
clonk->Sound("Objects::WallKit::Lock");
// Now check whether some of the living objects got stuck and try to move them out of the bridge.
for (var obj in non_stuck_living)
{
var nr_tries = 200;
var try_nr = 0;
var max_dist = 6;
var ox = obj->GetX();
var oy = obj->GetY();
// Unstuck objects by moving them in a random direction.
while (obj->Stuck() && try_nr++ < nr_tries)
{
var try_dist = BoundBy(try_nr * max_dist / nr_tries, 1, max_dist);
obj->SetPosition(ox + RandomX(-try_dist, try_dist), oy + RandomX(- 2 * try_dist, 2 * try_dist));
}
// If still stuck, keep the object at its original position.
if (obj->Stuck())
obj->SetPosition(ox, oy);
}
return true;
}

View File

@ -37,7 +37,7 @@ public func IsInventorProduct() { return true; }
func RejectUse(object clonk)
{
return clonk->GetProcedure() == "ATTACH";
return false;
}
// used by this object

View File

@ -28,6 +28,10 @@ func Fuse(bool explode_on_hit)
AddEffect("FuseBurn", this, 1,1, this);
}
public func FuseTime() { return 90; }
public func IsFusing() { return !!GetEffect("FuseBurn", this); }
public func OnCannonShot(object cannon)
{
Fuse(true);
@ -41,7 +45,7 @@ func FxFuseBurnTimer(object bomb, proplist effect, int timer)
CreateParticle("Smoke", x, y, x, y, PV_Random(18, 36), Particles_Smoke(), 2);
if(timer == 1) Sound("Fire::FuseLoop",nil,nil,nil,+1);
if(timer >= 90)
if(timer >= FuseTime())
{
Sound("Fire::FuseLoop",nil,nil,nil,-1);
DoExplode();

View File

@ -875,7 +875,7 @@ func ControlUse2Script(int ctrl, int x, int y, int strength, bool repeat, bool r
{
return StartUseControl(ctrl,x, y, obj);
}
else if (release && obj == this.control.current_object)
else if (release && (obj == this.control.current_object || obj == GetActionTarget()))
{
return StopUseControl(x, y, obj);
}
@ -887,7 +887,7 @@ func ControlUse2Script(int ctrl, int x, int y, int strength, bool repeat, bool r
{
return StartUseDelayedControl(ctrl, obj);
}
else if (release && obj == this.control.current_object)
else if (release && (obj == this.control.current_object || obj == GetActionTarget()))
{
return StopUseDelayedControl(obj);
}

View File

@ -88,7 +88,7 @@ private func FxIntHighlightInteractionStart(object target, proplist fx, temp, pr
{
Name = "Attach",
Procedure = DFA_ATTACH,
FaceBase = 1
FacetBase = 1
}
};
fx.dummy.Visibility = VIS_Owner;

View File

@ -223,7 +223,7 @@ private func FxIntHighlightItemStart(object target, proplist fx, temp, object it
{
Name = "Attach",
Procedure = DFA_ATTACH,
FaceBase = 1
FacetBase = 1
}
};
fx.dummy.Visibility = VIS_Owner;

View File

@ -169,3 +169,11 @@ private func DoSeed()
}
return plant;
}
private func RemoveInTunnel()
{
if (GetMaterial() == Material("Tunnel") || GetMaterial(0, -10) == Material("Tunnel"))
{
RemoveObject();
}
}

View File

@ -310,4 +310,16 @@ private func FxTreeFallTimer(object target, proplist effect)
target->SetRDir(0);
return -1;
}
}
}
private func DoSeed()
{
var plant = _inherited(...);
if (plant)
{
plant->RemoveInTunnel();
}
return plant;
}

View File

@ -49,6 +49,7 @@ public func GetPowerDisplayMenuEntries(object clonk)
{
var entry =
{
Style = GUI_FitChildren,
Bottom = "1.1em",
BackgroundColor = {Std = 0, OnHover = 0x50ff0000},
Priority = 0,
@ -69,46 +70,38 @@ public func GetPowerDisplayMenuEntries(object clonk)
var power_consumption_need = power_network->GetPowerConsumptionNeed() / 10;
var power_stored = power_network->GetStoredPower();
var power_stored_capacity = power_network->GetStoredPowerCapacity();
var entry_prototype =
{
Style = GUI_FitChildren | GUI_TextVCenter | GUI_TextLeft,
Bottom = "1.1em",
BackgroundColor = {Std = 0, OnHover = 0x50ff0000}
};
// Show power production.
var entry =
{
Bottom = "1.1em",
BackgroundColor = {Std = 0, OnHover = 0x50ff0000},
Prototype = entry_prototype,
Priority = 0,
text =
{
Style = GUI_TextVCenter | GUI_TextLeft,
Text = Format("$MsgPowerProduction$ %d {{Icon_Lightbulb}} ($MsgPowerProductionCapacity$ %d {{Icon_Lightbulb}})", power_production_current, power_production_capacity)
}
Text = Format("$MsgPowerProduction$ %d {{Icon_Lightbulb}} ($MsgPowerProductionCapacity$ %d {{Icon_Lightbulb}})", power_production_current, power_production_capacity)
};
PushBack(menu_entries, {symbol = Icon_Lightbulb, extra_data = "production", custom = entry});
// Show power consumption.
var entry =
{
Bottom = "1.1em",
BackgroundColor = {Std = 0, OnHover = 0x50ff0000},
Prototype = entry_prototype,
Priority = 1,
text =
{
Style = GUI_TextVCenter | GUI_TextLeft,
Text = Format("$MsgPowerConsumption$ %d {{Icon_Lightbulb}} ($MsgPowerConsumptionDemand$ %d {{Icon_Lightbulb}})", power_consumption_current, power_consumption_need)
}
Text = Format("$MsgPowerConsumption$ %d {{Icon_Lightbulb}} ($MsgPowerConsumptionDemand$ %d {{Icon_Lightbulb}})", power_consumption_current, power_consumption_need)
};
PushBack(menu_entries, {symbol = Icon_Lightbulb, extra_data = "consumption", custom = entry});
// Show power storage.
var entry =
{
Bottom = "1.1em",
BackgroundColor = {Std = 0, OnHover = 0x50ff0000},
Prototype = entry_prototype,
Priority = 2,
text =
{
Style = GUI_TextVCenter | GUI_TextLeft,
Text = Format("$MsgPowerStored$ %s {{Icon_Lightbulb}} ($MsgPowerStoredCapacity$ %s {{Icon_Lightbulb}})", GetStoredPowerString(power_stored), GetStoredPowerString(power_stored_capacity))
}
Text = Format("$MsgPowerStored$ %s {{Icon_Lightbulb}} ($MsgPowerStoredCapacity$ %s {{Icon_Lightbulb}})", GetStoredPowerString(power_stored), GetStoredPowerString(power_stored_capacity))
};
PushBack(menu_entries, {symbol = Icon_Lightbulb, extra_data = "storage", custom = entry});
return menu_entries;

View File

@ -219,13 +219,13 @@ public func GetBuyMenuEntries(object clonk)
var wealth = GetWealth(wealth_player);
var menu_entries = [];
var i = 0, item, amount;
var index = 0, item, amount;
for (item in this->GetBuyableItems(for_player))
{
amount = this->GetBuyableAmount(for_player, item);
var value = this->GetBuyValue(item);
var entry = GetBuyMenuEntry(i, item, amount, value);
var entry = GetBuyMenuEntry(index++, item, amount, value);
if (value > wealth) // If the player can't afford it, the item (except for the price) is overlayed by a greyish color.
{
entry.overlay = {Priority = 2, BackgroundColor = RGBa(50, 50, 50, 150)};

View File

@ -7,7 +7,7 @@
protected func Initialize()
{
SetProperty("MeshTransformation", Trans_Mul(Trans_Scale(1000, 1400, 1000), Trans_Rotate(RandomX(0, 359), 0, 1, 0)));
this.MeshTransformation = Trans_Mul(Trans_Scale(1000, 1400, 1000), Trans_Translate(0, 3500, 0), Trans_Rotate(RandomX(0, 359), 0, 1, 0));
SetR(RandomX(-30, 30));
return;
}

View File

@ -6,11 +6,16 @@
*/
local segments;
local leaf_particle;
protected func Initialize()
{
// Create vine segments to climb on.
CreateSegments();
// Initialize the leaf particle.
leaf_particle = Particles_Leaf(RGB(0, 255, 0));
leaf_particle.Phase = 2;
leaf_particle.Size = PV_Random(3, 5);
return;
}
@ -49,6 +54,7 @@ private func CreateSegments()
public func OnLadderGrab(object clonk, object segment, int segment_index)
{
segment->Sound("Environment::Vine::Grab?");
segment->CreateParticle("Leaf", PV_Random(-2, 2), PV_Random(-3, 3), PV_Random(-4, 4), PV_Random(-4, 4), PV_Random(210, 240), leaf_particle, 6);
return;
}
@ -56,8 +62,12 @@ public func OnLadderGrab(object clonk, object segment, int segment_index)
public func OnLadderClimb(object clonk, object segment, int segment_index)
{
if (clonk->GetComDir() == COMD_Up || clonk->GetComDir() == COMD_Down)
{
if (!Random(20))
segment->Sound("Environment::Vine::Grab?", {volume = 35});
if (!Random(8))
segment->CreateParticle("Leaf", PV_Random(-2, 2), PV_Random(-3, 3), PV_Random(-4, 4), PV_Random(-4, 4), PV_Random(210, 240), leaf_particle, 1);
}
return;
}
@ -65,6 +75,7 @@ public func OnLadderClimb(object clonk, object segment, int segment_index)
public func OnLadderReleased(object clonk, object segment, int segment_index)
{
segment->Sound("Environment::Vine::Grab?", {volume = 50});
segment->CreateParticle("Leaf", PV_Random(-2, 2), PV_Random(-3, 3), PV_Random(-4, 4), PV_Random(-4, 4), PV_Random(210, 240), leaf_particle, 3);
return;
}
@ -83,6 +94,8 @@ public func Place(int amount, proplist area, proplist settings)
settings = {};
if (!settings.min_dist)
settings.min_dist = 32;
if (!settings.attach_material)
settings.attach_material = Loc_Or(Loc_Material("Granite"), Loc_Material("Rock"), Loc_MaterialVal("Soil", "Material", nil, 1));
var loc_area = nil;
if (area)
loc_area = Loc_InArea(area);
@ -91,7 +104,7 @@ public func Place(int amount, proplist area, proplist settings)
var nr_created = 0;
for (var i = 0; i < max_tries && nr_created < amount; i++)
{
var loc = FindLocation(Loc_Sky(), Loc_Not(Loc_Liquid()), Loc_Wall(CNAT_Top, Loc_Or(Loc_Material("Granite"), Loc_Material("Rock"), Loc_MaterialVal("Soil", "Material", nil, 1))), loc_area);
var loc = FindLocation(Loc_Sky(), Loc_Not(Loc_Liquid()), Loc_Wall(CNAT_Top, settings.attach_material), loc_area);
if (!loc)
continue;
var vine = CreateObject(Vine);

View File

@ -2,10 +2,6 @@
Aerobatics
Several small sky islands form a chaotic parkour with lots of usable and respawning items.
TODO:
horizontal mode with large map
reset player cp completion to killer (idea)
@author Maikel
*/
@ -187,6 +183,7 @@ private func InitVegetation(int amount)
Tree_Coniferous2->Place(amount / 4);
Tree_Coniferous3->Place(amount / 4);
Cotton->Place(amount / 2);
Vine->Place(amount);
return;
}

View File

@ -243,6 +243,27 @@ global func Particles_Straw()
};
}
global func Particles_Leaf(int color)
{
return
{
Size = PV_Random(4, 6),
Phase = PV_Random(0, 2),
Rotation = PV_Random(0, 360),
R = (color >> 16) & 0xff,
G = (color >> 8) & 0xff,
B = (color >> 0) & 0xff,
Alpha = PV_KeyFrames(0, 0, 255, 900, 255, 1000, 0),
CollisionVertex = 800,
OnCollision = PC_Die(),
ForceX = PV_Wind(50),
ForceY = PV_Gravity(100),
DampingX = 975, DampingY = 975,
Rotation = PV_Direction(PV_Random(750, 1250)),
Attach = ATTACH_Front
};
}
global func Particles_CottonBalloon()
{
return

View File

@ -0,0 +1,43 @@
/* A map for testing the Random() number generator. */
#include Library_Map
// Overload Random to make it show up in the script profiler.
func Random()
{
return inherited(...);
}
func InitializeMap(proplist map)
{
Resize(800, 800);
var layer1 = CreateLayer(nil, map.Wdt, map.Hgt / 2);
var layer2 = CreateLayer(nil, map.Wdt, map.Hgt / 2);
StartScriptProfiler();
DrawRandomPattern(layer1, "Water");
DrawRandomPattern2(layer2);
StopScriptProfiler();
Blit(layer1, [0, 0, layer1.Wdt, layer1.Hgt]);
Blit({Algo=MAPALGO_Offset, OffY=map.Hgt / 2, Op=layer2});
return true;
}
// For each pixel: either fill or don't fill.
func DrawRandomPattern(proplist layer, string mat)
{
for (var y = 0; y < layer.Hgt; y++)
for (var x = 0; x < layer.Wdt; x++)
if (!Random(2))
layer->SetPixel(x, y, mat);
}
// Fill each pixel with a random material.
func DrawRandomPattern2(proplist layer)
{
var mats = [ "Acid", "Amethyst", "Ashes", "Brick", "BrickSoft", "Coal", "DuroLava", "Earth", "Everrock", "Firestone", "Gold", "Granite", "HalfVehicle", "Ice", "Lava", "ORE", "Rock", "Ruby", "SandDry", "Sand", "Snow", "Tunnel", "Vehicle", "Water" ];
var n = GetLength(mats);
for (var y = 0; y < layer.Hgt; y++)
for (var x = 0; x < layer.Wdt; x++)
layer->SetPixel(x, y, mats[Random(n)]);
}

View File

@ -0,0 +1,2 @@
[Landscape]
MapZoom=2

View File

@ -88,8 +88,9 @@ protected func InitializePlayer(int plr)
SetBaseMaterial(plr, Cloth, 10);
SetBaseProduction(plr, Cloth, 5);
// Set player wealth.
SetWealth(plr, 75 - 25 * SCENPAR_Difficulty);
// Ensure mimimum player wealth.
var add_wealth = Max(0, 75 - 25 * SCENPAR_Difficulty - GetWealth(plr));
DoWealth(plr, add_wealth);
// Initialize the intro sequence if not yet started.
if (!intro_init)

View File

@ -84,8 +84,9 @@ protected func InitializePlayer(int plr)
// Additional explosives: dynamite boxes.
GivePlayerSpecificBaseMaterial(plr, [[DynamiteBox, 4, 2]]);
// Set player wealth.
SetWealth(plr, 75 - 25 * SCENPAR_Difficulty);
// Ensure mimimum player wealth.
var add_wealth = Max(0, 75 - 25 * SCENPAR_Difficulty - GetWealth(plr));
DoWealth(plr, add_wealth);
// Initialize the intro sequence if not yet started.
if (!intro_init)

View File

@ -131,6 +131,7 @@ private func InitVegetation(int amount)
Mushroom->Place(10 + 4 * amount);
Branch->Place(10 + 4 * amount);
Trunk->Place(4 + 2 * amount);
Vine->Place(8 + 3 * amount);
// Place trees around the islands.
Tree_Deciduous->Place(10 + 4 * amount);

View File

@ -85,8 +85,9 @@ protected func InitializePlayer(int plr)
GivePlayerElementaryBaseMaterial(plr);
GivePlayerToolsBaseMaterial(plr);
// Set player wealth.
SetWealth(plr, 20 + 20 * amount);
// Ensure mimimum player wealth.
var add_wealth = Max(0, 20 + 20 * amount - GetWealth(plr));
DoWealth(plr, add_wealth);
// Initialize the intro sequence if not yet started.
if (!intro_init)

View File

@ -34,7 +34,7 @@ DWORD GenerateRandomPlayerColor(int32_t iTry) // generate a random player color
{
// generate a random one biased towards max channel luminance
// (for greater color difference and less gray-ish colors)
return C4RGB(std::min(SafeRandom(302), 256), std::min(SafeRandom(302), 256), std::min(SafeRandom(302), 256));
return C4RGB(std::min<int>(SafeRandom(302), 256), std::min<int>(SafeRandom(302), 256), std::min<int>(SafeRandom(302), 256));
}
bool IsColorConflict(DWORD dwClr1, DWORD dwClr2) // return whether dwClr1 and dwClr2 are closely together

View File

@ -140,8 +140,8 @@ struct C4RCMassMover
struct C4RCRandom
{
int Cnt; // index in seed
int Range; // random range query
int Val; // random value
uint32_t Range; // random range query
uint32_t Val; // random value
};
struct C4RCCreateObj

View File

@ -338,7 +338,9 @@ void C4TeamList::AddTeam(C4Team *pNewTeam)
// add team; grow vector if necessary
if (iTeamCount >= iTeamCapacity)
{
C4Team **ppNewTeams = new C4Team*[(iTeamCapacity = iTeamCount+4)&~3];
// grow up to the nearest multiple of 4 elements
// (TODO: Replace the whole thing e.g. with a simple std::vector<C4Team>)
C4Team **ppNewTeams = new C4Team*[(iTeamCapacity = ((iTeamCount+4)&~3))];
if (iTeamCount) memcpy(ppNewTeams, ppList, iTeamCount*sizeof(C4Team *));
delete [] ppList; ppList = ppNewTeams;
}

View File

@ -3095,7 +3095,7 @@ C4Player *C4Game::JoinPlayer(const char *szFilename, int32_t iAtClient, const ch
return pPlr;
}
void C4Game::FixRandom(int32_t iSeed)
void C4Game::FixRandom(uint64_t iSeed)
{
FixedRandom(iSeed);
}
@ -3416,6 +3416,13 @@ bool C4Game::LoadScenarioSection(const char *szSection, DWORD dwFlags)
// would leave those values in the altered state of the previous section
// scenario designers should regard this and always define any values, that are defined in subsections as well
C4Group hGroup, *pGrp;
// if current section was the loaded section (maybe main, but need not for resumed savegames)
if (!pCurrentScenarioSection)
{
pCurrentScenarioSection = new C4ScenarioSection(CurrentScenarioSection);
pCurrentScenarioSection->pObjectScripts = Game.pScenarioObjectsScript;
if (!*CurrentScenarioSection) SCopy(C4ScenSect_Main, CurrentScenarioSection, C4MaxName);
}
// find section to load
C4ScenarioSection *pLoadSect = pScenarioSections;
while (pLoadSect) if (SEqualNoCase(pLoadSect->szName, szSection)) break; else pLoadSect = pLoadSect->pNext;
@ -3424,21 +3431,8 @@ bool C4Game::LoadScenarioSection(const char *szSection, DWORD dwFlags)
DebugLogF("LoadScenarioSection: scenario section %s not found!", szSection);
return false;
}
// don't load if it's current
if (pLoadSect == pCurrentScenarioSection)
{
DebugLogF("LoadScenarioSection: section %s is already current", szSection);
return false;
}
// if current section was the loaded section (maybe main, but need not for resumed savegames)
if (!pCurrentScenarioSection)
{
pCurrentScenarioSection = new C4ScenarioSection(CurrentScenarioSection);
pCurrentScenarioSection->pObjectScripts = Game.pScenarioObjectsScript;
if (!*CurrentScenarioSection) SCopy(C4ScenSect_Main, CurrentScenarioSection, C4MaxName);
}
// save current section state
if (dwFlags & (C4S_SAVE_LANDSCAPE | C4S_SAVE_OBJECTS))
if (pLoadSect != pCurrentScenarioSection && dwFlags & (C4S_SAVE_LANDSCAPE | C4S_SAVE_OBJECTS))
{
// ensure that the section file does point to temp store
if (!pCurrentScenarioSection->EnsureTempStore(!(dwFlags & C4S_SAVE_LANDSCAPE), !(dwFlags & C4S_SAVE_OBJECTS)))
@ -3548,6 +3542,11 @@ bool C4Game::LoadScenarioSection(const char *szSection, DWORD dwFlags)
// remove reference to FoW from viewports, so that we can safely
// reload the landscape and its FoW.
Viewports.DisableFoW();
// landscape initialization resets the RNG
// set a new seed here to get new dynamic landscapes
// TODO: add an option to disable this?
RandomSeed = Random(2147483647);
FixRandom(RandomSeed);
// re-init game in new section
C4ValueNumbers numbers;
if (!InitGame(*pGrp, true, fLoadNewSky, &numbers))

View File

@ -148,7 +148,7 @@ public:
bool DoKeyboardInput(C4KeyCode vk_code, C4KeyEventType eEventType, bool fAlt, bool fCtrl, bool fShift, bool fRepeated, class C4GUI::Dialog *pForDialog=NULL, bool fPlrCtrlOnly=false, int32_t iStrength=-1);
bool DoKeyboardInput(C4KeyCodeEx Key, C4KeyEventType eEventType, class C4GUI::Dialog *pForDialog=NULL, bool fPlrCtrlOnly=false, int32_t iStrength=-1);
void DrawCrewOverheadText(C4TargetFacet &cgo, int32_t iPlayer);
void FixRandom(int32_t iSeed);
void FixRandom(uint64_t iSeed);
bool Init();
bool PreInit();
void SetScenarioFilename(const char*);

View File

@ -1496,7 +1496,12 @@ bool C4ScriptGuiWindow::DrawChildren(C4TargetFacet &cgo, int32_t player, int32_t
if (clipping)
{
myClippingRect = C4Rect(targetClipX1, targetClipY1, targetClipX2, targetClipY2);
// Take either the parent rectangle or restrict it additionally by the child's geometry.
myClippingRect = C4Rect(
std::max(currentClippingRect->x, targetClipX1),
std::max(currentClippingRect->y, targetClipY1),
std::min(currentClippingRect->Wdt, targetClipX2),
std::min(currentClippingRect->Hgt, targetClipY2));
currentClippingRect = &myClippingRect;
}

View File

@ -29,7 +29,7 @@ const int C4NetRefRequestTimeout = 12; // seconds after which the reference requ
const int C4NetReferenceTimeout = 42; // seconds after which references are removed from the list (C4NetRefRequestTimeout + C4NetMasterServerQueryInterval)
const int C4NetErrorRefTimeout = 10; // seconds after which failed reference requestsare removed
const int C4NetGameDiscoveryInterval = 30; // seconds
const int C4NetMinRefreshInterval = 8; // seconds; minimum time between refreshes
const int C4NetMinRefreshInterval = 1; // seconds; minimum time between refreshes
class C4StartupNetListEntry : public C4GUI::Window

View File

@ -441,8 +441,8 @@ static std::vector<int32_t> GetRoundPolygon(int32_t x, int32_t y, int32_t size,
vertices.reserve(count * 2);
// varying phase of the sin/cos waves
C4Real begin = itofix(360)*Random(100) / 100;
C4Real begin2 = itofix(360)*Random(100) / 100;
C4Real begin = itofix(360)*(int32_t)Random(100) / 100;
C4Real begin2 = itofix(360)*(int32_t)Random(100) / 100;
// parameters:
// the bigger the factor, the smaller the divergence from a circle

View File

@ -30,10 +30,10 @@
#include "landscape/C4Material.h"
#include "object/C4MeshAnimation.h"
#include "graphics/C4DrawGL.h"
#include "lib/C4Random.h"
#include "landscape/C4Landscape.h"
#include "landscape/C4Weather.h"
#include "object/C4Object.h"
#include <random>
#endif
@ -384,52 +384,6 @@ void C4ParticleValueProvider::Floatify(float denominator)
}
}
void C4ParticleValueProvider::RollRandom(const C4Particle *forParticle)
{
if (randomSeed == -1) return RollRandomUnseeded();
return RollRandomSeeded(forParticle);
}
void C4ParticleValueProvider::RollRandomUnseeded()
{
float range = endValue - startValue;
float rnd = (float)(rand()) / (float)(RAND_MAX);
currentValue = startValue + rnd * range;
}
void C4ParticleValueProvider::RollRandomSeeded(const C4Particle *forParticle)
{
// We need a particle-local additional seed.
// Since this is by no means synchronisation relevant and since the particles lie on the heap
// we just use the address here.
// These conversion steps here just make it explicit that we do not care about the upper 32bit
// of a pointer in case it's too long.
const std::uintptr_t ourAddress = reinterpret_cast<std::uintptr_t>(forParticle);
const unsigned long mostSignificantBits = ourAddress & 0xffffffff;
const unsigned long particleLocalSeed = mostSignificantBits;
// The actual seed is then calculated from the last random value (or initial seed) and the local seed.
unsigned long seed = static_cast<unsigned long>(randomSeed) + particleLocalSeed;
// This is a simple linear congruential generator which should suffice for our graphical effects.
// https://en.wikipedia.org/wiki/Linear_congruential_generator
const unsigned long maxRandomValue = 32767;
auto roll = [&seed, &maxRandomValue]()
{
const unsigned long value = seed * 1103515245l + 12345l;
return static_cast<unsigned int>(value / 65536) % (maxRandomValue + 1);
};
const unsigned int randomNumber = roll();
assert(randomNumber >= 0 && randomNumber <= maxRandomValue);
// Now force the integer-random-value into our float-range.
const float range = endValue - startValue;
const float rnd = static_cast<float>(randomNumber) / static_cast<float>(maxRandomValue);
currentValue = startValue + rnd * range;
// Finally update our seed to the new random value.
randomSeed = static_cast<int> (randomNumber);
}
float C4ParticleValueProvider::GetValue(C4Particle *forParticle)
{
UpdateChildren(forParticle);
@ -460,7 +414,13 @@ float C4ParticleValueProvider::Random(C4Particle *forParticle)
if (needToReevaluate)
{
alreadyRolled = 1;
RollRandom(forParticle);
// Even for seeded PV_Random, each particle should behave differently. Thus, we use a different
// stream for each one. Since this is by no means synchronisation relevant and since the
// particles lie on the heap we just use the address here.
const std::uintptr_t ourAddress = reinterpret_cast<std::uintptr_t>(forParticle);
rng.set_stream(ourAddress);
std::uniform_real_distribution<float> distribution(startValue, endValue);
currentValue = distribution(rng);
}
return currentValue;
}
@ -622,7 +582,16 @@ void C4ParticleValueProvider::Set(const C4ValueArray &fromArray)
if (arraySize >= 4 && fromArray[3].GetType() != C4V_Type::C4V_Nil)
SetParameterValue(VAL_TYPE_INT, fromArray[3], 0, &C4ParticleValueProvider::rerollInterval);
if (arraySize >= 5 && fromArray[4].GetType() != C4V_Type::C4V_Nil)
SetParameterValue(VAL_TYPE_INT, fromArray[4], 0, &C4ParticleValueProvider::randomSeed);
{
// We don't need the seed later on, but SetParameterValue won't accept local
// variables. Use an unrelated member instead which is reset below.
SetParameterValue(VAL_TYPE_INT, fromArray[4], 0, &C4ParticleValueProvider::alreadyRolled);
rng.seed(alreadyRolled);
}
else
{
rng.seed(SafeRandom());
}
alreadyRolled = 0;
}
break;

View File

@ -14,6 +14,7 @@
*/
#include "graphics/C4FacetEx.h"
#include "lib/C4Random.h"
#include "platform/StdScheduler.h"
@ -122,7 +123,7 @@ private:
float maxValue; // for Step & Sin
};
int randomSeed = -1; // for Random
pcg32 rng; // for Random
size_t keyFrameCount;
std::vector<float> keyFrames;
@ -159,11 +160,6 @@ public:
}
C4ParticleValueProvider(const C4ParticleValueProvider &other) { *this = other; }
C4ParticleValueProvider & operator= (const C4ParticleValueProvider &other);
// The random roll is implemented in two variants, one using the default RNG and one using an own implementation that makes use of a seed.
// RollRandom is a wrapper that will select the approprate function to call.
void RollRandom(const C4Particle *forParticle);
void RollRandomUnseeded();
void RollRandomSeeded(const C4Particle *forParticle);
// divides by denominator
void Floatify(float denominator);

View File

@ -40,7 +40,7 @@ void C4SVal::Set(int32_t std, int32_t rnd, int32_t min, int32_t max)
int32_t C4SVal::Evaluate()
{
return Clamp(Std+Random(2*Rnd+1)-Rnd,Min,Max);
return Clamp<int32_t>(Std+Random(2*Rnd+1)-Rnd,Min,Max);
}
void C4SVal::Default()
@ -278,7 +278,7 @@ void C4SLandscape::Default()
InEarth.Default();
MapWdt.Set(100,0,64,250);
MapHgt.Set(50,0,40,250);
MapZoom.Set(8,0,5,15);
MapZoom.Set(8,0,1,15);
Amplitude.Set(0,0);
Phase.Set(50);
Period.Set(15);
@ -322,7 +322,7 @@ void C4SLandscape::CompileFunc(StdCompiler *pComp)
pComp->Value(mkNamingAdapt(AutoScanSideOpen, "AutoScanSideOpen", true));
pComp->Value(mkNamingAdapt(MapWdt, "MapWidth", C4SVal(100,0,64,250), true));
pComp->Value(mkNamingAdapt(MapHgt, "MapHeight", C4SVal(50,0,40,250), true));
pComp->Value(mkNamingAdapt(MapZoom, "MapZoom", C4SVal(8,0,5,15), true));
pComp->Value(mkNamingAdapt(MapZoom, "MapZoom", C4SVal(8,0,1,15), true));
pComp->Value(mkNamingAdapt(Amplitude, "Amplitude", C4SVal(0)));
pComp->Value(mkNamingAdapt(Phase, "Phase", C4SVal(50)));
pComp->Value(mkNamingAdapt(Period, "Period", C4SVal(15)));

View File

@ -28,6 +28,7 @@
#include "landscape/C4Material.h"
#include "landscape/C4Landscape.h"
#include "lib/C4Log.h"
#include "lib/C4Random.h"
#include "lib/StdColors.h"
#include <ctype.h>
@ -570,9 +571,9 @@ void C4TextureMap::StoreMapPalette(CStdPalette *Palette, C4MaterialMap &rMateria
if (j >= i) break;
// change randomly
Palette->Colors[i] = C4RGB(
(rand() < RAND_MAX / 2) ? GetRedValue(Palette->Colors[i]) + 3 : GetRedValue(Palette->Colors[i]) - 3,
(rand() < RAND_MAX / 2) ? GetGreenValue(Palette->Colors[i]) + 3 : GetGreenValue(Palette->Colors[i]) - 3,
(rand() < RAND_MAX / 2) ? GetBlueValue(Palette->Colors[i]) + 3 : GetBlueValue(Palette->Colors[i]) - 3);
SafeRandom(2) ? GetRedValue(Palette->Colors[i]) + 3 : GetRedValue(Palette->Colors[i]) - 3,
SafeRandom(2) ? GetGreenValue(Palette->Colors[i]) + 3 : GetGreenValue(Palette->Colors[i]) - 3,
SafeRandom(2) ? GetBlueValue(Palette->Colors[i]) + 3 : GetBlueValue(Palette->Colors[i]) - 3);
}
}

View File

@ -22,40 +22,42 @@
#include "control/C4Record.h"
int RandomCount = 0;
static unsigned int RandomHold = 0;
static pcg32 RandomRng;
pcg32 SafeRandom;
void FixedRandom(DWORD dwSeed)
void FixedRandom(uint64_t seed)
{
// for SafeRandom
srand((unsigned)time(NULL));
RandomHold = dwSeed;
SafeRandom.seed(seed);
RandomRng.seed(seed);
RandomCount = 0;
}
int Random(int iRange)
static void RecordRandom(uint32_t range, uint32_t val)
{
RandomCount++;
if (Config.General.DebugRec)
{
// next pseudorandom value
RandomCount++;
C4RCRandom rc;
rc.Cnt=RandomCount;
rc.Range=iRange;
if (iRange<=0)
rc.Val=0;
else
{
RandomHold = ((uint64_t)RandomHold * 16807) % 2147483647;
rc.Val = RandomHold % iRange;
}
rc.Range=range;
rc.Val=val;
AddDbgRec(RCT_Random, &rc, sizeof(rc));
return rc.Val;
}
else
{
RandomCount++;
if (iRange<=0) return 0;
RandomHold = ((uint64_t)RandomHold * 16807) % 2147483647;
return RandomHold % iRange;
}
}
uint32_t Random()
{
uint32_t result = RandomRng();
RecordRandom(UINT32_MAX, result);
return result;
}
uint32_t Random(uint32_t iRange)
{
if (!iRange) return 0u;
uint32_t result = RandomRng(iRange);
RecordRandom(iRange, result);
return result;
}

View File

@ -20,24 +20,20 @@
#ifndef INC_C4Random
#define INC_C4Random
#include <pcg/pcg_random.hpp>
extern int RandomCount;
extern pcg32 SafeRandom;
void FixedRandom(DWORD dwSeed);
void FixedRandom(uint64_t dwSeed);
int Random(int iRange);
uint32_t Random(uint32_t iRange);
inline unsigned int SeededRandom(unsigned int iSeed, unsigned int iRange)
inline uint32_t SeededRandom(uint64_t iSeed, uint32_t iRange)
{
if (!iRange) return 0;
iSeed = iSeed * 214013L + 2531011L;
return (iSeed >> 16) % iRange;
}
inline int SafeRandom(int range)
{
if (!range) return 0;
return rand()%range;
pcg32 rng(iSeed);
return rng(iRange);
}
#endif // INC_C4Random

View File

@ -148,7 +148,7 @@ void StdCompilerBinRead::String(char **pszString, RawCompileType eType)
if (iPos >= Buf.getSize())
{ excEOF(); return; }
// Allocate and copy data
*pszString = new char [iPos - iStart];
*pszString = (char *) malloc(iPos - iStart);
memcpy(*pszString, Buf.getPtr(iStart), iPos - iStart);
}

View File

@ -17,6 +17,7 @@
#include "C4Include.h"
#include "network/C4NetIO.h"
#include "lib/C4Random.h"
#include <iostream>
#include <sstream>
@ -101,7 +102,7 @@ int main(int argc, char * argv[])
for (i = 0; i < sizeof(DummyData); i++)
DummyData[i] = 'A' + i % 100;
srand(time(NULL));
FixedRandom(time(NULL));
#ifdef USE_UDP
C4NetIOUDP NetIO;

View File

@ -15,6 +15,7 @@
*/
#include "C4Include.h"
#include "network/C4NetIO.h"
#include "lib/C4Random.h"
#include "config/C4Constants.h"
#include "config/C4Config.h"
@ -1887,7 +1888,7 @@ bool C4NetIOUDP::InitBroadcast(addr_t *pBroadcastAddr)
{
// create new - random - address
MCAddr.sin_addr.s_addr =
0x000000ef | ((rand() & 0xff) << 24) | ((rand() & 0xff) << 16) | ((rand() & 0xff) << 8);
0x000000ef | (SafeRandom(0x1000000) << 8);
// init broadcast
if (!C4NetIOSimpleUDP::InitBroadcast(&MCAddr))
return false;
@ -3031,7 +3032,7 @@ bool C4NetIOUDP::DoLoopbackTest()
if (!C4NetIOSimpleUDP::getMCLoopback()) return false;
// send test packet
const PacketHdr TestPacket = { uint8_t(IPID_Test | 0x80), static_cast<uint32_t>(rand()) };
const PacketHdr TestPacket = { uint8_t(IPID_Test | 0x80), SafeRandom(UINT32_MAX) };
if (!C4NetIOSimpleUDP::Broadcast(C4NetIOPacket(&TestPacket, sizeof(TestPacket))))
return false;

View File

@ -1215,9 +1215,9 @@ bool C4Network2ResChunk::Set(C4Network2Res *pRes, uint32_t inChunk)
if (lseek(f, iOffset, SEEK_SET) != iOffset)
{ close(f); LogF("Network: could not read resource file %s!", pRes->getFile()); return false; }
// read chunk of data
char *pBuf = new char[iSize];
char *pBuf = (char *) malloc(iSize);
if (read(f, pBuf, iSize) != iSize)
{ delete [] pBuf; close(f); LogF("Network: could not read resource file %s!", pRes->getFile()); return false; }
{ free(pBuf); close(f); LogF("Network: could not read resource file %s!", pRes->getFile()); return false; }
// set
Data.Take(pBuf, iSize);
// close

View File

@ -632,34 +632,25 @@ void C4Object::DrawFace(C4TargetFacet &cgo, float offX, float offY, int32_t iPha
fhgt = thgt;
}
// Straight or a mesh; meshes are rotated before the draw transform is applied to ensure correct lighting
if (GetGraphics()->Type == C4DefGraphics::TYPE_Mesh || ((!Def->Rotateable || (fix_r == Fix0)) && !pDrawTransform))
C4DrawTransform transform;
bool transform_active = false;
if (pDrawTransform)
{
DrawFaceImpl(cgo, false, fx, fy, fwdt, fhgt, tx, ty, twdt, thgt, NULL);
/* pDraw->Blit(GetGraphics()->GetBitmap(Color),
fx, fy, fwdt, fhgt,
cgo.Surface, tx, ty, twdt, thgt,
true, NULL);*/
transform.SetTransformAt(*pDrawTransform, offX, offY);
transform_active = true;
}
// Rotated or transformed
else
// Meshes aren't rotated via DrawTransform to ensure lighting is applied correctly.
if (GetGraphics()->Type != C4DefGraphics::TYPE_Mesh && Def->Rotateable && fix_r != Fix0)
{
C4DrawTransform rot;
if (pDrawTransform)
{
rot.SetTransformAt(*pDrawTransform, offX, offY);
if (fix_r != Fix0) rot.Rotate(fixtof(fix_r), offX, offY);
}
transform.Rotate(fixtof(fix_r), offX, offY);
else
{
rot.SetRotate(fixtof(fix_r), offX, offY);
}
DrawFaceImpl(cgo, false, fx, fy, fwdt, fhgt, tx, ty, twdt, thgt, &rot);
/* pDraw->Blit(GetGraphics()->GetBitmap(Color),
fx, fy, fwdt, fhgt,
cgo.Surface, tx, ty, twdt, thgt,
true, &rot);*/
transform.SetRotate(fixtof(fix_r), offX, offY);
transform_active = true;
}
DrawFaceImpl(cgo, false, fx, fy, fwdt, fhgt, tx, ty, twdt, thgt, transform_active ? &transform : NULL);
}
void C4Object::DrawActionFace(C4TargetFacet &cgo, float offX, float offY) const
@ -704,33 +695,26 @@ void C4Object::DrawActionFace(C4TargetFacet &cgo, float offX, float offY) const
fy += offset_from_top;
fhgt -= offset_from_top;
}
C4DrawTransform transform;
bool transform_active = false;
if (pDrawTransform)
{
transform.SetTransformAt(*pDrawTransform, offX, offY);
transform_active = true;
}
// Straight or a mesh; meshes are rotated before the draw transform is applied to ensure correct lighting
if (GetGraphics()->Type == C4DefGraphics::TYPE_Mesh || ((!Def->Rotateable || (fix_r == Fix0)) && !pDrawTransform))
// Meshes aren't rotated via DrawTransform to ensure lighting is applied correctly.
if (GetGraphics()->Type != C4DefGraphics::TYPE_Mesh && Def->Rotateable && fix_r != Fix0)
{
DrawFaceImpl(cgo, true, fx, fy, fwdt, fhgt, tx, ty, twdt, thgt, NULL);
}
// Rotated or transformed
else
{
// rotate midpoint of action facet around center of shape
// combine with existing transform if necessary
C4DrawTransform rot;
if (pDrawTransform)
{
rot.SetTransformAt(*pDrawTransform, offX, offY);
if (fix_r != Fix0) rot.Rotate(fixtof(fix_r), offX, offY);
}
transform.Rotate(fixtof(fix_r), offX, offY);
else
{
rot.SetRotate(fixtof(fix_r), offX, offY);
}
DrawFaceImpl(cgo, true, fx, fy, fwdt, fhgt, tx, ty, twdt, thgt, &rot);
/* pDraw->Blit(Action.Facet.Surface,
fx, fy, fwdt, fhgt,
cgo.Surface, tx, ty, twdt, thgt,
true, &rot);*/
transform.SetRotate(fixtof(fix_r), offX, offY);
transform_active = true;
}
DrawFaceImpl(cgo, true, fx, fy, fwdt, fhgt, tx, ty, twdt, thgt, transform_active ? &transform : NULL);
}
void C4Object::UpdateMass()

644
thirdparty/pcg/pcg_extras.hpp vendored 100644
View File

@ -0,0 +1,644 @@
/*
* PCG Random Number Generation for C++
*
* Copyright 2014 Melissa O'Neill <oneill@pcg-random.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* For additional information about the PCG random number generation scheme,
* including its license and other licensing options, visit
*
* http://www.pcg-random.org
*/
/*
* Modified by The OpenClonk.org Project to improve compatibility with
* Microsoft Visual C++.
*/
/*
* This file provides support code that is useful for random-number generation
* but not specific to the PCG generation scheme, including:
* - 128-bit int support for platforms where it isn't available natively
* - bit twiddling operations
* - I/O of 128-bit and 8-bit integers
* - Handling the evilness of SeedSeq
* - Support for efficiently producing random numbers less than a given
* bound
*/
#ifndef PCG_EXTRAS_HPP_INCLUDED
#define PCG_EXTRAS_HPP_INCLUDED 1
#include <cinttypes>
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <limits>
#include <iostream>
#include <type_traits>
#include <utility>
#include <locale>
#include <iterator>
#include <utility>
#ifdef __GNUC__
#include <cxxabi.h>
#endif
/*
* Abstractions for compiler-specific directives
*/
#ifdef __GNUC__
#define PCG_NOINLINE __attribute__((noinline))
#define PCG_ALWAYS_INLINE __attribute__((always_inline))
#else
#define PCG_NOINLINE
#define PCG_ALWAYS_INLINE
#endif
/*
* Some members of the PCG library use 128-bit math. When compiling on 64-bit
* platforms, both GCC and Clang provide 128-bit integer types that are ideal
* for the job.
*
* On 32-bit platforms (or with other compilers), we fall back to a C++
* class that provides 128-bit unsigned integers instead. It may seem
* like we're reinventing the wheel here, because libraries already exist
* that support large integers, but most existing libraries provide a very
* generic multiprecision code, but here we're operating at a fixed size.
* Also, most other libraries are fairly heavyweight. So we use a direct
* implementation. Sadly, it's much slower than hand-coded assembly or
* direct CPU support.
*
*/
#if __SIZEOF_INT128__
namespace pcg_extras {
typedef __uint128_t pcg128_t;
}
#define PCG_128BIT_CONSTANT(high,low) \
((pcg128_t(high) << 64) + low)
#else
#include "pcg_uint128.hpp"
namespace pcg_extras {
typedef pcg_extras::uint_x4<uint32_t,uint64_t> pcg128_t;
}
#define PCG_128BIT_CONSTANT(high,low) \
pcg128_t(high,low)
#define PCG_EMULATED_128BIT_MATH 1
#endif
namespace pcg_extras {
/*
* We often need to represent a "number of bits". When used normally, these
* numbers are never greater than 128, so an unsigned char is plenty.
* If you're using a nonstandard generator of a larger size, you can set
* PCG_BITCOUNT_T to have it define it as a larger size. (Some compilers
* might produce faster code if you set it to an unsigned int.)
*/
#ifndef PCG_BITCOUNT_T
typedef uint8_t bitcount_t;
#else
typedef PCG_BITCOUNT_T bitcount_t;
#endif
/*
* C++ requires us to be able to serialize RNG state by printing or reading
* it from a stream. Because we use 128-bit ints, we also need to be able
* ot print them, so here is code to do so.
*
* This code provides enough functionality to print 128-bit ints in decimal
* and zero-padded in hex. It's not a full-featured implementation.
*/
template <typename CharT, typename Traits>
std::basic_ostream<CharT,Traits>&
operator<<(std::basic_ostream<CharT,Traits>& out, pcg128_t value)
{
auto desired_base = out.flags() & out.basefield;
bool want_hex = desired_base == out.hex;
if (want_hex) {
uint64_t highpart = uint64_t(value >> 64);
uint64_t lowpart = uint64_t(value);
auto desired_width = out.width();
if (desired_width > 16) {
out.width(desired_width - 16);
}
if (highpart != 0 || desired_width > 16)
out << highpart;
CharT oldfill;
if (highpart != 0) {
out.width(16);
oldfill = out.fill('0');
}
auto oldflags = out.setf(decltype(desired_base){}, out.showbase);
out << lowpart;
out.setf(oldflags);
if (highpart != 0) {
out.fill(oldfill);
}
return out;
}
constexpr size_t MAX_CHARS_128BIT = 40;
char buffer[MAX_CHARS_128BIT];
char* pos = buffer+sizeof(buffer);
*(--pos) = '\0';
constexpr auto BASE = pcg128_t(10ULL);
do {
auto div = value / BASE;
auto mod = uint32_t(value - (div * BASE));
*(--pos) = '0' + mod;
value = div;
} while(value != pcg128_t(0ULL));
return out << pos;
}
template <typename CharT, typename Traits>
std::basic_istream<CharT,Traits>&
operator>>(std::basic_istream<CharT,Traits>& in, pcg128_t& value)
{
typename std::basic_istream<CharT,Traits>::sentry s(in);
if (!s)
return in;
constexpr auto BASE = pcg128_t(10ULL);
pcg128_t current(0ULL);
bool did_nothing = true;
bool overflow = false;
for(;;) {
CharT wide_ch = in.get();
if (!in.good())
break;
auto ch = in.narrow(wide_ch, '\0');
if (ch < '0' || ch > '9') {
in.unget();
break;
}
did_nothing = false;
pcg128_t digit(uint32_t(ch - '0'));
pcg128_t timesbase = current*BASE;
overflow = overflow || timesbase < current;
current = timesbase + digit;
overflow = overflow || current < digit;
}
if (did_nothing || overflow) {
in.setstate(std::ios::failbit);
if (overflow)
current = ~pcg128_t(0ULL);
}
value = current;
return in;
}
/*
* Likewise, if people use tiny rngs, we'll be serializing uint8_t.
* If we just used the provided IO operators, they'd read/write chars,
* not ints, so we need to define our own. We *can* redefine this operator
* here because we're in our own namespace.
*/
template <typename CharT, typename Traits>
std::basic_ostream<CharT,Traits>&
operator<<(std::basic_ostream<CharT,Traits>&out, uint8_t value)
{
return out << uint32_t(value);
}
template <typename CharT, typename Traits>
std::basic_istream<CharT,Traits>&
operator>>(std::basic_istream<CharT,Traits>& in, uint8_t target)
{
uint32_t value = 0xdecea5edU;
in >> value;
if (!in && value == 0xdecea5edU)
return in;
if (value > uint8_t(~0)) {
in.setstate(std::ios::failbit);
value = ~0U;
}
target = uint8_t(value);
return in;
}
/* Unfortunately, the above functions don't get found in preference to the
* built in ones, so we create some more specific overloads that will.
* Ugh.
*/
inline std::ostream& operator<<(std::ostream& out, uint8_t value)
{
return pcg_extras::operator<< <char>(out, value);
}
inline std::istream& operator>>(std::istream& in, uint8_t& value)
{
return pcg_extras::operator>> <char>(in, value);
}
/*
* Useful bitwise operations.
*/
/*
* XorShifts are invertable, but they are someting of a pain to invert.
* This function backs them out. It's used by the whacky "inside out"
* generator defined later.
*/
template <typename itype>
inline itype unxorshift(itype x, bitcount_t bits, bitcount_t shift)
{
if (2*shift >= bits) {
return x ^ (x >> shift);
}
itype lowmask1 = (itype(1U) << (bits - shift*2)) - 1;
itype highmask1 = ~lowmask1;
itype top1 = x;
itype bottom1 = x & lowmask1;
top1 ^= top1 >> shift;
top1 &= highmask1;
x = top1 | bottom1;
itype lowmask2 = (itype(1U) << (bits - shift)) - 1;
itype bottom2 = x & lowmask2;
bottom2 = unxorshift(bottom2, bits - shift, shift);
bottom2 &= lowmask1;
return top1 | bottom2;
}
/*
* Rotate left and right.
*
* In ideal world, compilers would spot idiomatic rotate code and convert it
* to a rotate instruction. Of course, opinions vary on what the correct
* idiom is and how to spot it. For clang, sometimes it generates better
* (but still crappy) code if you define PCG_USE_ZEROCHECK_ROTATE_IDIOM.
*/
template <typename itype>
inline itype rotl(itype value, bitcount_t rot)
{
constexpr bitcount_t bits = sizeof(itype) * 8;
constexpr bitcount_t mask = bits - 1;
#if PCG_USE_ZEROCHECK_ROTATE_IDIOM
return rot ? (value << rot) | (value >> (bits - rot)) : value;
#else
return (value << rot) | (value >> ((- rot) & mask));
#endif
}
template <typename itype>
inline itype rotr(itype value, bitcount_t rot)
{
constexpr bitcount_t bits = sizeof(itype) * 8;
constexpr bitcount_t mask = bits - 1;
#if PCG_USE_ZEROCHECK_ROTATE_IDIOM
return rot ? (value >> rot) | (value << (bits - rot)) : value;
#else
return (value >> rot) | (value << ((- rot) & mask));
#endif
}
/* Unfortunately, both Clang and GCC sometimes perform poorly when it comes
* to properly recognizing idiomatic rotate code, so for we also provide
* assembler directives (enabled with PCG_USE_INLINE_ASM). Boo, hiss.
* (I hope that these compilers get better so that this code can die.)
*
* These overloads will be preferred over the general template code above.
*/
#if PCG_USE_INLINE_ASM && __GNUC__ && (__x86_64__ || __i386__)
inline uint8_t rotr(uint8_t value, bitcount_t rot)
{
asm ("rorb %%cl, %0" : "=r" (value) : "0" (value), "c" (rot));
return value;
}
inline uint16_t rotr(uint16_t value, bitcount_t rot)
{
asm ("rorw %%cl, %0" : "=r" (value) : "0" (value), "c" (rot));
return value;
}
inline uint32_t rotr(uint32_t value, bitcount_t rot)
{
asm ("rorl %%cl, %0" : "=r" (value) : "0" (value), "c" (rot));
return value;
}
#if __x86_64__
inline uint64_t rotr(uint64_t value, bitcount_t rot)
{
asm ("rorq %%cl, %0" : "=r" (value) : "0" (value), "c" (rot));
return value;
}
#endif // __x86_64__
#endif // PCG_USE_INLINE_ASM
/*
* The C++ SeedSeq concept (modelled by seed_seq) can fill an array of
* 32-bit integers with seed data, but sometimes we want to produce
* larger or smaller integers.
*
* The following code handles this annoyance.
*
* uneven_copy will copy an array of 32-bit ints to an array of larger or
* smaller ints (actually, the code is general it only needing forward
* iterators). The copy is identical to the one that would be performed if
* we just did memcpy on a standard little-endian machine, but works
* regardless of the endian of the machine (or the weirdness of the ints
* involved).
*
* generate_to initializes an array of integers using a SeedSeq
* object. It is given the size as a static constant at compile time and
* tries to avoid memory allocation. If we're filling in 32-bit constants
* we just do it directly. If we need a separate buffer and it's small,
* we allocate it on the stack. Otherwise, we fall back to heap allocation.
* Ugh.
*
* generate_one produces a single value of some integral type using a
* SeedSeq object.
*/
/* uneven_copy helper, case where destination ints are less than 32 bit. */
template<class SrcIter, class DestIter>
SrcIter uneven_copy_impl(
SrcIter src_first, DestIter dest_first, DestIter dest_last,
std::true_type)
{
typedef typename std::iterator_traits<SrcIter>::value_type src_t;
typedef typename std::iterator_traits<DestIter>::value_type dest_t;
constexpr bitcount_t SRC_SIZE = sizeof(src_t);
constexpr bitcount_t DEST_SIZE = sizeof(dest_t);
constexpr bitcount_t DEST_BITS = DEST_SIZE * 8;
constexpr bitcount_t SCALE = SRC_SIZE / DEST_SIZE;
size_t count = 0;
src_t value;
while (dest_first != dest_last) {
if ((count++ % SCALE) == 0)
value = *src_first++; // Get more bits
else
value >>= DEST_BITS; // Move down bits
*dest_first++ = dest_t(value); // Truncates, ignores high bits.
}
return src_first;
}
/* uneven_copy helper, case where destination ints are more than 32 bit. */
template<class SrcIter, class DestIter>
SrcIter uneven_copy_impl(
SrcIter src_first, DestIter dest_first, DestIter dest_last,
std::false_type)
{
typedef typename std::iterator_traits<SrcIter>::value_type src_t;
typedef typename std::iterator_traits<DestIter>::value_type dest_t;
constexpr auto SRC_SIZE = sizeof(src_t);
constexpr auto SRC_BITS = SRC_SIZE * 8;
constexpr auto DEST_SIZE = sizeof(dest_t);
constexpr auto SCALE = (DEST_SIZE+SRC_SIZE-1) / SRC_SIZE;
while (dest_first != dest_last) {
dest_t value(0UL);
unsigned int shift = 0;
for (size_t i = 0; i < SCALE; ++i) {
value |= dest_t(*src_first++) << shift;
shift += SRC_BITS;
}
*dest_first++ = value;
}
return src_first;
}
/* uneven_copy, call the right code for larger vs. smaller */
template<class SrcIter, class DestIter>
inline SrcIter uneven_copy(SrcIter src_first,
DestIter dest_first, DestIter dest_last)
{
typedef typename std::iterator_traits<SrcIter>::value_type src_t;
typedef typename std::iterator_traits<DestIter>::value_type dest_t;
constexpr bool DEST_IS_SMALLER = sizeof(dest_t) < sizeof(src_t);
return uneven_copy_impl(src_first, dest_first, dest_last,
std::integral_constant<bool, DEST_IS_SMALLER>{});
}
/* generate_to, fill in a fixed-size array of integral type using a SeedSeq
* (actually works for any random-access iterator)
*/
template <size_t size, typename SeedSeq, typename DestIter>
inline void generate_to_impl(SeedSeq&& generator, DestIter dest,
std::true_type)
{
generator.generate(dest, dest+size);
}
template <size_t size, typename SeedSeq, typename DestIter>
void generate_to_impl(SeedSeq&& generator, DestIter dest,
std::false_type)
{
typedef typename std::iterator_traits<DestIter>::value_type dest_t;
constexpr auto DEST_SIZE = sizeof(dest_t);
constexpr auto GEN_SIZE = sizeof(uint32_t);
constexpr bool GEN_IS_SMALLER = GEN_SIZE < DEST_SIZE;
constexpr size_t FROM_ELEMS =
GEN_IS_SMALLER
? size * ((DEST_SIZE+GEN_SIZE-1) / GEN_SIZE)
: (size + (GEN_SIZE / DEST_SIZE) - 1)
/ ((GEN_SIZE / DEST_SIZE) + GEN_IS_SMALLER);
// this odd code ^^^^^^^^^^^^^^^^^ is work-around for
// a bug: http://llvm.org/bugs/show_bug.cgi?id=21287
if (FROM_ELEMS <= 1024) {
uint32_t buffer[FROM_ELEMS];
generator.generate(buffer, buffer+FROM_ELEMS);
uneven_copy(buffer, dest, dest+size);
} else {
uint32_t* buffer = (uint32_t*) malloc(GEN_SIZE * FROM_ELEMS);
generator.generate(buffer, buffer+FROM_ELEMS);
uneven_copy(buffer, dest, dest+size);
free(buffer);
}
}
template <size_t size, typename SeedSeq, typename DestIter>
inline void generate_to(SeedSeq&& generator, DestIter dest)
{
typedef typename std::iterator_traits<DestIter>::value_type dest_t;
constexpr bool IS_32BIT = sizeof(dest_t) == sizeof(uint32_t);
generate_to_impl<size>(std::forward<SeedSeq>(generator), dest,
std::integral_constant<bool, IS_32BIT>{});
}
/* generate_one, produce a value of integral type using a SeedSeq
* (optionally, we can have it produce more than one and pick which one
* we want)
*/
template <typename UInt, size_t i = 0UL, size_t N = i+1UL, typename SeedSeq>
inline UInt generate_one(SeedSeq&& generator)
{
UInt result[N];
generate_to<N>(std::forward<SeedSeq>(generator), result);
return result[i];
}
template <typename RngType>
auto bounded_rand(RngType& rng, typename RngType::result_type upper_bound)
-> typename RngType::result_type
{
typedef typename RngType::result_type rtype;
rtype threshold = (RngType::max() - RngType::min() + rtype(1) - upper_bound)
% upper_bound;
for (;;) {
rtype r = rng() - RngType::min();
if (r >= threshold)
return r % upper_bound;
}
}
template <typename Iter, typename RandType>
void shuffle(Iter from, Iter to, RandType&& rng)
{
typedef typename std::iterator_traits<Iter>::difference_type delta_t;
auto count = to - from;
while (count > 1) {
delta_t chosen(bounded_rand(rng, count));
--count;
--to;
using std::swap;
swap(*(from+chosen), *to);
}
}
/*
* Although std::seed_seq is useful, it isn't everything. Often we want to
* initialize a random-number generator some other way, such as from a random
* device.
*
* Technically, it does not meet the requirements of a SeedSequence because
* it lacks some of the rarely-used member functions (some of which would
* be impossible to provide). However the C++ standard is quite specific
* that actual engines only called the generate method, so it ought not to be
* a problem in practice.
*/
template <typename RngType>
class seed_seq_from {
private:
RngType rng_;
typedef uint_least32_t result_type;
public:
template<typename... Args>
seed_seq_from(Args&&... args) :
rng_(std::forward<Args>(args)...)
{
// Nothing (else) to do...
}
template<typename Iter>
void generate(Iter start, Iter finish)
{
for (auto i = start; i != finish; ++i)
*i = result_type(rng_());
}
constexpr size_t size() const
{
return (sizeof(typename RngType::result_type) > sizeof(result_type)
&& RngType::max() > ~size_t(0UL))
? ~size_t(0UL)
: size_t(RngType::max());
}
};
/*
* Sometimes you might want a distinct seed based on when the program
* was compiled. That way, a particular instance of the program will
* behave the same way, but when recompiled it'll produce a different
* value.
*/
template <typename IntType>
struct static_arbitrary_seed {
private:
static constexpr IntType fnv(IntType hash, const char* pos) {
return *pos == '\0'
? hash
: fnv((hash * IntType(16777619U)) ^ *pos, (pos+1));
}
public:
static constexpr IntType value = fnv(IntType(2166136261U ^ sizeof(IntType)),
__DATE__ __TIME__ __FILE__);
};
// Sometimes, when debugging or testing, it's handy to be able print the name
// of a (in human-readable form). This code allows the idiom:
//
// cout << printable_typename<my_foo_type_t>()
//
// to print out my_foo_type_t (or its concrete type if it is a synonym)
template <typename T>
struct printable_typename {};
template <typename T>
std::ostream& operator<<(std::ostream& out, printable_typename<T>) {
const char *implementation_typename = typeid(T).name();
#ifdef __GNUC__
int status;
const char* pretty_name =
abi::__cxa_demangle(implementation_typename, NULL, NULL, &status);
if (status == 0)
out << pretty_name;
free((void*) pretty_name);
if (status == 0)
return out;
#endif
out << implementation_typename;
return out;
}
} // namespace pcg_extras
#endif // PCG_EXTRAS_HPP_INCLUDED

1756
thirdparty/pcg/pcg_random.hpp vendored 100644

File diff suppressed because it is too large Load Diff

756
thirdparty/pcg/pcg_uint128.hpp vendored 100644
View File

@ -0,0 +1,756 @@
/*
* PCG Random Number Generation for C++
*
* Copyright 2014 Melissa O'Neill <oneill@pcg-random.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* For additional information about the PCG random number generation scheme,
* including its license and other licensing options, visit
*
* http://www.pcg-random.org
*/
/*
* Modified by The OpenClonk.org Project to improve compatibility with
* Microsoft Visual C++.
*/
/*
* This code provides a a C++ class that can provide 128-bit (or higher)
* integers. To produce 2K-bit integers, it uses two K-bit integers,
* placed in a union that allowes the code to also see them as four K/2 bit
* integers (and access them either directly name, or by index).
*
* It may seem like we're reinventing the wheel here, because several
* libraries already exist that support large integers, but most existing
* libraries provide a very generic multiprecision code, but here we're
* operating at a fixed size. Also, most other libraries are fairly
* heavyweight. So we use a direct implementation. Sadly, it's much slower
* than hand-coded assembly or direct CPU support.
*/
#ifndef PCG_UINT128_HPP_INCLUDED
#define PCG_UINT128_HPP_INCLUDED 1
#include <cstdint>
#include <cstdio>
#include <cassert>
#include <climits>
#include <utility>
#include <initializer_list>
#include <type_traits>
/*
* We want to lay the type out the same way that a native type would be laid
* out, which means we must know the machine's endian, at compile time.
* This ugliness attempts to do so.
*/
#ifndef PCG_LITTLE_ENDIAN
#if defined(__BYTE_ORDER__)
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define PCG_LITTLE_ENDIAN 1
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define PCG_LITTLE_ENDIAN 0
#else
#error __BYTE_ORDER__ does not match a standard endian, pick a side
#endif
#elif __LITTLE_ENDIAN__ || _LITTLE_ENDIAN
#define PCG_LITTLE_ENDIAN 1
#elif __BIG_ENDIAN__ || _BIG_ENDIAN
#define PCG_LITTLE_ENDIAN 0
#elif __x86_64 || __x86_64__ || __i386 || __i386__ \
|| _M_X64 || _M_IX86 || _M_ARM || _M_IA64
#define PCG_LITTLE_ENDIAN 1
#elif __powerpc__ || __POWERPC__ || __ppc__ || __PPC__ \
|| __m68k__ || __mc68000__
#define PCG_LITTLE_ENDIAN 0
#else
#error Unable to determine target endianness
#endif
#endif
namespace pcg_extras {
// Recent versions of GCC have intrinsics we can use to quickly calculate
// the number of leading and trailing zeros in a number. If possible, we
// use them, otherwise we fall back to old-fashioned bit twiddling to figure
// them out.
#ifndef PCG_BITCOUNT_T
typedef uint8_t bitcount_t;
#else
typedef PCG_BITCOUNT_T bitcount_t;
#endif
/*
* Provide some useful helper functions
* * flog2 floor(log2(x))
* * trailingzeros number of trailing zero bits
*/
#ifdef __GNUC__ // Any GNU-compatible compiler supporting C++11 has
// some useful intrinsics we can use.
inline bitcount_t flog2(uint32_t v)
{
return 31 - __builtin_clz(v);
}
inline bitcount_t trailingzeros(uint32_t v)
{
return __builtin_ctz(v);
}
inline bitcount_t flog2(uint64_t v)
{
#if UINT64_MAX == ULONG_MAX
return 63 - __builtin_clzl(v);
#elif UINT64_MAX == ULLONG_MAX
return 63 - __builtin_clzll(v);
#else
#error Cannot find a function for uint64_t
#endif
}
inline bitcount_t trailingzeros(uint64_t v)
{
#if UINT64_MAX == ULONG_MAX
return __builtin_ctzl(v);
#elif UINT64_MAX == ULLONG_MAX
return __builtin_ctzll(v);
#else
#error Cannot find a function for uint64_t
#endif
}
#else // Otherwise, we fall back to bit twiddling
// implementations
inline bitcount_t flog2(uint32_t v)
{
// Based on code by Eric Cole and Mark Dickinson, which appears at
// https://graphics.stanford.edu/~seander/bithacks.html#IntegerLogDeBruijn
static const uint8_t multiplyDeBruijnBitPos[32] = {
0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30,
8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31
};
v |= v >> 1; // first round down to one less than a power of 2
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
return multiplyDeBruijnBitPos[(uint32_t)(v * 0x07C4ACDDU) >> 27];
}
inline bitcount_t trailingzeros(uint32_t v)
{
static const uint8_t multiplyDeBruijnBitPos[32] = {
0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
};
return multiplyDeBruijnBitPos[((uint32_t)((v & -v) * 0x077CB531U)) >> 27];
}
inline bitcount_t flog2(uint64_t v)
{
uint32_t high = v >> 32;
uint32_t low = uint32_t(v);
return high ? 32+flog2(high) : flog2(low);
}
inline bitcount_t trailingzeros(uint64_t v)
{
uint32_t high = v >> 32;
uint32_t low = uint32_t(v);
return low ? trailingzeros(low) : trailingzeros(high)+32;
}
#endif
template <typename UInt>
inline bitcount_t clog2(UInt v)
{
return flog2(v) + ((v & (-v)) != v);
}
template <typename UInt>
inline UInt addwithcarry(UInt x, UInt y, bool carryin, bool* carryout)
{
UInt half_result = y + carryin;
UInt result = x + half_result;
*carryout = (half_result < y) || (result < x);
return result;
}
template <typename UInt>
inline UInt subwithcarry(UInt x, UInt y, bool carryin, bool* carryout)
{
UInt half_result = y + carryin;
UInt result = x - half_result;
*carryout = (half_result < y) || (result > x);
return result;
}
template <typename UInt, typename UIntX2>
class uint_x4 {
// private:
public:
union {
#if PCG_LITTLE_ENDIAN
struct {
UInt v0, v1, v2, v3;
} w;
struct {
UIntX2 v01, v23;
} d;
#else
struct {
UInt v3, v2, v1, v0;
} w;
struct {
UIntX2 v23, v01;
} d;
#endif
// For the array access versions, the code that uses the array
// must handle endian itself. Yuck.
UInt wa[4];
UIntX2 da[2];
};
public:
uint_x4() = default;
constexpr uint_x4(UInt v3, UInt v2, UInt v1, UInt v0)
#if PCG_LITTLE_ENDIAN
: w{v0, v1, v2, v3}
#else
: w{v3, v2, v1, v0}
#endif
{
// Nothing (else) to do
}
constexpr uint_x4(UIntX2 v23, UIntX2 v01)
#if PCG_LITTLE_ENDIAN
: d{v01,v23}
#else
: d{v23,v01}
#endif
{
// Nothing (else) to do
}
template<class Integral,
typename std::enable_if<(std::is_integral<Integral>::value
&& sizeof(Integral) <= sizeof(UIntX2))
>::type* = nullptr>
constexpr uint_x4(Integral v01)
#if PCG_LITTLE_ENDIAN
: d{UIntX2(v01),0UL}
#else
: d{0UL,UIntX2(v01)}
#endif
{
// Nothing (else) to do
}
explicit constexpr operator uint64_t() const
{
return d.v01;
}
explicit constexpr operator uint32_t() const
{
return w.v0;
}
explicit constexpr operator int() const
{
return w.v0;
}
explicit constexpr operator uint16_t() const
{
return w.v0;
}
explicit constexpr operator uint8_t() const
{
return w.v0;
}
typedef typename std::conditional<std::is_same<uint64_t,
unsigned long>::value,
unsigned long long,
unsigned long>::type
uint_missing_t;
explicit constexpr operator uint_missing_t() const
{
return d.v01;
}
explicit constexpr operator bool() const
{
return d.v01 || d.v23;
}
template<typename U, typename V>
friend uint_x4<U,V> operator*(const uint_x4<U,V>&, const uint_x4<U,V>&);
template<typename U, typename V>
friend std::pair< uint_x4<U,V>,uint_x4<U,V> >
divmod(const uint_x4<U,V>&, const uint_x4<U,V>&);
template<typename U, typename V>
friend uint_x4<U,V> operator+(const uint_x4<U,V>&, const uint_x4<U,V>&);
template<typename U, typename V>
friend uint_x4<U,V> operator-(const uint_x4<U,V>&, const uint_x4<U,V>&);
template<typename U, typename V>
friend uint_x4<U,V> operator<<(const uint_x4<U,V>&, const uint_x4<U,V>&);
template<typename U, typename V>
friend uint_x4<U,V> operator>>(const uint_x4<U,V>&, const uint_x4<U,V>&);
template<typename U, typename V>
friend uint_x4<U,V> operator&(const uint_x4<U,V>&, const uint_x4<U,V>&);
template<typename U, typename V>
friend uint_x4<U,V> operator|(const uint_x4<U,V>&, const uint_x4<U,V>&);
template<typename U, typename V>
friend uint_x4<U,V> operator^(const uint_x4<U,V>&, const uint_x4<U,V>&);
template<typename U, typename V>
friend bool operator==(const uint_x4<U,V>&, const uint_x4<U,V>&);
template<typename U, typename V>
friend bool operator!=(const uint_x4<U,V>&, const uint_x4<U,V>&);
template<typename U, typename V>
friend bool operator<(const uint_x4<U,V>&, const uint_x4<U,V>&);
template<typename U, typename V>
friend bool operator<=(const uint_x4<U,V>&, const uint_x4<U,V>&);
template<typename U, typename V>
friend bool operator>(const uint_x4<U,V>&, const uint_x4<U,V>&);
template<typename U, typename V>
friend bool operator>=(const uint_x4<U,V>&, const uint_x4<U,V>&);
template<typename U, typename V>
friend uint_x4<U,V> operator~(const uint_x4<U,V>&);
template<typename U, typename V>
friend uint_x4<U,V> operator-(const uint_x4<U,V>&);
template<typename U, typename V>
friend bitcount_t flog2(const uint_x4<U,V>&);
template<typename U, typename V>
friend bitcount_t trailingzeros(const uint_x4<U,V>&);
uint_x4& operator*=(const uint_x4& rhs)
{
uint_x4 result = *this * rhs;
return *this = result;
}
uint_x4& operator/=(const uint_x4& rhs)
{
uint_x4 result = *this / rhs;
return *this = result;
}
uint_x4& operator%=(const uint_x4& rhs)
{
uint_x4 result = *this % rhs;
return *this = result;
}
uint_x4& operator+=(const uint_x4& rhs)
{
uint_x4 result = *this + rhs;
return *this = result;
}
uint_x4& operator-=(const uint_x4& rhs)
{
uint_x4 result = *this - rhs;
return *this = result;
}
uint_x4& operator&=(const uint_x4& rhs)
{
uint_x4 result = *this & rhs;
return *this = result;
}
uint_x4& operator|=(const uint_x4& rhs)
{
uint_x4 result = *this | rhs;
return *this = result;
}
uint_x4& operator^=(const uint_x4& rhs)
{
uint_x4 result = *this ^ rhs;
return *this = result;
}
uint_x4& operator>>=(bitcount_t shift)
{
uint_x4 result = *this >> shift;
return *this = result;
}
uint_x4& operator<<=(bitcount_t shift)
{
uint_x4 result = *this << shift;
return *this = result;
}
};
template<typename U, typename V>
bitcount_t flog2(const uint_x4<U,V>& v)
{
#if PCG_LITTLE_ENDIAN
for (uint8_t i = 4; i !=0; /* dec in loop */) {
--i;
#else
for (uint8_t i = 0; i < 4; ++i) {
#endif
if (v.wa[i] == 0)
continue;
return flog2(v.wa[i]) + (sizeof(U)*CHAR_BIT)*i;
}
abort();
}
template<typename U, typename V>
bitcount_t trailingzeros(const uint_x4<U,V>& v)
{
#if PCG_LITTLE_ENDIAN
for (uint8_t i = 0; i < 4; ++i) {
#else
for (uint8_t i = 4; i !=0; /* dec in loop */) {
--i;
#endif
if (v.wa[i] != 0)
return trailingzeros(v.wa[i]) + (sizeof(U)*CHAR_BIT)*i;
}
return (sizeof(U)*CHAR_BIT)*4;
}
template <typename UInt, typename UIntX2>
std::pair< uint_x4<UInt,UIntX2>, uint_x4<UInt,UIntX2> >
divmod(const uint_x4<UInt,UIntX2>& orig_dividend,
const uint_x4<UInt,UIntX2>& divisor)
{
// If the dividend is less than the divisor, the answer is always zero.
// This takes care of boundary cases like 0/x (which would otherwise be
// problematic because we can't take the log of zero. (The boundary case
// of division by zero is undefined.)
if (orig_dividend < divisor)
return { uint_x4<UInt,UIntX2>(0UL), orig_dividend };
auto dividend = orig_dividend;
auto log2_divisor = flog2(divisor);
auto log2_dividend = flog2(dividend);
// assert(log2_dividend >= log2_divisor);
bitcount_t logdiff = log2_dividend - log2_divisor;
constexpr uint_x4<UInt,UIntX2> ONE(1UL);
if (logdiff == 0)
return { ONE, dividend - divisor };
// Now we change the log difference to
// floor(log2(divisor)) - ceil(log2(dividend))
// to ensure that we *underestimate* the result.
logdiff -= 1;
uint_x4<UInt,UIntX2> quotient(0UL);
auto qfactor = ONE << logdiff;
auto factor = divisor << logdiff;
do {
dividend -= factor;
quotient += qfactor;
while (dividend < factor) {
factor >>= 1;
qfactor >>= 1;
}
} while (dividend >= divisor);
return { quotient, dividend };
}
template <typename UInt, typename UIntX2>
uint_x4<UInt,UIntX2> operator/(const uint_x4<UInt,UIntX2>& dividend,
const uint_x4<UInt,UIntX2>& divisor)
{
return divmod(dividend, divisor).first;
}
template <typename UInt, typename UIntX2>
uint_x4<UInt,UIntX2> operator%(const uint_x4<UInt,UIntX2>& dividend,
const uint_x4<UInt,UIntX2>& divisor)
{
return divmod(dividend, divisor).second;
}
template <typename UInt, typename UIntX2>
uint_x4<UInt,UIntX2> operator*(const uint_x4<UInt,UIntX2>& a,
const uint_x4<UInt,UIntX2>& b)
{
uint_x4<UInt,UIntX2> r = {0U, 0U, 0U, 0U};
bool carryin = false;
bool carryout;
UIntX2 a0b0 = UIntX2(a.w.v0) * UIntX2(b.w.v0);
r.w.v0 = UInt(a0b0);
r.w.v1 = UInt(a0b0 >> 32);
UIntX2 a1b0 = UIntX2(a.w.v1) * UIntX2(b.w.v0);
r.w.v2 = UInt(a1b0 >> 32);
r.w.v1 = addwithcarry(r.w.v1, UInt(a1b0), carryin, &carryout);
carryin = carryout;
r.w.v2 = addwithcarry(r.w.v2, UInt(0U), carryin, &carryout);
carryin = carryout;
r.w.v3 = addwithcarry(r.w.v3, UInt(0U), carryin, &carryout);
UIntX2 a0b1 = UIntX2(a.w.v0) * UIntX2(b.w.v1);
carryin = false;
r.w.v2 = addwithcarry(r.w.v2, UInt(a0b1 >> 32), carryin, &carryout);
carryin = carryout;
r.w.v3 = addwithcarry(r.w.v3, UInt(0U), carryin, &carryout);
carryin = false;
r.w.v1 = addwithcarry(r.w.v1, UInt(a0b1), carryin, &carryout);
carryin = carryout;
r.w.v2 = addwithcarry(r.w.v2, UInt(0U), carryin, &carryout);
carryin = carryout;
r.w.v3 = addwithcarry(r.w.v3, UInt(0U), carryin, &carryout);
UIntX2 a1b1 = UIntX2(a.w.v1) * UIntX2(b.w.v1);
carryin = false;
r.w.v2 = addwithcarry(r.w.v2, UInt(a1b1), carryin, &carryout);
carryin = carryout;
r.w.v3 = addwithcarry(r.w.v3, UInt(a1b1 >> 32), carryin, &carryout);
r.d.v23 += a.d.v01 * b.d.v23 + a.d.v23 * b.d.v01;
return r;
}
template <typename UInt, typename UIntX2>
uint_x4<UInt,UIntX2> operator+(const uint_x4<UInt,UIntX2>& a,
const uint_x4<UInt,UIntX2>& b)
{
uint_x4<UInt,UIntX2> r = {0U, 0U, 0U, 0U};
bool carryin = false;
bool carryout;
r.w.v0 = addwithcarry(a.w.v0, b.w.v0, carryin, &carryout);
carryin = carryout;
r.w.v1 = addwithcarry(a.w.v1, b.w.v1, carryin, &carryout);
carryin = carryout;
r.w.v2 = addwithcarry(a.w.v2, b.w.v2, carryin, &carryout);
carryin = carryout;
r.w.v3 = addwithcarry(a.w.v3, b.w.v3, carryin, &carryout);
return r;
}
template <typename UInt, typename UIntX2>
uint_x4<UInt,UIntX2> operator-(const uint_x4<UInt,UIntX2>& a,
const uint_x4<UInt,UIntX2>& b)
{
uint_x4<UInt,UIntX2> r = {0U, 0U, 0U, 0U};
bool carryin = false;
bool carryout;
r.w.v0 = subwithcarry(a.w.v0, b.w.v0, carryin, &carryout);
carryin = carryout;
r.w.v1 = subwithcarry(a.w.v1, b.w.v1, carryin, &carryout);
carryin = carryout;
r.w.v2 = subwithcarry(a.w.v2, b.w.v2, carryin, &carryout);
carryin = carryout;
r.w.v3 = subwithcarry(a.w.v3, b.w.v3, carryin, &carryout);
return r;
}
template <typename UInt, typename UIntX2>
uint_x4<UInt,UIntX2> operator&(const uint_x4<UInt,UIntX2>& a,
const uint_x4<UInt,UIntX2>& b)
{
return uint_x4<UInt,UIntX2>(a.d.v23 & b.d.v23, a.d.v01 & b.d.v01);
}
template <typename UInt, typename UIntX2>
uint_x4<UInt,UIntX2> operator|(const uint_x4<UInt,UIntX2>& a,
const uint_x4<UInt,UIntX2>& b)
{
return uint_x4<UInt,UIntX2>(a.d.v23 | b.d.v23, a.d.v01 | b.d.v01);
}
template <typename UInt, typename UIntX2>
uint_x4<UInt,UIntX2> operator^(const uint_x4<UInt,UIntX2>& a,
const uint_x4<UInt,UIntX2>& b)
{
return uint_x4<UInt,UIntX2>(a.d.v23 ^ b.d.v23, a.d.v01 ^ b.d.v01);
}
template <typename UInt, typename UIntX2>
uint_x4<UInt,UIntX2> operator~(const uint_x4<UInt,UIntX2>& v)
{
return uint_x4<UInt,UIntX2>(~v.d.v23, ~v.d.v01);
}
template <typename UInt, typename UIntX2>
uint_x4<UInt,UIntX2> operator-(const uint_x4<UInt,UIntX2>& v)
{
return uint_x4<UInt,UIntX2>(0UL,0UL) - v;
}
template <typename UInt, typename UIntX2>
bool operator==(const uint_x4<UInt,UIntX2>& a, const uint_x4<UInt,UIntX2>& b)
{
return (a.d.v01 == b.d.v01) && (a.d.v23 == b.d.v23);
}
template <typename UInt, typename UIntX2>
bool operator!=(const uint_x4<UInt,UIntX2>& a, const uint_x4<UInt,UIntX2>& b)
{
return !operator==(a,b);
}
template <typename UInt, typename UIntX2>
bool operator<(const uint_x4<UInt,UIntX2>& a, const uint_x4<UInt,UIntX2>& b)
{
return (a.d.v23 < b.d.v23)
|| ((a.d.v23 == b.d.v23) && (a.d.v01 < b.d.v01));
}
template <typename UInt, typename UIntX2>
bool operator>(const uint_x4<UInt,UIntX2>& a, const uint_x4<UInt,UIntX2>& b)
{
return operator<(b,a);
}
template <typename UInt, typename UIntX2>
bool operator<=(const uint_x4<UInt,UIntX2>& a, const uint_x4<UInt,UIntX2>& b)
{
return !(operator<(b,a));
}
template <typename UInt, typename UIntX2>
bool operator>=(const uint_x4<UInt,UIntX2>& a, const uint_x4<UInt,UIntX2>& b)
{
return !(operator<(a,b));
}
template <typename UInt, typename UIntX2>
uint_x4<UInt,UIntX2> operator<<(const uint_x4<UInt,UIntX2>& v,
const bitcount_t shift)
{
uint_x4<UInt,UIntX2> r = {0U, 0U, 0U, 0U};
const bitcount_t bits = sizeof(UInt) * CHAR_BIT;
const bitcount_t bitmask = bits - 1;
const bitcount_t shiftdiv = shift / bits;
const bitcount_t shiftmod = shift & bitmask;
if (shiftmod) {
UInt carryover = 0;
#if PCG_LITTLE_ENDIAN
for (uint8_t out = shiftdiv, in = 0; out < 4; ++out, ++in) {
#else
for (uint8_t out = 4-shiftdiv, in = 4; out != 0; /* dec in loop */) {
--out, --in;
#endif
r.wa[out] = (v.wa[in] << shiftmod) | carryover;
carryover = (v.wa[in] >> (bits - shiftmod));
}
} else {
#if PCG_LITTLE_ENDIAN
for (uint8_t out = shiftdiv, in = 0; out < 4; ++out, ++in) {
#else
for (uint8_t out = 4-shiftdiv, in = 4; out != 0; /* dec in loop */) {
--out, --in;
#endif
r.wa[out] = v.wa[in];
}
}
return r;
}
template <typename UInt, typename UIntX2>
uint_x4<UInt,UIntX2> operator>>(const uint_x4<UInt,UIntX2>& v,
const bitcount_t shift)
{
uint_x4<UInt,UIntX2> r = {0U, 0U, 0U, 0U};
const bitcount_t bits = sizeof(UInt) * CHAR_BIT;
const bitcount_t bitmask = bits - 1;
const bitcount_t shiftdiv = shift / bits;
const bitcount_t shiftmod = shift & bitmask;
if (shiftmod) {
UInt carryover = 0;
#if PCG_LITTLE_ENDIAN
for (uint8_t out = 4-shiftdiv, in = 4; out != 0; /* dec in loop */) {
--out, --in;
#else
for (uint8_t out = shiftdiv, in = 0; out < 4; ++out, ++in) {
#endif
r.wa[out] = (v.wa[in] >> shiftmod) | carryover;
carryover = (v.wa[in] << (bits - shiftmod));
}
} else {
#if PCG_LITTLE_ENDIAN
for (uint8_t out = 4-shiftdiv, in = 4; out != 0; /* dec in loop */) {
--out, --in;
#else
for (uint8_t out = shiftdiv, in = 0; out < 4; ++out, ++in) {
#endif
r.wa[out] = v.wa[in];
}
}
return r;
}
} // namespace pcg_extras
#endif // PCG_UINT128_HPP_INCLUDED