forked from Mirrors/openclonk
1310 lines
28 KiB
C
1310 lines
28 KiB
C
/*-- Der Clonk --*/
|
|
|
|
#strict 2
|
|
|
|
|
|
/* Initialisierung */
|
|
|
|
protected func Initialize()
|
|
{
|
|
// Clonks mit Magiephysikal aus fehlerhaften Szenarien korrigieren
|
|
if (GetID () == CLNK)
|
|
if (GetPhysical ("Magic", 1))
|
|
SetPhysical ("Magic", 0, 1);
|
|
SetAction("Walk");
|
|
SetDir(Random(2));
|
|
// Broadcast für Spielregeln
|
|
GameCallEx("OnClonkCreation", this);
|
|
return 1;
|
|
}
|
|
|
|
protected func Swimming()
|
|
{
|
|
if(GBackSemiSolid(0, -4))
|
|
SetAction("Swim2");
|
|
}
|
|
|
|
protected func Swimming2()
|
|
{
|
|
if(!GBackSemiSolid(0, -4))
|
|
SetAction("Swim");
|
|
}
|
|
|
|
/* Bei Hinzufügen zu der Crew eines Spielers */
|
|
|
|
protected func Recruitment(int iPlr) {
|
|
// Broadcast für Crew
|
|
GameCallEx("OnClonkRecruitment", this, iPlr);
|
|
}
|
|
|
|
/* Kontext */
|
|
|
|
public func HasConstructMenu() { return HasKnowledge() && GetPhysical("CanConstruct"); }
|
|
public func HasKnowledge() { return GetPlrKnowledge(GetOwner(),0,0,C4D_Structure); }
|
|
public func HasBase() { return FindBase(GetOwner()) && Contained()->GetBase() != GetOwner(); }
|
|
public func ReleaseAllowed() { return ObjectCount(REAC); }
|
|
public func AtConstructionSite() { return !Contained() && FindConstructionSite() && ObjectCount(CNMT); }
|
|
public func AtEnergySite() { return !Contained() && FindEnergySite(); }
|
|
public func AtTreeToChop() { return !Contained() && FindTree() && GetPhysical("CanChop"); }
|
|
|
|
public func FindConstructionSite()
|
|
{
|
|
return FindObject(Find_AtRect(-1,-16,2,32), Find_OCF(OCF_Construct), Find_Layer(GetObjectLayer()));
|
|
}
|
|
|
|
public func FindEnergySite()
|
|
{
|
|
return FindObject(Find_AtPoint(), Find_OCF(OCF_PowerConsumer), Find_NoContainer(), Find_Layer(GetObjectLayer()), Find_Func("NeedsEnergy"));
|
|
}
|
|
|
|
public func FindTree()
|
|
{
|
|
return FindObject(Find_AtPoint(), Find_OCF(OCF_Chop), Find_Layer(GetObjectLayer()));
|
|
}
|
|
|
|
|
|
/* Steuerung */
|
|
|
|
public func GetInteractionTarget()
|
|
{
|
|
// Contained interaction target
|
|
var container = Contained();
|
|
if (container)
|
|
{
|
|
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);
|
|
}
|
|
|
|
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)
|
|
{
|
|
if (interaction_target->ObjectControl(plr, ctrl, x,y, strength, repeat, release)) return true;
|
|
}
|
|
// 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()
|
|
{
|
|
// nur wenn an Meeresoberfläche
|
|
if(!InLiquid()) return 0;
|
|
if(GBackSemiSolid(0,-1)) return 0;
|
|
// Nicht wenn deaktiviert (z.B. Ohnmacht)
|
|
if (GetID()->GetActMapVal("ObjectDisabled", GetAction())) return false;
|
|
// herausspringen
|
|
SetPosition(GetX(),GetY()-1);
|
|
SetAction("Jump");
|
|
SetSpeed(GetXDir(),-BoundBy(GetPhysical("Swim")/2500,24,38));
|
|
var iX=GetX(),iY=GetY(),iXDir=GetXDir(),iYDir=GetYDir();
|
|
// Wenn Sprung im Wasser endet und das Wasser tief genug ist, Kopfsprung machen
|
|
if(SimFlight(iX,iY,iXDir,iYDir,25,50))
|
|
if(GBackLiquid(iX-GetX(),iY-GetY()) && GBackLiquid(iX-GetX(),iY+9-GetY()))
|
|
SetAction("Dive");
|
|
}
|
|
|
|
protected func ControlCommand(szCommand, pTarget, iTx, iTy, pTarget2, Data)
|
|
{
|
|
// Kommando MoveTo an Pferd weiterleiten
|
|
if (szCommand == "MoveTo")
|
|
if (IsRiding())
|
|
return GetActionTarget()->~ControlCommand(szCommand, pTarget, iTx, iTy);
|
|
// Anderes Kommando beim Reiten: absteigen (Ausnahme: Context)
|
|
if (IsRiding() && szCommand != "Context")
|
|
{
|
|
GetActionTarget()->SetComDir(COMD_Stop);
|
|
GetActionTarget()->~ControlDownDouble(this);
|
|
}
|
|
// RejectConstruction Callback beim Bauen durch Drag'n'Drop aus einem Gebaeude-Menu
|
|
if(szCommand == "Construct")
|
|
{
|
|
if(Data->~RejectConstruction(iTx - GetX(), iTy - GetY(), this) )
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
// Kein überladenes Kommando
|
|
return 0;
|
|
}
|
|
|
|
public func ControlDownDouble() {} // dummy
|
|
|
|
|
|
/* Verwandlung */
|
|
|
|
private func RedefinePhysical(szPhys, idTo)
|
|
{
|
|
// Physical-Werte ermitteln
|
|
var physDefFrom = GetID()->GetPhysical(szPhys),
|
|
physDefTo = idTo->GetPhysical(szPhys),
|
|
physCurr = GetPhysical(szPhys);
|
|
// Neuen Wert berechnen
|
|
var physNew; if (physDefTo) physNew=BoundBy(physDefTo-physDefFrom+physCurr, 0, 100000);
|
|
// Neuen Wert für den Reset immer temporär setzen, selbst wenn keine Änderung besteht, damit der Reset richtig funktioniert
|
|
SetPhysical(szPhys, physNew, PHYS_StackTemporary);
|
|
// Fertig
|
|
return 1;
|
|
}
|
|
|
|
protected func FxIntRedefineStart(object trg, int num, int tmp, id idTo)
|
|
{
|
|
// Ziel-ID in Effektvariable
|
|
if (tmp)
|
|
idTo = EffectVar(0, trg, num);
|
|
else
|
|
{
|
|
EffectVar(0, trg, num) = idTo;
|
|
EffectVar(1, trg, num) = GetID();
|
|
}
|
|
// Physicals anpassen
|
|
RedefinePhysical("Energy", idTo);
|
|
RedefinePhysical("Breath", idTo);
|
|
RedefinePhysical("Walk", idTo);
|
|
RedefinePhysical("Jump", idTo);
|
|
RedefinePhysical("Scale", idTo);
|
|
RedefinePhysical("Hangle", idTo);
|
|
RedefinePhysical("Dig", idTo);
|
|
RedefinePhysical("Swim", idTo);
|
|
RedefinePhysical("Throw", idTo);
|
|
RedefinePhysical("Push", idTo);
|
|
RedefinePhysical("Fight", idTo);
|
|
RedefinePhysical("Magic", idTo);
|
|
RedefinePhysical("Float", idTo);
|
|
/*if (GetRank()<4) RedefinePhysical("CanScale", idTo);
|
|
if (GetRank()<6) RedefinePhysical("CanHangle", idTo);*/ // z.Z. können es alle
|
|
RedefinePhysical("CanDig", idTo);
|
|
RedefinePhysical("CanConstruct", idTo);
|
|
RedefinePhysical("CanChop", idTo);
|
|
RedefinePhysical("CanSwimDig", idTo);
|
|
RedefinePhysical("CorrosionResist", idTo);
|
|
RedefinePhysical("BreatheWater", idTo);
|
|
// Damit Aufwertungen zu nicht-Magiern keine Zauberenergie übrig lassen
|
|
if (GetPhysical("Magic")/1000 < GetMagicEnergy()) DoMagicEnergy(GetPhysical("Magic")/1000-GetMagicEnergy());
|
|
// Echtes Redefine nur bei echten Aufrufen (hat zu viele Nebenwirkungen)
|
|
if (tmp) return FX_OK;
|
|
Redefine(idTo);
|
|
// Fertig
|
|
return FX_OK;
|
|
}
|
|
|
|
protected func FxIntRedefineStop(object trg, int num, int iReason, bool tmp)
|
|
{
|
|
// Physicals wiederherstellen
|
|
ResetPhysical("BreatheWater");
|
|
ResetPhysical("CorrosionResist");
|
|
ResetPhysical("CanSwimDig");
|
|
ResetPhysical("CanChop");
|
|
ResetPhysical("CanConstruct");
|
|
ResetPhysical("CanDig");
|
|
ResetPhysical("Float");
|
|
ResetPhysical("Magic");
|
|
ResetPhysical("Fight");
|
|
ResetPhysical("Push");
|
|
ResetPhysical("Throw");
|
|
ResetPhysical("Swim");
|
|
ResetPhysical("Dig");
|
|
ResetPhysical("Hangle");
|
|
ResetPhysical("Scale");
|
|
ResetPhysical("Jump");
|
|
ResetPhysical("Walk");
|
|
ResetPhysical("Breath");
|
|
ResetPhysical("Energy");
|
|
// Keine Rückänderung bei temporären Aufrufen oder beim Tod/Löschen
|
|
if (tmp || iReason) return;
|
|
// Damit Aufwertungen von nicht-Magiern keine Zauberenergie übrig lassen
|
|
if (GetPhysical("Magic")/1000 < GetMagicEnergy()) DoMagicEnergy(GetPhysical("Magic")/1000-GetMagicEnergy());
|
|
// OK; alte Definition wiederherstellen
|
|
Redefine(EffectVar(1, trg, num));
|
|
}
|
|
|
|
public func Redefine2(idTo)
|
|
{
|
|
if (GetID() == idTo) return true;
|
|
RemoveEffect("IntRedefine", this);
|
|
if (GetID() == idTo) return true;
|
|
return !!AddEffect("IntRedefine", this, 10, 0, this, 0, idTo);
|
|
}
|
|
|
|
public func Redefine(idTo)
|
|
{
|
|
// Aktivitätsdaten sichern
|
|
var phs=GetPhase(),act=GetAction();
|
|
// Umwandeln
|
|
ChangeDef(idTo);
|
|
// Aktivität wiederherstellen
|
|
var chg=SetAction(act);
|
|
if (!chg) SetAction("Walk");
|
|
if (chg) SetPhase(phs);
|
|
// Fertig
|
|
return 1;
|
|
}
|
|
|
|
|
|
/* Essen */
|
|
|
|
public func Feed(iLevel)
|
|
{
|
|
DoEnergy(iLevel);
|
|
Sound("ClonkMunch");
|
|
return 1;
|
|
}
|
|
|
|
|
|
/* Aktionen */
|
|
|
|
private func Riding()
|
|
{
|
|
// Richtung an die des Pferdes anpassen
|
|
SetDir(GetActionTarget()->GetDir());
|
|
// Pferd steht still: Clonk soll auch still sitzen
|
|
if (GetActionTarget()->~IsStill())
|
|
{
|
|
if (GetAction() != "RideStill")
|
|
SetAction("RideStill");
|
|
}
|
|
// Pferd steht nicht still: Clonk soll auch nicht still sitzen
|
|
else
|
|
if (GetAction() != "Ride")
|
|
SetAction("Ride");
|
|
return 1;
|
|
}
|
|
|
|
private func Throwing()
|
|
{
|
|
// Erstes Inhaltsobjekt werfen
|
|
var pObj = Contents(0);
|
|
// Wurfparameter berechnen
|
|
var iX, iY, iR, iXDir, iYDir, iRDir;
|
|
iX = 0; if (!GetDir()) iX = -iX;
|
|
iY = -10;
|
|
iR = Random(360);
|
|
iXDir = GetPhysical("Throw") / 25000; if(!GetDir()) iXDir = -iXDir;
|
|
iYDir = -GetPhysical("Throw") / 25000;
|
|
iRDir = Random(40) - 20;
|
|
// Reitet? Eigengeschwindigkeit addieren
|
|
if (GetActionTarget())
|
|
{
|
|
iXDir += GetActionTarget()->GetXDir() / 10;
|
|
iYDir += GetActionTarget()->GetYDir() / 10;
|
|
}
|
|
// Werfen!
|
|
pObj->Exit(iX, iY, iR, iXDir, iYDir, iRDir);
|
|
// Fertig
|
|
return 1;
|
|
}
|
|
|
|
private func Fighting()
|
|
{
|
|
if (!Random(2)) SetAction("Punch");
|
|
return 1;
|
|
}
|
|
|
|
private func Punching()
|
|
{
|
|
if (!Random(3)) Sound("Kime*");
|
|
if (!Random(5)) Sound("Punch*");
|
|
if (!Random(2)) return 1;
|
|
GetActionTarget()->Punch();
|
|
return 1;
|
|
}
|
|
|
|
private func Chopping()
|
|
{
|
|
if (!GetActTime()) return; // Erster Schlag kein Sound. Clonk holt noch aus.
|
|
Sound("Chop*");
|
|
CastParticles("Dust",Random(3)+1,6,-8+16*GetDir(),1,10,12);
|
|
return 1;
|
|
}
|
|
|
|
private func Building()
|
|
{
|
|
if (!Random(2)) Sound("Build*");
|
|
return 1;
|
|
}
|
|
|
|
private func Processing()
|
|
{
|
|
Sound("Build1");
|
|
return 1;
|
|
}
|
|
|
|
private func Digging()
|
|
{
|
|
Sound("Dig*");
|
|
return 1;
|
|
}
|
|
|
|
protected func Scaling()
|
|
{
|
|
var szDesiredAction;
|
|
if (GetYDir()>0) szDesiredAction = "ScaleDown"; else szDesiredAction = "Scale";
|
|
if (GetAction() != szDesiredAction) SetAction(szDesiredAction);
|
|
return 1;
|
|
}
|
|
|
|
|
|
/* Ereignisse */
|
|
|
|
protected func CatchBlow()
|
|
{
|
|
if (GetAction() == "Dead") return 0;
|
|
if (!Random(5)) Hurt();
|
|
return 1;
|
|
}
|
|
|
|
protected func Hurt()
|
|
{
|
|
Sound("Hurt*");
|
|
return 1;
|
|
}
|
|
|
|
protected func Grab(object pTarget, bool fGrab)
|
|
{
|
|
Sound("Grab");
|
|
return 1;
|
|
}
|
|
|
|
protected func Get()
|
|
{
|
|
Sound("Grab");
|
|
return 1;
|
|
}
|
|
|
|
protected func Put()
|
|
{
|
|
Sound("Grab");
|
|
return 1;
|
|
}
|
|
|
|
protected func Death(int iKilledBy)
|
|
{
|
|
// Info-Broadcasts für sterbende Clonks
|
|
GameCallEx("OnClonkDeath", this, iKilledBy);
|
|
|
|
// Der Broadcast könnte seltsame Dinge gemacht haben: Clonk ist noch tot?
|
|
if (GetAlive()) return;
|
|
|
|
Sound("Die");
|
|
DeathAnnounce();
|
|
// Letztes Mannschaftsmitglied tot: Script benachrichtigen
|
|
if (!GetCrew(GetOwner()))
|
|
GameCallEx("RelaunchPlayer",GetOwner());
|
|
return 1;
|
|
}
|
|
|
|
protected func Destruction()
|
|
{
|
|
// Clonk war noch nicht tot: Jetzt ist er es
|
|
if (GetAlive())
|
|
GameCallEx("OnClonkDeath", this, GetKiller());
|
|
// Dies ist das letztes Mannschaftsmitglied: Script benachrichtigen
|
|
if (GetCrew(GetOwner()) == this)
|
|
if (GetCrewCount(GetOwner()) == 1)
|
|
//Nur wenn der Spieler noch lebt und nicht gerade eleminiert wird
|
|
if (GetPlayerName(GetOwner()))
|
|
{
|
|
GameCallEx("RelaunchPlayer",GetOwner());
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
protected func DeepBreath()
|
|
{
|
|
Sound("Breath");
|
|
return 1;
|
|
}
|
|
|
|
protected func CheckStuck()
|
|
{
|
|
// Verhindert Festhängen am Mittelvertex
|
|
if(!GetXDir()) if(Abs(GetYDir()) < 5)
|
|
if(GBackSolid(0, 3))
|
|
SetPosition(GetX(), GetY() + 1);
|
|
}
|
|
|
|
|
|
/* Status */
|
|
|
|
public func IsRiding()
|
|
{
|
|
// Reitet der Clonk?
|
|
return (WildcardMatch(GetAction(), "Ride*"));
|
|
}
|
|
|
|
public func IsClonk() { return 1; }
|
|
|
|
|
|
/* Kontext */
|
|
|
|
public func ContextRelease(pCaller)
|
|
{
|
|
[$CtxRelease$|Image=CXRL|Condition=ReleaseAllowed]
|
|
FindObject(REAC)->Activate(GetOwner());
|
|
return 1;
|
|
}
|
|
|
|
public func ContextEnergy(pCaller)
|
|
{
|
|
[$TxtEnergysupply$|Image=CXEC|Condition=AtEnergySite]
|
|
var pSite;
|
|
if (pSite = FindEnergySite())
|
|
SetCommand(this, "Energy", pSite);
|
|
return 1;
|
|
}
|
|
|
|
public func ContextConstructionSite(pCaller)
|
|
{
|
|
[$CtxConstructionMaterial$|Image=CXCM|Condition=AtConstructionSite]
|
|
var pSite;
|
|
if (pSite = FindConstructionSite())
|
|
PlayerMessage(GetOwner(), pSite->GetNeededMatStr(), pSite);
|
|
return 1;
|
|
}
|
|
|
|
public func ContextChop(pCaller)
|
|
{
|
|
[$CtxChop$|Image=CXCP|Condition=AtTreeToChop]
|
|
var pTree;
|
|
if (pTree = FindTree())
|
|
SetCommand(this, "Chop", pTree);
|
|
return 1;
|
|
}
|
|
|
|
public func ContextConstruction(pCaller)
|
|
{
|
|
[$CtxConstructionDesc$|Image=CXCN|Condition=HasConstructMenu]
|
|
SetCommand(this, "Construct");
|
|
ExecuteCommand();
|
|
return 1;
|
|
}
|
|
|
|
public func ContextHome(pCaller)
|
|
{
|
|
[$CtxHomeDesc$|Image=CXHM|Condition=HasBase]
|
|
SetCommand(this, "Home");
|
|
return 1;
|
|
}
|
|
|
|
|
|
/* Hilfsfunktion */
|
|
|
|
public func ContainedCall(string strFunction, object pTarget)
|
|
{
|
|
// Erst das betreffende Gebäude betreten, dann die Zielfunktion aufrufen
|
|
SetCommand(this, "Call", pTarget, this, 0, 0, strFunction);
|
|
AddCommand(this, "Enter", pTarget);
|
|
}
|
|
|
|
|
|
/* Callback beim Auswahl aus dem Construct-Kontextmenu */
|
|
|
|
public func ControlCommandConstruction(target, x, y, target2, def)
|
|
{
|
|
// Keine Konstruktion erlaubt?
|
|
if(def->~RejectConstruction(x - GetX(), y - GetY(), this) )
|
|
// Construct-Kommando beenden
|
|
return FinishCommand(false, 0) ;
|
|
}
|
|
|
|
|
|
/* Automatische Produktion */
|
|
|
|
public func ControlCommandAcquire(target, x, y, target2, def)
|
|
{
|
|
// Falls das Teil rumliegt nur aufsammeln
|
|
var obj = GetAvailableObject (def, target2);
|
|
if (obj) {
|
|
AddEffect("IntNotAvailable", obj, 1, 5, this);
|
|
AddCommand ("Get", obj, 0, 0, 0, 40);
|
|
return 1;
|
|
}
|
|
// Gebäude suchen worin man's herstellen kann
|
|
if (obj = GetProducerOf (def)) {
|
|
AddCommand ("Call", this, 0, 0, 0, 0, "AutoProduction", 0, 1);
|
|
obj -> ~HowToProduce (this, def);
|
|
return 1;
|
|
}
|
|
AddCommand ("Buy", 0, 0, 0, 0, 100, def, 0, C4CMD_Sub);
|
|
return 1;
|
|
}
|
|
|
|
public func AutoProduction() { return 1; }
|
|
|
|
public func AutoProductionFailed()
|
|
{
|
|
var def = GetCommand (5, 1);
|
|
if (!FindContents(def)) {
|
|
var obj = GetAvailableObject (def, GetCommand (4, 1));
|
|
if (obj) {
|
|
AddEffect("IntNotAvailable", obj, 1, 5, this);
|
|
AddCommand ("Get", obj,0,0,0,40);
|
|
return 1;
|
|
}
|
|
AddCommand ("Buy", 0, 0, 0, 0, 100, GetCommand(5, 1), 0, C4CMD_Sub);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
public func FxIntNotAvailableStart(target, number)
|
|
{
|
|
EffectVar(0, target, number) = this;
|
|
}
|
|
|
|
public func FxIntNotAvailableTimer(target, number)
|
|
{
|
|
var clonk = EffectVar(0, target, number);
|
|
// Check wether the clonk still wants to get the object
|
|
for (var i = 0; GetCommand(clonk,0,i); ++i) {
|
|
if (GetCommand(clonk, 0, i) == "Get" && GetCommand(clonk, 1, i) == target)
|
|
return;
|
|
}
|
|
return FX_Execute_Kill;
|
|
}
|
|
|
|
public func GetProducerOf(def)
|
|
{
|
|
return FindObject(Find_InRect(-500,-250,1000,500), Find_Func("IsProducerOf", this, def), Sort_Distance());
|
|
}
|
|
|
|
|
|
/* Trinken */
|
|
|
|
public func Drink(object pDrink)
|
|
{
|
|
// Trinkaktion setzen, wenn vorhanden
|
|
if (GetActMapVal("Name", "Drink"))
|
|
SetAction("Drink");
|
|
// Vorsicht: erstmal nichts mit pDrink machen,
|
|
// die Potions löschen sich meist selber...
|
|
}
|
|
|
|
|
|
/* Einsammeln */
|
|
|
|
public func RejectCollect(id idObject, object pObject)
|
|
{
|
|
// Objekt kann gepackt werden
|
|
// automatisches Packen aber nur wenn die Paktteile nicht extra gezählt werden
|
|
if(!IsSpecialItem(pObject)) if(pObject->~JoinPack(this)) return 1;
|
|
|
|
// Objektaufnahme mit Limit verhindern, wenn bereits genug getragen
|
|
if(pObject->~CarryLimit() && ContentsCount(idObject) >= pObject->~CarryLimit() ) return 1;
|
|
|
|
// Spezialitem?
|
|
var i, iCount;
|
|
if(i = IsSpecialItem(pObject))
|
|
{
|
|
// Noch genug Platz für das ganze Packet?
|
|
if(GetSpecialCount(GetMaxSpecialCount(i-1))+Max(pObject->~PackCount(),1)<=GetMaxSpecialCount(i-1, 1)) return 0;
|
|
iCount = GetMaxSpecialCount(i-1, 1)-GetSpecialCount(GetMaxSpecialCount(i-1));
|
|
// Ansonten so viel wie geht rein
|
|
if(pObject->~SplitPack(pObject->~PackCount()-iCount)) return 0;
|
|
else return 1;
|
|
}
|
|
|
|
return GetNonSpecialCount()>=MaxContentsCount();
|
|
}
|
|
|
|
|
|
/* Itemlimit */
|
|
public func MaxContentsCount() { return 1; }
|
|
|
|
public func GetMaxSpecialCount(iIndex, fAmount)
|
|
{
|
|
// Hier könnten Spezialbehandlungen von Itemgruppen definiert werden
|
|
// wie z.B. zu dem Inventar noch 30 Pfeile aufnehmen (siehe auch Ritter)
|
|
// if(iIndex == 0) { if(fAmount) return(30); return("IsArrow"); }
|
|
}
|
|
|
|
/* Liefert die Gesamtzahl eines Objekt(paket)typs */
|
|
private func GetObjectCount(idObj)
|
|
{
|
|
var idUnpackedObj;
|
|
if (idUnpackedObj = idObj->~UnpackTo())
|
|
// Auch verschachtelte Pakete mitzählen
|
|
return GetObjectCount(idUnpackedObj) * (idObj->~PackCount()||1);
|
|
// Ansonsten ist es nur ein Objekt
|
|
return 1;
|
|
}
|
|
|
|
/* Spezialgegenstände im Inventar zählen */
|
|
private func GetSpecialCount(szTest)
|
|
{
|
|
var iCnt, pObj;
|
|
// Einzelne Pfeile...
|
|
for(var i = 0; pObj = Contents(i); i++)
|
|
if(pObj->Call(szTest))
|
|
iCnt++;
|
|
// Pakete...
|
|
for(var i = 0; pObj = Contents(i); i++)
|
|
if(pObj->~UnpackTo())
|
|
if(DefinitionCall(pObj->~UnpackTo(), szTest))
|
|
iCnt += GetObjectCount(pObj);
|
|
// Wert zurückgeben
|
|
return iCnt;
|
|
}
|
|
|
|
/* Testen eines Objektes */
|
|
private func IsSpecialItem(pObj)
|
|
{
|
|
// Spezialitem?
|
|
var j=-1;
|
|
while(GetMaxSpecialCount(++j, 1))
|
|
if(pObj->GetMaxSpecialCount(j))
|
|
return j+1;
|
|
// Spezialitempacket?
|
|
if(pObj->~UnpackTo())
|
|
{
|
|
j=-1;
|
|
while(GetMaxSpecialCount(++j, 1))
|
|
if(DefinitionCall(pObj->~UnpackTo(), GetMaxSpecialCount(j)))
|
|
return j+1;
|
|
}
|
|
}
|
|
|
|
/* Anzahl an normalen Objekten */
|
|
private func GetNonSpecialCount()
|
|
{
|
|
var iCnt, pObj;
|
|
// Inventar einzeln auf nicht-Spezial überprüfen
|
|
for(var i = 0; pObj = Contents(i); i++)
|
|
// Spezialitems nicht zählen
|
|
if(!IsSpecialItem(pObj))
|
|
iCnt++;
|
|
|
|
// Wert zurückgeben
|
|
return iCnt;
|
|
}
|
|
|
|
/* Reiten */
|
|
|
|
public func ContextDescend(pCaller)
|
|
{
|
|
[$TxtDescend$|Image=DSCN|Condition=IsRiding]
|
|
DescendVehicle();
|
|
}
|
|
|
|
public func DescendVehicle()
|
|
{
|
|
var pOldVehicle = GetActionTarget();
|
|
SetAction("Walk");
|
|
// Feststecken nach Absteigen? Dann besser direkt beim Gefährt absteigen.
|
|
if (Stuck()) if (pOldVehicle)
|
|
{
|
|
var x=GetX(), y=GetY();
|
|
SetPosition(pOldVehicle->GetX(), pOldVehicle->GetY());
|
|
if (Stuck())
|
|
{
|
|
// Das Gefährt steckt auch? Dann hilft es alles nichts. Zurück zum Ursprungsort.
|
|
SetPosition(x,y);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* Pfeile */
|
|
|
|
// Pfeilpaket aufteilen
|
|
public func SplitPack2Components(pPack)
|
|
{
|
|
// Aufteilen
|
|
if(!pPack->~Unpack(this) ) Split2Components(pPack);
|
|
// Fertig, Erfolg
|
|
return 1;
|
|
}
|
|
|
|
/* Pfeil aus dem Inventar nehmen */
|
|
public func GetArrow()
|
|
{
|
|
// Einzelne Pfeile suchen
|
|
var pObj, pArrow;
|
|
for(var i = 0; pObj = Contents(i); i++)
|
|
if(pObj->~IsArrow())
|
|
return pObj;
|
|
// Bei Bedarf Pakete aufteilen
|
|
for(var i = 0; pObj = Contents(i); i++)
|
|
if(pObj->~IsArrowPack())
|
|
{
|
|
// Pfeil aus Paket verwenden
|
|
if(pArrow = pObj->~GetItem()) return pArrow;
|
|
// oder bei alten Pfeilen Paket aufteilen
|
|
if (SplitPack2Components(pObj))
|
|
return FindSingleArrow();
|
|
}
|
|
// Keine Pfeile gefunden
|
|
return 0;
|
|
}
|
|
|
|
public func FindSingleArrow()
|
|
{
|
|
// Einzelne Pfeile suchen
|
|
var pObj;
|
|
for(var i = 0; pObj = Contents(i); i++)
|
|
if(pObj->~IsArrow())
|
|
return pObj;
|
|
// Keiner gefunden
|
|
return 0;
|
|
}
|
|
|
|
public func GetComboArrow()
|
|
{
|
|
// Pfeile als Komboobjekt: Nur wenn das erste Inventarobjekt ein Pfeil ist
|
|
var pObj = Contents(0), pArrow;
|
|
if (!pObj) return;
|
|
if(pObj->~IsArrow()) return pObj;
|
|
// Bei Bedarf Pakete aufteilen
|
|
if(pObj->~IsArrowPack())
|
|
{
|
|
// Pfeil aus Paket verwenden
|
|
if(pArrow = pObj->~GetItem()) return pArrow;
|
|
// oder bei alten Pfeilen Paket aufteilen
|
|
if (SplitPack2Components(pObj))
|
|
return FindSingleArrow();
|
|
}
|
|
// Keine Pfeile gefunden
|
|
return 0;
|
|
}
|
|
|
|
/* Pfeile im Inventar zählen */
|
|
private func GetArrowCount()
|
|
{
|
|
return GetSpecialCount("IsArrow");
|
|
}
|
|
|
|
|
|
/* Dummies, damit die Engine die Namen kennt... */
|
|
|
|
func Activate() {}
|
|
func HowToProduce() {}
|
|
func PackCount() {}
|
|
func Definition(def) {
|
|
SetProperty("ActMap", {
|
|
Walk = {
|
|
Prototype = Action,
|
|
Name = "Walk",
|
|
Procedure = DFA_WALK,
|
|
Directions = 2,
|
|
FlipDir = 1,
|
|
Length = 16,
|
|
Delay = 15,
|
|
X = 0,
|
|
Y = 0,
|
|
Wdt = 16,
|
|
Hgt = 20,
|
|
NextAction = "Walk",
|
|
InLiquidAction = "Swim",
|
|
},
|
|
StillTrans1 = {
|
|
Prototype = Action,
|
|
Name = "StillTrans1",
|
|
Procedure = DFA_THROW,
|
|
Directions = 2,
|
|
FlipDir = 1,
|
|
Length = 4,
|
|
Delay = 2,
|
|
X = 0,
|
|
Y = 280,
|
|
Wdt = 16,
|
|
Hgt = 20,
|
|
NextAction = "Still",
|
|
InLiquidAction = "Swim",
|
|
},
|
|
Still = {
|
|
Prototype = Action,
|
|
Name = "Still",
|
|
Procedure = DFA_THROW,
|
|
Directions = 2,
|
|
FlipDir = 1,
|
|
Length = 8,
|
|
Delay = 10,
|
|
X = 64,
|
|
Y = 280,
|
|
Wdt = 16,
|
|
Hgt = 20,
|
|
NextAction = "Still",
|
|
InLiquidAction = "Swim",
|
|
},
|
|
StillTrans2 = {
|
|
Prototype = Action,
|
|
Name = "StillTrans2",
|
|
Procedure = DFA_THROW,
|
|
Directions = 2,
|
|
Reverse = 1,
|
|
FlipDir = 1,
|
|
Length = 4,
|
|
Delay = 2,
|
|
X = 192,
|
|
Y = 280,
|
|
Wdt = 16,
|
|
Hgt = 20,
|
|
NextAction = "Still",
|
|
InLiquidAction = "Swim",
|
|
},
|
|
Scale = {
|
|
Prototype = Action,
|
|
Name = "Scale",
|
|
Procedure = DFA_SCALE,
|
|
Directions = 2,
|
|
FlipDir = 1,
|
|
Length = 16,
|
|
Delay = 15,
|
|
X = 0,
|
|
Y = 20,
|
|
Wdt = 16,
|
|
Hgt = 20,
|
|
OffX = 2,
|
|
OffY = 0,
|
|
NextAction = "Scale",
|
|
StartCall = "Scaling",
|
|
},
|
|
ScaleDown = {
|
|
Prototype = Action,
|
|
Name = "ScaleDown",
|
|
Procedure = DFA_SCALE,
|
|
Directions = 2,
|
|
FlipDir = 1,
|
|
Length = 16,
|
|
Delay = 15,
|
|
X = 0,
|
|
Y = 20,
|
|
Wdt = 16,
|
|
Hgt = 20,
|
|
OffX = 2,
|
|
OffY = 0,
|
|
Reverse = 1,
|
|
NextAction = "ScaleDown",
|
|
StartCall = "Scaling",
|
|
},
|
|
Tumble = {
|
|
Prototype = Action,
|
|
Name = "Tumble",
|
|
Procedure = DFA_FLIGHT,
|
|
Directions = 2,
|
|
FlipDir = 1,
|
|
Length = 16,
|
|
Delay = 1,
|
|
X = 0,
|
|
Y = 40,
|
|
Wdt = 16,
|
|
Hgt = 20,
|
|
NextAction = "Tumble",
|
|
ObjectDisabled = 1,
|
|
InLiquidAction = "Swim",
|
|
EndCall = "CheckStuck",
|
|
},
|
|
Dig = {
|
|
Prototype = Action,
|
|
Name = "Dig",
|
|
Procedure = DFA_DIG,
|
|
Directions = 2,
|
|
FlipDir = 1,
|
|
Length = 16,
|
|
Delay = 15,
|
|
X = 0,
|
|
Y = 60,
|
|
Wdt = 16,
|
|
Hgt = 20,
|
|
NextAction = "Dig",
|
|
StartCall = "Digging",
|
|
DigFree = 11,
|
|
InLiquidAction = "Swim",
|
|
},
|
|
Bridge = {
|
|
Prototype = Action,
|
|
Name = "Bridge",
|
|
Procedure = DFA_BRIDGE,
|
|
Directions = 2,
|
|
FlipDir = 1,
|
|
Length = 16,
|
|
Delay = 1,
|
|
X = 0,
|
|
Y = 60,
|
|
Wdt = 16,
|
|
Hgt = 20,
|
|
NextAction = "Bridge",
|
|
StartCall = "Digging",
|
|
InLiquidAction = "Swim",
|
|
},
|
|
Swim = {
|
|
Prototype = Action,
|
|
Name = "Swim",
|
|
Procedure = DFA_SWIM,
|
|
Directions = 2,
|
|
FlipDir = 1,
|
|
Length = 12,
|
|
Delay = 15,
|
|
X = 0,
|
|
Y = 80,
|
|
Wdt = 20,
|
|
Hgt = 20,
|
|
OffX = 0,
|
|
OffY = 1,
|
|
NextAction = "Swim",
|
|
StartCall = "Swimming",
|
|
},
|
|
Swim2 = {
|
|
Prototype = Action,
|
|
Name = "Swim2",
|
|
Procedure = DFA_SWIM,
|
|
Directions = 2,
|
|
FlipDir = 1,
|
|
Length = 12,
|
|
Delay = 15,
|
|
X = 0,
|
|
Y = 300,
|
|
Wdt = 20,
|
|
Hgt = 20,
|
|
OffX = 0,
|
|
OffY = 1,
|
|
NextAction = "Swim2",
|
|
StartCall = "Swimming2",
|
|
},
|
|
Hangle = {
|
|
Prototype = Action,
|
|
Name = "Hangle",
|
|
Procedure = DFA_HANGLE,
|
|
Directions = 2,
|
|
FlipDir = 1,
|
|
Length = 11,
|
|
Delay = 16,
|
|
X = 0,
|
|
Y = 100,
|
|
Wdt = 16,
|
|
Hgt = 20,
|
|
OffX = 0,
|
|
OffY = 3,
|
|
NextAction = "Hangle",
|
|
InLiquidAction = "Swim",
|
|
},
|
|
Jump = {
|
|
Prototype = Action,
|
|
Name = "Jump",
|
|
Procedure = DFA_FLIGHT,
|
|
Directions = 2,
|
|
FlipDir = 1,
|
|
Length = 8,
|
|
Delay = 3,
|
|
X = 0,
|
|
Y = 120,
|
|
Wdt = 16,
|
|
Hgt = 20,
|
|
NextAction = "Hold",
|
|
InLiquidAction = "Swim",
|
|
PhaseCall = "CheckStuck",
|
|
},
|
|
KneelDown = {
|
|
Prototype = Action,
|
|
Name = "KneelDown",
|
|
Procedure = DFA_KNEEL,
|
|
Directions = 2,
|
|
FlipDir = 1,
|
|
Length = 4,
|
|
Delay = 1,
|
|
X = 0,
|
|
Y = 140,
|
|
Wdt = 16,
|
|
Hgt = 20,
|
|
NextAction = "KneelUp",
|
|
},
|
|
KneelUp = {
|
|
Prototype = Action,
|
|
Name = "KneelUp",
|
|
Procedure = DFA_KNEEL,
|
|
Directions = 2,
|
|
FlipDir = 1,
|
|
Length = 4,
|
|
Delay = 1,
|
|
X = 64,
|
|
Y = 140,
|
|
Wdt = 16,
|
|
Hgt = 20,
|
|
NextAction = "Walk",
|
|
},
|
|
Dive = {
|
|
Prototype = Action,
|
|
Name = "Dive",
|
|
Procedure = DFA_FLIGHT,
|
|
Directions = 2,
|
|
FlipDir = 1,
|
|
Length = 8,
|
|
Delay = 4,
|
|
X = 0,
|
|
Y = 160,
|
|
Wdt = 16,
|
|
Hgt = 20,
|
|
NextAction = "Hold",
|
|
ObjectDisabled = 1,
|
|
InLiquidAction = "Swim",
|
|
PhaseCall = "CheckStuck",
|
|
},
|
|
FlatUp = {
|
|
Prototype = Action,
|
|
Name = "FlatUp",
|
|
Procedure = DFA_KNEEL,
|
|
Directions = 2,
|
|
FlipDir = 1,
|
|
Length = 8,
|
|
Delay = 1,
|
|
X = 0,
|
|
Y = 180,
|
|
Wdt = 16,
|
|
Hgt = 20,
|
|
NextAction = "KneelUp",
|
|
ObjectDisabled = 1,
|
|
},
|
|
Throw = {
|
|
Prototype = Action,
|
|
Name = "Throw",
|
|
Procedure = DFA_THROW,
|
|
Directions = 2,
|
|
FlipDir = 1,
|
|
Length = 8,
|
|
Delay = 1,
|
|
X = 0,
|
|
Y = 200,
|
|
Wdt = 16,
|
|
Hgt = 20,
|
|
NextAction = "Walk",
|
|
InLiquidAction = "Swim",
|
|
},
|
|
Punch = {
|
|
Prototype = Action,
|
|
Name = "Punch",
|
|
Procedure = DFA_FIGHT,
|
|
Directions = 2,
|
|
FlipDir = 1,
|
|
Length = 8,
|
|
Delay = 2,
|
|
X = 0,
|
|
Y = 220,
|
|
Wdt = 16,
|
|
Hgt = 20,
|
|
NextAction = "Fight",
|
|
EndCall = "Punching",
|
|
ObjectDisabled = 1,
|
|
},
|
|
Dead = {
|
|
Prototype = Action,
|
|
Name = "Dead",
|
|
Directions = 2,
|
|
FlipDir = 1,
|
|
X = 0,
|
|
Y = 240,
|
|
Wdt = 16,
|
|
Hgt = 20,
|
|
Length = 6,
|
|
Delay = 3,
|
|
NextAction = "Hold",
|
|
NoOtherAction = 1,
|
|
ObjectDisabled = 1,
|
|
},
|
|
Ride = {
|
|
Prototype = Action,
|
|
Name = "Ride",
|
|
Procedure = DFA_ATTACH,
|
|
Directions = 2,
|
|
FlipDir = 1,
|
|
Length = 4,
|
|
Delay = 3,
|
|
X = 128,
|
|
Y = 120,
|
|
Wdt = 16,
|
|
Hgt = 20,
|
|
NextAction = "Ride",
|
|
StartCall = "Riding",
|
|
InLiquidAction = "Swim",
|
|
},
|
|
RideStill = {
|
|
Prototype = Action,
|
|
Name = "RideStill",
|
|
Procedure = DFA_ATTACH,
|
|
Directions = 2,
|
|
FlipDir = 1,
|
|
Length = 1,
|
|
Delay = 10,
|
|
X = 128,
|
|
Y = 120,
|
|
Wdt = 16,
|
|
Hgt = 20,
|
|
NextAction = "RideStill",
|
|
StartCall = "Riding",
|
|
InLiquidAction = "Swim",
|
|
},
|
|
Push = {
|
|
Prototype = Action,
|
|
Name = "Push",
|
|
Procedure = DFA_PUSH,
|
|
Directions = 2,
|
|
FlipDir = 1,
|
|
Length = 8,
|
|
Delay = 15,
|
|
X = 128,
|
|
Y = 140,
|
|
Wdt = 16,
|
|
Hgt = 20,
|
|
NextAction = "Push",
|
|
InLiquidAction = "Swim",
|
|
},
|
|
Chop = {
|
|
Prototype = Action,
|
|
Name = "Chop",
|
|
Procedure = DFA_CHOP,
|
|
Directions = 2,
|
|
FlipDir = 1,
|
|
Length = 8,
|
|
Delay = 3,
|
|
X = 128,
|
|
Y = 160,
|
|
Wdt = 16,
|
|
Hgt = 20,
|
|
NextAction = "Chop",
|
|
StartCall = "Chopping",
|
|
InLiquidAction = "Swim",
|
|
},
|
|
Fight = {
|
|
Prototype = Action,
|
|
Name = "Fight",
|
|
Procedure = DFA_FIGHT,
|
|
Directions = 2,
|
|
FlipDir = 1,
|
|
Length = 7,
|
|
Delay = 4,
|
|
X = 128,
|
|
Y = 180,
|
|
Wdt = 16,
|
|
Hgt = 20,
|
|
NextAction = "Fight",
|
|
StartCall = "Fighting",
|
|
ObjectDisabled = 1,
|
|
},
|
|
GetPunched = {
|
|
Prototype = Action,
|
|
Name = "GetPunched",
|
|
Procedure = DFA_FIGHT,
|
|
Directions = 2,
|
|
FlipDir = 1,
|
|
Length = 8,
|
|
Delay = 3,
|
|
X = 128,
|
|
Y = 200,
|
|
Wdt = 16,
|
|
Hgt = 20,
|
|
NextAction = "Fight",
|
|
ObjectDisabled = 1,
|
|
},
|
|
Build = {
|
|
Prototype = Action,
|
|
Name = "Build",
|
|
Procedure = DFA_BUILD,
|
|
Directions = 2,
|
|
FlipDir = 1,
|
|
Length = 8,
|
|
Delay = 2,
|
|
X = 128,
|
|
Y = 220,
|
|
Wdt = 16,
|
|
Hgt = 20,
|
|
NextAction = "Build",
|
|
StartCall = "Building",
|
|
InLiquidAction = "Swim",
|
|
},
|
|
RideThrow = {
|
|
Prototype = Action,
|
|
Name = "RideThrow",
|
|
Procedure = DFA_ATTACH,
|
|
Directions = 2,
|
|
FlipDir = 1,
|
|
Length = 8,
|
|
Delay = 1,
|
|
X = 128,
|
|
Y = 240,
|
|
Wdt = 16,
|
|
Hgt = 20,
|
|
NextAction = "Ride",
|
|
StartCall = "Throwing",
|
|
InLiquidAction = "Swim",
|
|
},
|
|
Process = {
|
|
Prototype = Action,
|
|
Name = "Process",
|
|
Procedure = DFA_THROW,
|
|
Directions = 2,
|
|
FlipDir = 1,
|
|
Length = 8,
|
|
Delay = 3,
|
|
X = 0,
|
|
Y = 260,
|
|
Wdt = 16,
|
|
Hgt = 20,
|
|
NextAction = "Process",
|
|
EndCall = "Processing",
|
|
},
|
|
Drink = {
|
|
Prototype = Action,
|
|
Name = "Drink",
|
|
Procedure = DFA_THROW,
|
|
Directions = 2,
|
|
FlipDir = 1,
|
|
Length = 8,
|
|
Delay = 3,
|
|
X = 128,
|
|
Y = 260,
|
|
Wdt = 16,
|
|
Hgt = 20,
|
|
NextAction = "Walk",
|
|
}, }, def);
|
|
SetProperty("Name", "Clonk", def);
|
|
}
|