diff --git a/engine/src/C4PlayerControl.cpp b/engine/src/C4PlayerControl.cpp index 9cc6d93fe..74be2587b 100644 --- a/engine/src/C4PlayerControl.cpp +++ b/engine/src/C4PlayerControl.cpp @@ -204,8 +204,12 @@ bool C4PlayerControlAssignment::ResolveRefs(C4PlayerControlAssignmentSet *pParen KeyComboItem &rKeyComboItem = *i; if (rKeyComboItem.Key == KEY_Default && rKeyComboItem.sKeyName.getLength()) { - // this is a key reference - find it - C4PlayerControlAssignment *pRefAssignment = pParentSet->GetAssignmentByControlName(rKeyComboItem.sKeyName.getData()); + // this is a key reference + // it may be preceded by CON_ to avoid ambigous keus + const char *szKeyName = rKeyComboItem.sKeyName.getData(); + if (SEqual2(szKeyName, "CON_")) szKeyName +=4; + // - find it + C4PlayerControlAssignment *pRefAssignment = pParentSet->GetAssignmentByControlName(szKeyName); if (pRefAssignment) { // resolve itself if necessary @@ -303,7 +307,8 @@ void C4PlayerControlAssignmentSet::MergeFrom(const C4PlayerControlAssignmentSet for (C4PlayerControlAssignmentVec::const_iterator i = Src.Assignments.begin(); i != Src.Assignments.end(); ++i) { const C4PlayerControlAssignment &SrcAssignment = *i; - // overwrite if def of same name existed if it's not low priority anyway + // overwrite if def of same name existed if it's not low priority anyway? + // not so easy. Keys may be assigned to multiple controls and we may need to overwrite one or more of them... C4PlayerControlAssignment *pPrevAssignment = GetAssignmentByControlName(SrcAssignment.GetControlName()); if (pPrevAssignment) { @@ -333,7 +338,9 @@ C4PlayerControlAssignment *C4PlayerControlAssignmentSet::GetAssignmentByControlN { for (C4PlayerControlAssignmentVec::iterator i = Assignments.begin(); i != Assignments.end(); ++i) if (SEqual((*i).GetControlName(), szControlName)) - return &*i; + // We don't like release keys... (2do) + if (!((*i).GetTriggerMode() & C4PlayerControlAssignment::CTM_Release)) + return &*i; return NULL; } diff --git a/engine/src/C4Script.cpp b/engine/src/C4Script.cpp index 5deb18392..6eb33a521 100644 --- a/engine/src/C4Script.cpp +++ b/engine/src/C4Script.cpp @@ -753,6 +753,13 @@ static bool FnSetActionData(C4AulContext *cthr, long iData, C4Object *pObj) return TRUE; } +static long FnGetActionData(C4AulContext *cthr, C4Object *pObj) + { + if (!pObj) pObj=cthr->Obj; if (!pObj || !pObj->Status) return FALSE; + // get data + return pObj->Action.Data; + } + static bool FnObjectSetAction(C4AulContext *cthr, C4Object *pObj, C4String *szAction, C4Object *pTarget, C4Object *pTarget2, bool fDirect) { @@ -6509,6 +6516,7 @@ void InitFunctionMap(C4AulScriptEngine *pEngine) AddFunc(pEngine, "Bubble", FnBubble); AddFunc(pEngine, "SetAction", FnSetAction); AddFunc(pEngine, "SetActionData", FnSetActionData); + AddFunc(pEngine, "GetActionData", FnGetActionData); AddFunc(pEngine, "SetBridgeActionData", FnSetBridgeActionData); AddFunc(pEngine, "GetAction", FnGetAction); AddFunc(pEngine, "GetActTime", FnGetActTime); diff --git a/planet/Objects.c4d/Clonk.c4d/Script.c b/planet/Objects.c4d/Clonk.c4d/Script.c index c6684b449..cda3ed00c 100644 --- a/planet/Objects.c4d/Clonk.c4d/Script.c +++ b/planet/Objects.c4d/Clonk.c4d/Script.c @@ -2,12 +2,6 @@ #strict 2 -// Zauberei - benötigt, wenn der Clonk Zielzauber z.B. aus dem Zauberturm zaubert -// Auch benötigt für den König -local pAimer; // Aktive Zielsteuerung; wird abgrbrochen, wenn der Zauberer gestört wird (Nur Fantasypack) -local pAimedSpell; // Zauber, der gezielt wird (Nur Fantasypack) -local pAimedSpellOrigin; // Objekt, das einen Zielzauber initiiert hat. An dieses werden SpellFailed/SpellSucceeded-Nachrichten weitergeleitet - /* Initialisierung */ @@ -39,8 +33,6 @@ protected func Swimming2() /* Bei Hinzufügen zu der Crew eines Spielers */ protected func Recruitment(int iPlr) { - // Alchemieregel: Jeder Clonk kriegt einen angelegten Beutel spendiert - if(ObjectCount(ALCO)) CreateObject(ALC_,0,0,-1)->~BelongTo(this); // Broadcast für Crew GameCallEx("OnClonkRecruitment", this, iPlr); } @@ -70,82 +62,78 @@ public func FindTree() return FindObject2(Find_AtPoint(), Find_OCF(OCF_Chop), Find_Layer(GetObjectLayer())); } + /* Steuerung */ -protected func ControlLeft() +public func GetInteractionTarget() { - // Steuerung an Effekt weitergeben - if (Control2Effect("ControlLeft")) return 1; - // Steuerung an Pferd weiterleiten - if (IsRiding()) return GetActionTarget()->~ControlLeft(this); - // Keine überladene Steuerung - return 0; -} - -protected func ControlLeftDouble() + // Contained interaction target + var container = Contained(); + if (container) { - // Steuerung an Effekt weitergeben - if (Control2Effect("ControlLeftDouble")) return true; + if (container->GetCategory() & (C4D_Structure | C4D_Vehicle)) return container; } + // Procedure interaction target + // (Except for FIGHT, of course. You can't control your enemy ;)) + var proc = GetProcedure(); + if (proc == "PUSH" || proc == "PULL" || proc == "BUILD") return GetActionTarget(); + // First contents object interaction target + return Contents(0); +} -protected func ControlRightDouble() +public func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool repeat, bool release) +{ + // Generic movement + if (inherited(plr, ctrl, x, y, strength, repeat, release)) return true; + var proc = GetProcedure(); + // Handled by InteractionTarget? + var interaction_target = GetInteractionTarget(); + if (interaction_target) { - // Steuerung an Effekt weitergeben - if (Control2Effect("ControlRightDouble")) return true; + if (interaction_target->ObjectControl(plr, ctrl, x,y, strength, repeat, release)) return true; } - -protected func ControlLeftReleased() -{ - // Steuerung an Pferd weiterleiten - if (IsRiding()) return GetActionTarget()->~ControlLeftReleased(this); - // Keine überladene Steuerung - return 0; -} - -protected func ControlRight() -{ - // Steuerung an Effekt weitergeben - if (Control2Effect("ControlRight")) return 1; - // Steuerung an Pferd weiterleiten - if (IsRiding()) return GetActionTarget()->~ControlRight(this); - // Keine überladene Steuerung - return 0; -} - -protected func ControlRightReleased() -{ - // Steuerung an Pferd weiterleiten - if (IsRiding()) return GetActionTarget()->~ControlRightReleased(this); - // Keine überladene Steuerung - return 0; -} - -protected func ControlUp() -{ - // Steuerung an Effekt weitergeben - if (Control2Effect("ControlUp")) return 1; - // Steuerung an Pferd weiterleiten - if (IsRiding()) return GetActionTarget()->~ControlUp(this); - // Bei JnR Delfinsprung - if(GetPlrCoreJumpAndRunControl(GetController())) - DolphinJump(); - // Keine überladene Steuerung - return 0; -} - -protected func ControlUpReleased() -{ - // Steuerung an Pferd weiterleiten - if (IsRiding()) return GetActionTarget()->~ControlUpReleased(this); - // Keine überladene Steuerung - return 0; -} - -protected func ControlUpDouble() -{ - // Steuerung an Effekt weitergeben - if (Control2Effect("ControlUpDouble")) return 1; - DolphinJump(); + // Dolphin jump + if (ctrl == CON_DolphinJump) return DolphinJump(); + // Context menu + else if (ctrl == CON_Context) + { + // Context menu of interaction target (fallback to this if no interaction target) + if (!interaction_target) interaction_target = this; + SetCommand(this,"Context",0,0,0,interaction_target); + return ExecuteCommand(); + } + // Throw + else if (ctrl == CON_Throw) + { + // During Scale+Hangle, this means "Drop". During dig, this means object dig out request. Otherwise, throw. + if (proc == "DIG") + return SetActionData(!GetActionData()); + else if (proc == "SCALE" || proc == "HANGLE") + return PlayerObjectCommand(plr, false, "Drop"); + else + return PlayerObjectCommand(plr, false, "Throw"); + } + // Dig + else if (ctrl == CON_Dig) + { + if (proc == "DIG") + { + // Currently, another press on dig ends digging. Maybe changed once we have the shovel system? + SetAction("Walk"); + return true; + } + else if (proc == "WALK") + { + if (!GetPhysical("Dig")) return false; + if (!SetAction("Dig")) return false; + SetActionData(0); + return true; + } + // Can't dig now + return false; + } + // Unhandled + return false; } private func DolphinJump() @@ -166,105 +154,6 @@ private func DolphinJump() SetAction("Dive"); } -protected func ControlDown() -{ - // Steuerung an Effekt weitergeben - if (Control2Effect("ControlDown")) return 1; - // Steuerung an Pferd weiterleiten - if (IsRiding()) return GetActionTarget()->~ControlDown(this); - // Keine überladene Steuerung - return 0; -} - -protected func ControlDownReleased() -{ - // Steuerung an Pferd weiterleiten - if (IsRiding()) return GetActionTarget()->~ControlDownReleased(this); - // Keine überladene Steuerung - return 0; -} - -protected func ControlDownSingle() -{ - // Steuerung an Effekt weitergeben - if (Control2Effect("ControlDownSingle")) return 1; - // Steuerung an Pferd weiterleiten - if (IsRiding()) return GetActionTarget()->~ControlDownSingle(this); - // Keine überladene Steuerung - return 0; -} - -protected func ControlDownDouble() -{ - // Steuerung an Effekt weitergeben - if (Control2Effect("ControlDownDouble")) return 1; - // Steuerung an Pferd weiterleiten - if (IsRiding()) return GetActionTarget()->~ControlDownDouble(this); - // Keine überladene Steuerung - return 0; -} - -protected func ControlDig() -{ - // Steuerung an Effekt weitergeben - if (Control2Effect("ControlDig")) return 1; - // Steuerung an Pferd weiterleiten - if (IsRiding()) return GetActionTarget()->~ControlDig(this); - // Keine überladene Steuerung - return 0; -} - -protected func ControlDigReleased() -{ - // Steuerung an Pferd weiterleiten - if (IsRiding()) return GetActionTarget()->~ControlDigReleased(this); - // Keine überladene Steuerung - return 0; -} - -protected func ControlDigSingle() -{ - // Steuerung an Pferd weiterleiten - if (IsRiding()) return GetActionTarget()->~ControlDigSingle(this); - // Keine überladene Steuerung - return 0; -} - -protected func ControlDigDouble() -{ - // Steuerung an Effekt weitergeben - if (Control2Effect("ControlDigDouble")) return 1; - // Steuerung an Pferd weiterleiten - if (IsRiding()) return GetActionTarget()->~ControlDigDouble(this); - // Keine überladene Steuerung - return 0; -} - -protected func ControlThrow() -{ - // Bei vorherigem Doppel-Stop nur Ablegen - if (GetPlrDownDouble(GetOwner())) return 0; - // Steuerung an Effekt weitergeben - if (Control2Effect("ControlThrow")) return 1; - // Reiten und Werfen - if (IsRiding()) - if (Contents(0)) - { - SetAction("RideThrow"); - return 1; - } - // Keine überladene Steuerung - return 0; -} - -protected func ControlUpdate(object self, int comdir, bool dig, bool throw) -{ - // Steuerung an Pferd weiterleiten - if(IsRiding()) return GetActionTarget()->~ControlUpdate(self, comdir, dig, throw); - // Keine überladene Steuerung - return 0; -} - protected func ControlCommand(szCommand, pTarget, iTx, iTy, pTarget2, Data) { // Kommando MoveTo an Pferd weiterleiten @@ -291,6 +180,9 @@ protected func ControlCommand(szCommand, pTarget, iTx, iTy, pTarget2, Data) return 0; } +public func ControlDownDouble() {} // dummy + + /* Verwandlung */ private func RedefinePhysical(szPhys, idTo) @@ -400,6 +292,7 @@ public func Redefine(idTo) return 1; } + /* Essen */ public func Feed(iLevel) @@ -409,6 +302,7 @@ public func Feed(iLevel) return 1; } + /* Aktionen */ private func Riding() @@ -501,6 +395,7 @@ protected func Scaling() return 1; } + /* Ereignisse */ protected func CatchBlow() @@ -542,9 +437,6 @@ protected func Death(int iKilledBy) // Der Broadcast könnte seltsame Dinge gemacht haben: Clonk ist noch tot? if (GetAlive()) return; - // den Beutel fallenlassen - if(GetAlchemBag()) GetAlchemBag()->~Loose(); - Sound("Die"); DeathAnnounce(); // Letztes Mannschaftsmitglied tot: Script benachrichtigen @@ -583,6 +475,7 @@ protected func CheckStuck() SetPosition(GetX(), GetY() + 1); } + /* Status */ public func IsRiding() @@ -593,6 +486,7 @@ public func IsRiding() public func IsClonk() { return 1; } + /* Kontext */ public func ContextRelease(pCaller) @@ -644,6 +538,7 @@ public func ContextHome(pCaller) return 1; } + /* Hilfsfunktion */ public func ContainedCall(string strFunction, object pTarget) @@ -653,34 +548,6 @@ public func ContainedCall(string strFunction, object pTarget) AddCommand(this, "Enter", pTarget); } -/* Steuerung */ - -protected func ControlSpecial2() -{ - [$CtrlMenuDesc$|Image=CXTX] - // In einem Gebäude oder Fahrzeug: das Kontextmenü des Gebäudes öffnen - if (Contained()) - if ((Contained()->GetCategory() & C4D_Structure) || (Contained()->GetCategory() & C4D_Vehicle)) - { - SetCommand(this,"Context",0,0,0,Contained()); - return ExecuteCommand(); - } - // Fasst ein Objekt an: Kontextmenü des angefassten Objekts öffnen - if (GetAction() == "Push") - { - SetCommand(this,"Context",0,0,0,GetActionTarget()); - return ExecuteCommand(); - } - // Trägt ein Objekt: Kontextmenü des ersten getragenen Objekts öffnen - if (Contents(0)) - { - SetCommand(this,"Context",0,0,0,Contents(0)); - return ExecuteCommand(); - } - // Ansonsten das Kontextmenü des Clonks öffnen - SetCommand(this,"Context",0,0,0,this); - return ExecuteCommand(); -} /* Callback beim Auswahl aus dem Construct-Kontextmenu */ @@ -692,6 +559,7 @@ public func ControlCommandConstruction(target, x, y, target2, def) return FinishCommand(this, false, 0) ; } + /* Automatische Produktion */ public func ControlCommandAcquire(target, x, y, target2, def) @@ -751,6 +619,7 @@ public func GetProducerOf(def) return FindObject2(Find_InRect(-500,-250,1000,500), Find_Func("IsProducerOf", this, def), Sort_Distance()); } + /* Trinken */ public func Drink(object pDrink) @@ -762,6 +631,7 @@ public func Drink(object pDrink) // die Potions löschen sich meist selber... } + /* Einsammeln */ public func RejectCollect(id idObject, object pObject) @@ -788,6 +658,7 @@ public func RejectCollect(id idObject, object pObject) return GetNonSpecialCount()>=MaxContentsCount(); } + /* Itemlimit */ public func MaxContentsCount() { return 1; } @@ -884,24 +755,6 @@ public func DescendVehicle() } -/* Effektsteuerung */ - -private func Control2Effect(string szControl) - { - // Von Effektzahl abwärts zählen - var i = GetEffectCount(0, this), iEffect; - var res; - while (i--) - { - // Effekte mit Control im Namen benachrichtigen - iEffect = GetEffect("*Control*", this, i); - // Message("%s", this, GetEffect(0, this, iEffect, 1)); - if ( GetEffect(0, this, iEffect, 1) ) - res += EffectCall(this, iEffect, szControl); - } - return res; - } - /* Pfeile */ @@ -973,170 +826,8 @@ private func GetArrowCount() } -/* Zauberei - benötigt, wenn der Clonk Zielzauber z.B. aus dem Zauberturm zaubert */ +/* Dummies, damit die Engine die Namen kennt... */ -public func SpellFailed(id idSpell, object pByCaller) -{ - // Umleiten an eigentliche Zauberquelle? (Buch, Zauberturm, etc.) - var pSpellOrigin = pAimedSpellOrigin; - pAimedSpellOrigin = 0; - if (pSpellOrigin && pSpellOrigin != this) - // Auch bei nicht erfolgreicher Umleitung abbrechen: Das zaubernde Objekt hat im Normalfall die Zutaten/Zauberenergie für den - // Zauber bereit gestellt, und diese sollten nicht an den Clonk zurück gegeben werden - return (pSpellOrigin->~SpellFailed(idSpell, this)); - // Magieenergie zurückgeben - DoMagicEnergy(Value(idSpell), 0, true); - // Alchemische Zutaten zurückgeben - if(ObjectCount(ALCO)) IncreaseAlchem(idSpell); -} - -public func SpellSucceeded(id idSpell, object pByCaller) -{ - // Umleiten an eigentliche Zauberquelle? (Buch, Zauberturm, etc.) - var pSpellOrigin = pAimedSpellOrigin; - pAimedSpellOrigin = 0; - if (pSpellOrigin && pSpellOrigin != this) - // Auch bei nicht erfolgreicher Umleitung abbrechen: Das zaubernde Objekt hat im Normalfall das Magietraining schon erledigt - return (pSpellOrigin->~SpellSucceeded(idSpell, this)); - // Globaler Aufruf für Zauber - OnClonkSucceededSpell(idSpell); -} - -// Der Clonk kann von sich aus nicht zaubern und hat keine Aktivitäten dafür -private func SetMagicAction(id idForSpell) {} -private func SetCastAction() {} -private func EndMagicAction() {} - - -/* Zielsteuerung - nur aktiv, wenn das Fantasypack die globalen Funktionen CreateAimer und CreateSelector überladen hat */ - -public func DoSpellAim(object pSpell, object pSpellOrigin) - { - pAimedSpell = pSpell; - pAimedSpellOrigin = pSpellOrigin; - pAimer = CreateAimer(this, this, GetDir()*180-90); - - if (!pAimer) return 0; - - // Callback an die Zauberquelle, dass noch gezielt wird - if (pSpellOrigin) pSpellOrigin->~SpellAiming(pSpell, this); - - // Zielvorgang für Zauber - SetComDir(COMD_Stop); - SetCastAction(); - return pAimer; - } - -public func OnAimerEnter(int iAngle) - { - // Zauber weg? - if (!pAimedSpell) return OnAimerAbort(iAngle); - var idSpell = GetID(pAimedSpell); - // Aktivität - SetMagicAction(); - // Zauber benachrichtigen - if (!pAimedSpell->~ActivateAngle(this, iAngle)) - { - SpellFailed(idSpell); - return 0; - } - // OK; Zauber erfolgreich - return SpellSucceeded(idSpell); - } - -public func AimingAngle(int iAngle) - { - // Zauber weg? - if (!pAimedSpell) return OnAimerAbort(iAngle); - // Zielaktion setzen, wenn im Laufen. Das ist etwas ungeschickt, weil damit - // die Magic-Aktion abgebrochen wird, die der Magier bereits bis zur Haelfte - // durchgefuehrt hat. Dummerweise laesst sich frueher nicht feststellen, ob - // der auszufuehrende Zauber einen Aimer brauchen wird... - if(GetActMapVal("Name", "AimMagic") ) - if(GetAction() == "Walk" || GetAction() == "Magic") - SetAction("AimMagic"); - - // Phase anpassen - if(GetAction() == "AimMagic") - { - // Auch richtigen Winkel verwenden wenn nach links gedreht - var iHalfAngle = iAngle; - if(iHalfAngle < 0) iHalfAngle = -iHalfAngle; - SetPhase(BoundBy((iHalfAngle + 9) / 18, 0, 9) ); - } - // Weitergabe an den Zauber - return pAimedSpell->~AimingAngle(this, iAngle); - } - -public func OnAimerAbort(int iAngle) - { - // Aktivität zurücksetzen - EndMagicAction(); - // Benachrichtigung - if (!pAimedSpell) return 1; - var idSpell = GetID(pAimedSpell); - if (!pAimedSpell->~AbortAiming(this)) - // Standardaktion: Zauber löschen - RemoveObject(pAimedSpell); - pAimedSpell = 0; - // OK; Zauber nicht erfolgreich - return SpellFailed(idSpell); - } - -public func DoSpellSelect(object pSpell, int iRadius, object pSpellOrigin) - { - // Zauber sichern - pAimedSpell = pSpell; - pAimedSpellOrigin = pSpellOrigin; - pAimer = CreateSelector(pSpell, this, iRadius); - if (!pAimer) return; - // Callback an die Zauberquelle, dass noch gezielt wird - if (pSpellOrigin) pSpellOrigin->~SpellAiming(pSpell, this); - // Zielvorgang für Zauber - SetComDir(COMD_Stop); - SetCastAction(); - return pAimer; - } - -public func OnSelectorEnter(object pTarget) - { - // Zauber weg? - if (!pAimedSpell) return OnAimerAbort(); - var idSpell = GetID(pAimedSpell); - // Aktivität - SetMagicAction(); - // Zauber benachrichtigen - if (!pAimedSpell->~ActivateTarget(this, pTarget)) - { - SpellFailed(idSpell); - return 0; - } - // OK; Zauber erfolgreich - return SpellSucceeded(idSpell); - } - -public func OnSelectorAbort() - { - // Aktivität zurücksetzen - EndMagicAction(); - // Benachrichtigung - if (!pAimedSpell) return 1; - var idSpell = GetID(pAimedSpell); - if (!pAimedSpell->~AbortSelecting(this)) - // Standardaktion: Zauber löschen - RemoveObject(pAimedSpell); - pAimedSpell = 0; - // OK; Zauber nicht erfolgreich - return SpellFailed(idSpell); - } - -public func SelectorTarget(object pTarget) { if(pAimedSpell) return pAimedSpell->~SelectorTarget(this,pTarget); } - -// Momentanen Zauber abbrechen -protected func AbortCasting() - { - if (pAimer) pAimer->Abort(); - return 1; - } - -public func Abort() {} // dummy call to instantiate function name +func Activate() {} +func HowToProduce() {} +func PackCount() {} diff --git a/planet/System.c4g/C4.c b/planet/System.c4g/C4.c index ee5f0bba2..656355263 100644 --- a/planet/System.c4g/C4.c +++ b/planet/System.c4g/C4.c @@ -2,6 +2,7 @@ #strict 2 +/* proplist changes aren't in this branch? // stuff for the proplist changes static const DFA_NONE =-1; static const DFA_WALK = 0; @@ -28,18 +29,15 @@ global func GetActMapVal(string strEntry, string strAction, id idDef, int iEntry if (!idDef) idDef = GetID(); if (strEntry == "Facet") strEntry = ["X", "Y", "Wdt", "Hgt", "OffX", "OffY"][iEntryNr]; return GetProperty(strEntry, GetProperty(strAction, idDef)); -} +} */ global func CastC4ID(x) { return x; } -// Abgelöst durch SetPosition -global func ForcePosition(object obj, int x, int y) { return SetPosition(x, y, obj); } - -// Abgelöst durch RemoveObject -global func AssignRemoval(object obj) { return RemoveObject(obj); } - // Für Szenarien ohne Objects.c4d... global func EmptyBarrelID() { return BARL; } +global func GetBarrelType() {} +func BarrelDoFill() {} +func BarrelIsFull() {} // Fügt das Material in ein Fass im Objekt ein global func ObjectInsertMaterial(int imat, object pTarget) @@ -58,6 +56,7 @@ global func ObjectInsertMaterial(int imat, object pTarget) // Kein Fass? Dann Objekt überlaufen lassen return InsertMaterial(imat, GetX(pTarget)-GetX(), GetY(pTarget)-GetY()); } + // Auffüllbares Fass im Objekt suchen global func FindFillBarrel(object pInObj, id type) diff --git a/planet/System.c4g/PlayerControl.c b/planet/System.c4g/PlayerControl.c index 1bb541795..c47b1d040 100644 --- a/planet/System.c4g/PlayerControl.c +++ b/planet/System.c4g/PlayerControl.c @@ -13,21 +13,47 @@ global func PlayerControl(int plr, int ctrl, id spec_id, int x, int y, int stren if (spec_id) return spec_id->PlayerControl(plr, ctrl, x, y, strength, repeat, release); // Forward control to cursor var cursor = GetCursor(plr); - if (cursor) return cursor->ObjectControl(plr, ctrl, x,y, strength, repeat, release); + if (cursor) + { + // Object controlled by plr + cursor->SetController(plr); + // Overload by effect? + if (cursor->Control2Effect(plr, ctrl, x, y, strength, repeat, release)) return true; + return cursor->ObjectControl(plr, ctrl, x,y, strength, repeat, release); + } // No cursor? Nothing to handle control then return false; } + + /* Object functions */ // To be called in an object context only! +// Control2Effect +// Call control function in all effects that have "Control" in their name +global func Control2Effect(int ctrl, int x, int y, int strength, bool repeat, bool release) + { + // Count down from EffectCount, in case effects get deleted + var i = GetEffectCount("*Control*", this), iEffect; + var res; + while (i--) + { + iEffect = GetEffect("*Control*", this, i); + if ( GetEffect(0, this, iEffect, 1) ) + if (EffectCall(this, iEffect, "Control", ctrl, x,y,strength, repeat, release)) + return true; + } + // No effect handled the control + return false; + } + // ObjectControl // 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) { - // Object controlled by plr - SetController(plr); // Any control resets a previously given command SetCommand(this, "None"); // Movement controls @@ -36,9 +62,6 @@ global func ObjectControl(int plr, int ctrl, int x, int y, int strength, bool re return ObjectControlMovement(plr, ctrl, strength, release); } // Unhandled control - var srelease = ""; - if (release) srelease="Up"; - Log("Unhandled: %d, %s%s, %d, %d, %d, %v, %v", plr, GetPlayerControlName(ctrl), srelease, x,y,strength, repeat); return false; } @@ -108,9 +131,14 @@ global func ObjectControlUpdateComdir(int plr) var is_handled; var proc = GetProcedure(); if (proc == "WALK" || proc == "HANGLE" || proc == "PUSH" || proc == "PULL") - is_handled = (old_cx != new_cx) && !new_cy; // Only horizontal movement changed actual direction. Also, enfore clear Left/Right commands without leftover Up/Down + // Only horizontal movement changed actual direction + // Also, enfore clear Left/Right commands without leftover Up/Down + // CON_Down is never handled this way, thus forcing a CON_Stop + is_handled = (old_cx != new_cx) && !new_cy; else if (proc == "SCALE") - is_handled = (old_cy != new_cy) && !new_cx; // Only vertical movement changed actual direction. Also, enfore clear Up/Down to prevent "Zuppel" in corner + // Only vertical movement changed actual direction + // Also, enfore clear Up/Down to prevent "Zuppel" in corner + is_handled = (old_cy != new_cy) && !new_cx; else if (proc == "SWIM" || proc == "FLOAT" || proc == "DIG") is_handled = (old_cx != new_cx || old_cy != new_cy); // Free 360 degree movement else diff --git a/planet/System.c4g/PlayerControls.txt b/planet/System.c4g/PlayerControls.txt index 3bca3dfbf..bd0e15278 100644 --- a/planet/System.c4g/PlayerControls.txt +++ b/planet/System.c4g/PlayerControls.txt @@ -1,5 +1,8 @@ [ControlDefs] + [ControlDef] + Identifier=None + [ControlDef] Identifier=Left GUIName=Left @@ -36,6 +39,16 @@ Identifier=Dig GUIName=Dig GUIDesc=Delve through the earth + + [ControlDef] + Identifier=DolphinJump + GUIName=Dolphin Jump + GUIDesc=Jump out of the water while swimming + + [ControlDef] + Identifier=Context + GUIName=Context menu + GUIDesc=Open context menu of current interaction target @@ -70,19 +83,19 @@ TriggerMode=Hold [Assignment] - Key=A + Key=CON_Left Control=Right TriggerMode=Release | AlwaysUnhandled Priority=5 [Assignment] - Key=A + Key=CON_Left Control=Up TriggerMode=Release | AlwaysUnhandled Priority=-5 [Assignment] - Key=A + Key=CON_Left Control=Down TriggerMode=Release | AlwaysUnhandled Priority=-5 @@ -93,19 +106,19 @@ TriggerMode=Hold [Assignment] - Key=D + Key=CON_Right Control=Left TriggerMode=Release | AlwaysUnhandled Priority=5 [Assignment] - Key=D + Key=CON_Right Control=Up TriggerMode=Release | AlwaysUnhandled Priority=-5 [Assignment] - Key=D + Key=CON_Right Control=Down TriggerMode=Release | AlwaysUnhandled Priority=-5 @@ -116,55 +129,94 @@ TriggerMode=Hold [Assignment] - Key=S + Key=CON_Down Control=Up TriggerMode=Release | AlwaysUnhandled Priority=5 [Assignment] - Key=S + Key=CON_Down Control=Left - TriggerMode=Release | AlwaysUnhandled + TriggerMode=Release Priority=-5 [Assignment] - Key=S + Key=CON_Down Control=Right - TriggerMode=Release | AlwaysUnhandled + TriggerMode=Release Priority=-5 + [Assignment] + Key=CON_Down + Control=Down + TriggerMode=Release + Priority=-10 + [Assignment] Key=W Control=Up TriggerMode=Hold [Assignment] - Key=W + Key=CON_Up Control=Down TriggerMode=Release | AlwaysUnhandled Priority=5 [Assignment] - Key=W + Key=CON_Up Control=Left TriggerMode=Release | AlwaysUnhandled Priority=-5 [Assignment] - Key=W + Key=CON_Up Control=Right TriggerMode=Release | AlwaysUnhandled Priority=-5 + [Assignment] + Key=CON_Dig + Control=Down + TriggerMode=Release | AlwaysUnhandled + Priority=5 + + [Assignment] + Key=CON_Dig + Control=Left + TriggerMode=Release | AlwaysUnhandled + Priority=5 + + [Assignment] + Key=CON_Dig + Control=Right + TriggerMode=Release | AlwaysUnhandled + Priority=5 + + [Assignment] + Key=CON_Dig + Control=Up + TriggerMode=Release | AlwaysUnhandled + Priority=5 + + [ControlSet] Name=Keyboard2* [Assignment] Key=Q Control=Throw - Priority=50 [Assignment] Key=E Control=Dig - Priority=50 + + [Assignment] + Key=Up,Up + ComboIsSequence=1 + Control=DolphinJump + Priority=10 + + [Assignment] + Key=F + Control=Context