/
ConversationEntity.cpp
216 lines (175 loc) · 5.54 KB
/
ConversationEntity.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
#include "ConversationEntity.h"
#include <limits>
#include "i18n.h"
#include "itextstream.h"
#include "ientity.h"
#include "iundo.h"
#include "string/convert.h"
#include "ConversationKeyExtractor.h"
#include "ConversationCommandLibrary.h"
namespace conversation
{
// Constructor
ConversationEntity::ConversationEntity(const scene::INodePtr& node) :
_entityNode(node)
{
Entity* entity = Node_getEntity(node);
assert(entity != nullptr);
// Use an conversationKeyExtractor to populate the ConversationMap from the keys
// on the entity
ConversationKeyExtractor extractor(_conversations);
entity->forEachKeyValue(extractor);
}
// Delete the entity's world node
void ConversationEntity::deleteWorldNode()
{
UndoableCommand deleteCommand("removeConversationEntity");
// Try to convert the weak_ptr reference to a shared_ptr
auto node = _entityNode.lock();
if (node && node->getParent())
{
node->getParent()->removeChildNode(node);
}
}
int ConversationEntity::getHighestIndex()
{
if (_conversations.empty())
{
return -1;
}
return _conversations.rbegin()->first;
}
// Add a new conversation
int ConversationEntity::addConversation()
{
// Locate the first unused id
int index = 1;
while (_conversations.find(index) != _conversations.end())
{
if (index == std::numeric_limits<int>::max())
{
rError() << "Ran out of conversation indices." << std::endl;
throw new std::runtime_error("Ran out of conversation indices.");
}
++index;
}
// Insert a new conversation at this ID.
Conversation o;
o.name = _("New Conversation");
_conversations.insert(std::make_pair(index, o));
return index;
}
void ConversationEntity::deleteConversation(int index)
{
// Look up the conversation with the given index
auto i = _conversations.find(index);
if (i == _conversations.end())
{
// not found, nothing to do
return;
}
// Delete the found element and move the iterator past it
_conversations.erase(i++);
// Then iterate all the way to the highest index
while (i != _conversations.end())
{
// Decrease the index of this conversation
int newIndex = i->first - 1;
// Copy the conversation into a temporary object
Conversation temp = i->second;
// Remove the old one
_conversations.erase(i++);
// Re-insert with new index
_conversations.insert(std::make_pair(newIndex, temp));
}
}
int ConversationEntity::moveConversation(int index, bool moveUp)
{
if ((moveUp && index <= 1) || (!moveUp && index >= getHighestIndex()))
{
return index; // no change
}
int targetIndex = index + (moveUp ? -1 : +1);
if (_conversations.find(targetIndex) != _conversations.end())
{
// Swap with existing element
std::swap(_conversations[index], _conversations[targetIndex]);
}
else
{
// Nothing present at the target index, just move
_conversations[targetIndex] = _conversations[index];
_conversations.erase(index);
}
return targetIndex;
}
void ConversationEntity::populateListStore(wxutil::TreeModel& store, const ConversationColumns& columns) const
{
for (const auto& pair : _conversations)
{
wxutil::TreeModel::Row row = store.AddItem();
row[columns.index] = pair.first;
row[columns.name] = pair.second.name;
row.SendItemAdded();
}
}
void ConversationEntity::clearEntity(Entity* entity)
{
// Get all keyvalues matching the "obj" prefix.
auto keyValues = entity->getKeyValuePairs("conv_");
for (const auto& keyValuePair : keyValues)
{
// Set the spawnarg to empty, which is equivalent to a removal
entity->setKeyValue(keyValuePair.first, "");
}
}
// Write out conversations to entity keyvals
void ConversationEntity::writeToEntity()
{
// Try to convert the weak_ptr reference to a shared_ptr
Entity* entity = Node_getEntity(_entityNode.lock());
assert(entity != nullptr);
// greebo: Remove all conversation-related spawnargs first
clearEntity(entity);
for (const auto& pair : _conversations)
{
// Obtain the conversation and construct the key prefix from the index
const Conversation& conv = pair.second;
std::string prefix = "conv_" + string::to_string(pair.first) + "_";
// Set the entity keyvalues
entity->setKeyValue(prefix + "name", conv.name);
entity->setKeyValue(prefix + "actors_must_be_within_talkdistance",
conv.actorsMustBeWithinTalkdistance ? "1" : "0");
entity->setKeyValue(prefix + "talk_distance", string::to_string(conv.talkDistance));
entity->setKeyValue(prefix + "actors_always_face_each_other_while_talking",
conv.actorsAlwaysFaceEachOther ? "1" : "0");
entity->setKeyValue(prefix + "max_play_count", string::to_string(conv.maxPlayCount));
// Write the actor list
for (const auto& actor : conv.actors)
{
std::string actorKey = prefix + "actor_" + string::to_string(actor.first);
entity->setKeyValue(actorKey, actor.second);
}
// Write all the commands
for (const auto& cmd : conv.commands)
{
std::string cmdPrefix = prefix + "cmd_" + string::to_string(cmd.first) + "_";
try
{
const auto& cmdInfo = ConversationCommandLibrary::Instance().findCommandInfo(cmd.second->type);
entity->setKeyValue(cmdPrefix + "type", cmdInfo.name);
entity->setKeyValue(cmdPrefix + "actor", string::to_string(cmd.second->actor));
entity->setKeyValue(cmdPrefix + "wait_until_finished", cmd.second->waitUntilFinished ? "1" : "0");
for (const auto& arg : cmd.second->arguments)
{
entity->setKeyValue(cmdPrefix + "arg_" + string::to_string(arg.first), arg.second);
}
}
catch (const std::runtime_error&)
{
rError() << "Unrecognised conversation command ID: " << cmd.second->type << std::endl;
}
}
}
}
} // namespace conversations