package quests import ( "fmt" "strings" ) // Action management methods for Quest // AddCompleteAction adds a completion action for a step func (q *Quest) AddCompleteAction(stepID int32, action string) { q.completeActionsMutex.Lock() defer q.completeActionsMutex.Unlock() q.CompleteActions[stepID] = action q.SetSaveNeeded(true) } // AddProgressAction adds a progress action for a step func (q *Quest) AddProgressAction(stepID int32, action string) { q.progressActionsMutex.Lock() defer q.progressActionsMutex.Unlock() q.ProgressActions[stepID] = action q.SetSaveNeeded(true) } // AddFailedAction adds a failure action for a step func (q *Quest) AddFailedAction(stepID int32, action string) { q.failedActionsMutex.Lock() defer q.failedActionsMutex.Unlock() q.FailedActions[stepID] = action q.SetSaveNeeded(true) } // RemoveCompleteAction removes a completion action for a step func (q *Quest) RemoveCompleteAction(stepID int32) bool { q.completeActionsMutex.Lock() defer q.completeActionsMutex.Unlock() if _, exists := q.CompleteActions[stepID]; exists { delete(q.CompleteActions, stepID) q.SetSaveNeeded(true) return true } return false } // RemoveProgressAction removes a progress action for a step func (q *Quest) RemoveProgressAction(stepID int32) bool { q.progressActionsMutex.Lock() defer q.progressActionsMutex.Unlock() if _, exists := q.ProgressActions[stepID]; exists { delete(q.ProgressActions, stepID) q.SetSaveNeeded(true) return true } return false } // RemoveFailedAction removes a failure action for a step func (q *Quest) RemoveFailedAction(stepID int32) bool { q.failedActionsMutex.Lock() defer q.failedActionsMutex.Unlock() if _, exists := q.FailedActions[stepID]; exists { delete(q.FailedActions, stepID) q.SetSaveNeeded(true) return true } return false } // GetCompleteAction returns the completion action for a step func (q *Quest) GetCompleteAction(stepID int32) (string, bool) { q.completeActionsMutex.RLock() defer q.completeActionsMutex.RUnlock() action, exists := q.CompleteActions[stepID] return action, exists } // GetProgressAction returns the progress action for a step func (q *Quest) GetProgressAction(stepID int32) (string, bool) { q.progressActionsMutex.RLock() defer q.progressActionsMutex.RUnlock() action, exists := q.ProgressActions[stepID] return action, exists } // GetFailedAction returns the failure action for a step func (q *Quest) GetFailedAction(stepID int32) (string, bool) { q.failedActionsMutex.RLock() defer q.failedActionsMutex.RUnlock() action, exists := q.FailedActions[stepID] return action, exists } // HasCompleteAction checks if a step has a completion action func (q *Quest) HasCompleteAction(stepID int32) bool { q.completeActionsMutex.RLock() defer q.completeActionsMutex.RUnlock() _, exists := q.CompleteActions[stepID] return exists } // HasProgressAction checks if a step has a progress action func (q *Quest) HasProgressAction(stepID int32) bool { q.progressActionsMutex.RLock() defer q.progressActionsMutex.RUnlock() _, exists := q.ProgressActions[stepID] return exists } // HasFailedAction checks if a step has a failure action func (q *Quest) HasFailedAction(stepID int32) bool { q.failedActionsMutex.RLock() defer q.failedActionsMutex.RUnlock() _, exists := q.FailedActions[stepID] return exists } // SetCompleteAction sets the general quest completion action func (q *Quest) SetCompleteAction(action string) { q.CompleteAction = action q.SetSaveNeeded(true) } // GetQuestCompleteAction returns the general quest completion action func (q *Quest) GetQuestCompleteAction() string { return q.CompleteAction } // ClearAllActions removes all actions for all steps func (q *Quest) ClearAllActions() { q.completeActionsMutex.Lock() q.CompleteActions = make(map[int32]string) q.completeActionsMutex.Unlock() q.progressActionsMutex.Lock() q.ProgressActions = make(map[int32]string) q.progressActionsMutex.Unlock() q.failedActionsMutex.Lock() q.FailedActions = make(map[int32]string) q.failedActionsMutex.Unlock() q.CompleteAction = "" q.SetSaveNeeded(true) } // ClearStepActions removes all actions for a specific step func (q *Quest) ClearStepActions(stepID int32) { q.RemoveCompleteAction(stepID) q.RemoveProgressAction(stepID) q.RemoveFailedAction(stepID) } // GetAllCompleteActions returns a copy of all completion actions func (q *Quest) GetAllCompleteActions() map[int32]string { q.completeActionsMutex.RLock() defer q.completeActionsMutex.RUnlock() actions := make(map[int32]string) for stepID, action := range q.CompleteActions { actions[stepID] = action } return actions } // GetAllProgressActions returns a copy of all progress actions func (q *Quest) GetAllProgressActions() map[int32]string { q.progressActionsMutex.RLock() defer q.progressActionsMutex.RUnlock() actions := make(map[int32]string) for stepID, action := range q.ProgressActions { actions[stepID] = action } return actions } // GetAllFailedActions returns a copy of all failure actions func (q *Quest) GetAllFailedActions() map[int32]string { q.failedActionsMutex.RLock() defer q.failedActionsMutex.RUnlock() actions := make(map[int32]string) for stepID, action := range q.FailedActions { actions[stepID] = action } return actions } // ExecuteCompleteAction executes a completion action for a step func (q *Quest) ExecuteCompleteAction(stepID int32) error { action, exists := q.GetCompleteAction(stepID) if !exists || action == "" { return fmt.Errorf("no completion action for step %d", stepID) } // TODO: Execute Lua script with action // This would integrate with the Lua interface when available return q.executeLuaAction("complete", stepID, action) } // ExecuteProgressAction executes a progress action for a step func (q *Quest) ExecuteProgressAction(stepID int32, progressAmount int32) error { action, exists := q.GetProgressAction(stepID) if !exists || action == "" { return fmt.Errorf("no progress action for step %d", stepID) } // TODO: Execute Lua script with action and progress amount return q.executeLuaActionWithProgress("progress", stepID, action, progressAmount) } // ExecuteFailedAction executes a failure action for a step func (q *Quest) ExecuteFailedAction(stepID int32) error { action, exists := q.GetFailedAction(stepID) if !exists || action == "" { return fmt.Errorf("no failure action for step %d", stepID) } // TODO: Execute Lua script with action return q.executeLuaAction("failed", stepID, action) } // ExecuteQuestCompleteAction executes the general quest completion action func (q *Quest) ExecuteQuestCompleteAction() error { if q.CompleteAction == "" { return nil // No action to execute } // TODO: Execute Lua script with quest completion action return q.executeLuaAction("quest_complete", 0, q.CompleteAction) } // Placeholder methods for Lua integration (to be implemented when Lua interface is available) // executeLuaAction executes a Lua action script func (q *Quest) executeLuaAction(actionType string, stepID int32, action string) error { // TODO: Implement Lua script execution // This is a placeholder that would integrate with the Lua interface // when it becomes available in the Go codebase // For now, just log the action that would be executed fmt.Printf("Quest %d: Would execute %s action for step %d: %s\n", q.ID, actionType, stepID, action) return nil } // executeLuaActionWithProgress executes a Lua action script with progress information func (q *Quest) executeLuaActionWithProgress(actionType string, stepID int32, action string, progress int32) error { // TODO: Implement Lua script execution with progress parameter // This is a placeholder that would integrate with the Lua interface // For now, just log the action that would be executed fmt.Printf("Quest %d: Would execute %s action for step %d with progress %d: %s\n", q.ID, actionType, stepID, progress, action) return nil } // Action validation methods // ValidateActions validates all quest actions func (q *Quest) ValidateActions() error { // Validate completion actions q.completeActionsMutex.RLock() for stepID, action := range q.CompleteActions { if err := q.validateAction(stepID, action, "completion"); err != nil { q.completeActionsMutex.RUnlock() return err } } q.completeActionsMutex.RUnlock() // Validate progress actions q.progressActionsMutex.RLock() for stepID, action := range q.ProgressActions { if err := q.validateAction(stepID, action, "progress"); err != nil { q.progressActionsMutex.RUnlock() return err } } q.progressActionsMutex.RUnlock() // Validate failure actions q.failedActionsMutex.RLock() for stepID, action := range q.FailedActions { if err := q.validateAction(stepID, action, "failure"); err != nil { q.failedActionsMutex.RUnlock() return err } } q.failedActionsMutex.RUnlock() // Validate quest completion action if q.CompleteAction != "" { if err := q.validateAction(0, q.CompleteAction, "quest completion"); err != nil { return err } } return nil } // validateAction validates a single action func (q *Quest) validateAction(stepID int32, action, actionType string) error { if action == "" { return fmt.Errorf("empty %s action for step %d", actionType, stepID) } if len(action) > MaxCompleteActionLength { return fmt.Errorf("%s action too long for step %d (max %d)", actionType, stepID, MaxCompleteActionLength) } // Validate that the step exists (except for quest completion action) if stepID > 0 { if step := q.GetQuestStep(stepID); step == nil { return fmt.Errorf("%s action references non-existent step %d", actionType, stepID) } } // Basic Lua syntax validation (very basic check) if err := q.validateLuaSyntax(action); err != nil { return fmt.Errorf("invalid Lua syntax in %s action for step %d: %w", actionType, stepID, err) } return nil } // validateLuaSyntax performs basic Lua syntax validation func (q *Quest) validateLuaSyntax(luaCode string) error { // TODO: Implement proper Lua syntax validation // This is a placeholder that does very basic checks // Check for balanced parentheses, brackets, and braces if err := q.checkBalancedDelimiters(luaCode); err != nil { return err } // Check for obviously invalid syntax patterns invalidPatterns := []string{ "--[[", // Unfinished multi-line comments "function(", // Function without closing } for _, pattern := range invalidPatterns { if strings.Contains(luaCode, pattern) { // Do more thorough checking for these patterns // This is just a basic check - real validation would be more sophisticated } } return nil } // checkBalancedDelimiters checks if delimiters are balanced in Lua code func (q *Quest) checkBalancedDelimiters(code string) error { stack := make([]rune, 0) pairs := map[rune]rune{ ')': '(', ']': '[', '}': '{', } inString := false inComment := false var stringChar rune for i, char := range code { // Handle string literals if (char == '"' || char == '\'') && !inComment { if !inString { inString = true stringChar = char } else if char == stringChar { inString = false } continue } // Skip everything inside strings if inString { continue } // Handle line comments if i > 0 && code[i-1] == '-' && char == '-' && !inComment { inComment = true continue } // End line comment at newline if inComment && char == '\n' { inComment = false continue } // Skip everything in comments if inComment { continue } // Check delimiters switch char { case '(', '[', '{': stack = append(stack, char) case ')', ']', '}': if len(stack) == 0 { return fmt.Errorf("unmatched closing delimiter '%c'", char) } expected := pairs[char] if stack[len(stack)-1] != expected { return fmt.Errorf("mismatched delimiter: expected '%c', got '%c'", expected, char) } stack = stack[:len(stack)-1] } } if len(stack) > 0 { return fmt.Errorf("unclosed delimiter '%c'", stack[len(stack)-1]) } return nil }