1
/*
2
 *  The Mana World
3
 *  Copyright (C) 2004  The Mana World Development Team
4
 *
5
 *  This file is part of The Mana World.
6
 *
7
 *  This program is free software; you can redistribute it and/or modify
8
 *  it under the terms of the GNU General Public License as published by
9
 *  the Free Software Foundation; either version 2 of the License, or
10
 *  any later version.
11
 *
12
 *  This program is distributed in the hope that it will be useful,
13
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 *  GNU General Public License for more details.
16
 *
17
 *  You should have received a copy of the GNU General Public License
18
 *  along with this program; if not, write to the Free Software
19
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
 */
21
22
#include "beingmanager.h"
23
24
#include "localplayer.h"
25
#include "monster.h"
26
#include "npc.h"
27
#include "player.h"
28
29
#ifdef TMWSERV_SUPPORT
30
#include "net/tmwserv/protocol.h"
31
#endif
32
33
#include "utils/dtor.h"
34
35
#include <cassert>
36
37
class FindBeingFunctor
38
{
39
    public:
40
        bool operator() (Being *being)
41
        {
42
            Uint16 other_y = y + ((being->getType() == Being::NPC) ? 1 : 0);
43
            const Vector &pos = being->getPosition();
44
            return ((int) pos.x / 32 == x &&
45
                    ((int) pos.y / 32 == y || (int) pos.y / 32 == other_y) &&
46
                    being->mAction != Being::DEAD &&
47
                    (type == Being::UNKNOWN || being->getType() == type));
48
        }
49
50
        Uint16 x, y;
51
        Being::Type type;
52
} beingFinder;
53
54
BeingManager::BeingManager()
55
{
56
}
57
58
BeingManager::~BeingManager()
59
{
60
    clear();
61
}
62
63
void BeingManager::setMap(Map *map)
64
{
65
    mMap = map;
66
    if (player_node)
67
        player_node->setMap(map);
68
}
69
70
void BeingManager::setPlayer(LocalPlayer *player)
71
{
72
    player_node = player;
73
    mBeings.push_back(player);
74
}
75
76
Being *BeingManager::createBeing(int id, Being::Type type, int subtype)
77
{
78
    Being *being;
79
80
    switch (type)
81
    {
82
        case Being::PLAYER:
83
            being = new Player(id, subtype, mMap);
84
            break;
85
        case Being::NPC:
86
            being = new NPC(id, subtype, mMap);
87
            break;
88
        case Being::MONSTER:
89
            being = new Monster(id, subtype, mMap);
90
            break;
91
        case Being::UNKNOWN:
92
            being = new Being(id, subtype, mMap);
93
            break;
94
        default:
95
            assert(false);
96
    }
97
98
    mBeings.push_back(being);
99
    return being;
100
}
101
102
void BeingManager::destroyBeing(Being *being)
103
{
104
    mBeings.remove(being);
105
    delete being;
106
}
107
108
Being *BeingManager::findBeing(int id) const
109
{
110
    for (Beings::const_iterator i = mBeings.begin(), i_end = mBeings.end();
111
         i != i_end; ++i)
112
    {
113
        Being *being = (*i);
114
        if (being->getId() == id)
115
            return being;
116
    }
117
    return NULL;
118
}
119
120
Being *BeingManager::findBeing(int x, int y, Being::Type type) const
121
{
122
    beingFinder.x = x;
123
    beingFinder.y = y;
124
    beingFinder.type = type;
125
126
    Beings::const_iterator i = find_if(mBeings.begin(), mBeings.end(),
127
                                       beingFinder);
128
129
    return (i == mBeings.end()) ? NULL : *i;
130
}
131
132
Being *BeingManager::findBeingByPixel(int x, int y) const
133
{
134
    Beings::const_iterator itr = mBeings.begin();
135
    Beings::const_iterator itr_end = mBeings.end();
136
137
    for (; itr != itr_end; ++itr)
138
    {
139
        Being *being = (*itr);
140
141
        int xtol = being->getWidth() / 2;
142
        int uptol = being->getHeight();
143
144
        if ((being->mAction != Being::DEAD) &&
145
            (being != player_node) &&
146
            (being->getPixelX() - xtol <= x) &&
147
            (being->getPixelX() + xtol >= x) &&
148
            (being->getPixelY() - uptol <= y) &&
149
            (being->getPixelY() >= y))
150
        {
151
            return being;
152
        }
153
    }
154
155
    return NULL;
156
}
157
158
Being *BeingManager::findBeingByName(const std::string &name,
159
                                     Being::Type type) const
