package parser import ( "eq2emu/internal/common" "strconv" "strings" ) func (ctx *ParseContext) checkCondition(condition string) bool { if condition == "" { return true } // Handle comma-separated OR conditions if strings.Contains(condition, ",") { parts := strings.Split(condition, ",") for _, part := range parts { if ctx.evaluateCondition(strings.TrimSpace(part)) { return true } } return false } // Handle AND conditions with & if strings.Contains(condition, "&") && !strings.Contains(condition, "0x") { parts := strings.Split(condition, "&") for _, part := range parts { if !ctx.evaluateCondition(strings.TrimSpace(part)) { return false } } return true } return ctx.evaluateCondition(condition) } func (ctx *ParseContext) evaluateCondition(condition string) bool { // Flag conditions: flag:name or !flag:name if strings.HasPrefix(condition, "flag:") { flagName := condition[5:] return (ctx.flags & ctx.getFlagValue(flagName)) != 0 } if strings.HasPrefix(condition, "!flag:") { flagName := condition[6:] return (ctx.flags & ctx.getFlagValue(flagName)) == 0 } // Variable conditions: var:name or !var:name if strings.HasPrefix(condition, "var:") { varName := condition[4:] return ctx.hasVar(varName) } if strings.HasPrefix(condition, "!var:") { varName := condition[5:] return !ctx.hasVar(varName) } // Version comparisons if strings.HasPrefix(condition, "version") { return ctx.evaluateVersionCondition(condition) } // String length operators: name!>5, name!<=10 stringOps := []string{"!>=", "!<=", "!>", "!<", "!="} for _, op := range stringOps { if idx := strings.Index(condition, op); idx > 0 { varName := condition[:idx] valueStr := condition[idx+len(op):] return ctx.evaluateStringLength(varName, valueStr, op) } } // Comparison operators: >=, <=, >, <, ==, != compOps := []string{">=", "<=", ">", "<", "==", "!="} for _, op := range compOps { if idx := strings.Index(condition, op); idx > 0 { varName := condition[:idx] valueStr := condition[idx+len(op):] return ctx.evaluateComparison(varName, valueStr, op) } } // Bitwise AND: header_flag&0x01 if strings.Contains(condition, "&0x") { parts := strings.SplitN(condition, "&", 2) varName := parts[0] hexValue, _ := strconv.ParseUint(parts[1], 0, 64) varValue := ctx.getVarValue(varName) return (varValue & hexValue) != 0 } // Simple variable existence return ctx.hasVar(condition) } func (ctx *ParseContext) evaluateVersionCondition(condition string) bool { if strings.Contains(condition, ">=") { versionStr := condition[strings.Index(condition, ">=")+2:] targetVersion, _ := strconv.ParseUint(versionStr, 10, 32) return ctx.version >= uint32(targetVersion) } if strings.Contains(condition, "<=") { versionStr := condition[strings.Index(condition, "<=")+2:] targetVersion, _ := strconv.ParseUint(versionStr, 10, 32) return ctx.version <= uint32(targetVersion) } if strings.Contains(condition, ">") { versionStr := condition[strings.Index(condition, ">")+1:] targetVersion, _ := strconv.ParseUint(versionStr, 10, 32) return ctx.version > uint32(targetVersion) } if strings.Contains(condition, "<") { versionStr := condition[strings.Index(condition, "<")+1:] targetVersion, _ := strconv.ParseUint(versionStr, 10, 32) return ctx.version < uint32(targetVersion) } return false } func (ctx *ParseContext) evaluateStringLength(varName, valueStr, op string) bool { str := ctx.getStringVar(varName) targetLen, _ := strconv.Atoi(valueStr) strLen := len(str) switch op { case "!>": return strLen > targetLen case "!<": return strLen < targetLen case "!>=": return strLen >= targetLen case "!<=": return strLen <= targetLen case "!=": return strLen != targetLen } return false } func (ctx *ParseContext) evaluateComparison(varName, valueStr, op string) bool { varValue := ctx.getVarValue(varName) targetValue, _ := strconv.ParseUint(valueStr, 0, 64) switch op { case ">=": return varValue >= targetValue case "<=": return varValue <= targetValue case ">": return varValue > targetValue case "<": return varValue < targetValue case "==": return varValue == targetValue case "!=": return varValue != targetValue } return false } func (ctx *ParseContext) hasVar(name string) bool { // Handle %i substitution if strings.Contains(name, "%i") && len(ctx.arrayStack) > 0 { currentIndex := ctx.arrayStack[len(ctx.arrayStack)-1] name = strings.ReplaceAll(name, "%i", strconv.Itoa(currentIndex)) } if val, exists := ctx.vars[name]; exists { switch v := val.(type) { case uint8, uint16, uint32, uint64: return ctx.getVarValue(name) != 0 case string: return v != "" case common.EQ2String8: return v.Data != "" case common.EQ2String16: return v.Data != "" case common.EQ2String32: return v.Data != "" default: return true } } return false } func (ctx *ParseContext) getVarValue(name string) uint64 { if val, exists := ctx.vars[name]; exists { switch v := val.(type) { case uint8: return uint64(v) case uint16: return uint64(v) case uint32: return uint64(v) case uint64: return v } } return 0 } func (ctx *ParseContext) getStringVar(name string) string { if val, exists := ctx.vars[name]; exists { switch v := val.(type) { case string: return v case common.EQ2String8: return v.Data case common.EQ2String16: return v.Data case common.EQ2String32: return v.Data } } return "" } func (ctx *ParseContext) getFlagValue(flagName string) uint64 { flagMap := map[string]uint64{ "loot": 0x01, "has_equipment": 0x02, "no_colors": 0x04, } if val, exists := flagMap[flagName]; exists { return val } return 0 } func (ctx *ParseContext) getArraySize(condition string) int { if strings.HasPrefix(condition, "var:") { varName := condition[4:] return int(ctx.getVarValue(varName)) } return 0 }