If you only have a few conditional expressions, you could probably use a procedure pointer.
However, if you need to use multiple complex conditions, it's probably better to specify the condition as a string and parse it.
Example 1.
Code: Select all
Structure Quest
Name.s
Unlocked.b
*UnlockRequirements
EndStructure
Procedure Bool_A_ge_B_And_C_ge_D(a, b, c, d)
ProcedureReturn Bool(a >= b And c >= d)
EndProcedure
Procedure Bool_A_ge_B(a, b)
ProcedureReturn Bool(a >= b)
EndProcedure
a.Quest\UnlockRequirements = @Bool_A_ge_B_And_C_ge_D()
b.Quest\UnlockRequirements = @Bool_A_ge_B()
StepsTaken = 1001
TimePlayed = 60001
logsSold = 101
; StepsTaken >= 1000 And TimePlayed >= 60000
Debug CallFunctionFast(a\UnlockRequirements, StepsTaken, 1000, TimePlayed, 60000)
; logsSold >= 100
Debug CallFunctionFast(b\UnlockRequirements, logsSold, 100)
Example 2.
Code: Select all
Prototype Bool_A_ge_B_And_C_ge_D(a, b, c, d)
Prototype Bool_A_ge_B(a, b)
Structure Quest
Name.s
Unlocked.b
StructureUnion
UnlockRequirements_A_ge_B_And_C_ge_D.Bool_A_ge_B_And_C_ge_D
UnlockRequirements_A_ge_B.Bool_A_ge_B
EndStructureUnion
EndStructure
Procedure Bool_A_ge_B_And_C_ge_D(a, b, c, d)
ProcedureReturn Bool(a >= b And c >= d)
EndProcedure
Procedure Bool_A_ge_B(a, b)
ProcedureReturn Bool(a >= b)
EndProcedure
a.Quest\UnlockRequirements_A_ge_B_And_C_ge_D = @Bool_A_ge_B_And_C_ge_D()
b.Quest\UnlockRequirements_A_ge_B = @Bool_A_ge_B()
StepsTaken = 1001
TimePlayed = 60001
logsSold = 101
; StepsTaken >= 1000 And TimePlayed >= 60000
Debug a\UnlockRequirements_A_ge_B_And_C_ge_D(StepsTaken, 1000, TimePlayed, 60000)
; logsSold >= 100
Debug b\UnlockRequirements_A_ge_B(logsSold, 100)
Edit:
If your conditional expression has a specific pattern, you can parse it as shown below.
(use of runtime global variables.)
The code below is just a rough example, and will need more error checking for completeness.
Code: Select all
Structure Quest
Name.s
Unlocked.b
UnlockRequirements.s
EndStructure
Global StepsTaken
Runtime StepsTaken
Global TimePlayed
Runtime TimePlayed
Global logsSold
Runtime logsSold
Procedure BoolStr(exp.s)
Protected result, count, i, ii
Protected part.s
Protected Dim v.i(0)
Protected tmp = 1
exp = Trim(exp)
If exp = "" : ProcedureReturn 0 : EndIf
count = CountString(exp, "&") + 1
ReDim v.i(count * 2 - 1)
For i = 1 To count
part = Trim(StringField(exp, i, "&"))
If part
v(ii) = GetRuntimeInteger(StringField(part, 1, " "))
v(ii + 1) = Val(StringField(part, 2, " "))
ii + 2
EndIf
Next
i = 0
While ii > 0
tmp = Bool( tmp And Bool(v(i) >= v(i+1)) )
;Debug "v(i) : " + v(i)
;Debug "v(i + 1) : " + v(i + 1)
i + 2
ii - 2
result = tmp
;Debug "tmp : " + result
Wend
;Debug "final result : " + result
ProcedureReturn result
EndProcedure
a.Quest\UnlockRequirements = "StepsTaken 1000 & TimePlayed 60000"
b.Quest\UnlockRequirements = "logsSold 100"
StepsTaken = 1001
TimePlayed = 60001
logsSold = 101
; StepsTaken >= 1000 And TimePlayed >= 60000
Debug BoolStr(a\UnlockRequirements)
; logsSold >= 100
Debug BoolStr(b\UnlockRequirements)
Edit2:
If you have a fixed pattern of conditions, you can also use an interface instead of a string, as shown below.
As long as you're careful with the scopes of the variables, you can avoid using global variables.
Edit3:
Bug fixed, and shorten code.
By the way, I'm not sure there's any advantage to this approach other than convenience. If your condition expressions are simple, directly inserting it (or a function with a comparison expression) can result in shorter code.
Code: Select all
Structure Quest
Name.s
Unlocked.b
*UnlockRequirementsVar.Integer[2]
UnlockRequirementsValue.i[2]
EndStructure
StepsTaken = 1000
TimePlayed = 60000
logsSold = 100
Define a.Quest
Define b.Quest
; StepsTaken >= 1000 And TimePlayed >= 60000
a\UnlockRequirementsVar[0] = @StepsTaken
a\UnlockRequirementsValue[0] = 1000
a\UnlockRequirementsVar[1] = @TimePlayed
a\UnlockRequirementsValue[1] = 60000
If a\UnlockRequirementsVar[0]\i >= a\UnlockRequirementsValue[0] And a\UnlockRequirementsVar[1]\i >= a\UnlockRequirementsValue[1]
a\Unlocked = 1
Debug "a unlocked"
EndIf
; logsSold >= 100
b\UnlockRequirementsVar[0] = @logsSold
b\UnlockRequirementsValue[0] = 100
If b\UnlockRequirementsVar[0]\i >= b\UnlockRequirementsValue[0]
b\Unlocked = 1
Debug "b unlocked"
EndIf
Code: Select all
Interface IUnlockRequirements
GetUnlockResult()
SetExpressionVal(*var1.Integer, val1, *var2.Integer = 0, val2 = 0, *var3.Integer = 0, val3 = 0, *var4.Integer = 0, val4 = 0)
EndInterface
Structure IUnlockRequirementsVtbl
*vtble
*GetUnlockResult
*SetExpressionVal
*var.Integer[4]
val.i[4]
EndStructure
Procedure GetUnlockResult(*this.IUnlockRequirementsVtbl)
Protected Result, i, tmp = 1
If *this
For i = 0 To 3
If *this\var[i]
tmp = Bool( tmp And Bool( *this\var[i]\i >= *this\val[i]) )
Result = tmp
EndIf
Next
EndIf
ProcedureReturn Result
EndProcedure
Procedure SetExpressionVal(*this.IUnlockRequirementsVtbl, *var1.Integer, val1, *var2.Integer = 0, val2 = 0, *var3.Integer = 0, val3 = 0, *var4.Integer = 0, val4 = 0)
If *this
With *this
\var[0] = *var1
\val[0] = val1
\var[1] = *var2
\val[1] = val2
\var[2] = *var3
\val[2] = val3
\var[3] = *var4
\val[3] = val4
EndWith
If *var1 = 0 : ProcedureReturn 0 : EndIf
If *var2 = 0 : ProcedureReturn 1 : EndIf
If *var3 = 0 : ProcedureReturn 2 : EndIf
If *var4 = 0 : ProcedureReturn 3 : EndIf
ProcedureReturn 4
EndIf
ProcedureReturn 0
EndProcedure
Procedure CreateUnlockRequirementObj(*var1.Integer, val1, *var2.Integer = 0, val2 = 0, *var3.Integer = 0, val3 = 0, *var4.Integer = 0, val4 = 0)
Protected Result, *m.IUnlockRequirementsVtbl = AllocateMemory(SizeOf(IUnlockRequirementsVtbl))
If *m
*m\vtble = *m + OffsetOf(IUnlockRequirementsVtbl\GetUnlockResult)
*m\GetUnlockResult = @GetUnlockResult()
*m\SetExpressionVal = @SetExpressionVal()
Result = SetExpressionVal(*m, *var1, val1, *var2, val2, *var3, val3, *var4, val4)
If Result > 0
ProcedureReturn *m
EndIf
FreeMemory(*m)
EndIf
ProcedureReturn 0
EndProcedure
Structure Quest
Name.s
Unlocked.b
*UnlockRequirements.IUnlockRequirements
EndStructure
Global StepsTaken, TimePlayed, logsSold
a.Quest\UnlockRequirements = CreateUnlockRequirementObj(@StepsTaken, 1000, @TimePlayed, 60000)
If a\UnlockRequirements = 0
Debug "Obj A creation failed."
EndIf
b.Quest\UnlockRequirements = CreateUnlockRequirementObj(@logsSold, 100)
If b\UnlockRequirements = 0
Debug "Obj B creation failed."
EndIf
StepsTaken = 1000
TimePlayed = 60000
logsSold = 100
; StepsTaken >= 1000 And TimePlayed >= 60000
If a\UnlockRequirements
Debug a\UnlockRequirements\GetUnlockResult()
EndIf
; logsSold >= 100
If b\UnlockRequirements
Debug b\UnlockRequirements\GetUnlockResult()
EndIf
Debug "Values changed"
StepsTaken = 999
TimePlayed = 60000
logsSold = 99
; StepsTaken >= 1000 And TimePlayed >= 60000
If a\UnlockRequirements
Debug a\UnlockRequirements\GetUnlockResult()
EndIf
; logsSold >= 100
If b\UnlockRequirements
Debug b\UnlockRequirements\GetUnlockResult()
EndIf
Debug "Set new expressions"
Global StepsTaken2, TimePlayed2, logsSold2
StepsTaken2 = 100 ;- 1
TimePlayed2 = 6000 ;- 1
logsSold2 = 90 ;- 1
If a\UnlockRequirements
; StepsTaken2 >= 100 And TimePlayed2 >= 6000
a\UnlockRequirements\SetExpressionVal(@StepsTaken2, 100, @TimePlayed2, 6000)
Debug a\UnlockRequirements\GetUnlockResult()
StepsTaken2 = 100
; StepsTaken2 >= 1000
a\UnlockRequirements\SetExpressionVal(@StepsTaken2, 1000)
Debug a\UnlockRequirements\GetUnlockResult()
EndIf
If b\UnlockRequirements
; logsSold2 >= 90
b\UnlockRequirements\SetExpressionVal(@logsSold2, 90)
Debug b\UnlockRequirements\GetUnlockResult()
EndIf