160
{
161
    for (Beings::const_iterator i = mBeings.begin(), i_end = mBeings.end();
162
         i != i_end; ++i)
163
    {
164
        Being *being = (*i);
165
        if (being->getName() == name &&
166
           (type == Being::UNKNOWN || type == being->getType()))
167
            return being;
168
    }
169
    return NULL;
170
}
171
172
const Beings &BeingManager::getAll() const
173
{
174
    return mBeings;
175
}
176
177
void BeingManager::logic()
178
{
179
    Beings::iterator i = mBeings.begin();
180
    while (i != mBeings.end())
181
    {
182
        Being *being = (*i);
183
184
        being->logic();
185
186
#ifdef EATHENA_SUPPORT
187
        if (being->mAction == Being::DEAD && being->mFrame >= 20)
188
        {
189
            delete being;
190
            i = mBeings.erase(i);
191
        }
192
        else
193
#endif
194
        {
195
            ++i;
196
        }
197
    }
198
}
199
200
void BeingManager::clear()
201
{
202
    if (player_node)
203
        mBeings.remove(player_node);
204
205
    delete_all(mBeings);
206
    mBeings.clear();
207
208
    if (player_node)
209
        mBeings.push_back(player_node);
210
}
211
212
Being *BeingManager::findNearestLivingBeing(int x, int y, int maxdist,
213
                                            Being::Type type) const
214
{
215
    Being *closestBeing = NULL;
216
    int dist = 0;
217
218
#ifdef TMWSERV_SUPPORT
219
    //Why do we do this:
220
    //For some reason x,y passed to this function is always
221
    //in map coords, while down below its in pixels
222
    //
223
    //I believe there is a deeper problem under this, but
224
    //for a temp solution we'll convert to coords to pixels
225
    x = x * 32;
226
    y = y * 32;
227
    maxdist = maxdist * 32;
228
#endif
229
230
    Beings::const_iterator itr = mBeings.begin();
231
    Beings::const_iterator itr_end = mBeings.end();
232
233
    for (; itr != itr_end; ++itr)
234
    {
235
        Being *being = (*itr);
236
#ifdef TMWSERV_SUPPORT
237
        const Vector &pos = being->getPosition();
238
        int d = abs(((int) pos.x) - x) + abs(((int) pos.y) - y);
239
#else
240
        int d = abs(being->getTileX() - x) + abs(being->getTileY() - y);
241
#endif
242
243
        if ((being->getType() == type || type == Being::UNKNOWN)
244
                && (d < dist || closestBeing == NULL)   // it is closer
245
                && being->mAction != Being::DEAD)       // no dead beings
246
        {
247
            dist = d;
248
            closestBeing = being;
249
        }
250
    }
251
252
    return (maxdist >= dist) ? closestBeing : NULL;
253
}
254
255
Being *BeingManager::findNearestLivingBeing(Being *aroundBeing, int maxdist,
256
                                            Being::Type type) const
257
{
258
    Being *closestBeing = NULL;
259
    int dist = 0;
260
#ifdef TMWSERV_SUPPORT
261
    const Vector &apos = aroundBeing->getPosition();
262
    int x = apos.x;
263
    int y = apos.y;
264
    maxdist = maxdist * 32;
265
#else
266
    int x = aroundBeing->getTileX();
267
    int y = aroundBeing->getTileY();
268
#endif
269
270
    for (Beings::const_iterator i = mBeings.begin(), i_end = mBeings.end();
271
         i != i_end; ++i)
272
    {
273
        Being *being = (*i);
274
#ifdef TMWSERV_SUPPORT
275
        const Vector &pos = being->getPosition();
276
        int d = abs(((int) pos.x) - x) + abs(((int) pos.y) - y);
277
#else
278
        int d = abs(being->getTileX() - x) + abs(being->getTileY() - y);
279
#endif
280
281
        if ((being->getType() == type || type == Being::UNKNOWN)
282
                && (d < dist || closestBeing == NULL)   // it is closer
283
                && being->mAction != Being::DEAD        // no dead beings
284
                && being != aroundBeing)
285
        {
286
            dist = d;
287
            closestBeing = being;
288
        }
289
    }
290
291
    return (maxdist >= dist) ? closestBeing : NULL;
292
}
293
294
bool BeingManager::hasBeing(Being *being) const
295
{
296
    for (Beings::const_iterator i = mBeings.begin(), i_end = mBeings.end();
297
         i != i_end; ++i)
298
    {
299
        if (being == *i)
300
            return true;
301
    }
302
303
    return false;
304
}