From 21500a81a96183191b0fc2c0428c756469a0e594 Mon Sep 17 00:00:00 2001 From: Sven Eberhardt Date: Fri, 1 May 2015 18:04:42 +0200 Subject: [PATCH] Fix pump to clear the last row of pixels (#1057) and allow pumping from pump without source pipe. ExtractMaterial has been changed to be able to slurp in from the most distant horizontal position rather than the closest to the extraction top center. Also speed up ExtractMaterial for the common case of no required horizontal shifts. --- docs/sdk/script/fn/ExtractMaterialAmount.xml | 6 ++++ .../Items.ocd/Tools.ocd/Pipe.ocd/Script.c | 1 + .../Structures.ocd/Pump.ocd/Script.c | 30 +++++++++-------- planet/System.ocg/Material.c | 10 +++--- src/gamescript/C4Effect.cpp | 2 +- src/gamescript/C4GameScript.cpp | 4 +-- src/landscape/C4Landscape.cpp | 33 ++++++++++++------- src/landscape/C4Landscape.h | 4 +-- src/landscape/C4MassMover.cpp | 4 +-- src/landscape/C4Material.cpp | 4 +-- 10 files changed, 61 insertions(+), 37 deletions(-) diff --git a/docs/sdk/script/fn/ExtractMaterialAmount.xml b/docs/sdk/script/fn/ExtractMaterialAmount.xml index f438e623f..6ab685d9c 100644 --- a/docs/sdk/script/fn/ExtractMaterialAmount.xml +++ b/docs/sdk/script/fn/ExtractMaterialAmount.xml @@ -31,6 +31,12 @@ amount Maximum amount to be extracted. + + bool + distant_x + If true, material will be extracted at the most distant horizontal position of the top row of the material body, to a maximum of the material's MaxSlide parameter. If used on liquids, this mode ensures that level pools of 1px height can be extracted by extracting from anywhere horizontally. + + Extracts a certain amount of material at the specified position. The return value is the amount actually extracted. diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/Pipe.ocd/Script.c b/planet/Objects.ocd/Items.ocd/Tools.ocd/Pipe.ocd/Script.c index 277d610ba..7e0e8d2df 100644 --- a/planet/Objects.ocd/Items.ocd/Tools.ocd/Pipe.ocd/Script.c +++ b/planet/Objects.ocd/Items.ocd/Tools.ocd/Pipe.ocd/Script.c @@ -8,6 +8,7 @@ local Description = "$Description$"; local UsageHelp = "$UsageHelp$"; local Collectible = 1; local Rebuy = true; +local ApertureOffsetY = 3; // pump from bottom vertex protected func Hit() { diff --git a/planet/Objects.ocd/Structures.ocd/Pump.ocd/Script.c b/planet/Objects.ocd/Structures.ocd/Pump.ocd/Script.c index 0be1c28c5..2c126cce2 100644 --- a/planet/Objects.ocd/Structures.ocd/Pump.ocd/Script.c +++ b/planet/Objects.ocd/Structures.ocd/Pump.ocd/Script.c @@ -167,7 +167,8 @@ protected func Pumping() if (!stored_material_amount) { // get new materials - var mat = GetSourceObject()->ExtractLiquidAmount(0, 0, GetPumpSpeed() / 10); + var source_obj = GetSourceObject(); + var mat = source_obj->ExtractLiquidAmount(source_obj.ApertureOffsetX, source_obj.ApertureOffsetY, GetPumpSpeed() / 10, true); // no material to pump? if (mat) @@ -185,7 +186,8 @@ protected func Pumping() var i = stored_material_amount; while (i > 0) { - if (GetDrainObject()->InsertMaterial(stored_material_index)) + var drain_obj = GetDrainObject(); + if (GetDrainObject()->InsertMaterial(stored_material_index, drain_obj.ApertureOffsetX, drain_obj.ApertureOffsetY)) { i--; } @@ -250,17 +252,20 @@ private func GetPumpHeight() // compare each the surfaces of the bodies of liquid pumped // find Y position of surface of liquid that is pumped to target - var source_y = 0; - if (GetSourceObject()->GBackLiquid()) + var source_obj = GetSourceObject(); + var source_x = source_obj.ApertureOffsetX; + var source_y = source_obj.ApertureOffsetY; + if (source_obj->GBackLiquid(source_x, source_y)) { - var src_mat = GetSourceObject()->GetMaterial(); - while (src_mat == GetSourceObject()->GetMaterial(0, source_y - 1)) + var src_mat = source_obj->GetMaterial(source_x, source_y); + while (src_mat == source_obj->GetMaterial(source_x, source_y - 1)) --source_y; } // same for target (use same function as if inserting) var target_pos = {X = 0, Y = 0}; - GetDrainObject()->CanInsertMaterial(Material("Water"), 0, 0, target_pos); - return GetSourceObject()->GetY() + source_y - target_pos.Y; + var drain_obj = GetDrainObject(); + drain_obj->CanInsertMaterial(Material("Water"), drain_obj.ApertureOffsetX, drain_obj.ApertureOffsetY, target_pos); + return source_obj->GetY() + source_y - target_pos.Y; } /** Recheck power usage/production for current pump height @@ -340,15 +345,14 @@ private func PumpHeight2Power(int pump_height) /** Returns whether there is liquid at the source pipe to pump */ private func HasLiquidToPump() { - if (!source_pipe) - return false; - // source - if(!GetSourceObject()->GBackLiquid()) + var source_obj = GetSourceObject(); + if(!source_obj->GBackLiquid(source_obj.ApertureOffsetX, source_obj.ApertureOffsetY)) return false; // target (test with the very popular liquid "water") - if(!GetDrainObject()->CanInsertMaterial(Material("Water"),0,0)) + var drain_obj = GetDrainObject(); + if(!drain_obj->CanInsertMaterial(Material("Water"),drain_obj.ApertureOffsetX, drain_obj.ApertureOffsetY)) return false; return true; diff --git a/planet/System.ocg/Material.c b/planet/System.ocg/Material.c index 6009c82fe..b0884562f 100644 --- a/planet/System.ocg/Material.c +++ b/planet/System.ocg/Material.c @@ -54,10 +54,11 @@ global func FindPosInMat(string sMat, int iXStart, int iYStart, int iWidth, int /** Removes a material pixel from the specified location, if the material is a liquid. @param x X coordinate @param y Y coordinate + @param distant_first If true, extraction position takes largest horizontal distance from given offset at same height to a maximum value of MaxSlide. Useful to ensure that no floor of 1px of liquid remains. @return The material index of the removed pixel, or -1 if no liquid was found. */ -global func ExtractLiquid(int x, int y) +global func ExtractLiquid(int x, int y, bool distant_first) { - var result = ExtractLiquidAmount(x, y, 1); + var result = ExtractLiquidAmount(x, y, 1, distant_first); if(!result) return -1; return result[0]; @@ -67,9 +68,10 @@ global func ExtractLiquid(int x, int y) @param x X coordinate @param y Y coordinate @param amount amount of liquid that should be extracted + @param distant_first If true, extraction position takes largest horizontal distance from given offset at same height to a maximum value of MaxSlide. Useful to ensure that no floor of 1px of liquid remains. @return an array with the first position being the material index being extracted and the second the actual amount of pixels extracted OR nil if there was no liquid at all */ -global func ExtractLiquidAmount(int x, int y, int amount) +global func ExtractLiquidAmount(int x, int y, int amount, bool distant_first) { var mat = GetMaterial(x, y); if(mat == -1) @@ -77,7 +79,7 @@ global func ExtractLiquidAmount(int x, int y, int amount) var density = GetMaterialVal("Density", "Material", mat); if (density < C4M_Liquid || density >= C4M_Solid) return nil; - var amount = ExtractMaterialAmount(x, y, mat, amount); + var amount = ExtractMaterialAmount(x, y, mat, amount, distant_first); if (amount <= 0) return nil; return [mat, amount]; diff --git a/src/gamescript/C4Effect.cpp b/src/gamescript/C4Effect.cpp index ee0ebdcaf..2768b425d 100644 --- a/src/gamescript/C4Effect.cpp +++ b/src/gamescript/C4Effect.cpp @@ -607,7 +607,7 @@ void Splash(int32_t tx, int32_t ty, int32_t amt, C4Object *pByObj) { C4Real xdir = C4REAL100(Random(151)-75); C4Real ydir = C4REAL100(-Random(200)); - ::PXS.Create(::Landscape.ExtractMaterial(tx,ty), + ::PXS.Create(::Landscape.ExtractMaterial(tx,ty,false), itofix(tx),itofix(sy), xdir, ydir); diff --git a/src/gamescript/C4GameScript.cpp b/src/gamescript/C4GameScript.cpp index 0dd22798a..40b4f908f 100644 --- a/src/gamescript/C4GameScript.cpp +++ b/src/gamescript/C4GameScript.cpp @@ -445,13 +445,13 @@ static bool FnGBackSky(C4PropList * _this, long x, long y) return !GBackIFT(x, y); } -static long FnExtractMaterialAmount(C4PropList * _this, long x, long y, long mat, long amount) +static long FnExtractMaterialAmount(C4PropList * _this, long x, long y, long mat, long amount, bool distant_first) { if (Object(_this)) { x+=Object(_this)->GetX(); y+=Object(_this)->GetY(); } long extracted=0; for (; extracted