From 0afa589286cf57ec7211949dc99e119c3251c11e Mon Sep 17 00:00:00 2001 From: Lukas Werling Date: Tue, 23 Feb 2016 22:19:39 +0100 Subject: [PATCH 01/26] Replace all usage of "bool released" with "int status" --- .../CableCar.ocd/Selector.ocd/Script.c | 6 +- .../GrappleBow.ocd/Hook.ocd/Script.c | 4 +- .../Libraries.ocd/ClonkControl.ocd/Script.c | 59 ++++++++++--------- .../ClonkGamepadControl.ocd/Script.c | 14 ++--- .../ClonkInteractionControl.ocd/Script.c | 10 ++-- .../ClonkInventoryControl.ocd/Script.c | 18 +++--- .../Libraries.ocd/Constructor.ocd/Script.c | 6 +- .../Libraries.ocd/LadderClimb.ocd/Script.c | 4 +- planet/System.ocg/PlayerControl.c | 29 +++++---- .../PlayGround.ocs/System.ocg/SpawnMenu.c | 8 +-- .../System.ocg/HideShowTutorialGuide.c | 6 +- 11 files changed, 83 insertions(+), 81 deletions(-) diff --git a/planet/Experimental.ocf/CableLorrys.ocs/CableCars.ocd/Libraries.ocd/CableCar.ocd/Selector.ocd/Script.c b/planet/Experimental.ocf/CableLorrys.ocs/CableCars.ocd/Libraries.ocd/CableCar.ocd/Selector.ocd/Script.c index 9472d3273..cd94797dc 100644 --- a/planet/Experimental.ocf/CableLorrys.ocs/CableCars.ocd/Libraries.ocd/CableCar.ocd/Selector.ocd/Script.c +++ b/planet/Experimental.ocf/CableLorrys.ocs/CableCars.ocd/Libraries.ocd/CableCar.ocd/Selector.ocd/Script.c @@ -21,9 +21,9 @@ public func FixTo(object station) SetCursor(GetOwner(), this, true); } -public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool repeat, bool release) +public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool repeat, int status) { - if (release) return false; + if (status != CONS_Down) return false; if (ctrl == CON_Left) return cable_car->ShiftSelection(-1, this); @@ -40,4 +40,4 @@ protected func FxParticlesTimer(object target, effect, int time) { var angle = time*10 % 360; CreateParticle("SphereSpark", Sin(angle, 13), -Cos(angle, 13), 0, 0, PV_Random(20, 30), Particles_Spark()); -} \ No newline at end of file +} diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/GrappleBow.ocd/Hook.ocd/Script.c b/planet/Objects.ocd/Items.ocd/Tools.ocd/GrappleBow.ocd/Hook.ocd/Script.c index e3509df72..243fa784f 100644 --- a/planet/Objects.ocd/Items.ocd/Tools.ocd/GrappleBow.ocd/Hook.ocd/Script.c +++ b/planet/Objects.ocd/Items.ocd/Tools.ocd/GrappleBow.ocd/Hook.ocd/Script.c @@ -167,8 +167,10 @@ public func OnRopeBreak() /*-- Grapple rope controls --*/ -public func FxIntGrappleControlControl(object target, proplist effect, int ctrl, int x, int y, int strength, repeat, release) +public func FxIntGrappleControlControl(object target, proplist effect, int ctrl, int x, int y, int strength, bool repeat, int status) { + if (status == CONS_Moved) return false; + var release = status == CONS_Up; // Cancel this effect if clonk is now attached to something. if (target->GetProcedure() == "ATTACH") { diff --git a/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c index 1e54c47b2..94f6ae8f1 100644 --- a/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c @@ -178,13 +178,13 @@ public func GetExtraInteractions() /* +++++++++++++++++++++++++++ Clonk Control +++++++++++++++++++++++++++ */ /* Main control function */ -public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool repeat, bool release) +public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool repeat, int status) { if (!this) return false; // Contents menu - if (ctrl == CON_Contents && !release) + if (ctrl == CON_Contents && status == CONS_Down) { // Close any menu if open. if (GetMenu()) @@ -221,10 +221,11 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re else ctrl = CON_Use; repeat = true; - release = false; + status = CONS_Down; } // controls except a few reset a previously given command - else SetCommand("None"); + else if (status != CONS_Moved) + SetCommand("None"); /* aiming with analog pad or keys: This works completely different. There are CON_AimAxis* and CON_Aim*, @@ -241,7 +242,7 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re if (ctrl == CON_AimAxisUp || ctrl == CON_AimAxisDown || ctrl == CON_AimAxisLeft || ctrl == CON_AimAxisRight || ctrl == CON_AimUp || ctrl == CON_AimDown || ctrl == CON_AimLeft || ctrl == CON_AimRight) { - var success = VirtualCursor()->Aim(ctrl,this,strength,repeat,release); + var success = VirtualCursor()->Aim(ctrl,this,strength,repeat,status); // in any case, CON_Aim* is called but it is only successful if the virtual cursor is aiming return success && VirtualCursor()->IsAiming(); } @@ -269,7 +270,7 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re // menu if (this.control.menu) { - return Control2Menu(ctrl, x,y,strength, repeat, release); + return Control2Menu(ctrl, x,y,strength, repeat, status); } var contents = this->GetHandItem(0); @@ -280,12 +281,12 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re { if (house) { - return ControlUse2Script(ctrl, x, y, strength, repeat, release, house); + return ControlUse2Script(ctrl, x, y, strength, repeat, status, house); } // control to grabbed vehicle else if (vehicle && proc == "PUSH") { - return ControlUse2Script(ctrl, x, y, strength, repeat, release, vehicle); + return ControlUse2Script(ctrl, x, y, strength, repeat, status, vehicle); } else if (vehicle && proc == "ATTACH") { @@ -301,7 +302,7 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re usage via CancelUse(). */ - if (ControlUse2Script(ctrl, x, y, strength, repeat, release, vehicle)) + if (ControlUse2Script(ctrl, x, y, strength, repeat, status, vehicle)) return true; else { @@ -310,16 +311,16 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re // object returns true on that callback. Exactly what we want) if (this.control.current_object == vehicle) return true; // has been cancelled (it is not the start of the usage but no object is used) - if (!this.control.current_object && (repeat || release)) return true; + if (!this.control.current_object && (repeat || status == CONS_Up)) return true; } } // releasing the use-key always cancels shelved commands (in that case no this.control.current_object exists) - if(release) StopShelvedCommand(); + if(status == CONS_Up) StopShelvedCommand(); // Release commands are always forwarded even if contents is 0, in case we // need to cancel use of an object that left inventory - if (contents || (release && this.control.current_object)) + if (contents || (status == CONS_Up && this.control.current_object)) { - if (ControlUse2Script(ctrl, x, y, strength, repeat, release, contents)) + if (ControlUse2Script(ctrl, x, y, strength, repeat, status, contents)) return true; } } @@ -327,7 +328,7 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re // A click on throw can also just abort usage without having any other effects. // todo: figure out if wise. var currently_in_use = this.control.current_object != nil; - if ((ctrl == CON_Throw || ctrl == CON_ThrowDelayed) && currently_in_use && !release) + if ((ctrl == CON_Throw || ctrl == CON_ThrowDelayed) && currently_in_use && status == CONS_Down) { CancelUse(); return true; @@ -336,7 +337,7 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re // Throwing and dropping // only if not in house, not grabbing a vehicle and an item selected // only act on press, not release - if ((ctrl == CON_Throw || ctrl == CON_ThrowDelayed) && !house && (!vehicle || proc == "ATTACH") && !release) + if ((ctrl == CON_Throw || ctrl == CON_ThrowDelayed) && !house && (!vehicle || proc == "ATTACH") && status == CONS_Down) { if (contents) { @@ -368,7 +369,7 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re if (ctrl == CON_ThrowDelayed) { CancelUse(); - if (release) + if (status == CONS_Up) { VirtualCursor()->StopAim(); @@ -392,14 +393,14 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re // forward to script... if (house) { - return ControlMovement2Script(ctrl, x, y, strength, repeat, release, house); + return ControlMovement2Script(ctrl, x, y, strength, repeat, status, house); } else if (vehicle) { - if (ControlMovement2Script(ctrl, x, y, strength, repeat, release, vehicle)) return true; + if (ControlMovement2Script(ctrl, x, y, strength, repeat, status, vehicle)) return true; } - return ObjectControlMovement(plr, ctrl, strength, release); + return ObjectControlMovement(plr, ctrl, strength, status); } // Do a roll on landing or when standing. This means that the CON_Down was not handled previously. @@ -423,7 +424,7 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re // Fall through half-solid mask if (ctrl == CON_FallThrough) { - if(!release) + if(status == CONS_Down) { if (this->IsWalking()) { @@ -459,7 +460,7 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re } // Unhandled control - return _inherited(plr, ctrl, x, y, strength, repeat, release, ...); + return _inherited(plr, ctrl, x, y, strength, repeat, status, ...); } // A wrapper to SetCommand to catch special behaviour for some actions. @@ -866,16 +867,16 @@ func FxItemRemovalCheckStop(object target, proplist effect, int reason, bool tem // Control use redirected to script -func ControlUse2Script(int ctrl, int x, int y, int strength, bool repeat, bool release, object obj) +func ControlUse2Script(int ctrl, int x, int y, int strength, bool repeat, int status, object obj) { // standard use if (ctrl == CON_Use || ctrl == CON_UseAlt) { - if (!release && !repeat) + if (status == CONS_Down && !repeat) { return StartUseControl(ctrl,x, y, obj); } - else if (release && obj == this.control.current_object) + else if (status == CONS_Up && obj == this.control.current_object) { return StopUseControl(x, y, obj); } @@ -883,11 +884,11 @@ func ControlUse2Script(int ctrl, int x, int y, int strength, bool repeat, bool r // gamepad use else if (ctrl == CON_UseDelayed || ctrl == CON_UseAltDelayed) { - if (!release && !repeat) + if (status == CONS_Down && !repeat) { return StartUseDelayedControl(ctrl, obj); } - else if (release && obj == this.control.current_object) + else if (status == CONS_Up && obj == this.control.current_object) { return StopUseDelayedControl(obj); } @@ -896,7 +897,7 @@ func ControlUse2Script(int ctrl, int x, int y, int strength, bool repeat, bool r // more use (holding) if (ctrl == CON_Use || ctrl == CON_UseAlt || ctrl == CON_UseDelayed || ctrl == CON_UseAltDelayed) { - if (release) + if (status == CONS_Up) { // leftover use release CancelUse(); @@ -912,7 +913,7 @@ func ControlUse2Script(int ctrl, int x, int y, int strength, bool repeat, bool r } // Control use redirected to script -func ControlMovement2Script(int ctrl, int x, int y, int strength, bool repeat, bool release, object obj) +func ControlMovement2Script(int ctrl, int x, int y, int strength, bool repeat, int status, object obj) { // overloads of movement commandos if (ctrl == CON_Left || ctrl == CON_Right || ctrl == CON_Down || ctrl == CON_Up || ctrl == CON_Jump) @@ -921,7 +922,7 @@ func ControlMovement2Script(int ctrl, int x, int y, int strength, bool repeat, b if (Contained() == obj) control_string = "Contained"; - if (release) + if (status == CONS_Up) { // if any movement key has been released, ControlStop is called if (obj->Call(Format("~%sStop", control_string), this, ctrl)) diff --git a/planet/Objects.ocd/Libraries.ocd/ClonkGamepadControl.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/ClonkGamepadControl.ocd/Script.c index b061bcc9c..685cc7810 100644 --- a/planet/Objects.ocd/Libraries.ocd/ClonkGamepadControl.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/ClonkGamepadControl.ocd/Script.c @@ -19,7 +19,7 @@ local virtual_cursor; /* This part of gamepad control handles only object-style menus. Fullscreen menus are handled differently. */ -func Control2Menu(int ctrl, int x, int y, int strength, bool repeat, bool release) +func Control2Menu(int ctrl, int x, int y, int strength, bool repeat, int status) { /* all this stuff is already done on a higher layer - in playercontrol.c @@ -40,7 +40,7 @@ func Control2Menu(int ctrl, int x, int y, int strength, bool repeat, bool releas this->GetMenu()->~UpdateCursor(mex,mey); } // click on menu - if (release) + if (status == CONS_Up) { // select if (ctrl == CON_UseDelayed) @@ -50,13 +50,13 @@ func Control2Menu(int ctrl, int x, int y, int strength, bool repeat, bool releas return true; } -public func ObjectControlMovement(int plr, int ctrl, int strength, bool release) +public func ObjectControlMovement(int plr, int ctrl, int strength, int status) { // from PlayerControl.c - var result = inherited(plr,ctrl,strength,release,...); + var result = inherited(plr,ctrl,strength,status,...); // do the following only if strength >= CON_Gamepad_Deadzone - if(!release) + if(status == CONS_Down) if(strength != nil && strength < CON_Gamepad_Deadzone) return result; @@ -66,7 +66,7 @@ public func ObjectControlMovement(int plr, int ctrl, int strength, bool release) if(!virtual_cursor) return result; // change direction of virtual_cursor - if(!release) + if(status == CONS_Down) virtual_cursor->Direction(ctrl); return result; @@ -143,4 +143,4 @@ func RemoveVirtualCursor() { if (virtual_cursor) virtual_cursor->StopAim(); -} \ No newline at end of file +} diff --git a/planet/Objects.ocd/Libraries.ocd/ClonkInteractionControl.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/ClonkInteractionControl.ocd/Script.c index 4dea7a28c..efcd5eaf4 100644 --- a/planet/Objects.ocd/Libraries.ocd/ClonkInteractionControl.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/ClonkInteractionControl.ocd/Script.c @@ -26,13 +26,13 @@ public func OnShiftCursor(object new_cursor) return _inherited(new_cursor, ...); } -public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool repeat, bool release) +public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool repeat, int status) { if (!this) - return inherited(plr, ctrl, x, y, strength, repeat, release, ...); + return inherited(plr, ctrl, x, y, strength, repeat, status, ...); // Begin interaction. - if (ctrl == CON_Interact && !release) + if (ctrl == CON_Interact && status == CONS_Down) { this->CancelUse(); BeginInteract(); @@ -50,7 +50,7 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re } // Finish picking up (aka "collect"). - if (ctrl == CON_Interact && release) + if (ctrl == CON_Interact && status == CONS_Up) { EndInteract(); return true; @@ -71,7 +71,7 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re } } - return inherited(plr, ctrl, x, y, strength, repeat, release, ...); + return inherited(plr, ctrl, x, y, strength, repeat, status, ...); } private func FxIntHighlightInteractionStart(object target, proplist fx, temp, proplist interaction, proplist interaction_help) diff --git a/planet/Objects.ocd/Libraries.ocd/ClonkInventoryControl.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/ClonkInventoryControl.ocd/Script.c index e6428af7d..d27fca9e1 100644 --- a/planet/Objects.ocd/Libraries.ocd/ClonkInventoryControl.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/ClonkInventoryControl.ocd/Script.c @@ -46,17 +46,17 @@ func RejectCollect(id objid, object obj) return false; } -public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool repeat, bool release) +public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool repeat, int status) { if (!this) - return inherited(plr, ctrl, x, y, strength, repeat, release, ...); + return inherited(plr, ctrl, x, y, strength, repeat, status, ...); // Quickswitch changes the active slot to the last selected one if (ctrl == CON_QuickSwitch) { // but ignore quickswitch if we have more than 1 hand-slot if(this.HandObjects > 1) - return inherited(plr, ctrl, x, y, strength, repeat, release, ...);; + return inherited(plr, ctrl, x, y, strength, repeat, status, ...);; // select last slot SetHandItemPos(0, this.inventory.last_slot); // last_slot is updated in SetHandItemPos @@ -67,7 +67,7 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re if (!Contained()) { // Quick-pickup item via click? Note that this relies on being executed after the normal Clonk controls - if (ctrl == CON_Use && !this->GetHandItem(0) && !release) + if (ctrl == CON_Use && !this->GetHandItem(0) && status == CONS_Down) { var sort = Sort_Distance(x, y); var items = FindAllPickupItems(sort); @@ -78,7 +78,7 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re } // Begin picking up objects. - if (ctrl == CON_PickUp && !release) + if (ctrl == CON_PickUp && status == CONS_Down) { this->CancelUse(); BeginPickingUp(); @@ -86,7 +86,7 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re } // Drop the mouse item? - if (ctrl == CON_Drop && !release) + if (ctrl == CON_Drop && status == CONS_Down) { // Do not immediately collect another thing unless chosen with left/right. if (this.inventory.is_picking_up) @@ -120,7 +120,7 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re } // Finish picking up (aka "collect"). - if (ctrl == CON_PickUp && release) + if (ctrl == CON_PickUp && status == CONS_Up) { EndPickingUp(); return true; @@ -208,7 +208,7 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re return true; } - return inherited(plr, ctrl, x, y, strength, repeat, release, ...); + return inherited(plr, ctrl, x, y, strength, repeat, status, ...); } private func FxIntHighlightItemStart(object target, proplist fx, temp, object item) @@ -424,4 +424,4 @@ func Selected(object mnu, object mnu_item) mnu_item->SetSymbol(show_new_item); // swap index with backpack index this->Switch2Items(hands_index, backpack_index); -} \ No newline at end of file +} diff --git a/planet/Objects.ocd/Libraries.ocd/Constructor.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/Constructor.ocd/Script.c index 72fe37ab9..5b1d269e5 100644 --- a/planet/Objects.ocd/Libraries.ocd/Constructor.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/Constructor.ocd/Script.c @@ -68,12 +68,12 @@ public func FxControlConstructionPreviewStart(object clonk, effect, int temp, id } // Called by Control2Effect -public func FxControlConstructionPreviewControl(object clonk, effect, int ctrl, int x, int y, int strength, bool repeat, bool release) +public func FxControlConstructionPreviewControl(object clonk, effect, int ctrl, int x, int y, int strength, bool repeat, int status) { if (ctrl != CON_Aim) { // CON_Use is accept, but don't remove the preview, this is done on releasing the button. - if (ctrl == CON_Use && !release) + if (ctrl == CON_Use && status == CONS_Down) { var ok = CreateConstructionSite(clonk, effect.structure, AbsX(effect.preview->GetX()), AbsY(effect.preview->GetY() + effect.preview.dimension_y/2), effect.preview.blocked, effect.preview.direction, effect.preview.stick_to); if (ok) @@ -90,7 +90,7 @@ public func FxControlConstructionPreviewControl(object clonk, effect, int ctrl, // (yes, this means that actionbar-hotkeys wont work for it. However clicking the button will.) else if (IsInteractionControl(ctrl)) { - if (release) + if (status == CONS_Up) effect.preview->Flip(); return true; } diff --git a/planet/Objects.ocd/Libraries.ocd/LadderClimb.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/LadderClimb.ocd/Script.c index a3c845d75..58d669879 100644 --- a/planet/Objects.ocd/Libraries.ocd/LadderClimb.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/LadderClimb.ocd/Script.c @@ -311,13 +311,13 @@ public func FxIntClimbControlStop(target, effect) SetHandAction(0); } -public func FxIntClimbControlControl(object target, proplist effect, int ctrl, int x, int y, int strength, bool repeat, bool release) +public func FxIntClimbControlControl(object target, proplist effect, int ctrl, int x, int y, int strength, bool repeat, int status) { // Only handle movement controls. if (ctrl != CON_Up && ctrl != CON_Down && ctrl != CON_Right && ctrl != CON_Left) return false; // Perform actions on key down and not on release. - if (release) + if (status != CONS_Down) return false; if (ctrl == CON_Up) diff --git a/planet/System.ocg/PlayerControl.c b/planet/System.ocg/PlayerControl.c index 9bcb16ec0..ecaddac3f 100644 --- a/planet/System.ocg/PlayerControl.c +++ b/planet/System.ocg/PlayerControl.c @@ -18,12 +18,11 @@ global func PlayerControl(int plr, int ctrl, id spec_id, int x, int y, int stren { var release = status == CONS_Up; //Log("%d, %s, %i, %d, %d, %d, %v, %v", plr, GetPlayerControlName(ctrl), spec_id, x,y,strength, repeat, status); - if (status == CONS_Moved) return false; // Control handled by definition? Forward - if (spec_id) return spec_id->PlayerControl(plr, ctrl, x, y, strength, repeat, release); + if (spec_id) return spec_id->PlayerControl(plr, ctrl, x, y, strength, repeat, status); // Forward control to player - if (Control2Player(plr,ctrl, x, y, strength, repeat, release)) return true; + if (Control2Player(plr,ctrl, x, y, strength, repeat, status)) return true; // Forward control to cursor var cursor = GetCursor(plr); @@ -34,7 +33,7 @@ global func PlayerControl(int plr, int ctrl, id spec_id, int x, int y, int stren // menu controls: - if (cursor->~GetMenu()) + if (cursor->~GetMenu() && status != CONS_Moved) { // direction keys are always forwarded to the menu // (because the clonk shall not move while the menu is open) @@ -83,11 +82,11 @@ global func PlayerControl(int plr, int ctrl, id spec_id, int x, int y, int stren } // Overload by effect? - if (cursor->Control2Effect(plr, ctrl, cursorX, cursorY, strength, repeat, release)) return true; + if (cursor->Control2Effect(plr, ctrl, cursorX, cursorY, strength, repeat, status)) return true; - if (cursor->ObjectControl(plr, ctrl, cursorX, cursorY, strength, repeat, release)) + if (cursor->ObjectControl(plr, ctrl, cursorX, cursorY, strength, repeat, status)) { - if (cursor && !release && !repeat) + if (cursor && status == CONS_Down && !repeat) { // non-mouse controls reset view if (!x && !y) ResetCursorView(plr); @@ -127,7 +126,7 @@ global func PlayerHasVirtualCursor(int plr) // Control2Player // Player-wide controls -global func Control2Player(int plr, int ctrl, int x, int y, int strength, bool repeat, bool release) +global func Control2Player(int plr, int ctrl, int x, int y, int strength, bool repeat, int status) { // select previous or next if (ctrl == CON_PreviousCrew) @@ -202,7 +201,7 @@ global func StopSelected(int plr) // Control2Effect // Call control function in all effects that have "Control" in their name -global func Control2Effect(int plr, int ctrl, int x, int y, int strength, bool repeat, bool release) +global func Control2Effect(int plr, int ctrl, int x, int y, int strength, bool repeat, int status) { // x and y are local coordinates if (!this) return false; @@ -213,7 +212,7 @@ global func Control2Effect(int plr, int ctrl, int x, int y, int strength, bool r { iEffect = GetEffect("*Control*", this, i); if (iEffect) - if (EffectCall(this, iEffect, "Control", ctrl, x,y,strength, repeat, release)) + if (EffectCall(this, iEffect, "Control", ctrl, x,y,strength, repeat, status)) return true; } // No effect handled the control @@ -224,7 +223,7 @@ global func Control2Effect(int plr, int ctrl, int x, int y, int strength, bool r // Called from PlayerControl when a control is issued to the cursor // Return whether handled // To be overloaded by specific objects to enable additional controls -global func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool repeat, bool release) +global func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool repeat, int status) { if (!this) return false; @@ -233,7 +232,7 @@ global func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re // Movement controls if (ctrl == CON_Left || ctrl == CON_Right || ctrl == CON_Up || ctrl == CON_Down || ctrl == CON_Jump) - return ObjectControlMovement(plr, ctrl, strength, release, repeat); + return ObjectControlMovement(plr, ctrl, strength, status, repeat); // Unhandled control return false; @@ -276,7 +275,7 @@ global func NameComDir(comdir) } // Called when CON_Left/Right/Up/Down controls are issued/released // Return whether handled -global func ObjectControlMovement(int plr, int ctrl, int strength, bool release, bool repeat) +global func ObjectControlMovement(int plr, int ctrl, int strength, int status, bool repeat) { if (!this) return false; @@ -284,13 +283,13 @@ global func ObjectControlMovement(int plr, int ctrl, int strength, bool release, if (Contained()) return false; // this is for controlling movement with Analogpad - if(!release) + if(status == CONS_Down) if(strength != nil && strength < CON_Gamepad_Deadzone) return true; var proc = GetProcedure(); // Some specific movement controls - if (!release) + if (status == CONS_Down) { // Jump control if (ctrl == CON_Jump) diff --git a/planet/Tutorials.ocf/PlayGround.ocs/System.ocg/SpawnMenu.c b/planet/Tutorials.ocf/PlayGround.ocs/System.ocg/SpawnMenu.c index 9ebd166fe..1037cf6fc 100644 --- a/planet/Tutorials.ocf/PlayGround.ocs/System.ocg/SpawnMenu.c +++ b/planet/Tutorials.ocf/PlayGround.ocs/System.ocg/SpawnMenu.c @@ -2,13 +2,13 @@ #appendto Library_ClonkControl -public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool repeat, bool release) +public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool repeat, int status) { if (!this) return false; // Spawn menu - if (ctrl == CON_SpawnMenu && !release) + if (ctrl == CON_SpawnMenu && status == CONS_Down) { // Close any menu if open. if (GetMenu()) @@ -31,5 +31,5 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re } // Unhandled control will be handled by the library itself. - return _inherited(plr, ctrl, x, y, strength, repeat, release, ...); -} \ No newline at end of file + return _inherited(plr, ctrl, x, y, strength, repeat, status, ...); +} diff --git a/planet/Tutorials.ocf/Tutorial.ocd/System.ocg/HideShowTutorialGuide.c b/planet/Tutorials.ocf/Tutorial.ocd/System.ocg/HideShowTutorialGuide.c index 6ae73ada9..ebc09423e 100644 --- a/planet/Tutorials.ocf/Tutorial.ocd/System.ocg/HideShowTutorialGuide.c +++ b/planet/Tutorials.ocf/Tutorial.ocd/System.ocg/HideShowTutorialGuide.c @@ -1,9 +1,9 @@ // Shows and hides the tutorial guide if the [H] button is pressed. -global func PlayerControl(int plr, int ctrl, id spec_id, int x, int y, int strength, bool repeat, bool release) +global func PlayerControl(int plr, int ctrl, id spec_id, int x, int y, int strength, bool repeat, int status) { if (ctrl != CON_TutorialGuide) - return _inherited(plr, ctrl, spec_id, x, y, strength, repeat, release, ...); + return _inherited(plr, ctrl, spec_id, x, y, strength, repeat, status, ...); // Don't do anything if the player is a sequence. if (GetActiveSequence()) return; @@ -17,4 +17,4 @@ global func PlayerControl(int plr, int ctrl, id spec_id, int x, int y, int stren else guide->HideGuide(); return; -} \ No newline at end of file +} From 93dcb1d7293f719a4795bba9593d0b718fdfc923 Mon Sep 17 00:00:00 2001 From: Lukas Werling Date: Wed, 24 Feb 2016 18:50:06 +0100 Subject: [PATCH 02/26] Improve gamepad assignments - Add assignments for switching interaction and pickup targets (just like the keyboard control). - Remove double assignments of the sticks for walking and aiming. The left stick is now exclusively for walking and the right stick exclusively for aiming. --- planet/System.ocg/PlayerControls.txt | 83 ++++++++++++++-------------- 1 file changed, 43 insertions(+), 40 deletions(-) diff --git a/planet/System.ocg/PlayerControls.txt b/planet/System.ocg/PlayerControls.txt index ea76a248d..e29f7f8bd 100644 --- a/planet/System.ocg/PlayerControls.txt +++ b/planet/System.ocg/PlayerControls.txt @@ -949,11 +949,54 @@ GUIGroup=40 Control=Interact + [Assignment] + Key=CON_Interact,CON_Left + Control=InteractNext_Left + Priority=75 + + [Assignment] + Key=CON_Interact,CON_Right + Control=InteractNext_Right + Priority=75 + + [Assignment] + Key=CON_Interact,CON_Up + Control=InteractNext_CycleObject + Priority=75 + + [Assignment] + Key=CON_Interact,CON_Down + Control=InteractNext_Stop + Priority=75 + [Assignment] Key=ControllerButtonX Control=PickUp GUIGroup=50 + [Assignment] + Key=CON_PickUp,CON_Left + Control=PickUpNext_Left + + [Assignment] + Key=CON_PickUp,CON_Right + Control=PickUpNext_Right + + [Assignment] + Key=CON_PickUp,CON_Up + Control=PickUpNext_All + Priority=75 + + [Assignment] + Key=CON_PickUp,CON_Down + Control=PickUpNext_Stop + Priority=75 + + [Assignment] + Key=CON_PickUp,CON_ThrowDelayed + Control=Drop + Priority=75 + # Crew [Assignment] @@ -1005,46 +1048,6 @@ [ControlSet] Name=*_GamepadCon_* - [Assignment] - Key=CON_AimAxisLeft - Priority=50 - Control=Left - - [Assignment] - Key=CON_AimAxisRight - Priority=50 - Control=Right - - [Assignment] - Key=CON_AimAxisDown - Priority=50 - Control=Down - - [Assignment] - Key=CON_AimAxisUp - Priority=50 - Control=Up - - [Assignment] - Key=CON_Left - Priority=70 - Control=AimLeft - - [Assignment] - Key=CON_Right - Priority=70 - Control=AimRight - - [Assignment] - Key=CON_Down - Priority=70 - Control=AimDown - - [Assignment] - Key=CON_Up - Priority=70 - Control=AimUp - [Assignment] Key=CON_Down,CON_UseDelayed GUIDisabled=1 From b8c8bf825ccce21752052c5dfb1ce4ce7f3b449c Mon Sep 17 00:00:00 2001 From: Lukas Werling Date: Sat, 12 Mar 2016 19:25:05 +0100 Subject: [PATCH 03/26] Crosshair: Use analog stick input properly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Crosshair doesn't work with a dpad anymore. Supporting dpads adds unnecessary complexity, as a gamepad user with dpad will never be competitive with mouse users. - Crosshair isn't bound to item usage anymore, but will always show when the analog stick is outside of a deadzone. Future planned feature: Also use the actual strength to allow distance input in addition to direction. This is used heavily by Knüppeln.c4s. --- .../ClonkControl.ocd/Crosshair.ocd/Script.c | 122 +++++++----------- .../Libraries.ocd/ClonkControl.ocd/Script.c | 3 +- planet/System.ocg/PlayerControls.txt | 20 --- 3 files changed, 47 insertions(+), 98 deletions(-) diff --git a/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Crosshair.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Crosshair.ocd/Script.c index b82df0628..515b148dd 100644 --- a/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Crosshair.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Crosshair.ocd/Script.c @@ -5,61 +5,69 @@ Virtual cursor for gamepad controls */ -local crew, angle, dirx, diry, xpos,ypos, analogaim, aiming, menu; +local crew, angle, xpos, ypos, aiming, menu; static const CURSOR_Radius = 100; +// This is supposed to be a constant, but C4Script doesn't allow constant expressions there. +private func CURSOR_Deadzone() { return PLRCON_MaxStrength / 5; } protected func Initialize() { - this["Visibility"] = VIS_None; - dirx = diry = xpos = ypos = 0; + SetVisibility(false); + xpos = ypos = 0; aiming = false; } public func FxMoveTimer() { - var speed = 0; - var dpad_rotatespeed = 35; + var target_angle = Angle(0,0,xpos,ypos)*10; - // dpad mode - if(diry) + if (!Visible() && !InDeadzone()) { - if (diry < 0) speed = -Sin(angle,100,10); - else if (diry > 0) speed = +Sin(angle,100,10); - angle += dpad_rotatespeed*speed/100; - UpdateAnalogpadPos(); + // The player moved the aiming stick while the crosshair wasn't visible: Use angle directly. + angle = target_angle; + SetVisibility(true); } - if(dirx) + else if (!InDeadzone()) { - if (dirx < 0) speed = -Cos(angle,100,10); - else if (dirx > 0) speed = +Cos(angle,100,10); - angle += dpad_rotatespeed*speed/100; - UpdateAnalogpadPos(); - } - // analog pad mode - if(!dirx && !diry) - { - var target_angle = Angle(0,0,xpos,ypos)*10; - var analog_strength = BoundBy(Sqrt(xpos*xpos+ypos*ypos),0,100); - + // Smooth small movements of the stick while the crosshair is visible. var angle_diff = Normalize(target_angle - angle, -1800, 10); - if (angle_diff == 0) angle_diff = 1; - - angle = angle + angle_diff * analog_strength / 100 / 8; + if (Abs(angle_diff) < 450) + angle = angle + angle_diff / 8; + else + angle = target_angle; + } + else if (!aiming) + { + // The player doesn't touch the stick and no item is using the crosshair right now. + SetVisibility(false); } UpdatePosition(); - if(aiming) crew->TriggerHoldingControl(); + crew->TriggerHoldingControl(); } -private func UpdateAnalogpadPos() +private func AnalogStrength() { return BoundBy(Sqrt(xpos*xpos+ypos*ypos), 0, PLRCON_MaxStrength); } +private func InDeadzone() { return AnalogStrength() < CURSOR_Deadzone(); } +private func Visible() { return this.Visibility != VIS_None; } + +// Updates the visibility, returing true if it was changed. +private func SetVisibility(bool visible) { - xpos = Sin(angle/10,100); - ypos = Cos(angle/10,-100); + var newvis, oldvis; + if (visible) + newvis = VIS_Owner; + else + newvis = VIS_None; + oldvis = this.Visibility; + this.Visibility = newvis; + return newvis != oldvis; } public func StartAim(object clonk, bool stealth, object GUImenu) { + aiming = true; + // only reinitialize angle if the crosshair hasn't been there before if(!GetEffect("Move",this)) { @@ -79,22 +87,15 @@ public func StartAim(object clonk, bool stealth, object GUImenu) SetCategory(C4D_StaticBack | C4D_IgnoreFoW); menu = nil; } - - // set starting position for analog pad - UpdateAnalogpadPos(); + + // Aim somewhere useful if the crosshair wasn't visible before. + if (SetVisibility(true)) + angle = 800*(clonk->GetDir()*2-1); crew = clonk; UpdatePosition(); RemoveEffect("Move",this); AddEffect("Move",this,1,1,this); - - if(!stealth) - { - this["Visibility"] = VIS_Owner; - crew->SetComDir(COMD_Stop); - aiming = true; - EnableKeyAimControls(true); - } } private func UpdatePosition() @@ -112,65 +113,34 @@ private func UpdatePosition() private func MirrorCursor() { + return; angle = -Normalize(angle,-1800,10); - UpdateAnalogpadPos(); } public func StopAim() { - RemoveEffect("Move",this); - this["Visibility"] = VIS_None; - dirx = 0; - diry = 0; - EnableKeyAimControls(false); - analogaim = false; aiming = false; } -private func EnableKeyAimControls(bool enable) -{ - SetPlayerControlEnabled(GetOwner(), CON_AimUp, enable); - SetPlayerControlEnabled(GetOwner(), CON_AimDown, enable); - SetPlayerControlEnabled(GetOwner(), CON_AimLeft, enable); - SetPlayerControlEnabled(GetOwner(), CON_AimRight, enable); -} - public func IsAiming() { return aiming; } -public func Aim(int ctrl, object clonk, int strength, int repeat, int release) +public func Aim(int ctrl, object clonk, int strength, int repeat, int status) { // start (stealth) aiming if(!GetEffect("Move",this)) StartAim(clonk,true); // aiming with analog pad - if (ctrl == CON_AimAxisUp || ctrl == CON_AimAxisDown || ctrl == CON_AimAxisLeft || ctrl == CON_AimAxisRight) + if (status == CONS_Moved && + (ctrl == CON_AimAxisUp || ctrl == CON_AimAxisDown || ctrl == CON_AimAxisLeft || ctrl == CON_AimAxisRight)) { - dirx = diry = 0; - if(ctrl == CON_AimAxisUp) ypos = -strength; if(ctrl == CON_AimAxisDown) ypos = strength; if(ctrl == CON_AimAxisLeft) xpos = -strength; if(ctrl == CON_AimAxisRight) xpos = strength; - analogaim = true; - return true; - } - // stop - else if (release && !analogaim) - { - if(ctrl == CON_AimUp || ctrl == CON_AimDown) diry = 0; - else if(ctrl == CON_AimLeft || ctrl == CON_AimRight) dirx = 0; - return true; - } - else if(!release /*&& !repeat */ && !analogaim) - { - if(ctrl == CON_AimUp) diry = -1; - else if(ctrl == CON_AimDown) diry = 1; - else if(ctrl == CON_AimLeft) dirx = -1; - else if(ctrl == CON_AimRight) dirx = 1; return true; } return false; diff --git a/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c index 94f6ae8f1..2014abf5f 100644 --- a/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c @@ -239,8 +239,7 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re CON_Left is still called afterwards. So if the clonk finally starts to aim, the virtual cursor already aims into the direction in which he ran */ - if (ctrl == CON_AimAxisUp || ctrl == CON_AimAxisDown || ctrl == CON_AimAxisLeft || ctrl == CON_AimAxisRight - || ctrl == CON_AimUp || ctrl == CON_AimDown || ctrl == CON_AimLeft || ctrl == CON_AimRight) + if (ctrl == CON_AimAxisUp || ctrl == CON_AimAxisDown || ctrl == CON_AimAxisLeft || ctrl == CON_AimAxisRight) { var success = VirtualCursor()->Aim(ctrl,this,strength,repeat,status); // in any case, CON_Aim* is called but it is only successful if the virtual cursor is aiming diff --git a/planet/System.ocg/PlayerControls.txt b/planet/System.ocg/PlayerControls.txt index e29f7f8bd..cea23de6c 100644 --- a/planet/System.ocg/PlayerControls.txt +++ b/planet/System.ocg/PlayerControls.txt @@ -59,26 +59,6 @@ DefaultDisabled=1 CoordinateSpace=Viewport - [ControlDef] - Identifier=AimUp - DefaultDisabled=1 - Hold=1 - - [ControlDef] - Identifier=AimDown - DefaultDisabled=1 - Hold=1 - - [ControlDef] - Identifier=AimLeft - DefaultDisabled=1 - Hold=1 - - [ControlDef] - Identifier=AimRight - DefaultDisabled=1 - Hold=1 - [ControlDef] Identifier=AimAxisUp GUIName=$CON_AimAxisUp$ From f63f4b9ab38887a8a4b9cbb0b1ab467d91c4ead7 Mon Sep 17 00:00:00 2001 From: Lukas Werling Date: Sat, 12 Mar 2016 20:21:36 +0100 Subject: [PATCH 04/26] Use regular Throw instead of ThrowDelayed for gamepads There is no need to delay throwing as aiming is now possible at any time using the analog stick. --- .../Libraries.ocd/ClonkControl.ocd/Script.c | 34 ++++++------------- planet/System.ocg/Controls.c | 7 ++-- planet/System.ocg/PlayerControls.txt | 19 ++--------- 3 files changed, 17 insertions(+), 43 deletions(-) diff --git a/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c index 2014abf5f..d29c80a8a 100644 --- a/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c @@ -246,15 +246,22 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re return success && VirtualCursor()->IsAiming(); } + // Simulate a mouse cursor for gamepads. + if (PlayerHasVirtualCursor(GetOwner())) + { + x = this.control.mlastx; + y = this.control.mlasty; + } + // save last mouse position: // if the using has to be canceled, no information about the current x,y // is available. Thus, the last x,y position needs to be saved - if (ctrl == CON_Use || ctrl == CON_UseAlt) + else if (ctrl == CON_Use || ctrl == CON_UseAlt) { this.control.mlastx = x; this.control.mlasty = y; } - + var proc = GetProcedure(); // building, vehicle, mount, contents, menu control @@ -327,7 +334,7 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re // A click on throw can also just abort usage without having any other effects. // todo: figure out if wise. var currently_in_use = this.control.current_object != nil; - if ((ctrl == CON_Throw || ctrl == CON_ThrowDelayed) && currently_in_use && status == CONS_Down) + if (ctrl == CON_Throw && currently_in_use && status == CONS_Down) { CancelUse(); return true; @@ -336,7 +343,7 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re // Throwing and dropping // only if not in house, not grabbing a vehicle and an item selected // only act on press, not release - if ((ctrl == CON_Throw || ctrl == CON_ThrowDelayed) && !house && (!vehicle || proc == "ATTACH") && status == CONS_Down) + if (ctrl == CON_Throw && !house && (!vehicle || proc == "ATTACH") && status == CONS_Down) { if (contents) { @@ -364,25 +371,6 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re else return ObjectCommand("Throw", contents, x, y); } - // throw delayed - if (ctrl == CON_ThrowDelayed) - { - CancelUse(); - if (status == CONS_Up) - { - VirtualCursor()->StopAim(); - - if (only_drop) - return ObjectCommand("Drop", contents); - else - return ObjectCommand("Throw", contents, this.control.mlastx, this.control.mlasty); - } - else - { - VirtualCursor()->StartAim(this); - return true; - } - } } } diff --git a/planet/System.ocg/Controls.c b/planet/System.ocg/Controls.c index 0ba627b9b..ad1c35f84 100644 --- a/planet/System.ocg/Controls.c +++ b/planet/System.ocg/Controls.c @@ -21,9 +21,8 @@ global func IsMovementControl(int ctrl) /** Control throws selected item */ global func IsThrowControl(int ctrl) { - // left mouse button - if(ctrl == CON_Throw - || ctrl == CON_ThrowDelayed) + // right mouse button + if(ctrl == CON_Throw) return true; return false; @@ -99,4 +98,4 @@ global func IsUseControl(int ctrl) { if (ctrl == CON_Use || ctrl == CON_UseAlt) return true; return false; -} \ No newline at end of file +} diff --git a/planet/System.ocg/PlayerControls.txt b/planet/System.ocg/PlayerControls.txt index cea23de6c..b4bf39681 100644 --- a/planet/System.ocg/PlayerControls.txt +++ b/planet/System.ocg/PlayerControls.txt @@ -37,7 +37,6 @@ # # Gamepad controls # ------------------------------------- - # ThrowDelayed # UseDelayed # AimUp AimDown AimLeft AimRight # AimAxisUp AimAxisDown AimAxisLeft AimAxisRight @@ -142,12 +141,6 @@ Hold=1 SendCursorPos=1 - [ControlDef] - Identifier=ThrowDelayed - GUIName=$CON_Throw$ - GUIDesc=$CON_Throw_Desc$ - Hold=1 - [ControlDef] Identifier=Drop GUIName=$CON_Drop$ @@ -973,7 +966,7 @@ Priority=75 [Assignment] - Key=CON_PickUp,CON_ThrowDelayed + Key=CON_PickUp,CON_Throw Control=Drop Priority=75 @@ -1003,7 +996,7 @@ Key=ControllerLeftTrigger GUIGroup=20 Priority=100 - Control=ThrowDelayed + Control=Throw # TODO: Zoom @@ -1029,18 +1022,12 @@ Name=*_GamepadCon_* [Assignment] - Key=CON_Down,CON_UseDelayed + Key=CON_Down,CON_Throw GUIDisabled=1 GUIGroup=20 Priority=150 Control=Drop - [Assignment] - Key=CON_UseDelayed - GUIName=None - Priority=50 - Control=ThrowDelayed - # ======================================================================= # # Default mouse control # # ======================================================================= # From b30860112aa1b181aad46ddea1d3a10bf2b5e7c2 Mon Sep 17 00:00:00 2001 From: Lukas Werling Date: Sun, 13 Mar 2016 18:16:38 +0100 Subject: [PATCH 05/26] Use regular Use instead of UseDelayed for gamepads --- .../Libraries.ocd/ClonkControl.ocd/Script.c | 88 ++----------------- .../ClonkGamepadControl.ocd/Script.c | 24 +++-- planet/System.ocg/PlayerControls.txt | 17 +--- 3 files changed, 18 insertions(+), 111 deletions(-) diff --git a/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c index d29c80a8a..391b6a698 100644 --- a/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c @@ -247,7 +247,7 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re } // Simulate a mouse cursor for gamepads. - if (PlayerHasVirtualCursor(GetOwner())) + if (HasVirtualCursor()) { x = this.control.mlastx; y = this.control.mlasty; @@ -282,7 +282,7 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re var contents = this->GetHandItem(0); // usage - var use = (ctrl == CON_Use || ctrl == CON_UseDelayed || ctrl == CON_UseAlt || ctrl == CON_UseAltDelayed); + var use = (ctrl == CON_Use || ctrl == CON_UseAlt); if (use) { if (house) @@ -595,18 +595,12 @@ func CanReIssueCommand(proplist data) if(data.ctrl == CON_Use) return !data.obj->~RejectUse(this); - - if(data.ctrl == CON_UseDelayed) - return !data.obj->~RejectUse(this); } func ReIssueCommand(proplist data) { if(data.ctrl == CON_Use) return StartUseControl(data.ctrl, this.control.mlastx, this.control.mlasty, data.obj); - - if(data.ctrl == CON_UseDelayed) - return StartUseDelayedControl(data.ctrl, data.obj); } func StartUseControl(int ctrl, int x, int y, object obj) @@ -629,6 +623,9 @@ func StartUseControl(int ctrl, int x, int y, object obj) this.control.using_type = DetermineUsageType(obj); this.control.alt = ctrl != CON_Use; + if (HasVirtualCursor()) + VirtualCursor()->StartAim(this); + var hold_enabled = obj->Call("~HoldingEnabled"); if (hold_enabled) @@ -665,37 +662,6 @@ func StartUseControl(int ctrl, int x, int y, object obj) return handled; } -func StartUseDelayedControl(int ctrl, object obj) -{ - this.control.started_use = false; - - if(obj->~RejectUse(this)) - { - // remember for later: - ShelveCommand(this, "CanReIssueCommand", this, "ReIssueCommand", {obj = obj, ctrl = ctrl}); - // but still catch command - return true; - } - - // Disable climb/hangle actions for the duration of this use - if (obj.ForceFreeHands && !GetEffect("IntControlFreeHands", this)) AddEffect("IntControlFreeHands", this, 130, 0, this); - - this.control.current_object = obj; - this.control.using_type = DetermineUsageType(obj); - this.control.alt = ctrl != CON_UseDelayed; - - VirtualCursor()->StartAim(this); - - // call UseStart - var handled = obj->Call(GetUseCallString("Start"),this,this.control.mlastx,this.control.mlasty); - this.control.noholdingcallbacks = !handled; - - if(handled) - this.control.started_use = true; - - return handled; -} - func CancelUseControl(int x, int y) { // forget possibly stored commands @@ -760,11 +726,6 @@ func HoldingUseControl(int ctrl, int x, int y, object obj) { var mex = x; var mey = y; - if (ctrl == CON_UseDelayed || ctrl == CON_UseAltDelayed) - { - mex = this.control.mlastx; - mey = this.control.mlasty; - } //Message("%d,%d",this,mex,mey); @@ -807,29 +768,6 @@ func HoldingUseControl(int ctrl, int x, int y, object obj) return handled; } -func StopUseDelayedControl(object obj) -{ - // ControlUseStop, ControlUseAltStop, ContainedUseAltStop, etc... - var handled = obj->Call(GetUseCallString("Stop"), this, this.control.mlastx, this.control.mlasty); - if (!handled) - handled = obj->Call(GetUseCallString(), this, this.control.mlastx, this.control.mlasty); - - if (obj == this.control.current_object) - { - VirtualCursor()->StopAim(); - // see StopUseControl - if(handled != -1) - { - this.control.current_object = nil; - this.control.using_type = nil; - this.control.alt = false; - } - this.control.noholdingcallbacks = false; - } - - return handled; -} - // very infrequent timer to prevent dangling effects, this is not necessary for correct functioning func FxItemRemovalCheckTimer(object target, proplist effect, int time) { @@ -868,21 +806,9 @@ func ControlUse2Script(int ctrl, int x, int y, int strength, bool repeat, int st return StopUseControl(x, y, obj); } } - // gamepad use - else if (ctrl == CON_UseDelayed || ctrl == CON_UseAltDelayed) - { - if (status == CONS_Down && !repeat) - { - return StartUseDelayedControl(ctrl, obj); - } - else if (status == CONS_Up && obj == this.control.current_object) - { - return StopUseDelayedControl(obj); - } - } // more use (holding) - if (ctrl == CON_Use || ctrl == CON_UseAlt || ctrl == CON_UseDelayed || ctrl == CON_UseAltDelayed) + if (ctrl == CON_Use || ctrl == CON_UseAlt) { if (status == CONS_Up) { @@ -890,7 +816,7 @@ func ControlUse2Script(int ctrl, int x, int y, int strength, bool repeat, int st CancelUse(); return true; } - else if (repeat && !this.control.noholdingcallbacks) + else if (status == CONS_Down && repeat && !this.control.noholdingcallbacks) { return HoldingUseControl(ctrl, x, y, obj); } diff --git a/planet/Objects.ocd/Libraries.ocd/ClonkGamepadControl.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/ClonkGamepadControl.ocd/Script.c index 685cc7810..010b03acd 100644 --- a/planet/Objects.ocd/Libraries.ocd/ClonkGamepadControl.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/ClonkGamepadControl.ocd/Script.c @@ -24,7 +24,7 @@ func Control2Menu(int ctrl, int x, int y, int strength, bool repeat, int status) /* all this stuff is already done on a higher layer - in playercontrol.c now this is just the same for gamepad control */ - if (!PlayerHasVirtualCursor(GetOwner())) + if (!HasVirtualCursor()) return true; if (!this->GetMenu()) return false; @@ -36,14 +36,14 @@ func Control2Menu(int ctrl, int x, int y, int strength, bool repeat, int status) // update angle for visual effect on the menu if (repeat) { - if (ctrl == CON_UseDelayed || ctrl == CON_UseAltDelayed) + if (ctrl == CON_Use || ctrl == CON_UseAlt) this->GetMenu()->~UpdateCursor(mex,mey); } // click on menu if (status == CONS_Up) { // select - if (ctrl == CON_UseDelayed) + if (ctrl == CON_Use) this->GetMenu()->~OnMouseClick(mex,mey); } @@ -91,6 +91,9 @@ func ReinitializeControls() /* Virtual cursor stuff */ +// Helper function. +private func HasVirtualCursor() { return PlayerHasVirtualCursor(GetOwner()); } + // get virtual cursor, if noone is there, create it private func VirtualCursor() { @@ -122,19 +125,12 @@ public func UpdateVirtualCursorPos() public func TriggerHoldingControl() { - // using has been commented because it must be possible to use the virtual - // cursor aim also without a used object - for menus - // However, I think the check for 'this.control.current_object' here is just an unecessary safeguard - // since there is always a using-object if the clonk is aiming for a throw - // or a use. If the clonk uses it, there will be callbacks that cancel the - // callbacks to the virtual cursor - // - Newton - if (/*this.control.current_object && */!this.control.noholdingcallbacks) + if (this.control.current_object && !this.control.noholdingcallbacks) { - var ctrl = CON_UseDelayed; + var ctrl = CON_Use; if (this.control.alt) - ctrl = CON_UseAltDelayed; - ObjectControl(GetOwner(), ctrl, 0, 0, 0, true, false); + ctrl = CON_UseAlt; + ObjectControl(GetOwner(), ctrl, 0, 0, 0, true, CONS_Down); } } diff --git a/planet/System.ocg/PlayerControls.txt b/planet/System.ocg/PlayerControls.txt index b4bf39681..ea9fe241d 100644 --- a/planet/System.ocg/PlayerControls.txt +++ b/planet/System.ocg/PlayerControls.txt @@ -37,7 +37,6 @@ # # Gamepad controls # ------------------------------------- - # UseDelayed # AimUp AimDown AimLeft AimRight # AimAxisUp AimAxisDown AimAxisLeft AimAxisRight # @@ -247,13 +246,6 @@ Hold=1 SendCursorPos=1 - [ControlDef] - Identifier=UseDelayed - GUIName=$CON_Use$ - GUIDesc=$CON_Use_Desc$ - Hold=1 - SendCursorPos=1 - [ControlDef] Identifier=UseAlt GUIName=$CON_UseAlt$ @@ -261,13 +253,6 @@ Hold=1 SendCursorPos=1 - [ControlDef] - Identifier=UseAltDelayed - GUIName=$CON_UseAlt$ - GUIDesc=$CON_UseAlt_Desc$ - Hold=1 - SendCursorPos=1 - [ControlDef] Identifier=CancelUse @@ -990,7 +975,7 @@ GUIDesc=$KEY_GamepadUse_Desc$ GUIGroup=20 Priority=100 - Control=UseDelayed + Control=Use [Assignment] Key=ControllerLeftTrigger From fac684a9738fe006a0ec129795b4e559de4e689c Mon Sep 17 00:00:00 2001 From: Lukas Werling Date: Tue, 22 Mar 2016 17:13:21 +0100 Subject: [PATCH 06/26] Fix crosshair being visible initially --- .../Libraries.ocd/ClonkControl.ocd/Crosshair.ocd/Script.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Crosshair.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Crosshair.ocd/Script.c index 515b148dd..4ec764290 100644 --- a/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Crosshair.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Crosshair.ocd/Script.c @@ -37,7 +37,7 @@ public func FxMoveTimer() else angle = target_angle; } - else if (!aiming) + else if (!aiming && Visible()) { // The player doesn't touch the stick and no item is using the crosshair right now. SetVisibility(false); @@ -66,7 +66,7 @@ private func SetVisibility(bool visible) public func StartAim(object clonk, bool stealth, object GUImenu) { - aiming = true; + aiming = !stealth; // only reinitialize angle if the crosshair hasn't been there before if(!GetEffect("Move",this)) @@ -89,7 +89,7 @@ public func StartAim(object clonk, bool stealth, object GUImenu) } // Aim somewhere useful if the crosshair wasn't visible before. - if (SetVisibility(true)) + if (!stealth && SetVisibility(true)) angle = 800*(clonk->GetDir()*2-1); crew = clonk; From acc04b239832ba4fc58cb63c01e5b971f9e344da Mon Sep 17 00:00:00 2001 From: Lukas Werling Date: Tue, 22 Mar 2016 18:56:31 +0100 Subject: [PATCH 07/26] Improve default Use/Throw angles when not aiming --- .../Items.ocd/Tools.ocd/Shovel.ocd/Script.c | 2 + .../Items.ocd/Tools.ocd/WindBag.ocd/Script.c | 8 +++ .../ClonkControl.ocd/Crosshair.ocd/Script.c | 51 ++++++++++++------- .../Libraries.ocd/ClonkControl.ocd/Script.c | 34 +++++++++---- .../ClonkGamepadControl.ocd/Script.c | 2 +- 5 files changed, 68 insertions(+), 29 deletions(-) diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/Shovel.ocd/Script.c b/planet/Objects.ocd/Items.ocd/Tools.ocd/Shovel.ocd/Script.c index 9bbda3115..bf5672b57 100644 --- a/planet/Objects.ocd/Items.ocd/Tools.ocd/Shovel.ocd/Script.c +++ b/planet/Objects.ocd/Items.ocd/Tools.ocd/Shovel.ocd/Script.c @@ -37,6 +37,8 @@ public func IsDigging() { return is_digging; } public func HoldingEnabled() { return true; } +public func DefaultCrosshairAngle(object clonk, int d) { return 900 * d; } + public func ControlUseStart(object clonk, int x, int y) { AddEffect("ShovelDig", clonk, 1, 1, this); diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/WindBag.ocd/Script.c b/planet/Objects.ocd/Items.ocd/Tools.ocd/WindBag.ocd/Script.c index 4e374a425..e438ea27f 100644 --- a/planet/Objects.ocd/Items.ocd/Tools.ocd/WindBag.ocd/Script.c +++ b/planet/Objects.ocd/Items.ocd/Tools.ocd/WindBag.ocd/Script.c @@ -47,6 +47,14 @@ func ReadyToBeUsed(proplist data) return !RejectUse(clonk) && !GetEffect("IntReload", this); } +public func DefaultCrosshairAngle(object clonk, int d) +{ + // Easy mode for gamepad users: automatically boost a jump. + if (clonk->GetYDir() < -10) + return Angle(0, 0, -clonk->GetXDir(), -clonk->GetYDir(), 10); + return 0; +} + protected func ControlUse(object clonk, x, y) { if (!GetEffect("IntReload", this) && !GetEffect("IntBurstWind", this)) diff --git a/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Crosshair.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Crosshair.ocd/Script.c index 4ec764290..e3ecd0d3f 100644 --- a/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Crosshair.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Crosshair.ocd/Script.c @@ -20,6 +20,12 @@ protected func Initialize() public func FxMoveTimer() { + if (!crew) + { + RemoveObject(); + return FX_Execute_Kill; + } + var target_angle = Angle(0,0,xpos,ypos)*10; if (!Visible() && !InDeadzone()) @@ -37,10 +43,12 @@ public func FxMoveTimer() else angle = target_angle; } - else if (!aiming && Visible()) + else if (!aiming) { // The player doesn't touch the stick and no item is using the crosshair right now. SetVisibility(false); + // Aim somewhere useful. Note that this can be overwritten by objects and isn't used for throwing. + angle = 800*(crew->GetDir()*2-1); } UpdatePosition(); @@ -64,17 +72,18 @@ private func SetVisibility(bool visible) return newvis != oldvis; } -public func StartAim(object clonk, bool stealth, object GUImenu) +private func CreateMoveEffect(object clonk) { - aiming = !stealth; + crew = clonk; + UpdatePosition(); + RemoveEffect("Move",this); + AddEffect("Move",this,1,1,this); +} + +public func StartAim(object clonk, int default_angle, object GUImenu) +{ + aiming = true; - // only reinitialize angle if the crosshair hasn't been there before - if(!GetEffect("Move",this)) - { - // which should basically be only the case on the first time aiming - angle = 800*(clonk->GetDir()*2-1); - } - // gui or landscape mode: if (GUImenu) { @@ -88,14 +97,11 @@ public func StartAim(object clonk, bool stealth, object GUImenu) menu = nil; } - // Aim somewhere useful if the crosshair wasn't visible before. - if (!stealth && SetVisibility(true)) - angle = 800*(clonk->GetDir()*2-1); - - crew = clonk; - UpdatePosition(); - RemoveEffect("Move",this); - AddEffect("Move",this,1,1,this); + // Use the given angle if the player wasn't aiming before. + if (SetVisibility(true) && default_angle) + angle = default_angle; + + CreateMoveEffect(clonk); } private func UpdatePosition() @@ -122,16 +128,23 @@ public func StopAim() aiming = false; } +// Aiming means that some object is currently actively using the crosshair. public func IsAiming() { return aiming; } +// The crosshair is also active when the player is holding the aiming stick. +public func IsActive() +{ + return aiming || Visible(); +} + public func Aim(int ctrl, object clonk, int strength, int repeat, int status) { // start (stealth) aiming if(!GetEffect("Move",this)) - StartAim(clonk,true); + CreateMoveEffect(clonk); // aiming with analog pad if (status == CONS_Moved && diff --git a/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c index 391b6a698..43dec787d 100644 --- a/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/ClonkControl.ocd/Script.c @@ -46,6 +46,9 @@ static const ACTIONTYPE_EXTRA = 4; // elevators within this range (x) can be called static const ELEVATOR_CALL_DISTANCE = 30; +// default throwing angle used while the Clonk isn't aiming +static const DEFAULT_THROWING_ANGLE = 500; + /* ++++++++++++++++++++++++ Clonk Inventory Control ++++++++++++++++++++++++ */ /* @@ -362,14 +365,19 @@ public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re if (only_drop || Distance(0, 0, x, y) < 10 || (Abs(x) < 10 && y > 10)) only_drop = true; // throw - if (ctrl == CON_Throw) + CancelUse(); + + if (only_drop) + return ObjectCommand("Drop", contents); + else { - CancelUse(); - - if (only_drop) - return ObjectCommand("Drop", contents); - else - return ObjectCommand("Throw", contents, x, y); + if (HasVirtualCursor() && !VirtualCursor()->IsActive()) + { + var angle = DEFAULT_THROWING_ANGLE * (GetDir()*2 - 1); + x = +Sin(angle, CURSOR_Radius, 10); + y = -Cos(angle, CURSOR_Radius, 10); + } + return ObjectCommand("Throw", contents, x, y); } } } @@ -624,7 +632,15 @@ func StartUseControl(int ctrl, int x, int y, object obj) this.control.alt = ctrl != CON_Use; if (HasVirtualCursor()) - VirtualCursor()->StartAim(this); + { + var cursor = VirtualCursor(), angle; + if (!cursor->IsActive() && (angle = obj->~DefaultCrosshairAngle(this, GetDir()*2 - 1))) + { + x = +Sin(angle, CURSOR_Radius, 10); + y = -Cos(angle, CURSOR_Radius, 10); + } + cursor->StartAim(this, angle); + } var hold_enabled = obj->Call("~HoldingEnabled"); @@ -944,7 +960,7 @@ func SetMenu(new_menu, bool unclosable) SetComDir(COMD_Stop); if (PlayerHasVirtualCursor(GetOwner())) - VirtualCursor()->StartAim(this,false, new_menu); + VirtualCursor()->StartAim(this, 0, new_menu); else { if (GetType(new_menu) == C4V_C4Object && new_menu->~CursorUpdatesEnabled()) diff --git a/planet/Objects.ocd/Libraries.ocd/ClonkGamepadControl.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/ClonkGamepadControl.ocd/Script.c index 010b03acd..f92ec2c37 100644 --- a/planet/Objects.ocd/Libraries.ocd/ClonkGamepadControl.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/ClonkGamepadControl.ocd/Script.c @@ -79,7 +79,7 @@ func ReinitializeControls() // if is aiming or in menu and no virtual cursor is there, create one if (!virtual_cursor) if (this.menu || this.control.current_object) // properties declared in ClonkControl.ocd - VirtualCursor()->StartAim(this,false,this.menu); + VirtualCursor()->StartAim(this,0,this.menu); } else { From a52da814fa885043698c9fdb313f8944f67e7442 Mon Sep 17 00:00:00 2001 From: Lukas Werling Date: Tue, 22 Mar 2016 20:12:50 +0100 Subject: [PATCH 08/26] Play short rumble when a Clonk gets hurt --- planet/Objects.ocd/Clonk.ocd/Script.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/planet/Objects.ocd/Clonk.ocd/Script.c b/planet/Objects.ocd/Clonk.ocd/Script.c index ce2b58d41..39a6f0135 100644 --- a/planet/Objects.ocd/Clonk.ocd/Script.c +++ b/planet/Objects.ocd/Clonk.ocd/Script.c @@ -109,6 +109,13 @@ protected func CatchBlow() if (GetAction() == "Dead") return; if (!Random(5)) PlaySoundHurt(); } + +protected func OnEnergyChange(int change, int cause, int caused_by) +{ + if (change < 0 && GetCursor(GetOwner()) == this) + PlayRumble(GetOwner(), Min(300 + 1000 * -change / this.MaxEnergy, 1000), 150); + return _inherited(...); +} protected func Grab(object pTarget, bool fGrab) { From 809172e74cc1e2be964f5dfb6a81a260ba8db86f Mon Sep 17 00:00:00 2001 From: Maikel de Vries Date: Sun, 7 Aug 2016 14:19:31 +0200 Subject: [PATCH 09/26] new world: rapid refining --- planet/Worlds.ocf/AcidRift.ocs/Scenario.txt | 2 +- planet/Worlds.ocf/Chine.ocs/Scenario.txt | 2 +- planet/Worlds.ocf/FloodedVeins.ocs/DescUS.txt | 2 +- .../Worlds.ocf/GemGrabbers.ocs/Scenario.txt | 2 +- planet/Worlds.ocf/Krakatoa.ocs/Scenario.txt | 2 +- .../Worlds.ocf/RapidRefining.ocs/DescDE.txt | 9 + .../Worlds.ocf/RapidRefining.ocs/DescUS.txt | 9 + planet/Worlds.ocf/RapidRefining.ocs/Icon.png | Bin 0 -> 2507 bytes planet/Worlds.ocf/RapidRefining.ocs/Map.c | 237 ++++++++++++++++++ .../RapidRefining.ocs/ParameterDefs.txt | 47 ++++ .../RefineryDrain.ocd/DefCore.txt | 14 ++ .../RefineryDrain.ocd/Graphics.4.png | Bin 0 -> 5745 bytes .../RefineryDrain.ocd/Script.c | 94 +++++++ .../RefineryDrain.ocd/StringTblDE.txt | 9 + .../RefineryDrain.ocd/StringTblUS.txt | 9 + .../RefineryGoal.ocd/DefCore.txt | 5 + .../RefineryGoal.ocd/Graphics.png | Bin 0 -> 12471 bytes .../RefineryGoal.ocd/Script.c | 49 ++++ .../RefineryGoal.ocd/StringTblDE.txt | 3 + .../RefineryGoal.ocd/StringTblUS.txt | 3 + .../Worlds.ocf/RapidRefining.ocs/Scenario.txt | 31 +++ planet/Worlds.ocf/RapidRefining.ocs/Script.c | 207 +++++++++++++++ .../RapidRefining.ocs/StringTblDE.txt | 19 ++ .../RapidRefining.ocs/StringTblUS.txt | 19 ++ .../RapidRefining.ocs/System.ocg/PipeLength.c | 9 + planet/Worlds.ocf/RapidRefining.ocs/Title.jpg | Bin 0 -> 93197 bytes planet/Worlds.ocf/RapidRefining.ocs/Title.txt | 2 + 27 files changed, 780 insertions(+), 5 deletions(-) create mode 100644 planet/Worlds.ocf/RapidRefining.ocs/DescDE.txt create mode 100644 planet/Worlds.ocf/RapidRefining.ocs/DescUS.txt create mode 100644 planet/Worlds.ocf/RapidRefining.ocs/Icon.png create mode 100644 planet/Worlds.ocf/RapidRefining.ocs/Map.c create mode 100644 planet/Worlds.ocf/RapidRefining.ocs/ParameterDefs.txt create mode 100644 planet/Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/DefCore.txt create mode 100644 planet/Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/Graphics.4.png create mode 100644 planet/Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/Script.c create mode 100644 planet/Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/StringTblDE.txt create mode 100644 planet/Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/StringTblUS.txt create mode 100644 planet/Worlds.ocf/RapidRefining.ocs/RefineryGoal.ocd/DefCore.txt create mode 100644 planet/Worlds.ocf/RapidRefining.ocs/RefineryGoal.ocd/Graphics.png create mode 100644 planet/Worlds.ocf/RapidRefining.ocs/RefineryGoal.ocd/Script.c create mode 100644 planet/Worlds.ocf/RapidRefining.ocs/RefineryGoal.ocd/StringTblDE.txt create mode 100644 planet/Worlds.ocf/RapidRefining.ocs/RefineryGoal.ocd/StringTblUS.txt create mode 100644 planet/Worlds.ocf/RapidRefining.ocs/Scenario.txt create mode 100644 planet/Worlds.ocf/RapidRefining.ocs/Script.c create mode 100644 planet/Worlds.ocf/RapidRefining.ocs/StringTblDE.txt create mode 100644 planet/Worlds.ocf/RapidRefining.ocs/StringTblUS.txt create mode 100644 planet/Worlds.ocf/RapidRefining.ocs/System.ocg/PipeLength.c create mode 100644 planet/Worlds.ocf/RapidRefining.ocs/Title.jpg create mode 100644 planet/Worlds.ocf/RapidRefining.ocs/Title.txt diff --git a/planet/Worlds.ocf/AcidRift.ocs/Scenario.txt b/planet/Worlds.ocf/AcidRift.ocs/Scenario.txt index fd9c2db89..fa5d1232b 100644 --- a/planet/Worlds.ocf/AcidRift.ocs/Scenario.txt +++ b/planet/Worlds.ocf/AcidRift.ocs/Scenario.txt @@ -2,7 +2,7 @@ Icon=34 Title=AcidRift Version=6,0 -Difficulty=70 +Difficulty=80 [Definitions] Definition1=Objects.ocd diff --git a/planet/Worlds.ocf/Chine.ocs/Scenario.txt b/planet/Worlds.ocf/Chine.ocs/Scenario.txt index da3395859..b993a38cb 100644 --- a/planet/Worlds.ocf/Chine.ocs/Scenario.txt +++ b/planet/Worlds.ocf/Chine.ocs/Scenario.txt @@ -2,7 +2,7 @@ Icon=36 Title=Chine Version=6,0 -Difficulty=50 +Difficulty=60 [Definitions] Definition1=Objects.ocd diff --git a/planet/Worlds.ocf/FloodedVeins.ocs/DescUS.txt b/planet/Worlds.ocf/FloodedVeins.ocs/DescUS.txt index 796ae581e..9d431fed0 100644 --- a/planet/Worlds.ocf/FloodedVeins.ocs/DescUS.txt +++ b/planet/Worlds.ocf/FloodedVeins.ocs/DescUS.txt @@ -2,7 +2,7 @@ Flooded Veins You stumble upon an abandoned settlement beneath the Forest of Orgos in your quest for more gold. Legends tell a story of even more valuable materials named gems which may be found here. Might this abandoned settlement be a failed attempt to find these gems? Set up an expedition to explore the flooded caves around and to discover possible gem veins. -Goal: Sell gems +Goal: Sell gems. Hints: - The flooded caves may be drained using pumps, you can get rid off the excess water where you entered the cave. diff --git a/planet/Worlds.ocf/GemGrabbers.ocs/Scenario.txt b/planet/Worlds.ocf/GemGrabbers.ocs/Scenario.txt index 1fb23a875..b11cf3346 100644 --- a/planet/Worlds.ocf/GemGrabbers.ocs/Scenario.txt +++ b/planet/Worlds.ocf/GemGrabbers.ocs/Scenario.txt @@ -2,7 +2,7 @@ Title=GemGrabbers Icon=35 Version=6,0 -Difficulty=80 +Difficulty=90 [Definitions] Definition1=Objects.ocd diff --git a/planet/Worlds.ocf/Krakatoa.ocs/Scenario.txt b/planet/Worlds.ocf/Krakatoa.ocs/Scenario.txt index 14f3475b8..824360a9a 100644 --- a/planet/Worlds.ocf/Krakatoa.ocs/Scenario.txt +++ b/planet/Worlds.ocf/Krakatoa.ocs/Scenario.txt @@ -2,7 +2,7 @@ Icon=23 Title=Krakatoa Version=6,0 -Difficulty=60 +Difficulty=70 [Definitions] Definition1=Objects.ocd diff --git a/planet/Worlds.ocf/RapidRefining.ocs/DescDE.txt b/planet/Worlds.ocf/RapidRefining.ocs/DescDE.txt new file mode 100644 index 000000000..b2c3daa0c --- /dev/null +++ b/planet/Worlds.ocf/RapidRefining.ocs/DescDE.txt @@ -0,0 +1,9 @@ +Rasches Raffinieren + +An apparently infinite oil well is hidden deep inside a cave. Connect the well to the refinery drain outside of the cave using pumps and supply the refinery. + +Ziel: Pumpe Öl. + +Tipps: +- Do not set oil on fire, it will burn for a long time. +- You can connect multiple pipes to the refinery drain. diff --git a/planet/Worlds.ocf/RapidRefining.ocs/DescUS.txt b/planet/Worlds.ocf/RapidRefining.ocs/DescUS.txt new file mode 100644 index 000000000..5a1d29e52 --- /dev/null +++ b/planet/Worlds.ocf/RapidRefining.ocs/DescUS.txt @@ -0,0 +1,9 @@ +Rapid Refining + +An apparently infinite oil well is hidden deep inside a cave. Connect the well to the refinery drain outside of the cave using pumps and supply the refinery. + +Goal: Pump oil. + +Hints: +- Do not set oil on fire, it will burn for a long time. +- You can connect multiple pipes to the refinery drain. diff --git a/planet/Worlds.ocf/RapidRefining.ocs/Icon.png b/planet/Worlds.ocf/RapidRefining.ocs/Icon.png new file mode 100644 index 0000000000000000000000000000000000000000..6ff07f93b58ffda8f145593a290030ad202b63bd GIT binary patch literal 2507 zcmV;+2{iVJP)49lzGzD7)+RKIXAI zkDcl1>33D};T~&Z2ojH!)SA{*b=_0<+&cGOBBexc5JE`rHTk_gDf<`xABTE}aRNX| z{wE257yu`Pye}ZszIQSEPrRWYP0kP1aw0Vw1& zfLxE3WYFGo2W?8MSmeMqArcDUH3zwy! z32)dm#Dr<4RmNC&bnfmiQ9@3*VYt@mc7KqwviCTy`(?&dxqo)=7eP>0mj?n;(UIbFaJ%0+Ix+(G9SgBNA0nnYv=e6xHBn{Vf6F^aq zLrQ=-6$H>zu<|*i4FfESpaGhy={jX5<4{%Ck5MXDkC^@5PPaje9Kfq*e6ssbql z;xGWwG!Q}|rGStETyVq@hlnGDF-OEXwp(quo)13^gy(zQ^*w(epSLH*##Xzo`%2gI zio4?IJK^}$K4Was(xE&Kpa4L>tpjlwwIiKCkrI>=L{S9cxw6aiTWB`jkn?~-%(QJ= zjRlA8xX?5mw%x(_=$L$CWo5BcDW7s(Z#{~mRush@A%r8PYyo(w>p1sr*K6MuRskDM z=MsQ40Hp^&3QFrS7a%;sR%H`*y@t4BJ3o8t^7jC=cJI1tZhUNXUu(MoEoIgU#i61K z0_FzD8Ywb8J~6Siv2n~ajn?Lt^A><@05$**0G|&c2hHX;EN$iKg=X_IfCzx-Q6N2n z^(Y9CY19$@=I0oA^(81>rvYG#60)&xcJEV^021Jn6XO|5RYX$Y()Ib6bB@W09qDW# zf2cS#^wrtf+0OxR6A(=RO*e|F=i2tmVtBYtDcw%yVfp!;c~aVE~;eGudo* zSYuk(4}y9olhLOpC-+l;jgAb@NhzUL|RgM+8%1NX!GsRF?THX{BG z(=<^SD14#OXu$Pc$(VXw*Nr()f?Ph2lP69Rx9cM2F?NiPqw98&u`F$v;AyAbe!4hV zs1`;>6%oh9!9sy|y4`Sapm2U=b?pWKg(iw50QfOef3$9-e{6T!=S#l#$9XTfaQNWC zC&Dl)Y8pe=_5Na6xw5J;fKXYfY{mdVE|*2yZbM6HNLv<|s)DHut&R(8aA=eeQVaqg zDpQrf^9|ideKL{v+qXd6l2BUes_eC&RH`omP%@c}p0hIF=7M8ra0tcX@WUF@B8_RV zolf)Yo9Av2LXH8z@WI z+7O(>4391y)v87Oaf*SQte(xNi@RKX^Zw#y}MXL{Xq96pS%c z%4Nhc2c;B25NxeP{QJut=l1|w0Q~-fM3y#6?!?#x13>od-u+w@g+?xyhmp=az*4FD z)Q<5fT{pmE5wzRwV@y>?o_zdK<-G+Dss6jBnS*c2NxWg3WTl$E+v+imw(Z5 zoHqfi0@woJssEIq3G})B`)5+A)HBH`y;C$(CXU{%=>GG9tdak=*X0mV`2b#tPW_Hi$&2}3XF3-ac1@e{&9t+r&GL(7= zN*F>>R49}}Q5hW9JI^_<0H`Ml83K@ZdO$IBZKpz&Cw$+R8|Ct^094o4*BAHh+L=z9 zsk^t^HV7f8Zf|0%Rs$em=qgOpz}wfZW7xORP3aJ{4Qqga5P~p{8|8B4bpW;A$!}c> zDf??e3V>N=`a_=YtDf(_vAMN%6+j7qy>nvh2%!XwskkzK4XUalole6j6p%@$;dHwI zr6^VF7#*;Xwz9mwy}ekjRR6rXQ91))4L}t@7XZIq5%rbh>O&9Q{}IO2hq}HWFD)tcfN%qL`W&=IDk1}IgrUMgSQs8s&C zRjyMl9fyAo8^v_r@OAVfUeg_j5YvtlD)$I)As`)eh@T4X)UE| zql%(f4KEfxkoNL3ZF6w%Vs(nSF4VH7p4T%BLYWwXE4G_6pp*PBV| zbrPPp6T@DTdU+x_@?SP4XU?8Iy>HLV3p*z#zcw*GhH9;TAe~N+w%hHxX_}7{g~4&X za&x=6l|*s{fN0zHCV*5zV*tQUjE4P&->YBf&jo?tVm*o?sHzG=;0qy?iLud%lws^; zdJ5F_4bwE?x^B>;Cpo3kw@-XWN&ase6;(kpF-i1l^H#?<8GY^hwResize(map_size[0], map_size[1]); + + // The overground area is in the top left corner, the underground are thereby the remainder. + var underground = {Algo = MAPALGO_Not, Op = {Algo = MAPALGO_Rect, X = 0, Y = 0, Wdt = overground_wdt, Hgt = overground_hgt}}; + Draw("Earth", underground); + + // Draw materials in the underground area and then overlay the rest of the map. + DrawMaterial("Earth-earth_root", underground, 2, 12); + DrawMaterial("Earth-earth_spongy", underground, 2, 12); + DrawMaterial("Granite", underground, 3, 6); + DrawMaterial("Tunnel", underground, 5, 8); + DrawMaterial("Rock-rock", underground, 3, 4); + DrawMaterial("Rock", underground, 3, 4); + DrawMaterial("Ore", underground, 6, 6); + DrawMaterial("Firestone", underground, 5, 4); + DrawMaterial("Coal", underground, 6, 4); + + // Draw some underground water lakes. + var underground_water = {Algo = MAPALGO_And, Op = [underground, {Algo = MAPALGO_Rect, X = 0, Y = map.Hgt / 2, Wdt = map.Wdt - 20, Hgt = map.Hgt / 2}]}; + DrawMaterial("Water", underground_water, [4, 10], 6); + + // The entrance border is out of granite. + var entrance_border = {Algo = MAPALGO_Border, Left = 3, Op = underground}; + entrance_border = {Algo = MAPALGO_Or, Op = [entrance_border, {Algo = MAPALGO_Turbulence, Iterations = 2, Amplitude = [6, 8], Scale = [6, 8], Seed = Random(65536), Op = entrance_border}]}; + DrawRock(entrance_border); + + // The entrance floor is out of earth and brick. + var entrance_floor = {Algo = MAPALGO_Border, Top = 3, Op = underground}; + Draw("Brick", entrance_floor); + var entrance_floor_earth = {Algo = MAPALGO_Border, Top = 2, Op = underground}; + var entrance_floor_earth = {Algo = MAPALGO_And, Op = [entrance_floor_earth, {Algo = MAPALGO_Rect, X = 4, Y = 0, Wdt = 17, Hgt = map.Hgt}]}; + Draw("Earth", entrance_floor_earth); + + // There are borders on the full underground area of the map. + var wdt = 3; + var underground_border = {Algo = MAPALGO_Not, Op = {Algo = MAPALGO_Rect, X = wdt, Y = wdt, Wdt = map.Wdt - 2 * wdt, Hgt = map.Hgt - 2 * wdt}}; + underground_border = {Algo = MAPALGO_And, Op = [underground_border, underground]}; + underground_border = {Algo = MAPALGO_Or, Op = [underground_border, {Algo = MAPALGO_Turbulence, Iterations = 4, Amplitude = 16, Scale = 12, Seed = Random(65536), Op = underground_border}]}; + underground_border = {Algo = MAPALGO_And, Op = [underground_border, underground, {Algo = MAPALGO_Not, Op = entrance_floor}]}; + DrawRock(underground_border); + + // Draw a tunnel to the oil well. + DrawMainTunnel(map, overground_wdt, overground_hgt); + + // Some slabs of granite/rock which block the path to the oil. + DrawRockSlabs(map); + + // There is a smaller oil field below the entrance. + DrawOilLakes(map); + + // The main oil well is in the bottom right of the map. + DrawOilWell(map, underground_border); + + // A large water lake at the bottom of the map. + DrawWaterLake(map, underground_border); + + // Some liquid veins above the oil well. + DrawLiquidVeins(map, underground_border); + + // Fix liquid borders. + FixLiquidBorders(); + + // Return true to tell the engine a map has been successfully created. + return true; +} + +public func DrawMainTunnel(proplist map, int overground_wdt, int overground_hgt) +{ + var sx = overground_wdt; + var sy = overground_hgt - 3; + var ex = map.Wdt - 20; + var ey = map.Hgt - 30; + var nr_steps = 10; + var tunnel_x = [], tunnel_y = []; + for (var index = 0; index <= nr_steps; index++) + { + var dev = 4 * Min(index, nr_steps - index); + tunnel_x[index] = sx + (ex - sx) * index / nr_steps + RandomX(-dev, dev); + tunnel_y[index] = sy + (ey - sy) * index / nr_steps + RandomX(-dev, dev); + } + + // Draw main tunnel. + var tunnel = {Algo = MAPALGO_Polygon, X = tunnel_x, Y = tunnel_y, Wdt = 3, Empty = true, Open = true}; + tunnel = {Algo = MAPALGO_Or, Op = [tunnel, {Algo = MAPALGO_Turbulence, Iterations = 2, Amplitude = [6, 8], Scale = [6, 8], Seed = Random(65536), Op = tunnel}]}; + Draw("Tunnel", tunnel); + + // Draw branches. + for (var index = 2; index <= nr_steps - 2; index++) + { + var x = tunnel_x[index]; + var y = tunnel_y[index]; + var to_x = x + RandomX(-5, 5); + var to_y = y + (2 * Random(2) - 1) * RandomX(16, 22); + var tunnel_branch = {Algo = MAPALGO_Polygon, X = [x, to_x], Y = [y, to_y], Wdt = 2, Empty = true, Open = true}; + tunnel_branch = {Algo = MAPALGO_Turbulence, Iterations = 4, Amplitude = 12, Scale = 8, Seed = Random(65536), Op = tunnel_branch}; + Draw("Tunnel", tunnel_branch); + } + return; +} + +public func DrawRockSlabs(proplist map) +{ + var slabs = {Algo = MAPALGO_Lines, X = 6, Y = 1, Distance = 32}; + slabs = {Algo = MAPALGO_And, Op = [slabs, {Algo = MAPALGO_RndChecker, Ratio = 75, Seed = Random(65536)}]}; + slabs = {Algo = MAPALGO_Turbulence, Iterations = 2, Amplitude = [6, 8], Scale = [6, 8], Seed = Random(65536), Op = slabs}; + slabs = {Algo = MAPALGO_And, Op = [slabs, {Algo = MAPALGO_Rect, X = map.Wdt / 3, Y = 0, Wdt = 2 * map.Wdt / 3, Hgt = map.Hgt}]}; + DrawRock(slabs); + return; +} + +public func DrawWaterLake(proplist map, proplist underground_border) +{ + var lake_height = 20; + var lake_width = 80; + var tunnel_height = 6; + + underground_border = {Algo = MAPALGO_And, Op = [underground_border, {Algo = MAPALGO_Not, Op = {Algo = MAPALGO_Rect, X = 0, Y = map.Hgt - lake_height - 2, Wdt = lake_width, Hgt = 6}}]}; + + var tunnel = {Algo = MAPALGO_Rect, X = 0, Y = map.Hgt - lake_height - tunnel_height, Wdt = lake_width, Hgt = tunnel_height}; + tunnel = {Algo = MAPALGO_Or, Op = [tunnel, {Algo = MAPALGO_Turbulence, Iterations = 4, Amplitude = 16, Scale = 8, Seed = Random(65536), Op = tunnel}]}; + tunnel = {Algo = MAPALGO_And, Op = [tunnel, {Algo = MAPALGO_Not, Op = underground_border}]}; + Draw("Tunnel", tunnel); + + var lake = {Algo = MAPALGO_Rect, X = 0, Y = map.Hgt - lake_height, Wdt = lake_width, Hgt = lake_height}; + lake = {Algo = MAPALGO_And, Op = [lake, {Algo = MAPALGO_Not, Op = underground_border}]}; + Draw("Water:Water", lake); + + var lake_floor = {Algo = MAPALGO_Border, Bottom = 2, Op = lake}; + Draw("Sand", lake_floor); + + var lake_boundary = {Algo = MAPALGO_Rect, X = lake_width - 1, Y = map.Hgt - lake_height, Wdt = 2, Hgt = lake_height}; + lake_boundary = {Algo = MAPALGO_Or, Op = [lake_boundary, {Algo = MAPALGO_Turbulence, Iterations = 3, Amplitude = 12, Scale = 12, Seed = Random(65536), Op = lake_boundary}]}; + Draw("Everrock", lake_boundary); + var lake_boundary_rock = {Algo = MAPALGO_Border, Wdt = -2, Op = lake_boundary}; + DrawRock(lake_boundary_rock); + return; +} + +public func DrawOilLakes(proplist map) +{ + for (var cnt = 0; cnt < 3; cnt++) + { + var oil_lake_x = RandomX(map.Wdt / 10, 3 * map.Wdt / 10); + var oil_lake_y = RandomX(2 * map.Hgt / 7, 5 * map.Hgt / 7); + var oil_lake = {Algo = MAPALGO_Rect, X = oil_lake_x, Y = oil_lake_y, Wdt = 13, Hgt = 15}; + oil_lake = {Algo = MAPALGO_Turbulence, Iterations = 4, Amplitude = 10, Scale = 10, Seed = Random(65536), Op = oil_lake}; + var oil_lake_filled = {Algo = MAPALGO_And, Op = [oil_lake, {Algo = MAPALGO_Rect, X = 0, Y = oil_lake_y - 3, Wdt = map.Wdt, Hgt = map.Hgt}]}; + Draw("Tunnel", oil_lake); + Draw("Oil", oil_lake_filled); + var oil_lake_border = {Algo = MAPALGO_Border, Left = 2, Right = 2, Bottom = 3, Top = 1, Op = oil_lake}; + DrawRock(oil_lake_border); + } + return; +} + +public func DrawOilWell(proplist map, proplist underground_border) +{ + var oil_field = {Algo = MAPALGO_Polygon, + X = [map.Wdt, map.Wdt - 16, map.Wdt - 14, map.Wdt - 10, map.Wdt - 17, map.Wdt - 22, map.Wdt - 22, map.Wdt - 27, map.Wdt - 29], + Y = [map.Hgt - 5, map.Hgt - 5, map.Hgt - 12, map.Hgt - 18, map.Hgt - 23, map.Hgt - 20, map.Hgt - 12, map.Hgt - 12, map.Hgt - 16], + Wdt = 3, Empty = true, Open = true}; + var oil_field_oil = {Algo = MAPALGO_And, Op = [oil_field, {Algo = MAPALGO_Rect, X = 0, Y = map.Hgt - 8, Wdt = map.Wdt, Hgt = 8}]}; + var oil_field_water = {Algo = MAPALGO_And, Op = [oil_field, {Algo = MAPALGO_Rect, X = 0, Y = 0, Wdt = map.Wdt, Hgt = map.Hgt - 8}]}; + Draw("Oil:Oil", oil_field_oil); + Draw("Water", oil_field_water); + var oil_field_border = {Algo = MAPALGO_Border, Left = -3, Right = -3, Top = -3, Bottom = -5, Op = oil_field}; + Draw("Everrock", oil_field_border); + var oil_field_entrance = {Algo = MAPALGO_Rect, X = map.Wdt - 31, Y = map.Hgt - 22, Wdt = 5, Hgt = 5}; + Draw("Tunnel", oil_field_entrance); + return; +} + +public func DrawLiquidVeins(proplist map, proplist underground_border) +{ + // Draw some gold as a source of wealth. + var gold = {Algo = MAPALGO_Rect, X = map.Wdt - 60, Y = 10, Wdt = 50, Hgt = 36}; + gold = {Algo = MAPALGO_And, Op = [gold, {Algo = MAPALGO_Turbulence, Iterations = 4, Amplitude = 12, Scale = 12, Seed = Random(65536), Op = gold}]}; + DrawMaterial("Gold", gold, 4, 30); + + // Draw the veins. + var vein_material = "Water"; + if (SCENPAR_Difficulty == 2) + vein_material = "Acid"; + if (SCENPAR_Difficulty == 3) + vein_material = "DuroLava"; + var vein_area = {Algo = MAPALGO_Polygon, X = [map.Wdt - 96, map.Wdt, map.Wdt, map.Wdt - 44], Y = [0, 0, 108, 82]}; + vein_area = {Algo = MAPALGO_And, Op = [vein_area, {Algo = MAPALGO_Not, Op = underground_border}]}; + + var veins = {Algo = MAPALGO_Or, Op = [ + {Algo = MAPALGO_Lines, X = 2, Y = -1, Distance = 12}, + {Algo = MAPALGO_Lines, X = 2, Y = 1, Distance = 12}, + {Algo = MAPALGO_Lines, X = 0, Y = 1, Distance = 16} + ]}; + veins = {Algo = MAPALGO_And, Op = [veins, vein_area]}; + veins = {Algo = MAPALGO_Turbulence, Iterations = 4, Amplitude = 12, Scale = 12, Seed = Random(65536), Op = veins}; + + Draw(vein_material, veins); + return; +} + + +/*-- Helper Functions --*/ + +public func DrawRock(proplist layer) +{ + Draw("Granite", layer); + DrawMaterial("Rock-rock", layer, 4, 18); + DrawMaterial("Rock", layer, 4, 18); + return; +} \ No newline at end of file diff --git a/planet/Worlds.ocf/RapidRefining.ocs/ParameterDefs.txt b/planet/Worlds.ocf/RapidRefining.ocs/ParameterDefs.txt new file mode 100644 index 000000000..b9f83b2cc --- /dev/null +++ b/planet/Worlds.ocf/RapidRefining.ocs/ParameterDefs.txt @@ -0,0 +1,47 @@ +[ParameterDef] +Name=$Difficulty$ +Description=$DescDifficulty$ +ID=Difficulty +Default=1 +LeagueValue=3 + + [Options] + + [Option] + Name=$DiffNormal$ + Description=$DescDiffNormal$ + Value=1 + + [Option] + Name=$DiffHard$ + Description=$DescDiffHard$ + Value=2 + + [Option] + Name=$DiffInsane$ + Description=$DescDiffInsane$ + Value=3 + +[ParameterDef] +Name=$MapSize$ +Description=$DescMapSize$ +ID=MapSize +Default=1 +LeagueValue=1 + + [Options] + + [Option] + Name=$MapSmall$ + Description=$DescMapSmall$ + Value=1 + + [Option] + Name=$MapAverage$ + Description=$DescMapAverage$ + Value=2 + + [Option] + Name=$MapLarge$ + Description=$DescMapLarge$ + Value=3 diff --git a/planet/Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/DefCore.txt b/planet/Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/DefCore.txt new file mode 100644 index 000000000..21e1294e5 --- /dev/null +++ b/planet/Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/DefCore.txt @@ -0,0 +1,14 @@ +[DefCore] +id=RefineryDrain +Version=6,0 +Category=C4D_Structure +Width=16 +Height=32 +Offset=-8,-16 +Vertices=4 +VertexX=-8,-8,8,8 +VertexY=-2,15,-2,15 +VertexCNAT=5,9,6,10 +VertexFriction=50,50,100,100 +Construction=1 +Mass=10 diff --git a/planet/Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/Graphics.4.png b/planet/Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/Graphics.4.png new file mode 100644 index 0000000000000000000000000000000000000000..a1107ec0c3fdb0161130e9c65b948538c90e5b7d GIT binary patch literal 5745 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 literal 0 HcmV?d00001 diff --git a/planet/Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/Script.c b/planet/Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/Script.c new file mode 100644 index 000000000..ad666f299 --- /dev/null +++ b/planet/Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/Script.c @@ -0,0 +1,94 @@ +/** + Refinery Drain + Oil must be pumped into this structure to be processed further. + + @author Maikel +*/ + +#include Library_Structure +#include Library_Ownable +#include Library_Tank + + +/*-- Pipeline --*/ + +public func IsLiquidContainerForMaterial(string liquid) +{ + return WildcardMatch("Oil", liquid); +} + +public func QueryConnectPipe(object pipe) +{ + if (pipe->IsDrainPipe() || pipe->IsNeutralPipe()) + { + return false; + } + else + { + pipe->Report("$MsgPipeProhibited$"); + return true; + } +} + +public func OnPipeConnect(object pipe, string specific_pipe_state) +{ + SetNeutralPipe(pipe); + pipe->Report("$MsgConnectedPipe$"); +} + + +/*-- Interaction Interface --*/ + +public func GetOilAmount() +{ + var oil = FindObject(Find_ID(Oil), Find_Container(this)); + if (oil) + return oil->GetStackCount() / 1000; + return 0; +} + +public func HasInteractionMenu() { return true; } + +public func GetInteractionMenus(object clonk) +{ + var menus = _inherited() ?? []; + var oil_menu = + { + title = "$MsgOilOverview$", + entries_callback = this.GetOilDisplayMenuEntries, + callback_hover = "OnOilDisplayHover", + callback_target = this, + BackgroundColor = RGB(0, 50, 50), + Priority = 20 + }; + PushBack(menus, oil_menu); + return menus; +} + +public func GetOilDisplayMenuEntries(object clonk) +{ + return + [{ + symbol = Oil, + extra_data = "oil", + custom = { + Style = GUI_FitChildren | GUI_TextVCenter | GUI_TextLeft, + Bottom = "1.1em", + BackgroundColor = {Std = 0, OnHover = 0x50ff0000}, + Priority = 1, + Text = Format("$MsgOilPumped$", GetOilAmount()) + } + }]; +} + +public func OnOilDisplayHover(id symbol, string extra_data, desc_menu_target, menu_id) +{ + GuiUpdateText(Format("$MsgOilDescription$", GetOilAmount()), menu_id, 1, desc_menu_target); + return; +} + + +/*-- Properties --*/ + +local Name = "$Name$"; +local Description = "$Description$"; \ No newline at end of file diff --git a/planet/Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/StringTblDE.txt b/planet/Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/StringTblDE.txt new file mode 100644 index 000000000..124025bdc --- /dev/null +++ b/planet/Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/StringTblDE.txt @@ -0,0 +1,9 @@ +Name=Raffinerie Drain +Description=Attach the drain pipe of a pump to this structure to pump oil into the refinery. Multiple pipes can be connected to the refinery drain. + +MsgOilOverview=Oil Overview +MsgOilPumped=Oil amount: %d {{Oil}}. +MsgOilDescription=Currently %d {{Oil}} has been transferred into the refinery. + +MsgConnectedPipe=Rohr angeschlossen. +MsgPipeProhibited=Zuflussrohre können nicht an den Raffinerie angeschlossen werden. \ No newline at end of file diff --git a/planet/Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/StringTblUS.txt b/planet/Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/StringTblUS.txt new file mode 100644 index 000000000..6cf60abdd --- /dev/null +++ b/planet/Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/StringTblUS.txt @@ -0,0 +1,9 @@ +Name=Refinery Drain +Description=Attach the drain pipe of a pump to this structure to pump oil into the refinery. Multiple pipes can be connected to the refinery drain. + +MsgOilOverview=Oil Overview +MsgOilPumped=Oil amount: %d {{Oil}}. +MsgOilDescription=Currently %d {{Oil}} has been transferred into the refinery. + +MsgConnectedPipe=Connected pipe. +MsgPipeProhibited=Source pipes cannot be connected to the foundry. \ No newline at end of file diff --git a/planet/Worlds.ocf/RapidRefining.ocs/RefineryGoal.ocd/DefCore.txt b/planet/Worlds.ocf/RapidRefining.ocs/RefineryGoal.ocd/DefCore.txt new file mode 100644 index 000000000..d0267e7e4 --- /dev/null +++ b/planet/Worlds.ocf/RapidRefining.ocs/RefineryGoal.ocd/DefCore.txt @@ -0,0 +1,5 @@ +[DefCore] +id=Goal_Refinery +Version=6,0 +Category=C4D_StaticBack|C4D_Goal +Picture=0,0,128,128 diff --git a/planet/Worlds.ocf/RapidRefining.ocs/RefineryGoal.ocd/Graphics.png b/planet/Worlds.ocf/RapidRefining.ocs/RefineryGoal.ocd/Graphics.png new file mode 100644 index 0000000000000000000000000000000000000000..ddd20a87e26d7ff61ef8494c3976d170b4079533 GIT binary patch literal 12471 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 Bjy3=Q literal 0 HcmV?d00001 diff --git a/planet/Worlds.ocf/RapidRefining.ocs/RefineryGoal.ocd/Script.c b/planet/Worlds.ocf/RapidRefining.ocs/RefineryGoal.ocd/Script.c new file mode 100644 index 000000000..675afdc9b --- /dev/null +++ b/planet/Worlds.ocf/RapidRefining.ocs/RefineryGoal.ocd/Script.c @@ -0,0 +1,49 @@ +/** + Refinery Goal + A certain amount of oil has to be pumped into the refinery drain. + + @author Maikel +*/ + + +#include Library_Goal + +local goal_amount; + +protected func Initialize() +{ + goal_amount = 0; + return _inherited(...); +} + +public func SetGoalAmount(int amount) +{ + goal_amount = amount; + return; +} + +private func GetPumpedAmount() +{ + var refinery_drain = FindObject(Find_ID(RefineryDrain)); + if (!refinery_drain) + return 0; + return refinery_drain->GetOilAmount(); +} + +public func IsFulfilled() +{ + return GetPumpedAmount() >= goal_amount; +} + +public func GetDescription(int plr) +{ + if (IsFulfilled()) + return "$DescriptionCompleted$"; + return Format("$Description$", GetPumpedAmount(), goal_amount); +} + + +/*-- Proplist --*/ + +local Name = "$Name$"; +local Description = "$Description$"; diff --git a/planet/Worlds.ocf/RapidRefining.ocs/RefineryGoal.ocd/StringTblDE.txt b/planet/Worlds.ocf/RapidRefining.ocs/RefineryGoal.ocd/StringTblDE.txt new file mode 100644 index 000000000..9cd8cccaf --- /dev/null +++ b/planet/Worlds.ocf/RapidRefining.ocs/RefineryGoal.ocd/StringTblDE.txt @@ -0,0 +1,3 @@ +Name=Raffinerie +Description=You have currently pumped %d {{Oil}} into the refinery drain out of the %d {{Oil}} needed to fulfill this goal. +DescriptionCompleted=Congratulations! You have pumped enough oil into the refinery drain. \ No newline at end of file diff --git a/planet/Worlds.ocf/RapidRefining.ocs/RefineryGoal.ocd/StringTblUS.txt b/planet/Worlds.ocf/RapidRefining.ocs/RefineryGoal.ocd/StringTblUS.txt new file mode 100644 index 000000000..e1d7be9eb --- /dev/null +++ b/planet/Worlds.ocf/RapidRefining.ocs/RefineryGoal.ocd/StringTblUS.txt @@ -0,0 +1,3 @@ +Name=Refinery +Description=You have currently pumped %d {{Oil}} into the refinery drain out of the %d {{Oil}} needed to fulfill this goal. +DescriptionCompleted=Congratulations! You have pumped enough oil into the refinery drain. \ No newline at end of file diff --git a/planet/Worlds.ocf/RapidRefining.ocs/Scenario.txt b/planet/Worlds.ocf/RapidRefining.ocs/Scenario.txt new file mode 100644 index 000000000..a3955837d --- /dev/null +++ b/planet/Worlds.ocf/RapidRefining.ocs/Scenario.txt @@ -0,0 +1,31 @@ +[Head] +Title=RapidRefining +Icon=24 +Version=6,0 +Difficulty=50 + +[Definitions] +Definition1=Objects.ocd + +[Player1] +Crew=Clonk=2 + +[Player2] +Crew=Clonk=2 + +[Player3] +Crew=Clonk=2 + +[Player4] +Crew=Clonk=2 + +[Landscape] +Sky=Clouds1 +TopOpen=0 +BottomOpen=0 + +[Weather] +Climate=0 +YearSpeed=0 +Wind=0,50,-50,50 + diff --git a/planet/Worlds.ocf/RapidRefining.ocs/Script.c b/planet/Worlds.ocf/RapidRefining.ocs/Script.c new file mode 100644 index 000000000..d4cb8a75a --- /dev/null +++ b/planet/Worlds.ocf/RapidRefining.ocs/Script.c @@ -0,0 +1,207 @@ +/** + Rapid Refining + Use the oil from an underground well to power your settlement. + + @author Maikel +*/ + + +// Whether the intro has been initialized. +static intro_init; + +// Whether the first players has been initialized. +static first_plr_init; + +protected func Initialize() +{ + // Show wealth in HUD. + GUI_Controller->ShowWealth(); + + // Rules: team account and buying at flagpole. + CreateObject(Rule_TeamAccount); + CreateObject(Rule_BuyAtFlagpole); + + // Goal: pump oil into refinery drain. + var goal = CreateObject(Goal_Refinery); + var amount = 400; + if (SCENPAR_Difficulty == 2) + amount = 800; + else if (SCENPAR_Difficulty == 3) + amount = 1600; + goal->SetGoalAmount(amount); + + // Initialize different parts of the scenario. + InitEnvironment(SCENPAR_Difficulty); + InitVegetation(SCENPAR_MapSize); + InitAnimals(SCENPAR_MapSize, SCENPAR_Difficulty); + return; +} + +protected func OnGoalsFulfilled() +{ + // Give the remaining players their achievement. + GainScenarioAchievement("Done", BoundBy(SCENPAR_Difficulty, 1, 3)); + return false; +} + + +/*-- Player Initialization --*/ + +protected func InitializePlayer(int plr) +{ + // Harsh zoom range. + SetPlayerZoomByViewRange(plr, 400, nil, PLRZOOM_Direct | PLRZOOM_LimitMax); + SetPlayerViewLock(plr, true); + SetFoW(false, plr); + + // First player inits the base. + if (!first_plr_init) + { + InitBase(plr, 4 - SCENPAR_Difficulty); + first_plr_init = true; + // Give only the first joined player some wealth. + SetWealth(plr, 150 - 50 * SCENPAR_Difficulty); + } + + // Position and materials for the crew. + var crew; + for (var i = 0; crew = GetCrew(plr, i); ++i) + { + crew->SetPosition(20 + Random(32), 160 - 10); + crew->CreateContents(Shovel); + } + + // Give the player basic and pumping knowledge. + GivePlayerBasicKnowledge(plr); + GivePlayerPumpingKnowledge(plr); + GivePlayerWeaponryKnowledge(plr); + GivePlayerAdvancedKnowledge(plr); + GivePlayerFarmingKnowledge(plr); + RemovePlayerSpecificKnowledge(plr, [WindGenerator]); + + // Give the player the elementary base materials. + GivePlayerElementaryBaseMaterial(plr); + GivePlayerToolsBaseMaterial(plr); + + // Initialize the intro sequence if not yet started. + if (!intro_init) + { + //StartSequence("Intro", 0); + intro_init = true; + } + return; +} + +private func InitBase(int owner, int amount) +{ + var y = 160; + + // The basic settlement: flagpole, wind generator, chest. + CreateObjectAbove(Flagpole, 184, y, owner); + var chest = CreateObjectAbove(Chest, 202, y, owner); + chest->CreateContents(Hammer, 2); + chest->CreateContents(Axe, 2); + CreateObjectAbove(WindGenerator, 222, y, owner); + + // Two pumps connected to the refinery drain. + var refinery_exit = CreateObjectAbove(RefineryDrain, 8, y, owner); + var pump1 = CreateObjectAbove(Pump, 250, y, owner); + var pump2 = CreateObjectAbove(Pump, 284, y, owner); + var pipe1 = pump1->CreateObject(Pipe); + pipe1->ConnectPipeTo(pump1); + pipe1 = pump1->CreateObject(Pipe, 8); + pipe1->ConnectPipeTo(pump1); + pipe1->ConnectPipeTo(refinery_exit); + var pipe2 = pump2->CreateObject(Pipe, 8); + pipe2->ConnectPipeTo(pump2); + pipe2 = pump2->CreateObject(Pipe, -8); + pipe2->ConnectPipeTo(pump2); + + // Additional material in the chest. + if (amount >= 2) + { + chest->CreateContents(Wood, 12); + chest->CreateContents(Metal, 8); + chest->CreateContents(Dynamite, 4); + if (amount >= 3) + { + chest->CreateContents(Wood, 12); + chest->CreateContents(Metal, 8); + chest->CreateContents(Loam, 4); + chest->CreateContents(Pickaxe, 2); + chest->CreateContents(Bread, 4); + } + } + return; +} + + +/*-- Scenario Initialization --*/ + +private func InitEnvironment(int difficulty) +{ + // Sky has some parallax. + SetSkyParallax(1, 20, 20); + + // Some earthquakes if difficulty prescribes it. + if (difficulty >= 2) + Earthquake->SetChance(4 * (difficulty - 1)); + return; +} + +private func InitVegetation(int map_size) +{ + var wdt = LandscapeWidth(); + var hgt = LandscapeHeight(); + + // Some plants and trees on the outside. + Tree_Deciduous->Place(16, Shape->Rectangle(0, 0, 240, 160)); + Tree_Coniferous2->Place(2, Shape->Rectangle(0, 0, 240, 160)); + Cotton->Place(4, Shape->Rectangle(0, 0, 240, 160)); + SproutBerryBush->Place(2, Shape->Rectangle(0, 0, 240, 160)); + Grass->Place(100); + + // Some plants and in the caves. + LargeCaveMushroom->Place(40 + 6 * map_size, nil, {terraform = false}); + Fern->Place(40 + 6 * map_size); + Mushroom->Place(40 + 6 * map_size); + Branch->Place(20 + 3 * map_size); + + // Some objects in the earth. + PlaceObjects(Rock, 40 + 10 * map_size + Random(5),"Earth"); + PlaceObjects(Firestone, 40 + 10 * map_size + Random(5), "Earth"); + PlaceObjects(Loam, 40 + 10 * map_size + Random(5), "Earth"); + + // Underwater plants. + var place_rect = Shape->Rectangle(0, 2 * hgt / 3, wdt / 4, hgt / 3); + Seaweed->Place(12, place_rect); + Coral->Place(8, place_rect); + + // Place some diamonds in the hard to reach location. + Diamond->Place(20, Shape->Rectangle(5 * wdt / 6, 0, wdt / 6, hgt / 4)); + return; +} + +private func InitAnimals(int map_size, int difficulty) +{ + var wdt = LandscapeWidth(); + var hgt = LandscapeHeight(); + + // Some butterflies as atmosphere. + for (var i = 0; i < 8; i++) + PlaceAnimal(Butterfly); + + // Some wipfs underground. + Wipf->Place(10); + + // Place some fishes and piranhas as difficulty prescribes it. + var place_rect = Shape->Rectangle(0, 2 * hgt / 3, wdt / 4, hgt / 3); + var fish_count = 15; + Fish->Place(fish_count * (3 - difficulty), place_rect); + Piranha->Place(fish_count * (difficulty - 1), place_rect); + + // Bats on higher difficulty. + if (difficulty >= 2) + Bat->Place((difficulty - 1) * 12, Shape->Rectangle(2 * wdt / 3, 0, wdt / 3, hgt)); + return; +} diff --git a/planet/Worlds.ocf/RapidRefining.ocs/StringTblDE.txt b/planet/Worlds.ocf/RapidRefining.ocs/StringTblDE.txt new file mode 100644 index 000000000..bd0d3c937 --- /dev/null +++ b/planet/Worlds.ocf/RapidRefining.ocs/StringTblDE.txt @@ -0,0 +1,19 @@ +# Scenario parameters: difficulty +Difficulty=Schwierigkeit +DescDifficulty=Setzt die Schwierigkeit dieser Runde. +DiffNormal=Normal +DescDiffNormal=Die Schwierigkeit dieser Runde ist normal. +DiffHard=Schwer +DescDiffHard=Die Schwierigkeit dieser Runde ist schwer. +DiffInsane=Irrsinnig +DescDiffInsane=Die Schwierigkeit dieser Runde ist irrsinnig. + +# Scenario parameters: map size +MapSize=Kartengröße +DescMapSize=Setzt die Kartengröße dieser Runde. +MapSmall=Klein +DescMapSmall=Die Karte dieser Runde wird klein sein +MapAverage=Durchschnittlich +DescMapAverage=Die Karte dieser Runde wird durchschnittlich sein. +MapLarge=Groß +DescMapLarge=Die Karte dieser Runde wird groß sein. diff --git a/planet/Worlds.ocf/RapidRefining.ocs/StringTblUS.txt b/planet/Worlds.ocf/RapidRefining.ocs/StringTblUS.txt new file mode 100644 index 000000000..ec0653e17 --- /dev/null +++ b/planet/Worlds.ocf/RapidRefining.ocs/StringTblUS.txt @@ -0,0 +1,19 @@ +# Scenario parameters: difficulty +Difficulty=Difficulty +DescDifficulty=Sets this round's difficulty. +DiffNormal=Normal +DescDiffNormal=This round's difficulty will be set to normal. +DiffHard=Hard +DescDiffHard=This round's difficulty will be set to hard. +DiffInsane=Insane +DescDiffInsane=This round's difficulty will be set to insane. + +# Scenario parameters: map size +MapSize=Map size +DescMapSize=Sets this round's map size. +MapSmall=Small +DescMapSmall=This round's map will be small. +MapAverage=Average +DescMapAverage=This round's map will be average. +MapLarge=Large +DescMapLarge=This round's map will be large. diff --git a/planet/Worlds.ocf/RapidRefining.ocs/System.ocg/PipeLength.c b/planet/Worlds.ocf/RapidRefining.ocs/System.ocg/PipeLength.c new file mode 100644 index 000000000..dbf340872 --- /dev/null +++ b/planet/Worlds.ocf/RapidRefining.ocs/System.ocg/PipeLength.c @@ -0,0 +1,9 @@ +// Maximum pipe length depends on difficulty. + +#appendto PipeLine + +public func Definition(proplist def) +{ + def.PipeMaxLength = def.PipeMaxLength * (12 - 2 * SCENPAR_Difficulty) / 10; + return; +} diff --git a/planet/Worlds.ocf/RapidRefining.ocs/Title.jpg b/planet/Worlds.ocf/RapidRefining.ocs/Title.jpg new file mode 100644 index 0000000000000000000000000000000000000000..870f446e0fdd0fb074c515e0cee28ede7490b3c0 GIT binary patch literal 93197 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%0Ag1$Qo_c~vsH<9 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 ju4fiZr_2UbPwY literal 0 HcmV?d00001 diff --git a/planet/Worlds.ocf/RapidRefining.ocs/Title.txt b/planet/Worlds.ocf/RapidRefining.ocs/Title.txt new file mode 100644 index 000000000..cd783994a --- /dev/null +++ b/planet/Worlds.ocf/RapidRefining.ocs/Title.txt @@ -0,0 +1,2 @@ +DE:Rasches Raffinieren +US:Rapid Refining \ No newline at end of file From a9b1b975d393a7d8b64e7c7c6f67ea218673de04 Mon Sep 17 00:00:00 2001 From: David Dormagen Date: Sun, 7 Aug 2016 17:04:21 +0200 Subject: [PATCH 10/26] removed Libraries/Animal/CreatureControl (and thus the automatic script player) The script players was not treated correctly by the goals, so joining it automatically would break stuff. While I still like the implications of an automatic script player, it was too much of a hassle for now. Find_AnimalHostile works around the main issue as it allows just using Find_AnimalHostile and automatically have the animal work for both neutral owners and as pets. It does not allow for the distinction of hostile neutral and friendly neutral, though. --- .../Animals.ocd/Chippie.ocd/Egg.ocd/Script.c | 5 +- .../Animals.ocd/Chippie.ocd/Script.c | 6 +- .../Objects.ocd/Animals.ocd/Mooq.ocd/Script.c | 4 +- .../Objects.ocd/Animals.ocd/Puka.ocd/Script.c | 8 +- .../CreatureControl.ocd/DefCore.txt | 4 - .../Animal.ocd/CreatureControl.ocd/Script.c | 76 ------------------- planet/System.ocg/FindObject.c | 9 +++ 7 files changed, 16 insertions(+), 96 deletions(-) delete mode 100644 planet/Objects.ocd/Libraries.ocd/Animal.ocd/CreatureControl.ocd/DefCore.txt delete mode 100644 planet/Objects.ocd/Libraries.ocd/Animal.ocd/CreatureControl.ocd/Script.c diff --git a/planet/Objects.ocd/Animals.ocd/Chippie.ocd/Egg.ocd/Script.c b/planet/Objects.ocd/Animals.ocd/Chippie.ocd/Egg.ocd/Script.c index 2760dd766..e35d1e09e 100644 --- a/planet/Objects.ocd/Animals.ocd/Chippie.ocd/Egg.ocd/Script.c +++ b/planet/Objects.ocd/Animals.ocd/Chippie.ocd/Egg.ocd/Script.c @@ -17,7 +17,6 @@ public func Place(int amount, proplist area) var location = nil; if (area) location = Loc_InArea(area->GetBoundingRectangle()); - var owner = GetCreaturePlayer(); while(amount > 0) { var p = nil; @@ -33,9 +32,7 @@ public func Place(int amount, proplist area) // small circle for(var r = 0; (r < 360) && (amount > 0); r += 40+Random(40)) { - var o = CreateObject(Chippie_Egg, p.x + Sin(r, 10 + RandomX(-2, 2)), p.y - Cos(r, 10 + RandomX(-2, 2)), owner); - if(owner == nil) - o->SetCreatureControlled(); + var o = CreateObject(Chippie_Egg, p.x + Sin(r, 10 + RandomX(-2, 2)), p.y - Cos(r, 10 + RandomX(-2, 2)), NO_OWNER); o->SetCon(RandomX(90, 100)); --amount; } diff --git a/planet/Objects.ocd/Animals.ocd/Chippie.ocd/Script.c b/planet/Objects.ocd/Animals.ocd/Chippie.ocd/Script.c index c3dd28d4d..c2335a20e 100644 --- a/planet/Objects.ocd/Animals.ocd/Chippie.ocd/Script.c +++ b/planet/Objects.ocd/Animals.ocd/Chippie.ocd/Script.c @@ -15,8 +15,6 @@ public func Construction() { AddEffect("Activity", this, 1, 10, this); SetAction("Walk"); - if (GetOwner() == NO_OWNER) - SetCreatureControlled(); energy_sucked = 0; return true; } @@ -106,7 +104,7 @@ private func StartJump() private func FxJumpCheckTimer(target, effect, time) { - var e = FindObject(Find_AtPoint(), Find_OCF(OCF_Alive), Find_Hostile(GetOwner())); + var e = FindObject(Find_AtPoint(), Find_OCF(OCF_Alive), Find_AnimalHostile(GetOwner())); if(e) { ClawTo(e); @@ -191,7 +189,7 @@ private func FxActivityTimer(target, effect, time) if(!GetEffect("DmgShock", this) && !GBackSemiSolid()) { - for(var enemy in FindObjects(Find_Distance(100), Find_OCF(OCF_Alive), Find_Hostile(GetOwner()), Sort_Distance())) + for(var enemy in FindObjects(Find_Distance(100), Find_OCF(OCF_Alive), Find_AnimalHostile(GetOwner()), Sort_Distance())) { if(!PathFree(GetX(), GetY(), enemy->GetX(), enemy->GetY())) continue; diff --git a/planet/Objects.ocd/Animals.ocd/Mooq.ocd/Script.c b/planet/Objects.ocd/Animals.ocd/Mooq.ocd/Script.c index 4e81f3821..dd8e99333 100644 --- a/planet/Objects.ocd/Animals.ocd/Mooq.ocd/Script.c +++ b/planet/Objects.ocd/Animals.ocd/Mooq.ocd/Script.c @@ -62,8 +62,6 @@ func Construction() CheckTurn(GetDir()); SetTailOnFire(); - - SetCreatureControlled(); } func Death() @@ -508,7 +506,7 @@ func UpdateEnemy() var x = GetX(); var y = GetY(); - for (var obj in FindObjects(Find_Distance(200), Find_OCF(OCF_Alive), Find_Hostile(GetOwner()), Sort_Distance())) + for (var obj in FindObjects(Find_Distance(200), Find_OCF(OCF_Alive), Find_AnimalHostile(GetOwner()), Sort_Distance())) { if (!PathFree(x, y, obj->GetX(), obj->GetY())) continue; if (obj->GBackLiquid()) continue; diff --git a/planet/Objects.ocd/Animals.ocd/Puka.ocd/Script.c b/planet/Objects.ocd/Animals.ocd/Puka.ocd/Script.c index 5198090e1..51b7b42e4 100644 --- a/planet/Objects.ocd/Animals.ocd/Puka.ocd/Script.c +++ b/planet/Objects.ocd/Animals.ocd/Puka.ocd/Script.c @@ -71,8 +71,6 @@ public func Construction() if (Random(2)) SetDir(DIR_Left); else SetDir(DIR_Right); - SetCreatureControlled(); - // Two spot layouts are available. if (!Random(2)) SetMeshMaterial("Puka2"); @@ -348,7 +346,7 @@ private func UpdateEnemy() var x = GetX(); var y = GetY(); - for (var obj in FindObjects(Find_Distance(100), Find_OCF(OCF_Alive), Find_Hostile(GetOwner()), Sort_Distance())) + for (var obj in FindObjects(Find_Distance(100), Find_OCF(OCF_Alive), Find_AnimalHostile(GetOwner()), Sort_Distance())) { if (!PathFree(x, y, obj->GetX(), obj->GetY())) continue; enemy = obj; @@ -377,7 +375,7 @@ private func DoElectroCircle() }; // Punish all close enemies (not allied animals, though). - for (var obj in FindObjects(Find_Distance(30), Find_OCF(OCF_Alive), Find_Hostile(GetOwner()), Find_Exclude(this))) + for (var obj in FindObjects(Find_Distance(30), Find_OCF(OCF_Alive), Find_AnimalHostile(GetOwner()), Find_Exclude(this))) { var delta_x = 3 * (obj->GetX() - GetX()); var delta_y = 3 * (obj->GetY() - GetY()); @@ -645,7 +643,7 @@ private func EndShockWater() if (GetDir() == DIR_Right) x *= -1; var y = 15; - for (var obj in FindObjects(Find_Distance(120), Find_OCF(OCF_Alive), Find_Hostile(this->GetOwner()))) + for (var obj in FindObjects(Find_Distance(120), Find_OCF(OCF_Alive), Find_AnimalHostile(this->GetOwner()))) { if (!obj->GBackLiquid()) continue; var angle = Angle(GetX(), GetY(), obj->GetX(), obj->GetY()); diff --git a/planet/Objects.ocd/Libraries.ocd/Animal.ocd/CreatureControl.ocd/DefCore.txt b/planet/Objects.ocd/Libraries.ocd/Animal.ocd/CreatureControl.ocd/DefCore.txt deleted file mode 100644 index b4fc40814..000000000 --- a/planet/Objects.ocd/Libraries.ocd/Animal.ocd/CreatureControl.ocd/DefCore.txt +++ /dev/null @@ -1,4 +0,0 @@ -[DefCore] -id=Library_CreatureControl -Version=6,1 -Category=C4D_StaticBack diff --git a/planet/Objects.ocd/Libraries.ocd/Animal.ocd/CreatureControl.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/Animal.ocd/CreatureControl.ocd/Script.c deleted file mode 100644 index 4bf33369b..000000000 --- a/planet/Objects.ocd/Libraries.ocd/Animal.ocd/CreatureControl.ocd/Script.c +++ /dev/null @@ -1,76 +0,0 @@ -/** - AnimalControl - Cares about the ownership of non-player-controlled units. - They are hostile to every other player. - - global func GetCreaturePlayer() - global func SetAnimalControlled() -*/ - -static CreatureControl_animal_player; -static CreatureControl_yet_to_set; -static CreatureControl_initializing; - -private func Enqueue(obj) -{ - if(GetType(CreatureControl_yet_to_set) != C4V_Array) - CreatureControl_yet_to_set = []; - PushBack(CreatureControl_yet_to_set, obj); -} - -/** - Returns the hostile NPC player or creates it. - Returns nil when the NPC player is currently joining. -*/ -global func GetCreaturePlayer() -{ - if(CreatureControl_animal_player != nil) - return CreatureControl_animal_player; - if(CreatureControl_initializing == true) - return nil; - - CreatureControl_initializing = true; - CreateScriptPlayer("Creatures", RGB(50, 100, 50), 0, CSPF_NoScenarioInit | CSPF_NoEliminationCheck | CSPF_Invisible, Library_CreatureControl); - return nil; -} - -/** - Sets the owner of an object to the hostile NPC player. -*/ -global func SetCreatureControlled() -{ - if(!this) return false; - var o = GetCreaturePlayer(); - if(o != nil) return SetOwner(o); - - // No owner during creation. If the scripter overwrites it to a real owner, it's not changed later. - SetOwner(NO_OWNER); - Library_CreatureControl->Enqueue(this); -} - -public func InitializeScriptPlayer(plr, team) -{ - CreatureControl_animal_player = plr; - - if(CreatureControl_yet_to_set != nil) - { - for(var obj in CreatureControl_yet_to_set) - { - if (!obj) continue; - - // Overwritten by the scripter? - if (obj->GetOwner() != NO_OWNER) continue; - obj->SetOwner(CreatureControl_animal_player); - } - } - CreatureControl_yet_to_set = nil; - - // hostile! - for(var i = 0; i < GetPlayerCount(); ++i) - { - var p = GetPlayerByIndex(i); - if(p == CreatureControl_animal_player) continue; - SetHostility(p, plr, true, true, true); - SetHostility(plr, p, true, true, true); - } -} \ No newline at end of file diff --git a/planet/System.ocg/FindObject.c b/planet/System.ocg/FindObject.c index 4ebc4998d..66d6ed84c 100644 --- a/planet/System.ocg/FindObject.c +++ b/planet/System.ocg/FindObject.c @@ -137,6 +137,15 @@ global func Find_Hostile(int plr) return p; } +/* +Similar to Find_Hostile, but defaults to treating all players as hostile when plr = NO_OWNER. +*/ +global func Find_AnimalHostile(int plr) +{ + if (plr == NO_OWNER) return Find_Not(Find_Owner(NO_OWNER)); + return Find_Or(Find_Owner(NO_OWNER), Find_Hostile(plr)); +} + global func Find_Allied(int plr) { var p = [C4FO_Or]; From 51bab0b0b237ee8c8ef03ea01560796e0659b815 Mon Sep 17 00:00:00 2001 From: David Dormagen Date: Sun, 7 Aug 2016 17:26:36 +0200 Subject: [PATCH 11/26] renamed "Gaya" to "Gaia" This is necessary to not draw the attention of Zeus and find an end through a dramatic lightning strike. --- planet/Objects.ocd/Rules.ocd/Killlogs.ocd/Script.c | 2 +- planet/Objects.ocd/Rules.ocd/Killlogs.ocd/StringTblDE.txt | 6 +++--- planet/Objects.ocd/Rules.ocd/Killlogs.ocd/StringTblUS.txt | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/planet/Objects.ocd/Rules.ocd/Killlogs.ocd/Script.c b/planet/Objects.ocd/Rules.ocd/Killlogs.ocd/Script.c index ee0a6081b..25146f263 100644 --- a/planet/Objects.ocd/Rules.ocd/Killlogs.ocd/Script.c +++ b/planet/Objects.ocd/Rules.ocd/Killlogs.ocd/Script.c @@ -35,7 +35,7 @@ func OnClonkDeathEx(object clonk, int plr, int killed_by) var which_one = Random(3) + 1; var log=""; if (!GetPlayerName(killed_by)) - log=Format(Translate(Format("KilledByGaya%d", which_one)), GetTaggedPlayerName(plr), name); + log=Format(Translate(Format("KilledByGaia%d", which_one)), GetTaggedPlayerName(plr), name); else if (plr == killed_by) log=Format(Translate(Format("Selfkill%d", which_one)), GetTaggedPlayerName(plr), name); else if (!Hostile(plr,killed_by)) diff --git a/planet/Objects.ocd/Rules.ocd/Killlogs.ocd/StringTblDE.txt b/planet/Objects.ocd/Rules.ocd/Killlogs.ocd/StringTblDE.txt index 9789edc2d..d6e45a1f6 100644 --- a/planet/Objects.ocd/Rules.ocd/Killlogs.ocd/StringTblDE.txt +++ b/planet/Objects.ocd/Rules.ocd/Killlogs.ocd/StringTblDE.txt @@ -7,9 +7,9 @@ Selfkill3=%s hat Selbstmord begangen! Der arme %s. KilledByPlayer1=%s hat einen %s an %s verloren. KilledByPlayer2=%ss %s konnte nichts gegen %s machen. KilledByPlayer3=%s konnte mit seinem %s nicht gut genug kämpfen für %s. -KilledByGaya1=%s hat einen %s weggezaubert bekommen. -KilledByGaya2=%ss %s stirbt von alleine. -KilledByGaya3=%s hat einen %s an Gaya verloren. +KilledByGaia1=%s hat einen %s weggezaubert bekommen. +KilledByGaia2=%ss %s stirbt von alleine. +KilledByGaia3=%s hat einen %s an Gaia verloren. Teamkill1=%s hat einen %s an %s verloren. Teamkiller! Teamkill2=%ss %s ist bei %s in Ungnade gefallen. Teamkill3=%ss %s wurde von %s sauber hintergangen. diff --git a/planet/Objects.ocd/Rules.ocd/Killlogs.ocd/StringTblUS.txt b/planet/Objects.ocd/Rules.ocd/Killlogs.ocd/StringTblUS.txt index 97b7075c5..683683392 100644 --- a/planet/Objects.ocd/Rules.ocd/Killlogs.ocd/StringTblUS.txt +++ b/planet/Objects.ocd/Rules.ocd/Killlogs.ocd/StringTblUS.txt @@ -7,9 +7,9 @@ Selfkill3=%s committed suicide! Poor %s. KilledByPlayer1=%s has lost his %s to %s. KilledByPlayer2=%s's %s couldn't do anything against %s. KilledByPlayer3=%s's %s was not able to defeat %s. -KilledByGaya1=%s's %s was spirited away. -KilledByGaya2=%s's %s died on its own. -KilledByGaya3=%s lost a %s to Gaya. +KilledByGaia1=%s's %s was spirited away. +KilledByGaia2=%s's %s died on its own. +KilledByGaia3=%s lost a %s to Gaia. Teamkill1=%s has lost a %s to %s. Teamkiller! Teamkill2=%s's %s fell out of %s's favour. Teamkill3=%s's %s was denied by %s. From a9a2ffd95ccf134b56ad2beb86ee807f5836c6f6 Mon Sep 17 00:00:00 2001 From: Maikel de Vries Date: Sun, 7 Aug 2016 17:27:17 +0200 Subject: [PATCH 12/26] rapid refining: add waterfall as additional power source --- planet/Worlds.ocf/RapidRefining.ocs/Map.c | 15 ++++++++++++++- planet/Worlds.ocf/RapidRefining.ocs/Script.c | 16 ++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/planet/Worlds.ocf/RapidRefining.ocs/Map.c b/planet/Worlds.ocf/RapidRefining.ocs/Map.c index bdf252d63..9c0d024cb 100644 --- a/planet/Worlds.ocf/RapidRefining.ocs/Map.c +++ b/planet/Worlds.ocf/RapidRefining.ocs/Map.c @@ -62,7 +62,7 @@ protected func InitializeMap(proplist map) var wdt = 3; var underground_border = {Algo = MAPALGO_Not, Op = {Algo = MAPALGO_Rect, X = wdt, Y = wdt, Wdt = map.Wdt - 2 * wdt, Hgt = map.Hgt - 2 * wdt}}; underground_border = {Algo = MAPALGO_And, Op = [underground_border, underground]}; - underground_border = {Algo = MAPALGO_Or, Op = [underground_border, {Algo = MAPALGO_Turbulence, Iterations = 4, Amplitude = 16, Scale = 12, Seed = Random(65536), Op = underground_border}]}; + underground_border = {Algo = MAPALGO_Or, Op = [underground_border, {Algo = MAPALGO_Turbulence, Iterations = 6, Amplitude = 12, Scale = 16, Seed = Random(65536), Op = underground_border}]}; underground_border = {Algo = MAPALGO_And, Op = [underground_border, underground, {Algo = MAPALGO_Not, Op = entrance_floor}]}; DrawRock(underground_border); @@ -139,9 +139,16 @@ public func DrawWaterLake(proplist map, proplist underground_border) { var lake_height = 20; var lake_width = 80; + var waterfall_height = 62; var tunnel_height = 6; + // Draw a large lake with tunnel above. underground_border = {Algo = MAPALGO_And, Op = [underground_border, {Algo = MAPALGO_Not, Op = {Algo = MAPALGO_Rect, X = 0, Y = map.Hgt - lake_height - 2, Wdt = lake_width, Hgt = 6}}]}; + var lake_floor_rock = {Algo = MAPALGO_And, Op = [{Algo = MAPALGO_Lines, X = 3, Y = 0, Distance = 10}, {Algo = MAPALGO_Rect, X = 0, Y = map.Hgt - 7, Wdt = lake_width, Hgt = 7}]}; + var lake_floor_rock = {Algo = MAPALGO_Turbulence, Iterations = 4, Amplitude = 16, Scale = 8, Seed = Random(65536), Op = lake_floor_rock}; + underground_border = {Algo = MAPALGO_Or, Op = [underground_border, lake_floor_rock]}; + DrawRock(lake_floor_rock); + var tunnel = {Algo = MAPALGO_Rect, X = 0, Y = map.Hgt - lake_height - tunnel_height, Wdt = lake_width, Hgt = tunnel_height}; tunnel = {Algo = MAPALGO_Or, Op = [tunnel, {Algo = MAPALGO_Turbulence, Iterations = 4, Amplitude = 16, Scale = 8, Seed = Random(65536), Op = tunnel}]}; @@ -160,6 +167,12 @@ public func DrawWaterLake(proplist map, proplist underground_border) Draw("Everrock", lake_boundary); var lake_boundary_rock = {Algo = MAPALGO_Border, Wdt = -2, Op = lake_boundary}; DrawRock(lake_boundary_rock); + + // Draw a waterfall pooring into the lake. + var waterfall = {Algo = MAPALGO_Rect, X = 3, Y = map.Hgt - lake_height - waterfall_height, Wdt = 9, Hgt = waterfall_height}; + waterfall = {Algo = MAPALGO_Or, Op = [waterfall, {Algo = MAPALGO_Turbulence, Iterations = 3, Amplitude = 12, Scale = 12, Seed = Random(65536), Op = waterfall}]}; + waterfall = {Algo = MAPALGO_And, Op = [waterfall, {Algo = MAPALGO_Not, Op = underground_border}, {Algo = MAPALGO_Not, Op = lake}]}; + Draw("Tunnel", waterfall); return; } diff --git a/planet/Worlds.ocf/RapidRefining.ocs/Script.c b/planet/Worlds.ocf/RapidRefining.ocs/Script.c index d4cb8a75a..d1fa12ee2 100644 --- a/planet/Worlds.ocf/RapidRefining.ocs/Script.c +++ b/planet/Worlds.ocf/RapidRefining.ocs/Script.c @@ -146,6 +146,22 @@ private func InitEnvironment(int difficulty) // Some earthquakes if difficulty prescribes it. if (difficulty >= 2) Earthquake->SetChance(4 * (difficulty - 1)); + + // A waterfall above the underground lake. + var waterfall_x = 50; + var waterfall_y = LandscapeHeight() - 600; + var trunk = CreateObjectAbove(Trunk, waterfall_x, waterfall_y); + trunk->DoCon(30); trunk->SetR(150); trunk.Plane = 510; + trunk.MeshTransformation = [-70, 0, 998, 0, 0, 1000, 0, 0, -998, 0, -70, 0]; + trunk->MakeInvincible(); + + var waterfall = CreateWaterfall(waterfall_x + 22, waterfall_y - 10, 10, "Water"); + waterfall->SetDirection(2, 0, 3, 6); + waterfall->SetSoundLocation(waterfall_x + 40, waterfall_y + 240); + + CreateLiquidDrain(8, 1040, 10); + CreateLiquidDrain(16, 1040, 10); + CreateLiquidDrain(24, 1040, 10); return; } From 231a0ba9b40c1f6be3f50ffef91f1408e60456f4 Mon Sep 17 00:00:00 2001 From: Sven Eberhardt Date: Sun, 7 Aug 2016 10:48:54 -0400 Subject: [PATCH 13/26] Send mouse coordinates directly with control if SendCursorPos is true --- src/control/C4PlayerControl.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/control/C4PlayerControl.cpp b/src/control/C4PlayerControl.cpp index 675333564..d8a061c8d 100644 --- a/src/control/C4PlayerControl.cpp +++ b/src/control/C4PlayerControl.cpp @@ -1025,6 +1025,7 @@ bool C4PlayerControl::ProcessKeyEvent(const C4KeyCodeEx &pressed_key, const C4Ke assert(pControlSet); // shouldn't get this callback for players without control set pControlSet->GetAssignmentsByKey(ControlDefs, matched_key, state != CONS_Down, &Matches, DownKeys, RecentKeys); // process async controls + bool cursor_pos_added = false; C4ControlPlayerControl *pControlPacket = NULL; for (C4PlayerControlAssignmentPVec::const_iterator i = Matches.begin(); i != Matches.end(); ++i) { @@ -1055,7 +1056,21 @@ bool C4PlayerControl::ProcessKeyEvent(const C4KeyCodeEx &pressed_key, const C4Ke if (reset_down_states_only) extra_trigger_mode |= C4PlayerControlAssignment::CTM_HandleDownStatesOnly; pControlPacket->AddControl(iControlIndex, pAssignment->GetTriggerMode() | extra_trigger_mode); // sync cursor pos request; pos will be added to control before it is synced/executed - if (pControlDef->IsSendCursorPos()) IsCursorPosRequested = true; + if (pControlDef->IsSendCursorPos() && !cursor_pos_added) + { + int32_t x, y, game_x, game_y; + // Add current cursor pos in GUI and game coordinates to input + if (GetCurrentPlayerCursorPos(&x, &y, &game_x, &game_y)) + { + C4KeyEventData cursor_key_data(rKeyExtraData); + cursor_key_data.vp_x = x; cursor_key_data.vp_y = y; + cursor_key_data.game_x = game_x; cursor_key_data.game_y = game_y; + pControlPacket->SetExtraData(cursor_key_data); + } + // Will also send a CON_CursorPos packet separately + IsCursorPosRequested = true; + cursor_pos_added = true; + } } } } From eafa2e9305e3ad3140e95bc0d63cc152ccc49b66 Mon Sep 17 00:00:00 2001 From: Sven Eberhardt Date: Sun, 7 Aug 2016 11:08:42 -0400 Subject: [PATCH 14/26] Fix game coordinates for keyboard controls that request a cursor pos --- src/control/C4PlayerControl.cpp | 4 +++- src/gui/C4MouseControl.cpp | 5 +++-- src/gui/C4MouseControl.h | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/control/C4PlayerControl.cpp b/src/control/C4PlayerControl.cpp index d8a061c8d..cbb2364da 100644 --- a/src/control/C4PlayerControl.cpp +++ b/src/control/C4PlayerControl.cpp @@ -1459,8 +1459,10 @@ bool C4PlayerControl::GetCurrentPlayerCursorPos(int32_t *x_out, int32_t *y_out, // prefer mouse position if this is a mouse control if (pControlSet && pControlSet->HasMouse()) { - if (MouseControl.GetLastGUIPos(x_out, y_out)) + if (MouseControl.GetLastCursorPos(x_out, y_out, game_x_out, game_y_out)) + { return true; + } // if getting the mouse position failed, better fall back to cursor pos } // no mouse position known. Use cursor. diff --git a/src/gui/C4MouseControl.cpp b/src/gui/C4MouseControl.cpp index 1a855e326..9c8f64fc7 100644 --- a/src/gui/C4MouseControl.cpp +++ b/src/gui/C4MouseControl.cpp @@ -884,11 +884,12 @@ bool C4MouseControl::IsDragging() return Active && Drag == C4MC_Drag_Script; } -bool C4MouseControl::GetLastGUIPos(int32_t *x_out, int32_t *y_out) const +bool C4MouseControl::GetLastCursorPos(int32_t *x_out_gui, int32_t *y_out_gui, int32_t *x_out_game, int32_t *y_out_game) const { // safety if (!Active || !fMouseOwned) return false; // OK; assign last known pos - *x_out = GuiX; *y_out = GuiY; + *x_out_gui = GuiX; *y_out_gui = GuiY; + *x_out_game = GameX; *y_out_game = GameY; return true; } diff --git a/src/gui/C4MouseControl.h b/src/gui/C4MouseControl.h index e4dba30ca..143166e5c 100644 --- a/src/gui/C4MouseControl.h +++ b/src/gui/C4MouseControl.h @@ -113,7 +113,7 @@ public: void SetOwnedMouse(bool fToVal) { fMouseOwned = fToVal; } bool IsMouseOwned() { return fMouseOwned; } bool IsActive() { return !!Active; } - bool GetLastGUIPos(int32_t *x_out, int32_t *y_out) const; + bool GetLastCursorPos(int32_t *x_out_gui, int32_t *y_out_gui, int32_t *x_out_game, int32_t *y_out_game) const; const char *GetCaption(); void SetTooltipText(const StdStrBuf &text); From df098d2840eddb8fe5ab1392c1728ce82502c666 Mon Sep 17 00:00:00 2001 From: Maikel de Vries Date: Sun, 7 Aug 2016 21:26:15 +0200 Subject: [PATCH 15/26] pump only activates when drain is free or accepts liquid --- .../Items.ocd/Tools.ocd/Pipe.ocd/Script.c | 5 +- .../LiquidContainer.ocd/Script.c | 5 ++ .../Structures.ocd/Pump.ocd/Script.c | 50 +++++++++++-------- 3 files changed, 38 insertions(+), 22 deletions(-) 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 c9480ecb4..89eed571e 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 @@ -101,11 +101,14 @@ public func CanBeStackedWith(object other) return inherited(other) && (PipeState == other.PipeState); } + /** The pump calls this function to prevent clogging of the intake. Cycles through several aperture offset indices. */ -func CycleApertureOffset() +public func HasAperture() { return true; } + +public func CycleApertureOffset() { // Cycle in three steps of three px each through X and Y // covering a 3x3 grid on points -3,0,+3 diff --git a/planet/Objects.ocd/Libraries.ocd/LiquidControl.ocd/LiquidContainer.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/LiquidControl.ocd/LiquidContainer.ocd/Script.c index 63b1d7ddd..b0815c9d1 100644 --- a/planet/Objects.ocd/Libraries.ocd/LiquidControl.ocd/LiquidContainer.ocd/Script.c +++ b/planet/Objects.ocd/Libraries.ocd/LiquidControl.ocd/LiquidContainer.ocd/Script.c @@ -125,6 +125,11 @@ func PutLiquid(liquid_name, int amount, object source) return after - before; } +func AcceptsLiquid(liquid_name, int amount) +{ + return amount <= this->GetLiquidContainerMaxFillLevel() - GetLiquidAmount(liquid_name); +} + private func GetLiquidDef(liquid_name) { if (GetType(liquid_name) == C4V_String) diff --git a/planet/Objects.ocd/Structures.ocd/Pump.ocd/Script.c b/planet/Objects.ocd/Structures.ocd/Pump.ocd/Script.c index 86a66590e..3adc79e43 100644 --- a/planet/Objects.ocd/Structures.ocd/Pump.ocd/Script.c +++ b/planet/Objects.ocd/Structures.ocd/Pump.ocd/Script.c @@ -326,7 +326,6 @@ protected func Pumping() break; } } - stored_material_amount = i; if (stored_material_amount <= 0) stored_material_name = nil; @@ -338,8 +337,8 @@ protected func Pumping() } else { - // Put into wait state if no liquid could be pumped for a while - if (++clog_count >= max_clog_count) + // Put into wait state if no liquid could be pumped for a while or if the drain has no aperture, i.e. is a liquid tank. + if (++clog_count >= max_clog_count || !drain_obj->~HasAperture()) { SetState("WaitForLiquid"); } @@ -383,7 +382,6 @@ func InsertMaterialAtDrain(object drain_obj, string material_name, int amount) drain_obj->InsertMaterial(material_index, drain_obj.ApertureOffsetX, drain_obj.ApertureOffsetY); } } - return amount <= 0; } @@ -403,9 +401,10 @@ func CheckState() } else { - // can pump but has no liquid -> wait for liquid - var source_ok = IsLiquidSourceOk(); - var drain_ok = IsLiquidDrainOk(); + // Can pump but has no liquid or can't dispense liquid -> wait. + var source_mat = GetLiquidSourceMaterial(); + var source_ok = source_mat != nil; + var drain_ok = GetLiquidDrainOk(source_mat); if (!source_ok || !drain_ok) { if (!source_ok) @@ -532,30 +531,39 @@ private func PumpHeight2Power(int pump_height) return used_power; } -// TODO: check usage of this, probably has to return true if the source is a container // Returns whether there is liquid at the source pipe to pump. -private func IsLiquidSourceOk() +private func GetLiquidSourceMaterial() { - // source + // Get the source object and check whether there is liquid. + // TODO: If the source is a liquid container check which material will be supplied. var source_obj = GetSourceObject(); - if(!source_obj->GBackLiquid(source_obj.ApertureOffsetX, source_obj.ApertureOffsetY)) + var is_liquid = source_obj->GBackLiquid(source_obj.ApertureOffsetX, source_obj.ApertureOffsetY); + var liquid = MaterialName(source_obj->GetMaterial(source_obj.ApertureOffsetX, source_obj.ApertureOffsetY)); + if (!is_liquid) { - source_obj->~CycleApertureOffset(this); // try different offsets, so we can resume pumping after clog because 1px of earth was dropped on the source pipe - return false; + // Try different offsets, so we can resume pumping after clog because 1px of earth was dropped on the source pipe. + source_obj->~CycleApertureOffset(this); + return; } - return true; + return liquid; } -// TODO: check usage of this, probably has to return true if the drain is a container -// Returns whether the drain pipe is free. -private func IsLiquidDrainOk() +// Returns whether the drain pipe is free or the liquid container accepts the given material. +private func GetLiquidDrainOk(string liquid) { - // target (test with the very popular liquid "water") var drain_obj = GetDrainObject(); - if(!drain_obj->CanInsertMaterial(Material("Water"),drain_obj.ApertureOffsetX, drain_obj.ApertureOffsetY)) + if (drain_obj->~HasAperture()) { - drain_obj->~CycleApertureOffset(this); // try different offsets, so we can resume pumping after clog because 1px of earth was dropped on the source pipe - return false; + if (!drain_obj->CanInsertMaterial(Material(liquid), drain_obj.ApertureOffsetX, drain_obj.ApertureOffsetY)) + { + drain_obj->~CycleApertureOffset(this); // try different offsets, so we can resume pumping after clog because 1px of earth was dropped on the source pipe + return false; + } + } + else if (drain_obj->~IsLiquidContainer()) + { + if (!drain_obj->AcceptsLiquid(liquid, 1)) + return false; } return true; } From 700d5c199f052b50745834ecb3616fb46626e3b2 Mon Sep 17 00:00:00 2001 From: Maikel de Vries Date: Mon, 8 Aug 2016 16:54:28 +0200 Subject: [PATCH 16/26] rapid refining: fix pumping into refinery drain --- .../Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/Script.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/planet/Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/Script.c b/planet/Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/Script.c index ad666f299..3d66d1bf2 100644 --- a/planet/Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/Script.c +++ b/planet/Worlds.ocf/RapidRefining.ocs/RefineryDrain.ocd/Script.c @@ -12,6 +12,11 @@ /*-- Pipeline --*/ +public func GetLiquidContainerMaxFillLevel() +{ + return 10**9; +} + public func IsLiquidContainerForMaterial(string liquid) { return WildcardMatch("Oil", liquid); From e5d90c90c6f7bef56751e3a9698e9c5c352dccca Mon Sep 17 00:00:00 2001 From: Clonkonaut Date: Mon, 8 Aug 2016 18:25:15 +0200 Subject: [PATCH 17/26] HotIce: Balloon spawn added for extra fairness. --- planet/Arena.ocf/HotIce.ocs/Map.c | 3 ++ planet/Arena.ocf/HotIce.ocs/ParameterDefs.txt | 18 +++++++ planet/Arena.ocf/HotIce.ocs/Script.c | 49 ++++++++++++++----- planet/Arena.ocf/HotIce.ocs/StringTblDE.txt | 6 +++ planet/Arena.ocf/HotIce.ocs/StringTblUS.txt | 14 ++++-- 5 files changed, 75 insertions(+), 15 deletions(-) diff --git a/planet/Arena.ocf/HotIce.ocs/Map.c b/planet/Arena.ocf/HotIce.ocs/Map.c index 70c5533ce..837a208f5 100644 --- a/planet/Arena.ocf/HotIce.ocs/Map.c +++ b/planet/Arena.ocf/HotIce.ocs/Map.c @@ -77,6 +77,9 @@ func DrawSmallIslandsMap(proplist map) if (Abs(x-w/2) < w/10) szx += Random(3); // central islands sometimes wider map->Draw("^Ice-ice2", nil, [x-szx,y,1+2*szx,szy]); } + // Balloon spawn: do nothing further + if (SCENPAR_SpawnType == 1) + return true; // Starting islands for player spawns var spawn_island_count = Max(GetStartupPlayerCount(), 2); g_player_spawn_positions = CreateArray(spawn_island_count); diff --git a/planet/Arena.ocf/HotIce.ocs/ParameterDefs.txt b/planet/Arena.ocf/HotIce.ocs/ParameterDefs.txt index 0b0258015..ed18f2980 100644 --- a/planet/Arena.ocf/HotIce.ocs/ParameterDefs.txt +++ b/planet/Arena.ocf/HotIce.ocs/ParameterDefs.txt @@ -34,6 +34,24 @@ Default=1 Description=$DescWeaponsExplosive$ Value=1 +[ParameterDef] +Name=$SpawnType$ +Description=$DescSpawn$ +ID=SpawnType +Default=1 + + [Options] + + [Option] + Name=$ClassicSpawn$ + Description=$DescClassicSpawn$ + Value=0 + + [Option] + Name=$BalloonSpawn$ + Description=$DescBalloonSpawn$ + Value=1 + [ParameterDef] Name=$Rounds$ Description=$DescRounds$ diff --git a/planet/Arena.ocf/HotIce.ocs/Script.c b/planet/Arena.ocf/HotIce.ocs/Script.c index a52397dc2..26e6bb980 100644 --- a/planet/Arena.ocf/HotIce.ocs/Script.c +++ b/planet/Arena.ocf/HotIce.ocs/Script.c @@ -60,7 +60,8 @@ func InitializeRound() // Checking for victory: Only active after a Clonk dies. g_check_victory_effect = AddEffect("CheckVictory", nil, 1, 0); g_player_spawn_index = 0; - ShuffleArray(g_player_spawn_positions); + if (GetType(g_player_spawn_positions) == C4V_Array) + ShuffleArray(g_player_spawn_positions); // Materials: Chests var i,pos; @@ -136,20 +137,34 @@ func InitPlayerRound(int plr) var ls_wdt = LandscapeWidth(), ls_hgt = LandscapeHeight(); var crew = GetCrew(plr), start_pos; // Position by map type? - if (g_player_spawn_positions && g_player_spawn_index < GetLength(g_player_spawn_positions)) + if (SCENPAR_SpawnType == 0) { - start_pos = g_player_spawn_positions[g_player_spawn_index++]; - var map_zoom = ls_wdt / g_map_width; - start_pos = {x=start_pos[0]*map_zoom+map_zoom/2, y=start_pos[1]*map_zoom}; + if (g_player_spawn_positions && g_player_spawn_index < GetLength(g_player_spawn_positions)) + { + start_pos = g_player_spawn_positions[g_player_spawn_index++]; + var map_zoom = ls_wdt / g_map_width; + start_pos = {x=start_pos[0]*map_zoom+map_zoom/2, y=start_pos[1]*map_zoom}; + } + else + { + // Start positions not defined or exhausted: Spawn in lower area for both maps becuase starting high is an an advantage. + start_pos = FindLocation(Loc_InRect(ls_wdt/5,ls_hgt/2,ls_wdt*3/5,ls_hgt/3), Loc_Wall(CNAT_Bottom), Loc_Func(Scenario.IsStartSpot)); + if (!start_pos) start_pos = FindLocation(Loc_InRect(ls_wdt/10,0,ls_wdt*8/10,ls_hgt*4/5), Loc_Wall(CNAT_Bottom), Loc_Func(Scenario.IsStartSpot)); + if (!start_pos) start_pos = {x=Random(ls_wdt*6/10)+ls_wdt*2/10, y=ls_hgt*58/100}; + } + crew->SetPosition(start_pos.x, start_pos.y-10); } - else + else // Balloon spawn { - // Start positions not defined or exhausted: Spawn in lower area for both maps becuase starting high is an an advantage. - start_pos = FindLocation(Loc_InRect(ls_wdt/5,ls_hgt/2,ls_wdt*3/5,ls_hgt/3), Loc_Wall(CNAT_Bottom), Loc_Func(Scenario.IsStartSpot)); - if (!start_pos) start_pos = FindLocation(Loc_InRect(ls_wdt/10,0,ls_wdt*8/10,ls_hgt*4/5), Loc_Wall(CNAT_Bottom), Loc_Func(Scenario.IsStartSpot)); - if (!start_pos) start_pos = {x=Random(ls_wdt*6/10)+ls_wdt*2/10, y=ls_hgt*58/100}; + var spawn_x = ls_wdt/3, spawn_y = 10; + spawn_x += Random(spawn_x); + var balloon = CreateObject(BalloonDeployed, spawn_x, spawn_y - 16, plr); + crew->SetPosition(spawn_x, spawn_y); + balloon->SetRider(crew); + crew->SetAction("Ride", balloon); + balloon->SetSpeed(0,0); + crew->SetSpeed(0,0); } - crew->SetPosition(start_pos.x, start_pos.y-10); // initial material if (SCENPAR_Weapons == 0) { @@ -181,9 +196,19 @@ func InitPlayerRound(int plr) // Disable the Clonk during the countdown. crew->SetCrewEnabled(false); crew->SetComDir(COMD_Stop); + + if (SCENPAR_SpawnType == 1 && balloon) + balloon->CreateEffect(IntNoGravity, 1, 1); + return true; } +local IntNoGravity = new Effect { + Timer = func() { + Target->SetSpeed(0,0); + } +}; + // Called by the round start countdown. func OnCountdownFinished() { @@ -192,6 +217,8 @@ func OnCountdownFinished() { clonk->SetCrewEnabled(true); SetCursor(clonk->GetOwner(), clonk); + if (SCENPAR_SpawnType == 1 && clonk->GetActionTarget()) + RemoveEffect("IntNoGravity", clonk->GetActionTarget()); } } diff --git a/planet/Arena.ocf/HotIce.ocs/StringTblDE.txt b/planet/Arena.ocf/HotIce.ocs/StringTblDE.txt index e1deac73b..fc3d3b0f6 100644 --- a/planet/Arena.ocf/HotIce.ocs/StringTblDE.txt +++ b/planet/Arena.ocf/HotIce.ocs/StringTblDE.txt @@ -10,6 +10,12 @@ WeaponsClassic=Klassisch DescWeaponsClassic=Bögen, Speere, Keulen und einige Feuersteine WeaponsExplosive=Explosiv DescWeaponsExplosive=Nur Granatwerfer mit Endlosmunition +SpawnType=Startpunkte +DescSpawn=Legt fest, wo die Clonks der Spieler starten. +ClassicSpawn=Klassisch +DescClassicSpawn=Die Clonks starten auf den Eisinseln. +BalloonSpawn=Ballons +DescBalloonSpawn=Die Clonks fallen mit Ballons vom Himmel. Rounds=Rundenzahl DescRounds=Mehrere Runden spielen Stalemate=Unentschieden! diff --git a/planet/Arena.ocf/HotIce.ocs/StringTblUS.txt b/planet/Arena.ocf/HotIce.ocs/StringTblUS.txt index 8b8692c38..6871e53d1 100644 --- a/planet/Arena.ocf/HotIce.ocs/StringTblUS.txt +++ b/planet/Arena.ocf/HotIce.ocs/StringTblUS.txt @@ -5,13 +5,19 @@ DescMapTypeBigIsland=One central main island with small spots of ice in the air MapTypeSpots=Small islands DescMapTypeSpots=Many small spots of ice in the air. Weapons=Weapons -DescWeapons=Defines which weapons are available for players +DescWeapons=Defines which weapons are available for players. WeaponsClassic=Classic -DescWeaponsClassic=Bows, spears and clubs available in chests +DescWeaponsClassic=Bows, spears and clubs available in chests. WeaponsExplosive=Explosive -DescWeaponsExplosive=Only grenade lauchers and wind bags available +DescWeaponsExplosive=Only grenade lauchers and wind bags available. +SpawnType=Spawn points +DescSpawn=Defines where the starting positions will be. +ClassicSpawn=Classic +DescClassicSpawn=All clonks start on the ice islands. +BalloonSpawn=Balloons +DescBalloonSpawn=The clonks will drop with balloons from the sky. Rounds=Number of rounds -DescRounds=Play for multiple rounds +DescRounds=Play for multiple rounds. Stalemate=Stalemate! WinningTeam=Winning team: %s RemainingRounds=%d rounds remaining. From daf45a17f5c06fb44d916a6c8604dce655a1120b Mon Sep 17 00:00:00 2001 From: Maikel de Vries Date: Mon, 8 Aug 2016 23:04:15 +0200 Subject: [PATCH 18/26] fix boiling lava name --- .../Disasters.ocd/BoilingLava.ocd/StringTblUS.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/planet/Objects.ocd/Environment.ocd/Disasters.ocd/BoilingLava.ocd/StringTblUS.txt b/planet/Objects.ocd/Environment.ocd/Disasters.ocd/BoilingLava.ocd/StringTblUS.txt index eab9a8282..7762cb1a5 100644 --- a/planet/Objects.ocd/Environment.ocd/Disasters.ocd/BoilingLava.ocd/StringTblUS.txt +++ b/planet/Objects.ocd/Environment.ocd/Disasters.ocd/BoilingLava.ocd/StringTblUS.txt @@ -1,2 +1,2 @@ -Name=Boiling Laval +Name=Boiling Lava Description=Causes Lava on the map to boil From 07ea0fe438c43ef29c85d018ff78bf71a5c52bf3 Mon Sep 17 00:00:00 2001 From: Clonkonaut Date: Tue, 9 Aug 2016 23:44:14 +0200 Subject: [PATCH 19/26] Dynamite Box is now a container holding 5 sticks of dynamite. Can be taken out separately (and put back in). --- .../Items.ocd/Tools.ocd/Dynamite.ocd/Script.c | 185 ++++++++++-------- .../DynamiteBox.ocd/Igniter.ocd/Script.c | 16 +- .../Tools.ocd/DynamiteBox.ocd/Script.c | 135 +++++++++---- 3 files changed, 220 insertions(+), 116 deletions(-) diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/Dynamite.ocd/Script.c b/planet/Objects.ocd/Items.ocd/Tools.ocd/Dynamite.ocd/Script.c index 5659d7dd5..71654eeb5 100644 --- a/planet/Objects.ocd/Items.ocd/Tools.ocd/Dynamite.ocd/Script.c +++ b/planet/Objects.ocd/Items.ocd/Tools.ocd/Dynamite.ocd/Script.c @@ -1,13 +1,91 @@ /** Dynamite - A volatile tool that can be pressed into wallsfor accurate - mining, burning a short fuse before exploding. - - @author Newton + A volatile tool that can be pressed into wallsfor accurate mining, burning a short fuse before exploding. + + @author: Newton */ -// time in frames until explosion -func FuseTime() { return 140; } +/*-- Engine Callbacks --*/ + +func Hit() +{ + Sound("Hits::GeneralHit?"); +} + +func Incineration(int caused_by) +{ + Extinguish(); + Fuse(); + SetController(caused_by); +} + +func RejectEntrance() +{ + return GetAction() == "Ready"; +} + +/*-- Callbacks --*/ + +public func OnCannonShot(object cannon) +{ + Fuse(); +} + +// Drop fusing dynamite on death to prevent explosion directly after respawn +public func IsDroppedOnDeath(object clonk) +{ + return (GetAction() == "Fuse"); +} + +public func IsFusing() +{ + return GetAction() == "Fuse"; +} + +// Called by the Dynamite box +public func SetReady() +{ + SetAction("Ready"); +} +// Called by the Dynamite box +public func SetFuse() +{ + SetAction("Fuse"); + // Object can't be collected anymore when it fuses. + this.Collectible = false; +} + +public func Reset() +{ + SetAction("Idle"); + // Object can be collected again. + this.Collectible = true; +} + +public func OnFuseFinished(object fuse) +{ + SetController(fuse->GetController()); + DoExplode(); +} + +// This will only when inside a dynamite box to display the remaining dynamite sticks in the HUD +public func GetStackCount() +{ + if (Contained()) + if (Contained()->GetID() == DynamiteBox) + { + return Contained()->ContentsCount(GetID()); + } +} + +public func IsInfiniteStackCount() +{ + return false; +} + +public func IsGrenadeLauncherAmmo() { return true; } + +/*-- Usage --*/ public func ControlUse(object clonk, int x, int y, bool box) { @@ -52,7 +130,25 @@ public func ControlUse(object clonk, int x, int y, bool box) return false; } -private func Place(object clonk, int x, int y, bool box) +public func Fuse() +{ + if (GetAction() != "Fuse") + { + if (!FindObject(Find_Category(C4D_StaticBack), Find_Func("IsFuse"), Find_ActionTargets(this))) + Sound("Fire::Fuse"); + SetAction("Fuse"); + // Object can't be collected anymore when it fuses. + this.Collectible = false; + } +} + +// time in frames until explosion +func FuseTime() +{ + return 140; +} + +func Place(object clonk, int x, int y, bool box) { var angle = Angle(0,0,x,y); var pos = GetWall(angle); @@ -69,26 +165,9 @@ private func Place(object clonk, int x, int y, bool box) return false; } -public func Fuse() -{ - if (GetAction() != "Fuse") - { - if (!FindObject(Find_Category(C4D_StaticBack), Find_Func("IsFuse"), Find_ActionTargets(this))) - Sound("Fire::Fuse"); - SetAction("Fuse"); - // Object can't be collected anymore when it fuses. - this.Collectible = false; - } -} - -public func OnCannonShot(object cannon) -{ - Fuse(); -} - // returns true if there is a wall in direction in which "clonk" looks // and puts the offset to the wall into "xo, yo" - looking from the clonk -private func GetWall(int angle) +func GetWall(int angle) { var dist = 12; for (var dist = 12; dist < 18; dist++) @@ -101,41 +180,7 @@ private func GetWall(int angle) return false; } -protected func Hit() { Sound("Hits::GeneralHit?"); } - -protected func Incineration(int caused_by) -{ - Extinguish(); - Fuse(); - SetController(caused_by); -} - -protected func RejectEntrance() -{ - return GetAction() == "Ready"; -} - -// Controle of the Dynamite box -public func SetReady() -{ - SetAction("Ready"); -} -// Controle of the Dynamite box -public func SetFuse() -{ - SetAction("Fuse"); - // Object can't be collected anymore when it fuses. - this.Collectible = false; -} - -public func Reset() -{ - SetAction("Idle"); - // Object can be collected again. - this.Collectible = true; -} - -private func Fusing() +func Fusing() { var x = Sin(GetR(), 5); var y = -Cos(GetR(), 5); @@ -155,11 +200,6 @@ private func Fusing() return; } -public func OnFuseFinished(object fuse) -{ - SetController(fuse->GetController()); - DoExplode(); -} public func DoExplode() { @@ -169,17 +209,9 @@ public func DoExplode() Explode(26); } +/*-- Production --*/ + 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) -{ - return (GetAction() == "Fuse"); -} - /*-- Properties --*/ @@ -207,8 +239,7 @@ local ActMap = { }; local Name = "$Name$"; local Description = "$Description$"; -local Collectible = 1; - +local Collectible = true; local BlastIncinerate = 1; local ContactIncinerate = 1; local Components = {Coal = 1, Firestone = 1}; \ No newline at end of file diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/DynamiteBox.ocd/Igniter.ocd/Script.c b/planet/Objects.ocd/Items.ocd/Tools.ocd/DynamiteBox.ocd/Igniter.ocd/Script.c index 11c8a2f73..03a067b63 100644 --- a/planet/Objects.ocd/Items.ocd/Tools.ocd/DynamiteBox.ocd/Igniter.ocd/Script.c +++ b/planet/Objects.ocd/Items.ocd/Tools.ocd/DynamiteBox.ocd/Igniter.ocd/Script.c @@ -38,9 +38,11 @@ public func ControlUse(object clonk, int x, int y) { if (clonk->GetAction() != "Walk") return true; - - ignited = 1; - + if (ignited) + return true; + + ignited = true; + // The clonk has to stand. clonk->SetAction("Stand"); clonk->SetXDir(0); @@ -91,7 +93,13 @@ public func GetCarryMode() public func GetCarryPhase() { return 250; } -public func GetCarrySpecial(clonk) +public func GetCarryTransform() +{ + if (ignited) + return Trans_Mul(Trans_Rotate(0, 1), Trans_Translate(-1000)); +} + +public func GetCarrySpecial() { if (ignited) return "pos_hand2"; diff --git a/planet/Objects.ocd/Items.ocd/Tools.ocd/DynamiteBox.ocd/Script.c b/planet/Objects.ocd/Items.ocd/Tools.ocd/DynamiteBox.ocd/Script.c index 337ea7191..848f47938 100644 --- a/planet/Objects.ocd/Items.ocd/Tools.ocd/DynamiteBox.ocd/Script.c +++ b/planet/Objects.ocd/Items.ocd/Tools.ocd/DynamiteBox.ocd/Script.c @@ -1,10 +1,12 @@ /** Dynamite box - Contains five dynamite sticks which can be placed and detonated from a distance. + Contains five dynamite sticks which can be placed and detonated from a distance. @author: Newton */ +#include Library_HasExtraSlot + static const DYNA_MaxLength = 500; static const DYNA_MaxCount = 5; @@ -17,6 +19,8 @@ local wire; func Initialize() { + CreateContents(Dynamite, DYNA_MaxCount); + count = DYNA_MaxCount; dynamite_sticks = []; wires = []; @@ -29,7 +33,6 @@ func Initialize() // Hide it TODO: Remove if the mesh isn't shown if there is a picture set this.PictureTransformation = Trans_Scale(); UpdatePicture(); - return; } func Hit() @@ -37,24 +40,84 @@ func Hit() Sound("Hits::Materials::Wood::DullWoodHit?"); } -func Incineration(int caused_by) +func Incineration(int caused_by) { ActivateFuse(); if (!GetEffect("Fuse", this)) AddEffect("Fuse", this, 100, 1, this); Sound("Fire::Fuse"); SetController(caused_by); - return; } func Damage(int change, int type, int by_player) { Incinerate(nil, by_player); - return; } -public func OnCannonShot(object cannon) +func RejectCollect(id def, object obj) { - Incinerate(nil, cannon->GetController()); + if (obj->GetID() != Dynamite) + return true; + // One dynamite box can only support 5 sticks of dynamite, regardless if these are in the box + // or already taken out (connected with wires) + var sticks = ContentsCount(Dynamite); + for (var i = 0; i < GetLength(wires); i++) + if (wires[i]) + sticks++; + + if (sticks >= DYNA_MaxCount) + return true; + + return false; +} + +func Ejection() +{ + count--; + + if (count == 0) + { + ChangeToIgniter(); + if (Contained()) + { + var pos = Contained()->~GetItemPos(this); + Contained()->~UpdateAttach(); + Contained()->~OnSlotFull(pos); + } + } + else + { + UpdatePicture(); + } + + // Make sure the inventory gets notified of the changes. + if (Contained()) + Contained()->~OnInventoryChange(); +} + +func ContentsDestruction() +{ + Ejection(); +} + +func Collection2() +{ + if (count == 0 && GetID() == Igniter) + { + ChangeToBox(); + if (Contained()) + { + var pos = Contained()->~GetItemPos(this); + Contained()->~UpdateAttach(); + Contained()->~OnSlotFull(pos); + } + } + + count++; + + UpdatePicture(); + + if (Contained()) + Contained()->~OnInventoryChange(); } /*-- Callbacks --*/ @@ -78,6 +141,11 @@ public func OnFuseFinished(object fuse) DoExplode(); } +public func OnCannonShot(object cannon) +{ + Incinerate(nil, cannon->GetController()); +} + /*-- Usage --*/ public func SetDynamiteCount(int new_count) @@ -87,49 +155,34 @@ public func SetDynamiteCount(int new_count) // Update inventory if contained in a crew member. if (Contained()) Contained()->~OnInventoryChange(); - return; } -public func HoldingEnabled() { return true; } - public func ControlUse(object clonk, int x, int y) { - var dynamite = dynamite_sticks[count - 1] = CreateContents(Dynamite); + var dynamite = Contents(); + + if (!dynamite || dynamite->GetID() != Dynamite) + return false; + if (!dynamite->ControlUse(clonk, x, y, 1)) - { - dynamite->RemoveObject(); return true; - } + if(wire) wire->Connect(dynamite_sticks[count], dynamite); wire = CreateObject(Fuse); wire->Connect(dynamite, this); Sound("Objects::Connect"); - wires[count - 1] = wire; - - count--; - - if (count == 0) - { - var pos = clonk->GetItemPos(this); - ChangeToIgniter(); - clonk->UpdateAttach(); - clonk->OnSlotFull(pos); - } - else - { - UpdatePicture(); - } + wires[count] = wire; - // Make sure the inventory gets notified of the changes. - clonk->~OnInventoryChange(); return true; } // Empty this box and turn it into an igniter public func ChangeToIgniter() { + if (GetID() == Igniter) return; + count = 0; UpdatePicture(); ChangeDef(Igniter); @@ -137,6 +190,16 @@ public func ChangeToIgniter() return true; } +// Change back into a box +public func ChangeToBox() +{ + if (GetID() == DynamiteBox) return; + + ChangeDef(DynamiteBox); + UpdatePicture(); + return true; +} + public func ActivateFuse() { // Activate all fuses. @@ -199,7 +262,7 @@ func UpdatePicture() } // Display the remaining dynamite sticks in menus. -public func GetInventoryIconOverlay() +/*public func GetInventoryIconOverlay() { // Full boxes don't need an overlay. Same for igniters. if (count == DYNA_MaxCount || count <= 0) return nil; @@ -231,17 +294,19 @@ public func GetInventoryIconOverlay() } return overlay; -} +}*/ -func Definition(def) { +func Definition(def) +{ SetProperty("PictureTransformation", Trans_Mul(Trans_Rotate(150, 1, 0, 0), Trans_Rotate(140, 0, 1, 0)), def); } /*-- Properties --*/ -local Collectible = 1; local Name = "$Name$"; local Description = "$Description$"; +local Collectible = true; local BlastIncinerate = 1; local ContactIncinerate = 2; local Components = {Wood = 1, Coal = 2, Firestone = 2}; +local MaxContentsCount = 5; \ No newline at end of file From 05a814461f08b418421fae0b685dbf19f222c8fe Mon Sep 17 00:00:00 2001 From: Clonkonaut Date: Tue, 9 Aug 2016 23:45:48 +0200 Subject: [PATCH 20/26] ObjectInteractionMenu: don't create infinite ExtraSlotTracker effects. I think there's a bug in the effects system. It seems that effects are not removed properly if command_target is deleted. I will investigate. --- .../HUD.ocd/ObjectInteractionMenu.ocd/Script.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/planet/Objects.ocd/HUD.ocd/ObjectInteractionMenu.ocd/Script.c b/planet/Objects.ocd/HUD.ocd/ObjectInteractionMenu.ocd/Script.c index 6cae1926d..c58598a0e 100644 --- a/planet/Objects.ocd/HUD.ocd/ObjectInteractionMenu.ocd/Script.c +++ b/planet/Objects.ocd/HUD.ocd/ObjectInteractionMenu.ocd/Script.c @@ -997,7 +997,7 @@ func FxIntRefreshContentsMenuTimer(target, effect, time) { var j = 0, e = nil; var found_tracker = false; - while (e = GetEffect(nil, obj, j++)) + while (e = GetEffect("ExtraSlotTracker", obj, j++)) { if (e.keep_alive != extra_slot_keep_alive) continue; found_tracker = true; @@ -1005,9 +1005,10 @@ func FxIntRefreshContentsMenuTimer(target, effect, time) } if (!found_tracker) { - var e = AddEffect("ExtraSlotTracker", obj, 1, 30 + Random(60), this); + var e = AddEffect("ExtraSlotTracker", obj, 1, 30 + Random(60), nil, GetID()); e.keep_alive = extra_slot_keep_alive; e.callback_effect = effect; + e.obj = effect.obj; } } // How many objects are this object?! @@ -1170,8 +1171,10 @@ func FxIntRefreshContentsMenuTimer(target, effect, time) func FxExtraSlotTrackerTimer(object target, proplist effect, int time) { - if (!effect.keep_alive) return -1; - return 1; + Log("timer?"); + + if (!effect.keep_alive) + return -1; } // This is called by the extra-slot library. From 51a18f42b2e7d179c104315a32f36964e88915dd Mon Sep 17 00:00:00 2001 From: Clonkonaut Date: Wed, 10 Aug 2016 00:01:27 +0200 Subject: [PATCH 21/26] Expand ObjectInteractionMenu search radius one pixel lower (#1788). I don't think this pixel will hurt too much. --- planet/Objects.ocd/HUD.ocd/ObjectInteractionMenu.ocd/Script.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/planet/Objects.ocd/HUD.ocd/ObjectInteractionMenu.ocd/Script.c b/planet/Objects.ocd/HUD.ocd/ObjectInteractionMenu.ocd/Script.c index c58598a0e..9d65ac056 100644 --- a/planet/Objects.ocd/HUD.ocd/ObjectInteractionMenu.ocd/Script.c +++ b/planet/Objects.ocd/HUD.ocd/ObjectInteractionMenu.ocd/Script.c @@ -156,7 +156,7 @@ func FxIntCheckObjectsTimer(target, effect fx) container_restriction = Find_Or(Find_Container(container), Find_InArray([container])); } - var new_objects = FindObjects(Find_AtRect(target->GetX() - 5, target->GetY() - 10, 10, 20), container_restriction, Find_Layer(target->GetObjectLayer()), + var new_objects = FindObjects(Find_AtRect(target->GetX() - 5, target->GetY() - 10, 10, 21), container_restriction, Find_Layer(target->GetObjectLayer()), // Find all containers and objects with a custom menu. Find_Or(Find_Func("IsContainer"), Find_Func("HasInteractionMenu")), // Do not show objects with an extra slot though - even if they are containers. They count as items here and can be accessed via the surroundings tab. @@ -1171,8 +1171,6 @@ func FxIntRefreshContentsMenuTimer(target, effect, time) func FxExtraSlotTrackerTimer(object target, proplist effect, int time) { - Log("timer?"); - if (!effect.keep_alive) return -1; } From 52fdcec172b9183f51d872d7986f301b71da5a2f Mon Sep 17 00:00:00 2001 From: Clonkonaut Date: Wed, 10 Aug 2016 00:08:01 +0200 Subject: [PATCH 22/26] Renamed coconut tree (#1752). --- .../Vegetation.ocd/Trees.ocd/Coconut.ocd/StringTblDE.txt | 2 +- .../Vegetation.ocd/Trees.ocd/Coconut.ocd/StringTblUS.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/planet/Objects.ocd/Vegetation.ocd/Trees.ocd/Coconut.ocd/StringTblDE.txt b/planet/Objects.ocd/Vegetation.ocd/Trees.ocd/Coconut.ocd/StringTblDE.txt index 4d6509f68..8f0f23be1 100644 --- a/planet/Objects.ocd/Vegetation.ocd/Trees.ocd/Coconut.ocd/StringTblDE.txt +++ b/planet/Objects.ocd/Vegetation.ocd/Trees.ocd/Coconut.ocd/StringTblDE.txt @@ -1 +1 @@ -Name=Kokosnussbaum \ No newline at end of file +Name=Kokospalme \ No newline at end of file diff --git a/planet/Objects.ocd/Vegetation.ocd/Trees.ocd/Coconut.ocd/StringTblUS.txt b/planet/Objects.ocd/Vegetation.ocd/Trees.ocd/Coconut.ocd/StringTblUS.txt index 7f72f6ab9..8c07a102a 100644 --- a/planet/Objects.ocd/Vegetation.ocd/Trees.ocd/Coconut.ocd/StringTblUS.txt +++ b/planet/Objects.ocd/Vegetation.ocd/Trees.ocd/Coconut.ocd/StringTblUS.txt @@ -1 +1 @@ -Name=Coconut Tree \ No newline at end of file +Name=Coconut Palm \ No newline at end of file From 7a56086d130c0b3ddf962e8eb3109535ad0bdb22 Mon Sep 17 00:00:00 2001 From: Clonkonaut Date: Wed, 10 Aug 2016 01:07:42 +0200 Subject: [PATCH 23/26] Fix Brick density in VolcanoEscapeEx (#1781). --- planet/Parkour.ocf/VolcanoEscapeEx.ocs/Material.ocg/Brick.ocm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/planet/Parkour.ocf/VolcanoEscapeEx.ocs/Material.ocg/Brick.ocm b/planet/Parkour.ocf/VolcanoEscapeEx.ocs/Material.ocg/Brick.ocm index 8a6ee7805..5d40a079a 100644 --- a/planet/Parkour.ocf/VolcanoEscapeEx.ocs/Material.ocg/Brick.ocm +++ b/planet/Parkour.ocf/VolcanoEscapeEx.ocs/Material.ocg/Brick.ocm @@ -1,7 +1,7 @@ [Material] Name=Brick Shape=Smoother -Density=50 +Density=90 Friction=15 Placement=80 TextureOverlay=brick From 825c0653e547f6e8df7f63059fd6cff7a1a83683 Mon Sep 17 00:00:00 2001 From: Clonkonaut Date: Wed, 10 Aug 2016 01:19:11 +0200 Subject: [PATCH 24/26] Added a slight helper for corner scaling when just pressing up (#1770, #1630). The problem occurred as soon as the clonk's leg vertices passed the edge. It seems the engine does not really align the bottom vertex to the material. However, the bottom vertex does have CNAT_Bottom & _Left & _Right, in theory it should be properly attached. Maybe this is a little bit broken engine-wise or maybe assigning both left and right to a vertex isn't supported? Because the lower vertex (foot vertex) isn't attached, the clonk falls down onto its leg vertex and gets stuck in an endless loop of Scale, Jump, Walk, Scale, ... When pressing left/right, this is no problem as the clonk will be pushed towards the edge when walking and soon touch it with its foot vertex (I assume at this point regular engine behaviour kicks in). I added a little helper in the scale effect that sets COMD_UpLeft / UpRight whenever this situation is detected and only Up is pressed. 2 frames (1 is not enough) after the effect ended, the ComDir will reset to COMD_Up. It is then possible to climb an edge and stand still on top of it. Maybe not a perfect solution (a perfect solution would probably be to fix attachment in the engine but I couldn't pinpoint the exact problem) but it works for now. --- .../Clonk.ocd/Animations.ocd/Script.c | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/planet/Objects.ocd/Clonk.ocd/Animations.ocd/Script.c b/planet/Objects.ocd/Clonk.ocd/Animations.ocd/Script.c index 467a58c5f..7ed073701 100644 --- a/planet/Objects.ocd/Clonk.ocd/Animations.ocd/Script.c +++ b/planet/Objects.ocd/Clonk.ocd/Animations.ocd/Script.c @@ -594,6 +594,16 @@ func CheckScaleTop() return true; } +func CheckScaleTopHelper() +{ + // Check if the clonk has passed the material with its leg vertices + // and if COMD_Up is used to climb in which case corner scale would fail + + if (GBackSolid(-3+6*GetDir(), 6)) return false; + if (GetComDir() != COMD_Up) return false; + return true; +} + func FxIntScaleStart(target, effect, tmp) { if(tmp) return; @@ -624,6 +634,22 @@ func FxIntScaleTimer(target, number, time) // The animation's graphics has to be shifet a bit to adjust to the clonk movement var pos = GetAnimationPosition(number.animation_id); SetScaleRotation(0, 0, 0, 0, 0, 1); + // Check if corner scale help is needed + if (CheckScaleTopHelper()) + { + if (GetDir() == DIR_Left) + SetComDir(COMD_UpLeft); + else + SetComDir(COMD_UpRight); + number.corner_scale_helper = true; + } + else if (number.corner_scale_helper) + number.corner_scale_helper = false; + } + else if (number.corner_scale_helper) + { + // This will delay everything for 1 frame just for cleanup, hopefully it's not too bad + number.corner_scale_helper = false; } else if(!GBackSolid(-10+20*GetDir(), 8)) { @@ -708,9 +734,13 @@ func FxIntScaleStop(target, number, reason, tmp) /* if(number.animation_mode == 1) PlayAnimation(Clonk_WalkStand, CLONK_ANIM_SLOT_Movement, GetWalkAnimationPosition(Clonk_WalkStand), Anim_Const(1000)); // Finally stop if the user has scheduled a stop if(number.ScheduleStop) SetComDir(COMD_Stop);*/ - // and reset the transform + + // Reset the transform SetScaleRotation(0); -// SetObjDrawTransform(1000, 0, 0, 0, 1000, 0); + // Remove the corner scale helper com dir + if (number.corner_scale_helper) + if (GetComDir() == COMD_UpLeft || GetComDir() == COMD_UpRight) + Schedule(this, "SetComDir(COMD_Up)", 2); } /*-- From 43117a53bdabd814697fca162cdf7b1054e32b8c Mon Sep 17 00:00:00 2001 From: Clonkonaut Date: Fri, 12 Aug 2016 18:22:50 +0200 Subject: [PATCH 25/26] Added Library_Wearable for clothing or other worn items. --- .../Libraries.ocd/Wearable.ocd/DefCore.txt | 4 + .../Libraries.ocd/Wearable.ocd/Script.c | 180 ++++++++++++++++++ 2 files changed, 184 insertions(+) create mode 100644 planet/Objects.ocd/Libraries.ocd/Wearable.ocd/DefCore.txt create mode 100644 planet/Objects.ocd/Libraries.ocd/Wearable.ocd/Script.c diff --git a/planet/Objects.ocd/Libraries.ocd/Wearable.ocd/DefCore.txt b/planet/Objects.ocd/Libraries.ocd/Wearable.ocd/DefCore.txt new file mode 100644 index 000000000..11e494853 --- /dev/null +++ b/planet/Objects.ocd/Libraries.ocd/Wearable.ocd/DefCore.txt @@ -0,0 +1,4 @@ +[DefCore] +id=Library_Wearable +Version=8,0 +Category=C4D_StaticBack \ No newline at end of file diff --git a/planet/Objects.ocd/Libraries.ocd/Wearable.ocd/Script.c b/planet/Objects.ocd/Libraries.ocd/Wearable.ocd/Script.c new file mode 100644 index 000000000..996fd67e2 --- /dev/null +++ b/planet/Objects.ocd/Libraries.ocd/Wearable.ocd/Script.c @@ -0,0 +1,180 @@ +/** + Library_Wearable + Library for all clothing and other things worn on the clonk. + The library will make sure that not two objects are worn at the same + position at the same time. + + @author: Clonkonaut +*/ + +/* Bone names of attachment on the clonk and also identifiers */ + +// Headwear like helmets, caps or similar +static const WEARABLE_Head = "skeleton_head"; + +local wear_effect; + +local display_disabled = false; + +/* Overloads */ + +// These functions must exist in order for this library to work + +public func GetWearPlace() +{ + return; // must return one of the WEARABLE_* constants +} + +/* Other functions that can be present in the object: + +func GetWearBone: return the bone with which it is attached to the clonk (default: "main") +func GetWearTransform(clonk): transformation added when worn + +func StayAfterDeath: return true if the item should remain on the clonk after its death (default is that it does not stay) + +func OnPutOn(clonk): callback after the item was put on +func OnTakenOff(clonk): callback after the item was taken off + +func OnDamage(damage_amount, cause, by_player): Callback whenever the wearer is damaged, parameters are passed on from the effect Damage callback + Return value is returned (useful for protective clothing) + +func GetCarryMode: must(!) return CARRY_None whenever display_disabled is true, otherwise display error will likely occur + +*/ + +/* Engine Callbacks */ + +// It is assumed that a wearable must be contained in the clonk to be worn. +func Departure() +{ + if (IsWorn()) + TakeOff(); + _inherited(...); +} + +func Destruction() +{ + if (IsWorn()) + TakeOff(); + _inherited(...); +} + +/* Interface */ + +// The clonk will put on the item and take off any other item currently worn +// in the same place, unless no_force is true in which case false will be returned +// when something else is worn. +public func PutOn(object clonk, bool no_force) +{ + // ??? + if (!clonk->~IsClonk()) return false; + + // Remove all other things before putting on + if (!no_force) + { + var effect; + for (var i = GetEffectCount("Wearing", clonk); effect = GetEffect("Wearing", clonk, i); i--) + if (effect.identifier == GetWearPlace()) + RemoveEffect(nil, clonk, effect); + } + + // It is not impossible that the item is currently held in the hand of the clonk. + // If so, temporarily disable display because the same mesh cannot be attached twice. + // Any item must adhere this variable in GetCarryMode! + display_disabled =true; + clonk->~UpdateAttach(); + + wear_effect = clonk->CreateEffect(Wearing, 2, nil, GetWearPlace(), this); + + if (wear_effect == -1) // got rejected + wear_effect = nil; + + display_disabled = false; + clonk->~UpdateAttach(); + + if (wear_effect) + { + // Callback to do whatever + this->~OnPutOn(clonk); + return true; + } + + return false; +} + +public func IsWorn() +{ + return wear_effect; +} + +public func TakeOff() +{ + if (!wear_effect) + return false; + + return RemoveEffect(nil, nil, wear_effect); +} + +func TakenOff() +{ + wear_effect = nil; + if (Contained()) + Contained()->~UpdateAttach(); + // Callback to do whatever; note that at this point the item isn't necessary contained. + this->~OnTakenOff(); +} + +/* Wearing effect */ + +local Wearing = new Effect { + Construction = func(string wearing_identifier, object worn_item) { + // Save where this thing is worn + this.identifier = wearing_identifier; + // Save what is worn + this.item = worn_item; + }, + + Start = func() { + // Check if parameters are properly set + if (this.identifier == nil) return -1; + if (this.item == nil) return -1; + + var attachment_bone = this.item->~GetWearBone() ?? "main"; + var attachment_transform = this.item->~GetWearTransform(this.Target); + + this.attach = Target->AttachMesh(this.item, this.identifier, attachment_bone, attachment_transform); + }, + + Damage = func(int damage, int cause, int by_player) { + if (!this.item) return damage; + + var ret = this.item->~OnDamage(damage, cause, by_player); + if (ret == nil) + ret = damage; + return ret; + }, + + Effect = func(string new_name, var1) { + // Reject wearing effects if in the same place + if (new_name == "Wearing") + if (var1 == this.identifier) + return -1; + }, + + Stop = func(int reason) { + // Items can prevent being removed from the clonk on death + if (reason == FX_Call_RemoveDeath) + if (this.item && this.item->~StayAfterDeath(this.Target)) + return -1; + + if (this.Target) this.Target->DetachMesh(this.attach); + this.attach = nil; + }, + + Destruction = func() { + if (this.attach != nil && this.Target) + this.Target->DetachMesh(this.attach); + if (this.item) + this.item->TakenOff(); + } +}; \ No newline at end of file From 1036bad7fbc04b7e220b726bafa7cb6089d8a344 Mon Sep 17 00:00:00 2001 From: Clonkonaut Date: Fri, 12 Aug 2016 18:25:01 +0200 Subject: [PATCH 26/26] Added a helmet by pluto. Wear and get 20% off damage*! *: not all damage is reduced, does not help against explosions, fire, asphyxiation or corrosion. We assume no liability for any deaths or injuries occurred while wearing. --- .../Weapons.ocd/Helmet.ocd/DefCore.txt | 14 +++ .../Weapons.ocd/Helmet.ocd/Graphics.mesh | Bin 0 -> 8262 bytes .../Helmet.ocd/Helmet_greek.skeleton | Bin 0 -> 267 bytes .../Weapons.ocd/Helmet.ocd/Scene.material | 23 ++++ .../Items.ocd/Weapons.ocd/Helmet.ocd/Script.c | 102 ++++++++++++++++++ .../Weapons.ocd/Helmet.ocd/StringTblDE.txt | 2 + .../Weapons.ocd/Helmet.ocd/StringTblUS.txt | 2 + .../Weapons.ocd/Helmet.ocd/helmet.jpg | Bin 0 -> 31899 bytes 8 files changed, 143 insertions(+) create mode 100644 planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/DefCore.txt create mode 100644 planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/Graphics.mesh create mode 100644 planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/Helmet_greek.skeleton create mode 100644 planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/Scene.material create mode 100644 planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/Script.c create mode 100644 planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/StringTblDE.txt create mode 100644 planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/StringTblUS.txt create mode 100644 planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/helmet.jpg diff --git a/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/DefCore.txt b/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/DefCore.txt new file mode 100644 index 000000000..9a8aa0eff --- /dev/null +++ b/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/DefCore.txt @@ -0,0 +1,14 @@ +[DefCore] +id=Helmet +Version=8,0 +Category=C4D_Object +Width=10 +Height=10 +Offset=-5,-5 +Vertices=2 +VertexX=0,0 +VertexY=-4,5 +VertexFriction=50,50 +Value=10 +Mass=10 +Rotate=1 \ No newline at end of file diff --git a/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/Graphics.mesh b/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/Graphics.mesh new file mode 100644 index 0000000000000000000000000000000000000000..3e75179f7c2af27e4990f39a6a49d2f99e66f1f5 GIT binary patch literal 8262 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 YOWj-hU=mz2(!r{>Jo9#7h}dcm0LhCq3jhEB literal 0 HcmV?d00001 diff --git a/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/Scene.material b/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/Scene.material new file mode 100644 index 000000000..7abc790c7 --- /dev/null +++ b/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/Scene.material @@ -0,0 +1,23 @@ +material Helmet_Greek +{ + receive_shadows on + technique + { + pass + { + cull_hardware none + + ambient 0.8 0.8 0.8 1.0 + diffuse 0.64 0.64 0.64 1.0 + specular 0.16 0.16 0.16 1.0 12.5 + emissive 0.0 0.0 0.0 1.0 + + texture_unit + { + texture helmet.jpg + tex_address_mode wrap + filtering trilinear + } + } + } +} diff --git a/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/Script.c b/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/Script.c new file mode 100644 index 000000000..e18b41a60 --- /dev/null +++ b/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/Script.c @@ -0,0 +1,102 @@ +/** + Helmet + Protective head armor. + + @author: pluto, Clonkonaut +*/ + +#include Library_Wearable + +/*-- Engine Callbacks --*/ + +func Hit() +{ + Sound("Hits::Materials::Metal::DullMetalHit?"); +} + +/*-- Usage --*/ + +public func ControlUse(object clonk) +{ + if (IsWorn()) + TakeOff(); + else + PutOn(clonk); + + return true; +} + +// Helmet effect: 20% less damage +func OnDamage(int damage, int cause, int by_player) +{ + // Do nothing on energy gained + if (damage > 0) return damage; + // Doesn't protect against all damage + if (cause == FX_Call_EngBlast || cause == FX_Call_EngFire || cause == FX_Call_EngAsphyxiation || cause == FX_Call_EngCorrosion) + return damage; + + return damage - (damage*20/100); +} + +/*-- Production --*/ + +public func IsWeapon() { return true; } +public func IsArmoryProduct() { return true; } + +/*-- Display --*/ + +public func GetWearPlace() +{ + return WEARABLE_Head; +} + +public func GetWearBone() +{ + return "Main"; +} + +public func GetWearTransform() +{ + return Trans_Mul(Trans_Rotate(90, 0, 0, 1), Trans_Translate(0, -300)); +} + +public func GetCarryMode(object clonk, bool secondary) +{ + if (IsWorn() || display_disabled) + return CARRY_None; + if (secondary || !clonk->~HasHandAction(false, true)) + return CARRY_Back; + return CARRY_BothHands; +} + +public func GetCarryPhase(object clonk) +{ + return 550; +} + +public func GetCarryBone(object clonk, bool secondary) +{ + return "Main"; +} + +public func GetCarryTransform(object clonk, bool secondary, bool no_hand, bool on_back) +{ + if (secondary) + return Trans_Mul(Trans_Rotate(180, 1), Trans_Rotate(0, 0, 1), Trans_Rotate(90, 0, 0, 1), Trans_Translate(-4000)); + if (no_hand || on_back) + return Trans_Mul(Trans_Rotate(0, 1), Trans_Rotate(0, 0, 1), Trans_Rotate(90, 0, 0, 1), Trans_Translate(-4000)); + + return Trans_Mul(Trans_Rotate(80, 0, 0, 1), Trans_Rotate(-90, 0, 1), Trans_Rotate(-45, 0, 0, 1), Trans_Translate(-1000, 4000)); +} + +func Definition(def) +{ + SetProperty("PictureTransformation", Trans_Mul(Trans_Rotate(45, 0, 1), Trans_Rotate(10, 0, 0, 1)),def); +} + +/*-- Properties --*/ + +local Name = "$Name$"; +local Description = "$Description$"; +local Collectible = true; +local Components = {Wood = 1, Metal = 1}; \ No newline at end of file diff --git a/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/StringTblDE.txt b/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/StringTblDE.txt new file mode 100644 index 000000000..acde36bfa --- /dev/null +++ b/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/StringTblDE.txt @@ -0,0 +1,2 @@ +Name=Helm +Description=Bietet dem Clonk einigen Schutz. Drücke [Benutzen] um den Helm auf- oder abzusetzen. \ No newline at end of file diff --git a/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/StringTblUS.txt b/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/StringTblUS.txt new file mode 100644 index 000000000..98e9a04b8 --- /dev/null +++ b/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/StringTblUS.txt @@ -0,0 +1,2 @@ +Name=Helmet +Description=Provides the clonk with some protection. Press [Use] to take the helmet on or off. \ No newline at end of file diff --git a/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/helmet.jpg b/planet/Objects.ocd/Items.ocd/Weapons.ocd/Helmet.ocd/helmet.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f3653e1c8c3ff5604814494bdfed882d8068d5f1 GIT binary patch literal 31899 zcmbq)V{j%>*XYN+s*_}Y}>Xuv2EMQ1QYA#eed^G-T$|{>Qr^@>ht4t zpS{-EYwfSquU!C=l$fL#00aaCAn|@=sGqjp4(d@<#5qdH(+Cy(TGFK*b9AGkEtGokaX< z2^{dnExClYl6m%0e2`<%oEeGDpoPZ_M`ZG$MZO zd%_3g_5G1#?MoU0jil^E$n`|LCt`!w6H>ow*b^JXAPqaBC!XwZA^S=jrQBUHW}But z7zqbckEB$+HGH+jS)6A3I9tb_NL}jlWy7K)0?aL>hp;yBoT4I0DmJ-lKu_zPR5afL zQZ%!6I#7ONk!l}g4_RSXM=C3siWv>79`%;pC)bj`&R+yO5(A8jVM zrmH096uEwvepBI8%iC~!Wu>mFpdMLp$B@aSdS2f4!0|eN??3<-@+VI^Z$C zTH<0>VQe2YaFY@_%o&J*{}9bdoW8ZgTXSby`^rjva+bAafST-FHp^2Wktmp$qg?f0r#^!?#!epH4!mzt z$C+0&3dsO#)~bq}XON^b+yk7p{(#pJ2f{_{2mDFQE<)$n8N`@1zo00ge~QN|CQrJ( z=*!^p>Z|a&ZW3!DrHWYeztHQkhZB`B$aZ`z3k3HEB?n$VPAFt{zpOGXdsLgfw} zy6ho$XYK^ggeYmcmbj@%(xj%&6LH+C>Q3eSg$vA4k$KsD5=M#0eN0$VvbG+T7ruU# zx_+D?ISUu#VbDi5Xm?vA4vN#s1B|HmoS)NcF6!CRnHQ_lc-HnuFu5b@vCvWYa2DKN zQ|dqY6f3@I(rUA8tvIkM)kO)}JNQjYqN|prpNIzhl_?k~Z=^=_)IJoxI`VpQUQ@1P({vWTy`>7Z*KJ`dH!;n|xC+2OLRqMzSI@ z+Oi<)P*&$jR$F(rOrm6li&nG4Iw$u$J*rk}7}+NG`fvHF|bQAa1J~*b#keArIn- zHpCO}3VU!b-)^h=Q;DtA>|=U~<)b2c(Oh&w*dULcjHue9Gz56$!z*R0*2N+lOQZBC zRMD`Kkfe1^|GIFz#(hDR$P#)3<9TEM)s!9C@ZgNG2+m^=wC_W~Y;g(WrwN7e?H;6k z1$}T9AQ0s00Etk4zn|66`6NmfqU9B-^WkGCd1^h>&V_977Bk!$HvFAx(VoqPMKuKZ?&0Q^1Di;TRFEr=qi@F zU|WI1@kD6)&XUL$vF1vsAC~KrQ+~s02?&D+h1%M=DCT^9#&S&%l{*;BJA70qQbGwJ zSXK;7kBHchTAi?Xs>zenON5ktD=)nK!nj@tnvzVG>Np*Y)ns>Z3z_FObQ8VicZE3Z2=j zZY@&mlvg8Y^Bb#-8-;qY-b&zVa;i{HYPP5@X*1X=pLW2qegtdpU}oxPxNwDhJnAfnwEv$XKbJl`V9{ zkSK^X+e?wwWtvM;7WK`{KzZI1T6TF7%K;-Gs=k)ja`_H*y3qQ-GOZsbBmH$CMAkPjpa1<-mhSu)X-1s>SuNIa=Q9ComYX; z1;ucXT7!||d5^b8@>cqGHH<59WU!m7PKal@3!=8d9lc2nfTFso&^7`0qGE?1v?{IG z(n}(Vg`$k{SVA@O&9l43>6O^R^ttUVjZ?Idv$Ub_Iv3SE(X+{+G>d@}E%7l62XkR| zqb?Sugg%8GV<~-LyS1=A=Z~Ei%%3gg6i?0kx6=cxDXGqP-i>s`%SJMv_Cw1~bcSMz zx-@C`rX3o3&2cRxqHrBzmkJEAzJQ;jvXvV>=h~PNZ|QxVZ8oV?$Q!M7lwyjFa!fy? z2dl^TnRD-mc;|Sw->dgv`Ym*sUtBS;!;-HQ96hd4sme#VCB+n|hmTL(jdIjX(RpGd z2L{+AdxveP-g!;X;tnfG8j*=8T$SoH;*4d%{+8WM;CG}E!5e)9s8qI8I>-Big-Y(7@dnH(PK=Ibf_;2?5ELW?u4IqpqnB+f?Uf z?SJoL(ySjubix8fCO2)B6e}g_>!XV&T&qjzmmwPm+k7H?++}~7b?$IVU>rBO9^c^w zY0XZJ>2~VD2{rhwHZ@GjJ8B#WuT>__l4@ktzU(cWTh6S}Og1l=(5O`>H3`NDmvwhP z!CF35xcUnQcV3M;i~0B8%LnarX%+#rzsq1d@GZs3Vc2H9Kq7K_Adz8je8zh=wHnTelX!7X~tr>y@`SUolQu+`h+;?fCD^BXJ($ne!F(`7~Veh&>p%yP2t=v zf>1#!XG)#CH-+To;g*#9rg6P_YX79T+!o5Ag-X=GVHwGsM@g$gr~Fpz;K)V~0gH!& zk`cCixYB$AIePo9SG%nWMyS}!saXGVZ5<6ZJ9*VYmq$aqU<8J645Yjqo4g8I($f#? zmYL8#($LwK1Syh3Ir*gtV2|3^?FtF!h2|QnHrm4Qg~k{fazZX4cBMzW8nv`exjvCs zYe;6AOQ-AaDp~U2%2+3bIYVJA;ASgsb;zlqju%ATnl~~(o-(Q=e%u;;!u=Vf`70xG zQ&|1-ycW(!R6Dupq(t}llTO14VSAW5XeaC^5%j ze%uTS8w^apxYm)mn@4s^hHKAjs1$+)!vhCyO{DeD=)~a`=1R2HOnQ}k^G1F?jLOkj zH3Ll3!hF-F?~lGt;if$zn84nQG=i(>w%15xOKS3A80rr({vdLtw0c!!44#HwWboC2BDk`~Z-1G%#oWqFtcgFwl!fJ91 zbp-BIBQl-7^aaRgc4y(M$%d^~XJop@c52vchj+rUMASGWf~C-IO;~ze%@tf)u4#5{ zU&x?BO?Ys<`Q44J_uBiJ!LQoPgkGP`BUzvg-7)f%{TOmMy)8{>7h(idIsCgIt`K_Y z_>?`R-E)v3~s6@GsBWkE)E;kGj4nEPXg z{GS)nnATv+V8OuQK4243+ZGbHt1+>l!;r9vd1PTE7v)x0)UR6hx*zLv9jh&6Mn^wu z@$B&!6Yy(9TI+LppE0PbdZmclx*AdeD7F*b?EzLJK^ z;PqvMz-v~no2}a7eqi@~Ydb9=KX}vU{vNX1>f!GEWk&^KWg9D`|$Az)O=-=VK``buIZ*V0*IEKA(E3b~=zIDR{V?vSC0Z(V_j zeww|b|KNl~)G}OLfQQ=zk0cH)~q2_XYOK|sMlAt9h4At3%kpg=&u0Lb7d z#Ehtd5G0C*j)6!_O7ZoOXhft!`G4ka&@srEjS?A*gXZ^~5(*j){>!SqPrCdduY|Q> z&-_2tMEkZSLDb_j$h*hsD|~+SWqRIM#>}bX7sQTT#{&|G7v7Hu@u?-&e_Cv>#jUP} z639UR81%*W3stsWU3G5B`2vU`7CL%dZh~V->t-G5dV<-?ThwlCCtQZT_1@}tc9UNT ze;j`SO#QC^r8XlzWqu^zrExN_qs(cP%dDGkq7)n+V*--vCdx4hV*GMvPDxD-1}@`V zi_ap^nM~X^b*8=mlkZlN>(;2nEywl;#Xh<5MSZSE`^m{G+9`sj4UF86F$ebfwDaTQ z=xbMblah5Ca(@x~YfpjLKOO38jN7@XV=ZIGxn}~}>&iOl5pixAodbG!IK~!?-^cjp zN$(4P3Y7rSJD-*LcSwDxIlO2vT4IAU8~%a^4^$_;1koVRMsdyZjx^FWe*sEFu;nvq zBMS5DXQQEbVz%R7@0$%AyYc5VScStSi{fta1Rp{gwdFL00)A+eb7eY}y{Z=$iTdXl zt}ygyl8ZQQjt?S*$l#TIGgsI+u|!k0M!4Wv(e&=Z-p)!CojEk)Ey=hGGRv9PsNKuuVVKd*W^u zN^A9J9}SMV8(p8Iza`=SFe|fdM+1cV>7w-EZd2U zO*OvOtlew5dEfI85gAM>>NMm+R-@}3YFru}>s|^^;3Ffku5)$ds7sDA0JNBYgvMTJ zPD0fMb+l&O{e^do$L3kAJn*A>DZ)$=!5Sow+hZl>0hl%s3B;P}k9XkANMZu@vbrCjrXf6t&69uBtrdT{|(|QN~hNlYH7%KUs?`VTw8JWJ&(e zd9=d8eu10lrJq#l}aP=_Uk@&|EQBj9@S%E%K`D!LU0(Z8^;u9}TPM}V&qiGJq` zfX;&w2YPo|)mU=A?a~mPE#CnYTd(bp(^#F0T1+sVwU@@7kPNzN&4!~!)C~L07|OV$ zAnO9e6T>RCXlu2t)kSKBi*miZc{^YJ=OV8}Ojmp_L*L zGhshl-e1=?pNmdrPSH|^Cgse|B{6F&x4as_ZTYsD3(wERMria&@dbcYmiZ%q9P7vm zmq77LrmOgnla3c~be zaMeQUun92%-v`dl&&~=$1vM|XaXXq5c-zO~)Nlb(t$3->8`e z%eyV%G?+yPLTKBatBre?A-Vl?gyO31s$hDtw;f}t@qDM&)Y%si1eR+@DwCbBh)=Rp zTf+lkb~Korx+PRoE33^ESXl^!yn+VS?Z<%(N}KAF5KkuxM!2EvQ`3soWak^1ek^CW z6C}+YeN6FfET;+^ezyYg_03dm#St)x)@K`A8je`M?UOtfr?58Y<9^(h&)h;ye6U*U zH_Z>$a9t?vnPBWnDC-KYY$@&~Sv@&Vw%T&(Etlxjv)lGk0}i#lN%u5IS%+Vbeys8T z#%0(JF?(IA7Sa@564=NVB_PpAU2Kg#T@0`D=Mw2{X#KgT1eyE?$ZVKe<+7f8`SG}u z4Brz{w#!XCc1 zhQ_kN`i&$n@$$IhkAXKtORM+Y{@-XS{y%66@dN4y1oZ!)DL66!0)-fr5t2ku(GUrZ z$uTg#{s*a$(tptulgKHkV2@c?IcWidjK#<}I3aQVzmN+0A4t8kkG}QM#~k_|?yvjq z-V4U$e|eYWWT$9Q&2yD|c&S+;PLqfK1B&fQe*qBZhErZkHyw+6%AfFlj$?}J230QW zTzvtcPA-+?+fad4;T3tn0(>1#1uko`=qkSk4!F`T25?Wep;la@0som8x=0UCj`&a* zT~_@5bC7VnOL}J;z2|8!>7+v)Vtr=oOttVmJ=y?zHdAnP-Am|WPq%}I$hpF)3&fhZ zFTg|W@=r0pV*3}CFMv8>m0r{rAWZvHj{l+l&SDn4HfsL7;#UIgD~KI@5EnGTcmW&r zknp)5c|TjQJ$b#gCwt$WEK&-4cmjC%sKn}OB;m#NU^iTGf*;ouxIwZltOy&)R*wVZ zp|6h8tf*KO+WE?vZ84o;OJv>OUOzqsOT*HcSjZ%$s-!syso%)chi#Us>ZV8ezmv|D z2JM}XN(+k%m8cAWNGHlSbLxsGZlq3jk~>W~_uj@nYU)ZyH@6kV$hBnpQj)ki;f0u% zxPJueI$4uYs5>;%R3(qscwy5e{|UhW#509+kP0^Q^+n{-bF8SCB7g!VWs8mx zK8U3L#k);7apAloSyJNdBo7?F>D~7i9aZb~xbRU3oqqlwImrc3Ce5AJx!W5b)?k zJ3Jyq!yA)n6iHWp#%n5TYic|q51WPvy1rJ0H301}0l{MsnGA8{ox=6N8JZJITMP{+ z4Tn_r4=J%_eY1>q@IFDj{rGyheUNjCPUYXMvMk)Op~4+jk){%B2@s5=Dtz6-hzi}lzswYnb_j2baV;qZV?!^wfHrzMj{sdBZi~Vyfl_H-D=_E5h;cr_6Ne@02AKA;I~e;WvAdN~fEj_?VRm zom4Re1|3lk(1xS5PH5WteLBwvrIATvLOuQz23ZsbBM|s35hrjhQ5O{n30AIqVRYsu z$L#D_Z0*fg&er#>rZ4t8EleF8r*~c*=gITa)nqWX(!dFQIQ5!03`}Z z7$p@AN$VON$uK$@*!QL3-lE+QO9`*sJY{|p=TH?|7H5d2a|A{W)TH*R@%nRB05izC z)2QaPS!!bP&yCA-xFRr2J;Bh8s8y=I0B<1Vz}52$ggS7=;{<`Z2cQLGvMU)=lUKO^ z_K|UOcU$Fj1zEK5eT0d+Kc^`Zr!Y?*G`VZ9mbQ%~__dEPB< zuquYipi;8Z5?3(7W6R4aST4M+R3f~(#|8~X?I0b?KFQ)oVe+`YUj-Tec!G~3|2X4b zPgD(qOLL^!PGb{{VNC45)f2~wlngJ8#i~?@qWB5OMb2a;`ZXKL`I-ciJ4r#Qrg))* z&Yy1$=)}=~ovlAT4>-@%d^3rQYO5e&D_M|4(HK(z8_FcmI-0F&PO0?^4sbne^f$w0PX7Wli1BemsVx$8MMZ4>^359N zB4s*S%a4z48U;h09=dw^8d-!oJUk`eP^heC}Aw!8nx|Cyb{kg{JUjW5-SZ8shP@b8(D50&k-RVHplb zH&`RfBO_PXos||6;9D}SZ(6w4aAr zTMVNiV_Em-RxD4HFW5U9>Ghy15;3u{U#HG1&rBuasr~#&h~gxIK3>uw~oZ!RCR41V4gzo_Wd1T+?1KHsYqzHjA zST<60G)q}DEb=v(qF-X}*gdAs}K;Pq554^0DZFc5ATN@70(Gvzbx$zMjE))ka$&tQzq%8vU5 zH)bGWZy&zef5r}56Fv>e$0u5@8dFVR1uTB2u@^-g+Lw+TSV7k<#c)H3iNROEC@l+f zR8ltBAl0yXem&?sI}S_~9`F;Ky}BAUO-?86W`-8$w)LMmUMyR(gl;M);>dpu{XI2apaPH@v>gvYI?I3E%Qq5tG*fUU$Tt!>M ziqH)^F=lUuo#!KMSL~wx@zU{Frb%gik|Q9x`q9u;WTWfu|8|ByXnDsVn2C9OGe@zOe~8k2QkCzjl?d7Fj3+u6KR@W4~bZ= zW8+@k4=oI9Mc3}Tzr5{lvjT|Qq*=_p1V)qx*&)zM*6l1Zz>6c3(h-vffN9q6tVA?~ zNG0cVFOe=_@9k7=DbCysi5Y{$21-^?CJU8C3+bm^dhU@?+Sl{(+}v3;xBUGmJEu0} zXD6S%k9bmIq(g^y*R+*X-1x-BQxR8BRut-Z&L}3Au^ZI3Gxib98v8in&P6IkS`=65 z9PWE!ihtZCQ_MV@_rCVWHU1AhM*@HXz`t!8kWk>@;6MIb>;ixx6QeK+f`6B~kWh)f z$@w=kkI(g?sS6SbbkNr*7fQDLiZ_8RD* zs@(%LR&SuYy_0)u&)~0Z?B}Uf~sk%CPgVH^{JROZpop@l96t~)81vp#GWMowIs7T|Dsig z-g#s#4|fJrF5^sHaZW7-TQ^80tdok7TBJ}f-vp0vb$>IHL{`TSEIeSQEzqD?GZWz7 zpQoVASeX25a7Z~hkN@GO6t#jpV0~NT*pzN{nh(Bzp9$B6S{Xe6SOAlNv806HNONyB z;PmT}5N6GYnqq`iuj&&tbCMX@0;${tgVL?=OpozmNI^GeU|JG6hqjIohG?g)SgR3Y z3v9W(W77?`NDY2&_ZC1M`^>R|J*X{|LB~{6)K}88-#NjCbzXMwIsJ$VY4~1H9d@fP3&%fyc z<`&mCM&XBqzL>ktnN0#X5!y4Y_KBe=TgXkZS?2h^<8c2O1Rq~`&oRY_u0g5@1~ z$U0>D*zF}EDnmb8P>F9VeO0>XPnYE2M4qm;+MdSO$!*deP2!oWHcHTG6}&2#YdB5V zG%UlfGj}~>nT?^BUGGa?)tL#-L^%3XxI5HCg;d&6E+`ZXe#&^Y64+r4`(t|ULvz_`| z%xXqtkYaa2>Wxp&QNU}h+DCz&5lSCg6hR$ctwq#!LACsc=5E0F zP1{mYNDItTCOkuyT1$x14Vuk^8d+DrrR*kIv~_V)6zM!z_(P0)DqSCQ{_V`Z10}sy zFhgTx<|69AFNc5hoIeZ3e6!llkLdmw(pDqzh$B_$HJM|7zz-fpn-Jldvg28K@FiI^@ zV#P_P$h{YOWvmeV!YeO@5?)TGe%Ruy31TQJF=o=_0|rHE>0KmCei(y~0kOC$uCteR zW!L`=<#^@*d@bnJM$QA3qR>{nW$8-l8HHHJ|4x|E1o*~q;h>I#VV?Knp9zEx4R}l4 z^eDJvqgeR0sDd7tPvzvaa*Zg`RQ>ULGh#32f>;p%_unUfkk(f+%nYf6t5BQ|7#oCu zB=bV!Ve`CG>LR}mb$1pyI%C+iPEy4B9<%GPY?+|nT7UHhHN!rn~hrh<}+Pi{=Qrt_f zUi+sIZOxYIBT>s!4T=@MjIlFvP>edqSkIvb*H={3*L6vL;voQOpEe}p?&F;(TBRYE z{t21t_n8@iLeWJy;gBE0iGWrv;xwSu)sO!Q?$Y7f@JR?KbCRMLu}^51EXe1SIkJA} z84G0q=hwgC$E?>LVSZvPX+5st>Rz{iEsNSlEv(GOnT*C|lR;4JC$ElZ(I*`+1>5Hc zr&G`XG+0W|K9D}RFod9cd=&%=+)7Oinod>LQr^?+vA62aw(HUVjGw8SAI7ix&JVF? zzB9}G#ZUYi$#j=hE3qPh4&J2v)9m(Flz$N^2XR77Ck2%|1{i$pjH8TFO`OH{lnn+( zNc)B%ZTDRGdt*78qkU(}ZVWwqd99ow!;T0ja^AuRndRdl5pzH4de`}}Qlc-w?rIP4 zEm*d;a8%o!kcNI!iRz*0Z@mnW&t~ijYpbi>OxNrBesg%`Tzr0s3xa!!Bfov;mrn;% zApRAnS}#;81KA-0i{zD;K3Rk->hN8>Ca%C2;66f{25S%&bd1rvm9uP~p?P;kcD|{s zyx*rXca{RxM*yVQ+77LkLo!e%l`Wk-)rFy+bXnDA$X{a^QJtx|>|h+O6-1ZUv6hF+ zH$SByUd;B^mGh;151e6p(eaqyvk&9K)cWdI*huX9ZA_gzVfR>DKYwK;_%!Z*S{DUyOAULi9VC(@?Uh+NG|yUP|7wh6r5AdCJN8cCsvozzScuxcQ>xGyw|;% zbp`^r$tCoiIIp4JH5*i(0E@mx2(c%%zKJx;M?4zy(cvG~N~Hs$_wS??$<+~$X{Vg< z28LS?*$>7q4lik{>COpKkL@`+-8Y)Q1Zq{f7h6gI6xFr#5=_xaxoTQUWKL@Qcj0^t zrs{sSl}?vYitd?{@_3oSf? zjmNplcOyF3L_WU&J|#AH=;o7SQ@-GZb`RU{Jtx9jBlpYta6uM!n=65V;(iKwNm& z7;~lc3t&LNznC{y1la7oV4$GyCP8lT-fByO)?&G%slPwA$T^V)-Pa%XIVho zL7X9mKLys1tG?aR8d!sCEoA*V8~tQthRK@ZQ_wOB?assr_(5JR-oeZF(@reF&+)w> zEcLO3B>AXIL`Cv@t4z^+I4lrI?TONEXDG5@vW@uDJVLS}%KVjjF$FzVKCdnfqlbx6 z^hUj?5g(=z7RIKN*_tvc4o&V3Nk>V*|oIg`2|>CE9$WlOdtH^ zD>n2CNEZ%2wA4E$sFAEY$D|jYz{{Kz}VV^kpod-Cw?F%*ER6_ zUtjQ_*ydAV)bdwQPV1i&7cD=!jdJ?K&CJS)INlx`;(9%3vtThD%xZj5OL|fJ{QDwO zB!LO=x0mmGBe!Ces+o?@K?vGkH;2(q*O7O%qCE<}K)trFt>{l9C1)^X92&z!G~MuL znKEx0|9l>7u0dwUA7kADtiKZ%OB)USa=*ozCuw*0s%aDkFR}FnAOO?e@D4{qu?9LL>`un#?-mqb*{11k z7n9Kwklj5-r%K_Xgqoc{p|pU>VU-Uv(%`S_l`_^wk*1$9>|)B6TBoZmb~J|k2rrI8 zw@hNMQ!ny0;DdS{Ss}d3;A{H=B+cplceH%*@8{35aZLx_Uj@|uYa5;m=D!+}!g~>4 zZl?$gMMC$C96%*WQX zl%@_-(3X#}wW=DR7+H5F$m!!CgW8-&*jt8Y4yyumte9I&=p12gkXg-s^i^q_XVNpv zU8!U*A6i8xmZ2jpRMVCGRA;Wl*JG@qHjiAMeHQu1&@7mKsEuH;!OR>|q6CT{WoM<(rrPkD_g3;ZJgpeTlPLyv>$y zT2SZzut;Wf@5ki5a~2{ohDLQ{6)#lj(cCv}(l=j6hCfGVG`i0w2s6w0R!q=}>g8CK zncmBI3>sC*H{b#;=a+Mu;p?6IxukERh_(uu(aR%I0kRYZI`x(>eU{EyhGULQN0WrZ z7;3YE3QHY-aZI~kp}<#%{frwRJ3e1d(Cvaf>Vp?~`l`?OS)xRbeV=09d{5pFE^rTC z{tPkZ#njgr{2)sk1lObGMnAx9g$1#!qN2$%y@@LP1q2R_1wco=VgKnj)~JNK9v0%4 z_#iIpa0mtW`T}sIKo%f|Akm}q0*^!^LQ5V3Jp1W?4aXVHsWO12VFH)o_agyKrgL_Y z{|KS%Y*8%7(ev&vUj##0s!95p7;ELaA?Fm}6r)Mf3V;R}_!wv1;FixrNx76P!U*S~ zdHu@;aWrXBifNbe;MsmbA8=|6`Wz7LV!Dx7U8dMRM9&VPDeHGYx)9s}vF;2d+WI6@ zY!{t>C$qNbC3QXcnD|*8UfV#y%az6~bL?T?;1dD|zMx^|r~?kj4pD3DM+Py+Ec3Zs zvu=0-2X4>DA5pZ3dDC>O3|#VAo_$x^4R8Q%;nvhFq$*g4ORNbEe4vVYh^yr%3Cj_{ zja^1z^>IWL`ce<3x`H`Mtc}qV8Rl+u!oz_V?X;Tp64QxM+102*8^o&7K_l;S`xm!+ zkm2e-okwg9`@oLPy#x)rDpo2XLFD)0X+#uSV}HEHr-Dje$-VeUra-BEGX;LU-7f$$ z4Q8}I6fuQNnkO6y!{uG=Rc8Ii-EUNp6^P$u4uLZvWOeLij5)qhy8`?|M&ISn^{O?d z&0A{dVBKu-5HAXoAUDs4U8dif#+FPM=Zyx_&$C+aOO5On7EP*t7bC(E1Z=`PE`lV4U z%31oS4q5xNUaYUQ&~GI){|4y~(RZQcmf?Tx+5E)ew8G0G zXeOZWhD1ZbHp@inqr?rrkv%B(Y-%;q>1g zYS5y|;3n^@aDhY-rb!y{-6l?T_NP4#0bqilXzB6Mcgn&wdTEf_C_&+H|0tw1h04;9 z*DQBma~%Ehf*J6Um@IH572B$GDIH-KJ&-~N7~({P zz{%@yLWZDdUp+$_)l4Oo&K-DKAk%^YPK{hx6G$s)XU|84gg*uN?}muWXRJON7=KXY&=sdGA5xCD&Qa<&ks|P;@e7Kp;(n1kwJjQ zd|1qbhsS3cbA#H-^T>I>pQA-P?SfsDlmK`&7XHMz?Ch`zzD{N($Uc~%IxKoz@lu6D^LW)aA|6=f+&qa%E5o+IBp}7 zzs`IN`~PMB0(j=WO_B)$z(9qd)0IM&43xrY8M??4+rWP();PnFL@Re#JPnD2X|4*% zBKMt51khNvRIBu(huaO;)$Gp`8>G#l{c!)y+i!E1d49V$e_$nnj1F z`0WHq8WBHMTmcEx3^8#R|LIk170Z^@K}1>S*a}YIBHOE zOsA|zEW+f+9AUoX*O_9!#xwn@SM>|@j8_GmnG5#OL&TI(Clh#4O?;9B`WOP4G=+|a ziMFr&P#!iz;P;>{McAgI*P>++naLS zA}CPl&)fc?<AN?4o0tbs|;wjG;3UbvJ1-coFg5scs%0Cfsh7=iR zeUz>#1mwL3HJ-|^G@>hfN1sWthSLcO-d-mVrr&0^8>9v7whm?nYNRQ^bK`rW0#k~) zAiAq_Zze`9@FLwbxk7IkD~5vp3RhTcg&NGOdLVVJ3Je zpL!lnY5|vsDw5TcNdTy>%e&SP5h26fAKzZ6+o4CtA*}i{iJhM&Y1cxj;CrHQyoHq2 z3tL2QmM>nRmHyL)%r-mNLEabsKFvu{JV+zSal)2%au=+MV}DLt4`j7Oe_H_B08XK2 z(ST9p{W-4t+v2fHbTEg&qpg#ys%V1ooT|}d^B*3uYZ)wmSQQn|^kmwi`H1+jvQBfU z^>GX*=VA_PN4x7}4WTD(*_(Dg_jTelTTIFRC9XsFPe&m#>_eRQvym6VdjA=R&o9^8 z0T@Wbq%0u)>bn@;w?`?q4KGJm7~M4$Q}H01V#80Suuq7J(nCu;J;8#zd(3zqw1NM# z#Ee(NkJiRN1Q*w-#MHi|BBeZFQrri%9BahULLh-^&9BRAjGS*SaDL~R_%`geLYYo8 z`d$O7pP=*wF#l1J0aa1GAzyy2IeR-$*oRP)cErpJ>SU}X3q}5@aL)&ZAwGd4XrFp$ z(yxYCJ>Wv7Y3tzCfP*qtlXKvHX%wshg?sJ3fDa76u%Qe~jL{tB4I)ELo5TQQA4Sb^ zHMo&^;~7djuzz0Y0FWExnY?aM{XljhA-TfgM>ekQ*Alv7vL`Nt*^%`a%c+RcmVabq z=>Dma>}-i1>MnlRmY<0Cvh1aB{sIWblPo0v&YgAD80&@09n5fb$81#>E0uG0vA1qJ z85!Y7NEj$AAK1Hyhf``J47j*Ye8(izS3Uj7T-8oCI`^@DHcw>Xpm2y^`ZGgngl98; zJ1jkqiX&sir7iN%4no+ak zV|1q?7!{doD=8jY0iPVf4KKsQY3hzpmEbjnO%w>D^`gJsd;}@7Z70pS>uGvVIfrn2B)k{*eXOF0 zZ0SB8L*I>k(mB_MIhVLfN;BtPIi%bNMcq!YKXAnk?Ma}xK{mpAwi|0ml;+0N+etE` zB8*!=wBW}!MWcRYCSt(%No}6LH748Pz`h6_uZJIwg2XeiVn*E5d#aZqKnZ2b*IXd$ z3}byaQMgdYwD$$u#+>uU$vbCp2qYN=%;2P*diRE=>N?--SdPSgMirvBIg$Fn=7nLF z{I$MlUWh!XTIi5IrxKUpRjt0*9@?o+gu_qt0&5eu;}KKZO)E8(gQ{lOD6K6KC6322 zFZm%G{efrw?+Z|65eH7YFRs+HDocCX@6_>%xw_xM2)3*4i*h{6GMl zhJ42%0nw;FLV`m?ymwzGB^#3`d&GD%N|hz)fmnTFD`3(3lN+q>T(YYMl+3;;Q#U>r zoAcSbjE$_@Q43uc2Q(Fv(5S&ZuSx3X4wo+6J~RUpt3HBK<==+SfBe|z$insO?GjR1j@+Tjw&+8eER_l^N6LO$`z*|epZ9VwK5P5n42;Y8hpb-25kR@Mw znKT%p)+N1^B?m5qxM2pB7&{r*fCgiS7RM8+Q_o%mSxPKAxROPqbGPz#(twCrAS5?O zr>gzr+Rq4x4nStSW4h%~kulPr9?Tg50tYe5pn5YwqRv{ic;?f|Q+OZX?mC7A?9 z?tm08p@@$R#|ee91qyCJ6bBfqF3Hmv7w?0UwhlU>SIMNDH8nRbkjBlYJeAE%czYh4 zCND8NsedYQ9{}fm`f-8wkQ2P~7Yi%(!y`+i9u@qN^L zVsJt(BZ3cC5bkc9#?6yJ5rV;#`R-xkj34>}^ooP0?fld${oKH&UUAk*?#dddfvxN(cTW{}^e2=-Yt{-Ka=H0lPHhUsUjCx}Sn zi21Kkx>`=Y-(W-$kv#2-kY*J1^aniST_y{@+IIhsWQXTuVV{e1uTJHwF1kXG()A;tC zz-xlumzevREd%((4a^k|2^H=mRA2j_e+YFFEm`?>P(`rxuI_nFKApGWROjBAk_R`N&TAvrzc|wf|Hk&Sw8ibBzJQewPS&l zp|U~$k+mUSUw@`q`Rx}D35Pb}4Zg+cC%(mj97LUxSQ(0}zy-4Z)6`c6#SwN(?=J3( zySs$!BEj9=HMqN5aM#7%HF%Ja1PN}7YmfwjYY6U|%lp>-zPeNMd+OBG)SQ0$bobdz z1+VFT66C&i?OAWlyu}thIu+=5kHq~$!Y)R#&X1y&e2FkG|KN%nV$#%wjY-pZ}#Zzht z84p^JqD+=cL7sP7_#p^dctV4}Mw`WULZOw#`t|lHZ|rG%F`#|*KX=)z@~UV!fYosH0nvcSHYk$A_IENz-D1QGqj}#-ROEo?Hb4mQtK{6P!S{I61 zmmTd$ljauC_)T`BndJ73KK$dDy#ZC3i{?dh$Bj;EMvP)32 zILWynMX2pO47z!QNUXQUmFU9dtrfZP_Bd6RH3L5##i@c6UqZmSj7u2mVYYf6uQWQ8 zyD9jBOOC1Q%is5MCY=T^9=^D%`bL*{`$QoTTMwua&IvNDFI0&0Ex7AkgJ?>?@(iu5 zx$OIjrgD*4ykX)If{2?9ptFOs(3wSEe)Wy)v<_GTD%En7BaM3pJgE^g^(44>BeGxC zen-f{fO9@0zTU0C6@LlI-d&dNkO@;^TY!JN0jMPGbv;O1DIWI51TS=-NE*q1Yo`_( z-je4^V&(@`D(Z=pv-vPgTJwRZ&C+NX`%aEYVVGmfyn_pT7+)jIw1%ml+@QU`&bb=m z)a(+(?TN;>PYbVPkgks|kTY^&6yD8&hW~iEFj`3x{<*!;;r4{327bJ~&gw9CfKQ*T za=o0A!L+9^5yMV1uY3Q(Dm?EB;%<}>?HT@=^3k6p#Egu%A+;XSdWr6OYV<1cN z4O^RFW)$3~(h(2ptt!$U)_LI2FB@nCV3h< zIm>%czKdg60PF&gB<&TDWXIp-o3Ac^IFZRIUb@6~0W^Jf_Xwk9&N^i&53NaB?Ox1` zfK0mJi1Y0g4GUT=zVCn=m&o0ls(*HO(dNfL160!+>8$y-nDu120W>_T446++09S?L zfLBj<-&rIj-9fw<)(7+k4o#UCyzws)mrG(~1|@V-1%UH?h3zz^<=4`afRb&1S4xZ- z_mvU@A|N3CKSm7jN{K-M|4WHApY_e2gEwjZ%ZUBQS_ghSPn4jv70tA_xj!X)oOgM& z4YDjwqHg;+qip-mHNhsP=r@nkmP4fvy}&AG{<39M*NFpS*r+#_Yde0I_NQ}|1gHgQ%}Bxif=B ztiQ*M)*Kfg=hY8-}BQ_3pg1PD^ykdLT#i9})3xFe7a7+b`85r@B$OeO;=n&8961XKeJ&-s#2^F) zOaM@kfMCGb+j4vjt3d5l_ZkwIS2dmK3xgjYYw_mWciI~u0iKFUr2t)sw)d10abmB%0_C->1;B@ z@s+N0itKhV7KZhB0Vi%ZDS! zg=a7!GI1iQ7oazH7dd>RWocPHfG1iCE3wj}Dr@iguIoC>cUOSpl?@q?lT_Su<;PMg z-qY62UAKkOMpAf$m4I!0Yis~5Kw30BSz%OhS-ci~2I&<3Lb)9MAv)bR8P0*gY85f`3HZ(RG5by4a+=bpsCq;%(LMofxPQIICTUx3IMGaHLlg<}9%uPfP z2ZsR!4*_5tK$(*`8bjGsjU{ekd0cO}*gIsFC~bE@lAC~ixmxs-&w_T@xb%q+oC00R$MZNHp1mNUKQ}d^lHTNOYt@v0yc}ssot)a^u$6!z};u-T2fSprS^ApzGSV+K;E zOp-x03Ak`a4?$=V>hCQhk@gv29?hgO1Gm!j(+op6og$ME@8iA_4FIIy(VDbkbg0ZF z1aTVt43|5vc_n{p<2U#c_Mw72nTVPo#P>fUh7%G{tI!yPJX>=MbB4s-;p=MWZ7}yN zV60-^>WY$~nCW_msp-Zu--96y=ha{3mI-*5edu>=A?vd5-R`BVTneaCaeuCv{SK>a zm;>drR~ntgXT|xqp6j@|d8^Qo7?I*&CV~dtm7`5s6y}aYw&K>rGP-kiX(`! zGY%!hPydbh6rxx0=7uJS^-Ic-740-`UYo_O*YR+GZoI$`qve(HCCZg~n)-HpI6~iX zWhjcr&B}dzB58zUnedWxmj$kJe;W*|_p&HyxGI-UVuLTaeOne)nn5kZ+TY0@hsSw> z=&^8$T{-sKI|H@syvs^k7!&7Y>o3#AirwYt(a&!cW0us>s}bpTR?V_=w(V!Nl{5{Y z^S4X#gaRNU&9~F74-5`=o!ZJTUWg3xS~g<(D<2l#Vm?34c{A(P0OY0H6^^TE!sA;! z3?R}m!x^X}%Fy@zQ8)YK{G>U9(rcXVq+4Gs0>U6KokORF_Du}rsAwnMI;Wq0fJpol z2XEW{HkG+-Y7Dcfv>3Y@^xvgk4KGzPO@T=o6p1ZVUBwmgtBzc+#c5b!q^F#&bG!jF zz#JMCHDNh&hd2rX85gOk3(txY@weW8R_>qe`)vz0P}P%jDbsjt7)!89(9(r0Hs=Rv z8N>X!s0N7+gkh+o$c$2X3N1m*nRq31`3Nuv~^U|N`+4J_q8xony;umjs zQJHB!*f0~jDFofe#edhf9rD`_P15TrS4eDUELSfYoHSdg`AeD9S|FiQ?c*V;{9rt( z<)cm+x;8@{2AA)R-`sIGLm0`=THACo5Em=@mwl9B>)aoGc+I4o7oIRbK10kf7pMmE zd&hk#m%Z5K{)YA38Qd^=KxBlSzv^!ui6-JMqU$}3E(O2@J2J`jaS_k8gp4dQU$6WG z9MgUZ7=f^D!`-T=%qRxMSEh5QUU57okt0C<}Ef&;SAZkoH zh1U;K76R7c+37c1WOJxK0(|Dz2}Lm~EOdqMR{9b<4$U!7h#z3T?Zq<@YRROBFzaI6 zSIAZ*Ip~`mLOTE4U&t`Bg8v@BKbYEZ2YbPnXH^V*{GC@$lb=#3`2Cz`Q>Vrr?O7La z`B|bp4-2m(5djfQB-CPqYtnuio`sKBb5PXZDxcM&KOR<8ml$cm3mex>Uy%cjY? z+rYFIPoltm+*1*fT>`E78^7*{-5}IulHr^Emofgf;Pc13rTy(}81dlyO%dm)qnE^Bdmhp~z9%Ll%P z{TtWo!BIB^hdi}xWg8s3v^;_XjOS`PPr`wP5PXs6fXfVC6xC$8q-wFH&=k;i#owuJ zet>Yyh}rn;i|6IgmtOoq3%LIhc9_tTiMO%kIv6^B)b|gd+Ia~)DE<_ZB(G67C0){_ zZ`qANOI1UC^!RkHrG{;%HwhjGro;m``4$a|{cfipSG;LHQ|X^6Nl zj9ME=$^NhOr0+{RbjxQ?bv&+-q-#5rySXo!m9wXtx3@G8@`8hHp7cO4}cxD>@NRVeBwRkT{=FB}}a*EWhI51DZ&`Ht$z z?7q?aS2@@a!5w91$P?L|gTpDA5Fy257$}~`T_%i=*y|LYWmLD*JJxOn*mVOS;f}Ve zzKXnT_Inx`=Sb?m(b?bD!LE~N?MS1mIXKwM75Cg4deMFmI=!z))TQ&Dd1F`C7AloY zYK)2iQs=OIq6jZX#0(@Sk|F82tR|-&pic(R!@icHCk&wCU`N8p5rFvk4a&r{6A;H^-ysD5l4?T9ex2Bu}CTT(QAy7n!%9MsTQ&hOHE2+`Oc+jF#* zpk#r1$(M5p%eL--9T#&F>`}@CrJWt2X-Q2$>Uf0BV5DM`ouFF(mM}${43j*F{SIe? z96JjUQ(*jO@jBHRdgV<2sIqytEABfJ<>mzudw4_d)-E!bKDI%WI$;Qj_X|=qc@Pux z2Y#A+ZVmsjkM15zjd-7TLci?@Q~A*}g?D3`62IzEazy~x*~3XaVn!3Ju{7rk4=Y0& zC?Kt2_Yl#dmJucd86zZ)jDhSZS9@p?H>={R`4(1(`~YCXMdRUD?4X8&@u%sh7hrRL zxfaLykCSXTiE-?ktlX*TqXB*I5@F+@mrgfAbqIv___n0D0qQ}Naa6v(Jw97r(d3mQ z{}1376sw%134(Z%^l(34k~5;^MUHaeQ$fx?Siwhmtb$=NMhs$Q(d|53@AT*2ZwupD zF=4~Beh6-NNL(4~1V4+MEB6bL^-l677@zsn$f|F=1CkgP+9oQ$dI{l$zQr55vnu_G z(p|-O1OTuZBFe(OnCLx6%(7Srcf(zxnE7u%;KH;ooFvDHOtp+uZb)Q}99*L@HL;gA z>Dc|YCtX(QzF4iB-%usU%=b_GTEiW)ITLVBuU$z+tyP_;Y$Qj0G@zPr<%z}Y(B%n?L$CH|Wvp_eIi3#s+_#YrM+J>4ziuqR9Dw@D}@{C2z#n~5p zAWKP{nhdn*N7W)}-9|{V$N=Mh4ULhINOH_A!ZP|A%DqqRKjZ$Mk*uYD^waK+ymUQ0 z>ckQGJpxJp5bdvty!WuuZjh3E&io95jzuUv9@Gk~}{ry+*n_%l-Hk zEX`;ZlW4M}l!zh9(rgoAPwf{KhxVZ+^leHD$7?cTRSXD+2PSn(PWCS$OPa06Cw^Rh zDo_d_)c;})*F58O`XTS2JWCYSyz5O)CC!#nGT#z4wP_6QPX!1qd2i}0rlJYfic}u; zm#(4jBO!j{T~7EQT2`W(H5b(v3qJ2hr#JgJd9?jvD~u#>*T6I8FnQ$db9N{aA3}PlzM&hJu1v7TxzUe&B*cliWO|yD*Va(D|8C;= zHX{81dDAL2gHFy!G>yz=taGBNhw@AnETORx&#CLw;fdZHAd5`0O?vZ|TiD7hSBF{F zHQo)yx+T4&(mCpfmJtAHMOn}ly>)e1U=db!PcTH^R!fhQ1Z7m;<1^0>K$Mo<{HEL~{{gC^Ka&MUV-}KiKk)w{`mi?j zecJo^ELOa!o)fTcEO$UKjH_RwBRp|8?HlV~6so~xXg8y4EDizp)Blo`&5X?bC z9^e>1UV>xt)-#fk5Edf`QXC;_@;blo>G_^eP7~(<&7N_*9pNGP(LUnsUx0{C8(Qc} zS~XB?Kcs;Ws!Hbk{%5$6Pw4VT3e(D*ird9|uIAX;fltQ)fmLMnJ?p1MZ!G!SM#B&T zBi5jA4#B8{%cN7Rn0|Y_W=_rNzwCeSR(vdsrAj@yag7Y`Vs%mtbogkCI`q*X{b)(< ztd6~&+HkK;jS2um%u)Tbs?sY1?ezqVie%ror*7&kM;`xC4sIJk@FFsMo6KBz-!$mG zhOy|KI|f3LY`bpsFAs7u)3cHB#ObWyp~-dUv!0Hv91DuQe=|{nJ@K0Y#|U z?4FFUo6m@IjWFBpv{I1(fe$8O#^A^6&9$EU;3Xg?BsNy_PeA9pu~@1kHPXex0sMp= zB9u2k(3M)ZH2BdL&j@Ax{Ui-$x(TLrs3<3GK>V zr}+PJOyF0bb+$?Ke`Hr+HE|}QUVTwFa*U)hmZ~>!niXM-Sc3`{eLX*{AL6*=~53IV!p*k34F7RQLl6Gc~xd_X3 zQM5jKsQ@=qvsX8400xC8x;1MJr>Xhx z(As|iG8n&EvGL&G=II1Yv>7I9zLb0tI8VuuPraIgvrRf&+ih*Lr(Ak zaD~b}%#+F9h}3>0L0e6bT2*8xpjikgE#V?`Ca|YNKmzwNF7b#YuSDz15)nf_@iMi) zBqq}rGdE1b#rjW;J)hs6Pha)GF|T}4+1S2>c8D86(w0QcB}D-OKy@{Wy# zdFo^o?P!F*Z;c~=AmiufW{%Jk2hNJ~Z2w<_4Ceg|#_ zp+fu^1pR$zq&O`&3O$F_PCyHqu;fNshNSm#8pj}!q6_4}L`DigjvUnDV|BL~V4xmS zK-I1v5p^Arsb=d17NiYi8_F-KbB3?TZ&bAB)C?2K(I5yUgyzp}@L&?A(@VSakXZY3 z%k2CNHMZ6-{ z3299>J>K|R4vRL`l){-#t!{{!q!oux35!DLDm%5SPZ{TY1wRDEx&PNvjJoAZgc}PR68FcjN9Be6ZR7E#f}C*fowkz z5vv0e)tj`TKH~|c}axOzWE_k3|8fO87W*cAFEm*NK#<77cjde(Q;69MzY2> zvE}y2`?-w;HI_9pfcPcEbg}?<{vV)RMR-MDx+E$?{tW*|DS|(QN*C3L1C^aTRdWR5 zV_Jg;W_IEg$C-HSAL;xMi+EvD?bwJOp63DNricCV$bxR|x zsI71Krm=xWCWQ)wdPN)M6zQ}Fnp;#N=lx={#cdTt>W+a#Y)g|$6JTX(@iZXTE&**F z63~-u#q|i%-xAII6qh`)%d}=6Z^nL2Z;27#V*IqB$@WLWpD5n*edKRzic(7`SsSyb zc0aZs>kLIximpr;dfKdqbT2r2P(x zx+8nPr5-0fyjhN<`BkVK0guHX4qTlf5kB+TELNL}T@gH!uUkX8B(Mao15>5@)_Igv z?x+3fl|a2Tlgt^>io{$mm{zg6UMig=JzFb&e0rQx2w=Sa2MBrPC-xAlWDszbY^>#f zZHJd*n7x$&&KS*$@;5oh2*tdBgPQwC8uNtR}QrYf^0%%o{)N}!`; z?T1LgC=z2AvgpE!x7O(o6c(X!=UPBIV&g#z2HyThlLIjUSQ9?YR?oHcq zoF_8(`0->dP#m0^rHr2w$c8nH*TmvBmAOG9jTfa5PpHt;&fh!v2dt`Z;X#K(fhdi} zz~qrZ3@o6w)h_QpE5^EHdVG%9e`P z+jW8mrOgQKX$^a|tirD}>z8Sr;sYT(RzJk2uA(3tub2J=|-sj)LQXTKFR{s`vgvG%%(aL-9VD`8z%@^C;WT4CkI z$3$hQLbzv=(U-Sshb@z!VPg&FB!jr8h`N?$yk#Uw*~{dp%$ z7He!(X)KY331n^g8yuzHNTZn2S9vauYS9j}c)thN9JLDC3)*p8`tKRd8pQmiY6( zTeGUU-5yH&QO0xal=S{%EEq<*J_sce;IH6XXhIp*;HO`hDgD+kufQMBYP8J(R^|lalAM+iV6Qv0ExT$1-4YPMVftBml2_z9oLCItv&pSUq*uR+oJL1C)4zmOT4m8^(qO^cPWXt+7ykj(TteA#KCa(n~aAFdpmnI`h zG0D`Z4$-A*+CuJk&&*y;ozCh>CWn4aWxf|z#Xqbfv@ufQg)u#qs?b_QdbFg+2~WNx zl<*u4f*57XhSNsGQW_b;pQ}6*ho0T^p(9rEv#lid^qEU!U|h8H>2|9e zL>M-zcAs~@YV0=GZj>4~Az9B^k}6u6u^{Ms6>wr8B^NegBjnI#+0>FOz1Jd|_xhO^ z7#JK;G8T@^6D22(>Pd?NFe596;ep#Sd*2V0=;=^|(I}Poy7^{`hQa$=FZ;wH%Da_Y zu*yiO3jThKU*%Q`HblVE+}(pgE=GfDoiOgivlLgv_erSh!LEMWI$E{G%AW%)m46P+ zQI?6|9sH({jbYa_sx8rDI~Z!4q7in>)ww9u$2r!y@c0lv_oeWt{YGXppP16_t5ZV6 z+wPBC%(z@jNy$O$<852*6aoW{uP)Q}5aSZs(e4Y9>(z9^Ju%P@19EHoGSMw@WI7N* z*<@bj0G>ppL@Y8lHOtubc|Vm9DV;5`cH2#=&zj!@bxbsp08d3Bu#Pm9VGyqi$~zk(a44+?Y}h+wL}&M!JRIXxo4i^Ly3@!t2w)+o7~= zIKd@}URmX;V1GgZDKQFGImukMpse|B0Z+3t>fIFateY*7J3ugcfg(p8GV$|Jpv$QO zX*@A2K-=TX#vWqzGR?8*c}XslzPl)}50Y&v+$fOE)*r4(>HA4}o+cx_{~iuc)(ZXA zBpI~)@l4pQD6I6=_|IGtyd`A{turvLsvCd5i1YSMZ(%fv zJW5gll|ndjruXbwmn}|to}1Bb4OU>!^fR8G)p9zfma(d3SRq>rKk4S!VYf7(zvlB7 zOg(OW^aZ!r{@)oxU(gkm9XB^La>6Tu5Z?xC3yFv7>LFUDF%=yARP=bY|1pp0Grf23 z%ucHOf~jJ-Cq*PMb35W$Y1d}i<+SL8z_Q?s*s+*s9wz#uthO$^PCD!MJNF4t8}%dl zaOA*Eca{SV+if?mwB)6Ev57HCbB z@4(UFz&tp;pQD;FU^%m)WMndpODR!0)m;xSyW4RPUqL5^B-O1|L3s+tD`Fi5Zd--T z0Ev)s6|Q#Z-|euI;^N0XisG8TqJYm(_n5W)sNNJQ%q7;?p=3;v-=M86xF7*kvV7(jg6P z8xbdF$!TOwQ)yP_82dgEre_?@K*@;U5qSs4J5Lm;FM{VrPd2U%dMxZBuJ>2hen+yG z#PcoGkeAI7%PiLYiHob83m&AH6n3}x9<5=1AFbJ7{i%n`euRAvNW^Xqy` z*C_;ORoGbh=Mf7_WFZoQL<&dy6I*ZFX?Z3rm-Bj)NGt}o+yX2Ww-={{8Zs@R_x_Sd{VoahE&Mk++6UfP{b6NrBF zQRk?U!YDg&r{&J6U9vC0Wb$5t7qx?SP0}?besoz6g#xjfu``D|f^d!05gB_A7B5cU zoJOWle8CwSyoVDcB6GeXPZ6=ZzOcTSNB=LrZEB1$UEPx@ zVKmVq+Su_jsao!x+w*~Sl32bRJ-M3GBFfrSvi2W~K|RcjkqBkiMU^5?oyN9-bZ_!T zgGFue#d)og&RVH4-L#H;L_7w9i|(KGd2q>)f^eU12TA!QsJg$y_YDl8y0~2%rlNXB zMc<$NFJC43A%T<`{w2Ytzs~)MGsM1yP(}Fpa5%Q^ujjRp_S<4J=l^+m3K|J0Em+%M zkHHU(QT1UzVt-%NKr+^BCG+?8Y0}7(c0ykud3=9Vy}pu0fQ~`X;95k1f~+#b90LZ? zZ(Z;+iv>w_D&Je(m?p_GUh@?dn!2A4Y{`A)KJjkkU77fX)l6Qv|H1h+KteKA!q|4jKgPSL~B;|6on&5i%w2+01Yu!p<&UzL3i0eO|P2Y}rfg|i(G zscPJQW756CHzUBh)y`>4`NKazcCOp%RWLN^Ox^vkKLyzvb{8|;?f(oMk!+TwdPg{W zoa0fX){=1%R8W=vcfUHQV3vG`dKyhdwOF+6ZNhk#2#EO2e%oZjxLa zg(o*Xzjv<{g&hB>wdLb8*$VIt@ojHf47hC^ZJh>`2@R-D{|Y@g=_Jc|#=T}#-1@^O zJkp zYN-#}N{h458L(a7|vJSQhhseyKEfT50a1=x%_m48FC6t#SI_2)vNr@AQn` zZzOK+iblP(vjc2Br{v~a+B0MLrUTX|S#GA4PYVwzjMY?M_X7N}4AX3WyI(%HK222Q zy|7gDb?}Zc--Vs(8u=u>NWAUJ0Cu$UayiT7s*XE3dI___#>8w3KkoTl?0w=MQ#$MN zqbne&K(T}ATEw^DDR8q_xnbaT=EWT5n0jyx<6bd6TTdcKlr3PrySaGWBKAy!Nh12N z_q-HNOi203|n28==5?hmZmEF(J z-Hol3l9Bqi?VCNmqbnqC(=?;d2+XyBwfI>yX|UE8_&)&e4i8nKEW&(Sb}v;sa@%~c z+mUG@rCXR7TI1^ny;}9S(ECu(`vhfF!5l5vT@Z3=qM2zXDR<|RPdD7bdEI!Df!*}S zo4lzH$UsPW+PKo)reL8L;xFdp?{42aCwY&{6fjTveL}&!_V=m%pDw>GeF@jmN7wC0 zj#^h>u>1V?(;==pNXU-Og_!+BJj%Fhv)Ch?mS=os$@6Xb>diJ&{=(0fbyJCl)X}$P z@THrD)$OXtP;|pjCq{>j*o#`R7X2(H-@jcUBJi|{oYo(-GQ96a8tBqDyJnf%pJuSq z#PVNHr;6#mQ;o;|SRQNgm_n@(W`s0sPQ`J$u@3r!i#n=S=;}a6uwfvj`er49Sl0F1 zg99~l&+{dPswI(V*Hm4PVBXCJHI7n>QgdRy^G+1uX_C6~5K*-k4T}a~yOmPFAlAz= zdIo2GI^A9)PHt$bFjwDgXCNWyutKDK$B*a zhGTZ_MQwd49D_m2OW5~V)VJ^PRiz@f(#gyO-+z8Nef8}7UNRAlyhK96TxB{OgH+2SkOqP zWYmYn4s7(1jUS)tyIs^9tY52p1)~yW?c0o(#fC8$;0q{?%FgOaRs_M0?6R?h6iT}u z+wLCCXf>I?e?XTzp)rT;@t)6v^D`0`^uj&NBn)xo`XKHqx&<$4m^JsBz6-=)cE(>sb$&oHTpA(7-FP9?3`Z_+`dOhI@35+&T( zzxIW$kA$aF0MyDjaohs2sYYJOO?$#qQTceHEuw`1RA0StgStZaOn=l6$}6p16*byi zCx0<}2&jZAKZtblKyx&x)gV{j`7193d5lc?g_RnWx}kDe%t7yM8$WH2^!>OAJDz{y z-4sMxW#8v&Z>(xWYpz*}du@}#>-H8#y_KTAO6%MS)n*lDHwlEGOgD5 z==V%w%_EX?doB{pU_vI9-sh->y|?Oy2Pm;Cl70r`BA#8ei)kI1 zqZ1|mzq;%$U)KB%cn>^$^Y0fa3$T!21Ra9Mo;}_9@@P3?F2XNwS>t=hlkta9NvDez zC1+?XWJTSuR@XC#kqBaih8NrCf0_>h(GhS~#L(W>xI7NFX zq?H5Q>?ykMZpLimkdil4?i+(@w=w$6K~-N6i-JVGso%7(P}fuQcb!>NFn^iex@~xs zRp;mB+@Cg>L>UKL74>8btNU!o`X0sy6i&4bK?Rrnv5E-`Cny?bkL(9xCl0u}+cw)q z1*aA#-dtD?XNSTtfszjif7Rqj_u}OGL&VO4`03LVbI!UC_n)~BCqt1DIG79ke%yBO zfAzP0e9>CUF_XrfP(~su7P)BTh9Khz1a5u4G2;+W;xZL4_HjRu19^jdPd9of@^;M| ztB9w+iO9O0OFGr}NURCp4l#_qD4RUDm6-k6`Pg7}1aI*3DWSwlvAO7mFHx#uM8G&S z*Y%qF)`3jM6r#q|YC)deC;>^jfAtJH40;itto`+UPm6FhaMSBkDv6)@nd$0y?#JUS z^N%KwwJpz?Wy0{+6iV$T=b=*BR3G3UdH@4ZDN>(RiclMlyJ zZmtrz8(pNgytl51Mp%{{SnGwhArxh?S9+Rw(@ zZ*GJ9;yay@cc=au-O|5dp2lBo{`+*la5P_rTM+Pq!XM24SCY&HPh)9+8q9c)IC(QM zk#eyeI}1uanJT)VUs+g26_rZxEb0>R9UiuzT5j)K5`T2JqNjDq6>dL#@VSszf4A89 ztwV(8deoyOedF$_{+OK=iBIvz7H4ViZ7q(z>QuF-N)7|dhQmtjt=gy1j zFO{U8ixTvi@W+P@8nREJFCoOdXS#(~*PYaPf7-a=Z1>Mh{q?yM=Vu;>FLem`cDbt)|++~mlQ+a}lE2@i3e%?Vu=brK1WiOYeI zFQ&=5y7}!BMLkKE^c!gX0FKh;m{(#>v+b+{R!mNCsT2S9AU_qK?AhAo+uWz!t=GT3 zM7Zn1QPkM*!1H?Xp1IC567O)h5so)am-AiZ@LHvg6@#Sr`K25MErf7#$|l`##Wr_> zkZP71{&Wtvi(#a!i&FN6<)3DR4_gb5!$z-H__J~6_|`?2*ORQZ1_RSvk4WHE-1uT@ z>&LF3i<61{>As(*<7~9eUnW+kJ8xs~^-qX8Bjq8kPOHgF=?ez9iavh`ibNcM@;bq7Z3xyhb z(BwZr*ImCO`cB@|<>_rV-3JPFooThoKoL(Mp{{m<&G^=C&gABAK)>{${i3Y%&4&3a z;201IQX>v?moNuoQtekJW%iP=5}b1#o%Xnh4lLO|9)*X?UY_O?#|;u_lOf`@wWK-BHLZ<}IKRI>eKoX3rp;19>!2=#~cKpnh} z^nGJfs)Pko=~Ai&W{KD6Din9I7pX-UHs)RQd2t9u9x0cNWhZ>0U9|{>Rh;*8AK#*A z=a~TTFEud2-SSy!u8iBYoL8@ju(@AYD{4YNXA?Y!~0R-C^eOQk>Wmk8mQ98{}s`EQstyAP;v<{`P!Lq;=~{&g+pJqWpWGe4`i*rS^bY zxU6}I`ulM`x2!7#!3Z#3rQ)4~ZD>kVzx7YHoXP1>p*@jq$&Mh1|MpSi40aLvL|#A< z%Jb=_LwCppQ`COR<;+Wn3*GD9jH>k0D~V;%-7P&70m%M`#~_imdjtn#$RCr7`_nXG zSrGckXQUJ3#4Y5EuvLh;@hx+~c4P%071`pA