forked from Mirrors/openclonk
Moving controls to script: Clonk movement
parent
3dcf0de818
commit
943b47ebd5
|
@ -80,7 +80,7 @@
|
|||
</row>
|
||||
<row>
|
||||
<col>Script (Standardwert)</col>
|
||||
<col>Ausfuehrung des Scriptbefehls <em>PlayerControl</em> bzw. <em>PlayerControlRelease</em>. Siehe <emlink href="playercontrols.xml#Script">Script-Callbacks</emlink>.</col>
|
||||
<col>Ausfuehrung des Scriptbefehls <em>PlayerControl</em>. Siehe <emlink href="playercontrols.xml#Script">Script-Callbacks</emlink>.</col>
|
||||
</row>
|
||||
<row>
|
||||
<col>Menu</col>
|
||||
|
@ -180,7 +180,7 @@
|
|||
</part>
|
||||
<h id="Script">Script-Callbacks</h>
|
||||
<text>Die meisten Kommandos (abgesehen von asyrnchronen Kommandos im Spielermenue), rufen eine globale Scriptfunktion auf:</text>
|
||||
<code>global func PlayerControl(int player, int control, C4ID control_extra, int x, int y, int strength, bool repeated)</code>
|
||||
<code>global func PlayerControl(int player, int control, C4ID control_extra, int x, int y, int strength, bool repeated, bool release)</code>
|
||||
<text>Fuer eine Erlaeuterung der Parameter siehe <funclink>PlayerControl</funclink>. Die Funktion erhaelt unter anderem den aufrufenden Spieler in iPlr, sowie das ausgefuehrte Kommando in iControl.</text>
|
||||
<text>Fuer ein einfaches Beispiel sei in der globalen <em>PlayerControls.txt</em> folgendes Kommando definiert:</text>
|
||||
<code>[ControlDefs]
|
||||
|
@ -200,11 +200,11 @@
|
|||
Control=Jump
|
||||
Priority=50</code>
|
||||
<text>Dies definiert eine Sprungtaste und die zugehoerige Standardbelegung auf der Tastatur fuer den ersten Spieler. Dazu folgendes Script zur Behandlung:</text>
|
||||
<code>global func PlayerControl(int player, int control, C4ID control_extra, int x, int y, int strength, bool repeated)
|
||||
<code>global func PlayerControl(int player, int control, C4ID control_extra, int x, int y, int strength, bool repeated, bool release)
|
||||
{
|
||||
// Welches Kommando wurde ausgeloest?
|
||||
// Die Konstante CON_Jump wurde automatisch durch die Definition in PlayerControls.txt angelegt
|
||||
if (control == CON_Jump)
|
||||
if (control == CON_Jump && !release)
|
||||
{
|
||||
// Sprungtaste gedrueckt. Der vom Spieler ausgewaehlte Clonk soll springen
|
||||
var player_clonk = GetCursor(player);
|
||||
|
@ -227,17 +227,17 @@
|
|||
GUIDesc=Going underground
|
||||
ExtraData=SHVL</code>
|
||||
<text>Dabei sei SHVL die ID eines Schaufelobjektes. Im globalen Script kann zum Beispiel folgende, allgemeine Behandlung fuer unbekannte Kommandos stehen:</text>
|
||||
<code>global func PlayerControl(int player, int control, C4ID control_extra, int x, int y, int strength, bool repeated)
|
||||
<code>global func PlayerControl(int player, int control, C4ID control_extra, int x, int y, int strength, bool repeated, bool release)
|
||||
{
|
||||
// Behandlung bekannter Befehle
|
||||
// [...]
|
||||
// Befehl mit eigener Behandlung
|
||||
if (control_extra) return control_extra->PlayerControl(player, control, x, y, strength, repeat);
|
||||
if (control_extra) return control_extra->PlayerControl(player, control, x, y, strength, repeat, release);
|
||||
// Unbekanntes Kommando
|
||||
return false;
|
||||
}</code>
|
||||
<text>Und im Script der Schaufel:</text>
|
||||
<code>func PlayerControl(int player, int control, int x, int y, int strength, bool repeated)
|
||||
<code>func PlayerControl(int player, int control, int x, int y, int strength, bool repeated, bool release)
|
||||
{
|
||||
// Behandlung bekannter Befehle
|
||||
// Grabkommando direkt an die Schaufel
|
||||
|
@ -257,7 +257,7 @@
|
|||
<h id="Hold">Gehaltene Tasten</h>
|
||||
<text>Wird fuer ein Kommando das <em>Hold</em>-Flag gesetzt, so speichert die Engine den gegenwaertigen Tastenzustand fuer diese Taste. Solche Tasten haben einige Besonderheiten:</text>
|
||||
<text><ul>
|
||||
<li>Sie generieren beim Loslassen <funclink>PlayerControlRelease</funclink>-Aufrufe im Script.</li>
|
||||
<li>Sie generieren auch beim Loslassen <funclink>PlayerControl</funclink>-Aufrufe mit gesetztem <em>Release</em>-Flag im Script.</li>
|
||||
<li>Belegungen koennen mit den <em>Hold</em>/<em>Release</em>-Flags dauerhafte Tastendruecke emulieren.</li>
|
||||
<li><emlink href="playercontrols.xml#Repeat">Tastenwiederholungen</emlink> werden erzeugt.</li>
|
||||
<li>Der Haltezustand der Taste kann mit <funclink>GetPlayerControlState</funclink> im Script abgefragt werden.</li>
|
||||
|
@ -269,13 +269,7 @@
|
|||
GUIDesc=Walk left
|
||||
Hold=1</code>
|
||||
<text>Im Script wird die Richtung dann auf den Clonk uebertragen:</text>
|
||||
<code>global func PlayerControl(int player, int control, C4ID control_extra, int x, int y, int strength, bool repeated)
|
||||
{
|
||||
if (control == CON_Left) return UpdateControlDir(player);
|
||||
// ...
|
||||
}
|
||||
|
||||
global func PlayerControlRelease(int player, int control, C4ID control_extra, int x, int y)
|
||||
<code>global func PlayerControl(int player, int control, C4ID control_extra, int x, int y, int strength, bool repeated, bool release)
|
||||
{
|
||||
if (control == CON_Left) return UpdateControlDir(player);
|
||||
// ...
|
||||
|
|
|
@ -185,7 +185,7 @@ class C4Player: public C4PlayerInfoCore
|
|||
BOOL Sell2Home(C4Object *tobj);
|
||||
BOOL DoWealth(int32_t change);
|
||||
BOOL SetHostility(int32_t iOpponent, int32_t iHostility, BOOL fSilent=FALSE);
|
||||
void CompileFunc(StdCompiler *pComp);
|
||||
void CompileFunc(StdCompiler *pComp, bool fExact);
|
||||
BOOL LoadRuntimeData(C4Group &hGroup);
|
||||
bool ActivateMenuMain();
|
||||
bool ActivateMenuTeamSelection(bool fFromMain);
|
||||
|
|
|
@ -201,6 +201,7 @@ class C4PlayerControlAssignmentSet
|
|||
void MergeFrom(const C4PlayerControlAssignmentSet &Src, bool fLowPrio); // take over all assignments defined in Src
|
||||
|
||||
const char *GetName() const { return sName.getData(); }
|
||||
bool IsWildcardName() const { return IsWildcardString(sName.getData()); }
|
||||
|
||||
C4PlayerControlAssignment *GetAssignmentByControlName(const char *szControlName);
|
||||
void GetAssignmentsByKey(const C4PlayerControlDefs &rDefs, const C4KeyCodeEx &key, bool fHoldKeysOnly, C4PlayerControlAssignmentPVec *pOutVec, const C4PlayerControlRecentKeyList &DownKeys, const C4PlayerControlRecentKeyList &RecentKeys) const; // match only by TriggerKey (last key of Combo) if fHoldKeysOnly
|
||||
|
@ -264,6 +265,7 @@ class C4PlayerControl
|
|||
C4PlayerControlRecentKeyList RecentKeys; // keys pressed recently; for combinations
|
||||
C4PlayerControlRecentKeyList DownKeys; // keys currently held down
|
||||
|
||||
public:
|
||||
// sync values
|
||||
struct CSync
|
||||
{
|
||||
|
@ -294,7 +296,10 @@ class C4PlayerControl
|
|||
void Clear();
|
||||
void CompileFunc(StdCompiler *pComp);
|
||||
bool operator ==(const CSync &cmp) const;
|
||||
} Sync;
|
||||
};
|
||||
|
||||
private:
|
||||
CSync Sync;
|
||||
|
||||
// callbacks from Game.KeyboardInput
|
||||
bool ProcessKeyEvent(const C4KeyCodeEx &key, bool fUp, const C4KeyEventData &rKeyExtraData);
|
||||
|
@ -319,6 +324,8 @@ class C4PlayerControl
|
|||
void RegisterKeyset(int32_t iPlr, C4PlayerControlAssignmentSet *pKeyset); // register all keys into Game.KeyboardInput creating KeyBindings
|
||||
|
||||
bool IsGlobal() const { return iPlr==-1; }
|
||||
const CSync::ControlDownState *GetControlDownState(int32_t iControl) const
|
||||
{ return Sync.GetControlDownState(iControl); }
|
||||
|
||||
// callback from control queue
|
||||
void ExecuteControlPacket(const class C4ControlPlayerControl *pCtrl);
|
||||
|
|
|
@ -150,8 +150,7 @@ void InitFunctionMap(C4AulScriptEngine *pEngine); // add functions to engine
|
|||
#define PSF_OnHostilityChange "~OnHostilityChange" // int iPlr1, int iPlr2, bool fNewHostility, bool fOldHostility
|
||||
#define PSF_OnTeamSwitch "~OnTeamSwitch" // int iPlr1, int idNewTeam, int idOldTeam
|
||||
#define PSF_OnOwnerRemoved "~OnOwnerRemoved"
|
||||
#define PSF_PlayerControl "PlayerControl" // int iPlr, int iControl, C4ID idControlExtraData, int x, int y, int iStrength, bool fRepeated
|
||||
#define PSF_PlayerControlRelease "PlayerControlRelease" // int iPlr, int iControl, C4ID idControlExtraData, int x, int y
|
||||
#define PSF_PlayerControl "PlayerControl" // int iPlr, int iControl, C4ID idControlExtraData, int x, int y, int iStrength, bool fRepeated, bool fReleased
|
||||
|
||||
// Fx%s is automatically prefixed
|
||||
#define PSFS_FxAdd "Add" // C4Object *pTarget, int iEffectNumber, C4String *szNewEffect, int iNewTimer, C4Value vNewEffectVar1, C4Value vNewEffectVar2, C4Value vNewEffectVar3, C4Value vNewEffectVar4
|
||||
|
|
|
@ -1824,7 +1824,7 @@ void C4Game::CompileFunc(StdCompiler *pComp, CompileSettings comp)
|
|||
{
|
||||
if (!comp.fScenarioSection && comp.fExact)
|
||||
{
|
||||
pComp->Name("Game");
|
||||
pComp->Name("Game");
|
||||
pComp->Value(mkNamingAdapt(Time, "Time", 0));
|
||||
pComp->Value(mkNamingAdapt(FrameCounter, "Frame", 0));
|
||||
// pComp->Value(mkNamingAdapt(Control.ControlRate, "ControlRate", 0));
|
||||
|
@ -1856,24 +1856,30 @@ void C4Game::CompileFunc(StdCompiler *pComp, CompileSettings comp)
|
|||
if (comp.fExact)
|
||||
{
|
||||
pComp->Value(mkNamingAdapt(Weather, "Weather"));
|
||||
pComp->Value(mkNamingAdapt(Landscape, "Landscape"));
|
||||
pComp->Value(mkNamingAdapt(Landscape.Sky, "Sky"));
|
||||
pComp->Value(mkNamingAdapt(Landscape, "Landscape"));
|
||||
pComp->Value(mkNamingAdapt(Landscape.Sky, "Sky"));
|
||||
}
|
||||
|
||||
pComp->Value(mkNamingAdapt(mkNamingPtrAdapt(pGlobalEffects, "GlobalEffects"), "Effects"));
|
||||
|
||||
// scoreboard compiles into main level [Scoreboard]
|
||||
if (!comp.fScenarioSection && comp.fExact)
|
||||
pComp->Value(mkNamingAdapt(Scoreboard, "Scoreboard"));
|
||||
if (!comp.fScenarioSection && comp.fExact)
|
||||
{
|
||||
// scoreboard compiles into main level [Scoreboard]
|
||||
pComp->Value(mkNamingAdapt(Scoreboard, "Scoreboard"));
|
||||
// Keyboard status of global keys synchronized for exact (runtime join) only; not for savegames,
|
||||
// as keys might be released between a savegame save and its resume
|
||||
//pComp->Value(GlobalPlayerControl);
|
||||
}
|
||||
|
||||
if (comp.fPlayers)
|
||||
{
|
||||
assert(pComp->isDecompiler());
|
||||
assert(pComp->isDecompiler());
|
||||
// player parsing: Parse all players
|
||||
// This doesn't create any players, but just parses existing by their ID
|
||||
// Primary player ininitialization (also setting ID) is done by player info list
|
||||
// Won't work this way for binary mode!
|
||||
for (C4Player *pPlr=Players.First; pPlr; pPlr=pPlr->Next)
|
||||
pComp->Value(mkNamingAdapt(*pPlr, FormatString("Player%d", pPlr->ID).getData()));
|
||||
pComp->Value(mkNamingAdapt(mkParAdapt(*pPlr, comp.fExact), FormatString("Player%d", pPlr->ID).getData()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3231,7 +3237,8 @@ bool C4Game::InitPlayerControlSettings()
|
|||
C4PlayerControlFile PlayerControlFile;
|
||||
if (!PlayerControlFile.Load(Application.SystemGroup, C4CFN_PlayerControls, &MainSysLangStringTable)) { LogFatal("[!]Error loading player controls"); return false; }
|
||||
PlayerControlDefs = PlayerControlFile.GetControlDefs();
|
||||
PlayerControlAssignmentSets = PlayerControlFile.GetAssignmentSets();
|
||||
PlayerControlAssignmentSets.Clear();
|
||||
PlayerControlAssignmentSets.MergeFrom(PlayerControlFile.GetAssignmentSets(), false);
|
||||
PlayerControlAssignmentSets.ResolveRefs(&PlayerControlDefs);
|
||||
// And overwrites from config
|
||||
//PlayerControlAssignmentSets.MergeFrom(Config.Controls.Assignments);
|
||||
|
|
|
@ -1411,7 +1411,7 @@ void C4Player::ObjectCommand2Obj(C4Object *cObj, int32_t iCommand, C4Object *pTa
|
|||
else if (iMode & C4P_Command_Set) cObj->SetCommand(iCommand,pTarget,iX,iY,pTarget2,TRUE,iData);
|
||||
}
|
||||
|
||||
void C4Player::CompileFunc(StdCompiler *pComp)
|
||||
void C4Player::CompileFunc(StdCompiler *pComp, bool fExact)
|
||||
{
|
||||
assert(ID);
|
||||
|
||||
|
@ -1465,6 +1465,9 @@ void C4Player::CompileFunc(StdCompiler *pComp)
|
|||
pComp->Value(mkNamingAdapt(Crew, "Crew" ));
|
||||
pComp->Value(mkNamingAdapt(CrewInfoList.iNumCreated, "CrewCreated", 0));
|
||||
pComp->Value(mkNamingPtrAdapt( pMsgBoardQuery, "MsgBoardQueries" ));
|
||||
|
||||
// Keys held down
|
||||
pComp->Value(Control);
|
||||
}
|
||||
|
||||
BOOL C4Player::LoadRuntimeData(C4Group &hGroup)
|
||||
|
@ -1475,9 +1478,10 @@ BOOL C4Player::LoadRuntimeData(C4Group &hGroup)
|
|||
// safety: Do nothing if playeer section is not even present (could kill initialized values)
|
||||
if (!SSearch(pSource, FormatString("[Player%i]", ID).getData())) return FALSE;
|
||||
// Compile (Search player section - runtime data is stored by unique player ID)
|
||||
// Always compile exact. Exact data will not be present for savegame load, so it does not matter
|
||||
assert(ID);
|
||||
if(!CompileFromBuf_LogWarn<StdCompilerINIRead>(
|
||||
mkNamingAdapt(*this, FormatString("Player%i", ID).getData()),
|
||||
mkNamingAdapt(mkParAdapt(*this, true), FormatString("Player%i", ID).getData()),
|
||||
StdStrBuf(pSource),
|
||||
Game.GameText.GetFilePath()))
|
||||
return FALSE;
|
||||
|
|
|
@ -292,7 +292,7 @@ bool C4PlayerControlAssignment::operator ==(const C4PlayerControlAssignment &cmp
|
|||
void C4PlayerControlAssignmentSet::CompileFunc(StdCompiler *pComp)
|
||||
{
|
||||
if (!pComp->Name("ControlSet")) { pComp->NameEnd(); pComp->excNotFound("ControlSet"); }
|
||||
pComp->Value(mkNamingAdapt(mkParAdapt(sName, StdCompiler::RCT_Idtf), "Name", "None"));
|
||||
pComp->Value(mkNamingAdapt(mkParAdapt(sName, StdCompiler::RCT_All), "Name", "None")); // can't do RCT_Idtf because of wildcards
|
||||
pComp->Value(mkSTLContainerAdapt(Assignments, StdCompiler::SEP_NONE));
|
||||
pComp->NameEnd();
|
||||
}
|
||||
|
@ -420,15 +420,31 @@ void C4PlayerControlAssignmentSets::MergeFrom(const C4PlayerControlAssignmentSet
|
|||
{
|
||||
const C4PlayerControlAssignmentSet &SrcSet = *i;
|
||||
// overwrite if def of same name existed if it's not low priority anyway
|
||||
C4PlayerControlAssignmentSet *pPrevSet = GetSetByName(SrcSet.GetName());
|
||||
if (pPrevSet)
|
||||
bool fIsWildcardSet = SrcSet.IsWildcardName();
|
||||
if (!fIsWildcardSet)
|
||||
{
|
||||
pPrevSet->MergeFrom(SrcSet, fLowPrio);
|
||||
C4PlayerControlAssignmentSet *pPrevSet = GetSetByName(SrcSet.GetName());
|
||||
if (pPrevSet)
|
||||
{
|
||||
pPrevSet->MergeFrom(SrcSet, fLowPrio);
|
||||
}
|
||||
else
|
||||
{
|
||||
// new def: Append a copy
|
||||
Sets.push_back(SrcSet);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// new def: Append a copy
|
||||
Sets.push_back(SrcSet);
|
||||
// source is a wildcard: Merge with all matching sets
|
||||
for (AssignmentSetList::iterator j = Sets.begin(); j != Sets.end(); ++j)
|
||||
{
|
||||
C4PlayerControlAssignmentSet &DstSet = *j;
|
||||
if (WildcardMatch(SrcSet.GetName(), DstSet.GetName()))
|
||||
{
|
||||
DstSet.MergeFrom(SrcSet, fLowPrio);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -597,7 +613,6 @@ bool C4PlayerControl::ProcessKeyEvent(const C4KeyCodeEx &key, bool fUp, const C4
|
|||
// build a control packet and add control data instead. even for async controls later in chain, as they may be blocked by a sync handler
|
||||
if (!pControlPacket) pControlPacket = new C4ControlPlayerControl(iPlr, fUp, rKeyExtraData);
|
||||
pControlPacket->AddControl(iControlIndex, pAssignment->GetTriggerMode());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -766,22 +781,11 @@ bool C4PlayerControl::ExecuteControlScript(int32_t iControl, C4ID idControlExtra
|
|||
// player lost?
|
||||
return false;
|
||||
}
|
||||
if (!fUp)
|
||||
{
|
||||
// control down
|
||||
C4AulFunc *pFunc = Game.ScriptEngine.GetFirstFunc(PSF_PlayerControl);
|
||||
if (!pFunc) return false;
|
||||
C4AulParSet Pars(C4VInt(iPlr), C4VInt(iControl), C4VID(idControlExtraData), C4VInt(rKeyExtraData.x), C4VInt(rKeyExtraData.y), C4VInt(rKeyExtraData.iStrength), C4VBool(fRepeated));
|
||||
return !!pFunc->Exec(NULL, &Pars);
|
||||
}
|
||||
else
|
||||
{
|
||||
// control up
|
||||
C4AulFunc *pFunc = Game.ScriptEngine.GetFirstFunc(PSF_PlayerControlRelease);
|
||||
if (!pFunc) return false;
|
||||
C4AulParSet Pars(C4VInt(iPlr), C4VInt(iControl), C4VID(idControlExtraData), C4VInt(rKeyExtraData.x), C4VInt(rKeyExtraData.y));
|
||||
return !!pFunc->Exec(NULL, &Pars);
|
||||
}
|
||||
// control down
|
||||
C4AulFunc *pFunc = Game.ScriptEngine.GetFirstFunc(PSF_PlayerControl);
|
||||
if (!pFunc) return false;
|
||||
C4AulParSet Pars(C4VInt(iPlr), C4VInt(iControl), C4VID(idControlExtraData), C4VInt(rKeyExtraData.x), C4VInt(rKeyExtraData.y), C4VInt(rKeyExtraData.iStrength), C4VBool(fRepeated), C4VBool(fUp));
|
||||
return !!pFunc->Exec(NULL, &Pars);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -4368,7 +4368,7 @@ static C4Value FnGetPlayerVal(C4AulContext* cthr, C4Value* strEntry_C4V, C4Value
|
|||
C4Player* pPlayer = Game.Players.Get(iPlr);
|
||||
|
||||
// get value
|
||||
return GetValByStdCompiler(strEntry, strSection, iEntryNr, mkNamingAdapt(*pPlayer, "Player"));
|
||||
return GetValByStdCompiler(strEntry, strSection, iEntryNr, mkNamingAdapt(mkParAdapt(*pPlayer, true), "Player"));
|
||||
}
|
||||
|
||||
static C4Value FnGetPlayerInfoCoreVal(C4AulContext* cthr, C4Value* strEntry_C4V, C4Value* strSection_C4V, C4Value* iPlayer_C4V, C4Value *iEntryNr_C4V)
|
||||
|
@ -6307,6 +6307,32 @@ static bool FnSetNextMission(C4AulContext *ctx, C4String *szNextMission, C4Strin
|
|||
return true;
|
||||
}
|
||||
|
||||
static long FnGetPlayerControlState(C4AulContext *ctx, long iPlr, long iControl)
|
||||
{
|
||||
// get control set to check
|
||||
C4PlayerControl *pCheckCtrl = NULL;
|
||||
if (iPlr == NO_OWNER)
|
||||
{
|
||||
//pCheckCtrl = Game.GlobalPlayerControls;
|
||||
}
|
||||
else
|
||||
{
|
||||
C4Player *pPlr = Game.Players.Get(iPlr);
|
||||
if (pPlr)
|
||||
{
|
||||
pCheckCtrl = &(pPlr->Control);
|
||||
}
|
||||
}
|
||||
// invalid player or no controls
|
||||
if (!pCheckCtrl) return 0;
|
||||
// query control
|
||||
const C4PlayerControl::CSync::ControlDownState *pControlState = pCheckCtrl->GetControlDownState(iControl);
|
||||
// no state means not down
|
||||
if (!pControlState) return 0;
|
||||
// otherwise take down-value
|
||||
return pControlState->DownState.iStrength;
|
||||
}
|
||||
|
||||
//=========================== C4Script Function Map ===================================
|
||||
|
||||
// defined function class
|
||||
|
@ -6794,6 +6820,7 @@ void InitFunctionMap(C4AulScriptEngine *pEngine)
|
|||
AddFunc(pEngine, "LocateFunc", FnLocateFunc);
|
||||
AddFunc(pEngine, "PathFree", FnPathFree);
|
||||
AddFunc(pEngine, "SetNextMission", FnSetNextMission);
|
||||
AddFunc(pEngine, "GetPlayerControlState", FnGetPlayerControlState);
|
||||
new C4AulDefCastFunc(pEngine, "ScoreboardCol", C4V_C4ID, C4V_Int);
|
||||
new C4AulDefCastFunc(pEngine, "CastInt", C4V_Any, C4V_Int);
|
||||
new C4AulDefCastFunc(pEngine, "CastBool", C4V_Any, C4V_Bool);
|
||||
|
|
|
@ -1,13 +1,200 @@
|
|||
#strict 2
|
||||
|
||||
global func PlayerControl(int plr, int ctrl, id spec_id, int x, int y, int strength, bool repeat)
|
||||
// Functions to handle player controls (i.e., input keys)
|
||||
|
||||
// PlayerControlRelease
|
||||
// Called by engine whenever a control is issued
|
||||
// Forwards control to special handler or cursor
|
||||
// Return whether handled
|
||||
global func PlayerControl(int plr, int ctrl, id spec_id, int x, int y, int strength, bool repeat, bool release)
|
||||
{
|
||||
Log("%d, %d, %i, %d, %d, %d, %v", plr, ctrl, spec_id, x,y,strength, repeat);
|
||||
//Log("%d, %s, %i, %d, %d, %d, %v, %v", plr, GetPlayerControlName(ctrl), spec_id, x,y,strength, repeat, release);
|
||||
// Control handled by definition? Forward
|
||||
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);
|
||||
// No cursor? Nothing to handle control then
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Object functions */
|
||||
// To be called in an object context only!
|
||||
|
||||
// ObjectControl
|
||||
// Called from PlayerControl when a control is issued to the cursor
|
||||
// Return whether handled
|
||||
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
|
||||
if (ctrl==CON_Left || ctrl==CON_Right || ctrl==CON_Up || ctrl==CON_Down)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
// ObjectControlMovement
|
||||
// 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)
|
||||
{
|
||||
var proc = GetProcedure();
|
||||
// Some specific movement controls
|
||||
if (!release)
|
||||
{
|
||||
// Jump control
|
||||
if (ctrl == CON_Up && proc == "WALK")
|
||||
{
|
||||
return PlayerObjectCommand(plr, false, "Jump");
|
||||
}
|
||||
if (proc == "SCALE") // Let go from scaling a wall
|
||||
{
|
||||
if (ctrl == CON_Left && GetDir() == DIR_Right) return ObjectComLetGo(-10);
|
||||
if (ctrl == CON_Right && GetDir() == DIR_Left) return ObjectComLetGo(+10);
|
||||
}
|
||||
else if (proc == "HANGLE") // Let go from hangling the ceiling
|
||||
{
|
||||
if (ctrl == CON_Down) return ObjectComLetGo(0,0);
|
||||
}
|
||||
else if (proc == "FIGHT") // Clonk-to-Clonk-fight. Might want to implement some more sophisticated behaviour here?
|
||||
{
|
||||
// stop, but don't abort ComDir processing. May want to do Stop while holding a direction to run away?
|
||||
if (ctrl == CON_Down) ObjectComStop();
|
||||
}
|
||||
// Make sure other selected Clonks are following
|
||||
PlayerObjectCommand(plr, true, "Follow", this, GetX(), GetY());
|
||||
// Direct turnaround if object is standing still. Valid for any procedure in OC
|
||||
if (!GetXDir())
|
||||
{
|
||||
if (ctrl == CON_Left) SetDir(DIR_Left);
|
||||
else if (ctrl == CON_Right) SetDir(DIR_Right);
|
||||
}
|
||||
}
|
||||
return ObjectControlUpdateComdir(plr);
|
||||
}
|
||||
|
||||
// ObjectControlUpdateComdir
|
||||
// Updates ComDir of object based on current Con_*-directional controls
|
||||
// Return whether actual, effective direction of movement changed
|
||||
global func ObjectControlUpdateComdir(int plr)
|
||||
{
|
||||
// Generic movement: Update ComDir based on current control state
|
||||
var new_comdir = GetPlayerConDir(plr, CON_Left, CON_Up, CON_Right, CON_Down);
|
||||
var old_comdir = GetComDir();
|
||||
if (new_comdir != old_comdir)
|
||||
{
|
||||
// ComDir changed. Update.
|
||||
SetComDir(new_comdir);
|
||||
//var s = "";
|
||||
//if (GetPlayerControlState(plr, CON_Left)) s = Format("%sL", s);
|
||||
//if (GetPlayerControlState(plr, CON_Up)) s = Format("%sU", s);
|
||||
//if (GetPlayerControlState(plr, CON_Right)) s = Format("%sR", s);
|
||||
//if (GetPlayerControlState(plr, CON_Down)) s = Format("%sD", s);
|
||||
//s = Format("%s %s", s, ["Stop", "Up", "UpRight", "Right", "DownRight", "Down", "DownLeft", "Left", "UpLeft"][new_comdir]);
|
||||
//Message("@%s", this, s);
|
||||
// The control is only handled if it had an actual effect on the current movement direction of the Clonk
|
||||
var old_cx,old_cy,new_cx,new_cy;
|
||||
ComDir2XY(old_comdir, old_cx, old_cy);
|
||||
ComDir2XY(new_comdir, new_cx, new_cy);
|
||||
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
|
||||
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
|
||||
else if (proc == "SWIM" || proc == "FLOAT" || proc == "DIG")
|
||||
is_handled = (old_cx != new_cx || old_cy != new_cy); // Free 360 degree movement
|
||||
else
|
||||
is_handled = false;
|
||||
return is_handled;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ComDir did not change. -> The control was not handled
|
||||
//Log("NoChange");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// GetPlayerControlName
|
||||
// Helper function to turn CON_*-constants into strings
|
||||
global func GetPlayerControlName(int ctrl)
|
||||
{
|
||||
if (ctrl == CON_Left ) return "Left";
|
||||
if (ctrl == CON_Right ) return "Right";
|
||||
if (ctrl == CON_Up ) return "Up";
|
||||
if (ctrl == CON_Down ) return "Down";
|
||||
if (ctrl == CON_Throw ) return "Throw";
|
||||
if (ctrl == CON_Dig ) return "Dig";
|
||||
return Format("Unknown(%d)", ctrl);
|
||||
}
|
||||
|
||||
// GetPlayerConDir
|
||||
// Return COMD_*-constant corresponding to current state of passed directional controls
|
||||
global func GetPlayerConDir(int plr, int con_left, int con_up, int con_right, int con_down)
|
||||
{
|
||||
var x,y;
|
||||
if (GetPlayerControlState(plr, con_left)) --x;
|
||||
if (GetPlayerControlState(plr, con_up)) --y;
|
||||
if (GetPlayerControlState(plr, con_right)) ++x;
|
||||
if (GetPlayerControlState(plr, con_down)) ++y;
|
||||
// Creating an array here for every keypress/release
|
||||
// Would be so cool to have this static const. Guenther?
|
||||
var dir_coms = [COMD_UpLeft, COMD_Up, COMD_UpRight, COMD_Left, COMD_None, COMD_Right, COMD_DownLeft, COMD_Down, COMD_DownRight];
|
||||
return dir_coms[y*3+x+4];
|
||||
}
|
||||
|
||||
// ComDir2XY
|
||||
// Returns coordinate directions associated with a COMD_Constant
|
||||
global func ComDir2XY(int comd, &x, &y)
|
||||
{
|
||||
// Creating an array here for every keypress/release
|
||||
// Would be so cool to have this static const. Guenther?
|
||||
x = [0,0,1,1,1,0,-1,-1,-1][comd];
|
||||
y = [0,-1,-1,0,1,1,1,0,-1][comd];
|
||||
return true;
|
||||
}
|
||||
|
||||
global func PlayerControlRelease(int plr, int ctrl, id spec_id, int x, int y)
|
||||
// PlayerObjectCommand
|
||||
// Give a command to all selected Clonks of a player
|
||||
global func PlayerObjectCommand(int plr, bool exclude_cursor, string command, object target, int tx, int ty, object target2)
|
||||
{
|
||||
Log("re %d, %d, %i, %d, %d", plr, ctrl, spec_id, x,y);
|
||||
for (var i=exclude_cursor; i<GetSelectCount(plr); ++i)
|
||||
{
|
||||
var follow_clonk = GetCursor(plr, i);
|
||||
if (follow_clonk)
|
||||
{
|
||||
SetCommand(follow_clonk,command,target,tx,ty);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// ObjectComStop
|
||||
// Stop action and ComDir
|
||||
global func ObjectComStop()
|
||||
{
|
||||
SetComDir();
|
||||
SetAction("Idle");
|
||||
if (!SetAction("Walk")) return false;
|
||||
SetXDir(); SetYDir();
|
||||
return true;
|
||||
}
|
||||
|
||||
// ObjectComLetGo
|
||||
// Let go from scaling or hangling
|
||||
global func ObjectComLetGo(int vx, int vy)
|
||||
{
|
||||
if (!SetAction("Jump")) return false;
|
||||
SetXDir(vx); SetYDir(vy);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -3,10 +3,26 @@
|
|||
[ControlDef]
|
||||
Identifier=Left
|
||||
GUIName=Left
|
||||
GUIDesc=Walk left
|
||||
GUIDesc=Move left
|
||||
Hold=1
|
||||
|
||||
[ControlDef]
|
||||
Identifier=Right
|
||||
GUIName=Right
|
||||
GUIDesc=Move right
|
||||
Hold=1
|
||||
|
||||
[ControlDef]
|
||||
Identifier=Up
|
||||
GUIName=Up
|
||||
GUIDesc=Move up or jump
|
||||
Hold=1
|
||||
|
||||
[ControlDef]
|
||||
Identifier=Down
|
||||
GUIName=Down
|
||||
GUIDesc=Move down
|
||||
Hold=1
|
||||
RepeatDelay=5
|
||||
InitialRepeatDelay=35
|
||||
|
||||
[ControlDef]
|
||||
Identifier=Throw
|
||||
|
@ -16,23 +32,133 @@
|
|||
RepeatDelay=5
|
||||
InitialRepeatDelay=35
|
||||
|
||||
|
||||
[ControlDef]
|
||||
Identifier=Dig
|
||||
GUIName=Dig
|
||||
GUIDesc=Delve through the earth
|
||||
|
||||
[ControlDef]
|
||||
Identifier=Test
|
||||
GUIName=Test
|
||||
GUIDesc=Test key
|
||||
|
||||
|
||||
|
||||
[ControlSets]
|
||||
|
||||
[ControlSet]
|
||||
Name=Keyboard2
|
||||
|
||||
[Assignment]
|
||||
Key=A
|
||||
Control=Left
|
||||
|
||||
[Assignment]
|
||||
Key=D
|
||||
Control=Right
|
||||
|
||||
[Assignment]
|
||||
Key=S
|
||||
Control=Down
|
||||
|
||||
[Assignment]
|
||||
Key=W
|
||||
Control=Up
|
||||
TriggerMode=Hold
|
||||
|
||||
[ControlSet]
|
||||
Name=Keyboard2Classic
|
||||
|
||||
[Assignment]
|
||||
Key=A
|
||||
Control=Left
|
||||
TriggerMode=Hold
|
||||
|
||||
[Assignment]
|
||||
Key=A
|
||||
Control=Right
|
||||
TriggerMode=Release | AlwaysUnhandled
|
||||
Priority=5
|
||||
|
||||
[Assignment]
|
||||
Key=A
|
||||
Control=Up
|
||||
TriggerMode=Release | AlwaysUnhandled
|
||||
Priority=-5
|
||||
|
||||
[Assignment]
|
||||
Key=A
|
||||
Control=Down
|
||||
TriggerMode=Release | AlwaysUnhandled
|
||||
Priority=-5
|
||||
|
||||
[Assignment]
|
||||
Key=D
|
||||
Control=Right
|
||||
TriggerMode=Hold
|
||||
|
||||
[Assignment]
|
||||
Key=D
|
||||
Control=Left
|
||||
TriggerMode=Release | AlwaysUnhandled
|
||||
Priority=5
|
||||
|
||||
[Assignment]
|
||||
Key=D
|
||||
Control=Up
|
||||
TriggerMode=Release | AlwaysUnhandled
|
||||
Priority=-5
|
||||
|
||||
[Assignment]
|
||||
Key=D
|
||||
Control=Down
|
||||
TriggerMode=Release | AlwaysUnhandled
|
||||
Priority=-5
|
||||
|
||||
[Assignment]
|
||||
Key=S
|
||||
Control=Down
|
||||
TriggerMode=Hold
|
||||
|
||||
[Assignment]
|
||||
Key=S
|
||||
Control=Up
|
||||
TriggerMode=Release | AlwaysUnhandled
|
||||
Priority=5
|
||||
|
||||
[Assignment]
|
||||
Key=S
|
||||
Control=Left
|
||||
TriggerMode=Release | AlwaysUnhandled
|
||||
Priority=-5
|
||||
|
||||
[Assignment]
|
||||
Key=S
|
||||
Control=Right
|
||||
TriggerMode=Release | AlwaysUnhandled
|
||||
Priority=-5
|
||||
|
||||
[Assignment]
|
||||
Key=W
|
||||
Control=Up
|
||||
TriggerMode=Hold
|
||||
|
||||
[Assignment]
|
||||
Key=W
|
||||
Control=Down
|
||||
TriggerMode=Release | AlwaysUnhandled
|
||||
Priority=5
|
||||
|
||||
[Assignment]
|
||||
Key=W
|
||||
Control=Left
|
||||
TriggerMode=Release | AlwaysUnhandled
|
||||
Priority=-5
|
||||
|
||||
[Assignment]
|
||||
Key=W
|
||||
Control=Right
|
||||
TriggerMode=Release | AlwaysUnhandled
|
||||
Priority=-5
|
||||
|
||||
[ControlSet]
|
||||
Name=Keyboard2*
|
||||
|
||||
[Assignment]
|
||||
Key=Q
|
||||
Control=Throw
|
||||
|
@ -42,19 +168,3 @@
|
|||
Key=E
|
||||
Control=Dig
|
||||
Priority=50
|
||||
|
||||
[Assignment]
|
||||
Key=A
|
||||
Control=Left
|
||||
TriggerMode=Hold
|
||||
|
||||
[Assignment]
|
||||
Key=S
|
||||
Control=Left
|
||||
TriggerMode=Release | AlwaysUnhandled
|
||||
|
||||
[Assignment]
|
||||
Key=Throw,Throw,Dig
|
||||
ComboIsSequence=1
|
||||
Control=Test
|
||||
Priority=60
|
||||
|
|
|
@ -69,6 +69,7 @@ void TruncateBackslash(char *szFilename);
|
|||
void MakeTempFilename(char *szFileName);
|
||||
void MakeTempFilename(class StdStrBuf *sFileName);
|
||||
bool WildcardListMatch(const char *szWildcardList, const char *szString); // match string in list like *.png|*.bmp
|
||||
bool IsWildcardString(const char *szString); // does szString contain wildcard characters?
|
||||
bool WildcardMatch(const char *szFName1, const char *szFName2);
|
||||
bool TruncatePath(char *szPath);
|
||||
// szBuffer has to be of at least _MAX_PATH length.
|
||||
|
|
|
@ -369,6 +369,14 @@ bool WildcardListMatch(const char *szWildcardList, const char *szString)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool IsWildcardString(const char *szString)
|
||||
{
|
||||
// safety
|
||||
if(!szString) return false;
|
||||
// known wildcard characters: *?
|
||||
return (SCharCount('?', szString)>0) || (SCharCount('*', szString)>0);
|
||||
}
|
||||
|
||||
bool WildcardMatch(const char *szWildcard, const char *szString)
|
||||
{
|
||||
// safety
|
||||
|
|
Loading…
Reference in New Issue