1 /*
2 * Copyright (C) 2004 Ivo Danihelka (ivo@danihelka.net)
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 */
9 #include "WorldBranch.h"
10
11 #include "def-script.h"
12 #include "Log.h"
13 #include "Path.h"
14 #include "LevelNode.h"
15 #include "LevelStatus.h"
16 #include "ScriptState.h"
17 #include "ResDialogPack.h"
18 #include "LevelDesc.h"
19 #include "LogicException.h"
20
21 #include "worldmap-script.h"
22
23 //-----------------------------------------------------------------
WorldBranch(LevelNode * root)24 WorldBranch::WorldBranch(LevelNode *root)
25 {
26 m_root = root;
27 m_ending = NULL;
28 m_outPack = NULL;
29
30 m_script->registerFunc("worldmap_addDesc", script_worldmap_addDesc);
31 m_script->registerFunc("branch_addNode", script_branch_addNode);
32 m_script->registerFunc("branch_setEnding", script_branch_setEnding);
33 m_script->registerFunc("node_bestSolution", script_node_bestSolution);
34 }
35 //-----------------------------------------------------------------
36 /**
37 * Execute script which will add nodes.
38 * @param datafile worldmap file
39 * @param outEnding pointer to store ending node. It is not changed when
40 * endingNode is set.
41 * @param destPack pack to store node descriptions
42 * @return root node (can be NULL)
43 */
44 LevelNode *
parseMap(const Path & datafile,LevelNode ** outEnding,ResDialogPack * destPack)45 WorldBranch::parseMap(const Path &datafile, LevelNode **outEnding,
46 ResDialogPack *destPack)
47 {
48 m_outPack = destPack;
49 scriptInclude(datafile);
50 m_outPack = NULL;
51
52 if (m_ending) {
53 if (outEnding) {
54 *outEnding = m_ending;
55 }
56 else {
57 throw LogicException(ExInfo("cannot export ending node")
58 .addInfo("ending", m_ending->getCodename()));
59 }
60 }
61
62 if (m_root && m_root->getState() < LevelNode::STATE_OPEN) {
63 m_root->setState(LevelNode::STATE_OPEN);
64 }
65 return m_root;
66 }
67 //-----------------------------------------------------------------
68 void
addDesc(const std::string & codename,LevelDesc * desc)69 WorldBranch::addDesc(const std::string &codename, LevelDesc *desc)
70 {
71 if (m_outPack) {
72 m_outPack->addRes(codename, desc);
73 }
74 else {
75 throw LogicException(ExInfo("cannot export level description")
76 .addInfo("codename", codename));
77 }
78 }
79 //-----------------------------------------------------------------
80 /**
81 * Add new node to branch.
82 */
83 void
addNode(const std::string & parent,LevelNode * new_node,bool hidden)84 WorldBranch::addNode(const std::string &parent, LevelNode *new_node,
85 bool hidden)
86 {
87 prepareNode(new_node, hidden);
88 insertNode(parent, new_node);
89 }
90 //-----------------------------------------------------------------
91 /**
92 * Take ending node.
93 */
94 void
setEnding(LevelNode * new_node)95 WorldBranch::setEnding(LevelNode *new_node)
96 {
97 if (m_ending) {
98 delete m_ending;
99 }
100 m_ending = new_node;
101 if (wasSolved(m_ending->getCodename())) {
102 m_ending->setState(LevelNode::STATE_SOLVED);
103 }
104 else {
105 m_ending->setState(LevelNode::STATE_OPEN);
106 }
107 m_ending->setDepth(-1);
108 }
109 //-----------------------------------------------------------------
110 /**
111 * Store best solution author.
112 * @param codename level codename
113 * @param moves number of moves in solution
114 * @param author solution author
115 */
116 void
bestSolution(const std::string & codename,int moves,const std::string & author)117 WorldBranch::bestSolution(const std::string &codename, int moves,
118 const std::string &author)
119 {
120 LevelNode *node = m_root->findNamed(codename);
121 if (node) {
122 node->bestSolution(moves, author);
123 }
124 else {
125 LOG_WARNING(ExInfo("there is no such node")
126 .addInfo("codename", codename)
127 .addInfo("moves", moves)
128 .addInfo("author", author));
129 }
130 }
131 //-----------------------------------------------------------------
132 /**
133 * Returns true when level will solved in the past.
134 */
135 bool
wasSolved(const std::string & codename)136 WorldBranch::wasSolved(const std::string &codename)
137 {
138 Path solved =
139 Path::dataReadPath(LevelStatus::getSolutionFilename(codename));
140 return solved.exists();
141 }
142 //-----------------------------------------------------------------
143 /**
144 * Set node state.
145 * @param hidden whether node is start node of hidden branch
146 */
147 void
prepareNode(LevelNode * node,bool hidden)148 WorldBranch::prepareNode(LevelNode *node, bool hidden)
149 {
150 if (wasSolved(node->getCodename())) {
151 node->setState(LevelNode::STATE_SOLVED);
152 }
153 else if (hidden) {
154 node->setState(LevelNode::STATE_HIDDEN);
155 }
156 else {
157 node->setState(LevelNode::STATE_FAR);
158 }
159 }
160 //-----------------------------------------------------------------
161 /**
162 * Insert node as parent child.
163 * @throws LogicException when error occurs
164 */
165 void
insertNode(const std::string & parent,LevelNode * new_node)166 WorldBranch::insertNode(const std::string &parent, LevelNode *new_node)
167 {
168 try {
169 if (parent == "" && m_root) {
170 throw LogicException(ExInfo("there is a one root node already")
171 .addInfo("root", m_root->getCodename())
172 .addInfo("new_node", new_node->getCodename()));
173 }
174
175 if (m_root) {
176 LevelNode *parentNode = m_root->findNamed(parent);
177 if (parentNode) {
178 parentNode->addChild(new_node);
179 }
180 else {
181 throw LogicException(ExInfo("there is no such parent node")
182 .addInfo("parent", parent)
183 .addInfo("new_node", new_node->getCodename()));
184 }
185 }
186 else {
187 if (parent != "") {
188 LOG_WARNING(ExInfo("root node should have empty parent")
189 .addInfo("parent", parent)
190 .addInfo("new_node", new_node->getCodename()));
191 }
192 m_root = new_node;
193 }
194 }
195 catch (...) {
196 delete new_node;
197 throw;
198 }
199 }
200
201