Client Upload Part 2

RD Core / Commit #5

Commit Client Upload Part 2

Alex Alex committed 19/10/2026 00:06 main Patch
1,244 files +271,215 -0
A RD_Client/src/client/houses.h +113-0 View file
@@ -0,0 +1,113 @@
1+/*
2+ * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
3+ *
4+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5+ * of this software and associated documentation files (the "Software"), to deal
6+ * in the Software without restriction, including without limitation the rights
7+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+ * copies of the Software, and to permit persons to whom the Software is
9+ * furnished to do so, subject to the following conditions:
10+ *
11+ * The above copyright notice and this permission notice shall be included in
12+ * all copies or substantial portions of the Software.
13+ *
14+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+ * THE SOFTWARE.
21+ */
22+
23+#ifndef HOUSES_H
24+#define HOUSES_H
25+
26+#include "declarations.h"
27+#include "tile.h"
28+
29+#include <framework/luaengine/luaobject.h>
30+
31+enum HouseAttr : uint8
32+{
33+ HouseAttrId,
34+ HouseAttrName,
35+ HouseAttrTown,
36+ HouseAttrEntry,
37+ HouseAttrSize,
38+ HouseAttrRent
39+};
40+
41+class House : public LuaObject
42+{
43+public:
44+ House();
45+ House(uint32 hId, const std::string& name = "", const Position& pos=Position());
46+ ~House() { m_tiles.clear(); }
47+
48+ void setTile(const TilePtr& tile);
49+ TilePtr getTile(const Position& pos);
50+
51+ void setName(const std::string& name) { m_attribs.set(HouseAttrName, name); }
52+ std::string getName() { return m_attribs.get<std::string>(HouseAttrName); }
53+
54+ void setId(uint32 hId) { m_attribs.set(HouseAttrId, hId); }
55+ uint32 getId() { return m_attribs.get<uint32>(HouseAttrId); }
56+
57+ void setTownId(uint32 tid) { m_attribs.set(HouseAttrTown, tid); }
58+ uint32 getTownId() { return m_attribs.get<uint32>(HouseAttrTown); }
59+
60+ void setSize(uint32 s) { m_attribs.set(HouseAttrSize, s); }
61+ uint32 getSize() { return m_attribs.get<uint32>(HouseAttrSize); }
62+
63+ void setRent(uint32 r) { m_attribs.set(HouseAttrRent, r); }
64+ uint32 getRent() { return m_attribs.get<uint32>(HouseAttrRent); }
65+
66+ void setEntry(const Position& p) { m_attribs.set(HouseAttrEntry, p); }
67+ Position getEntry() { return m_attribs.get<Position>(HouseAttrEntry); }
68+
69+ void addDoor(const ItemPtr& door);
70+ void removeDoor(const ItemPtr& door) { removeDoorById(door->getDoorId()); }
71+ void removeDoorById(uint32 doorId);
72+
73+protected:
74+ void load(const TiXmlElement* elem);
75+ void save(TiXmlElement* elem);
76+
77+private:
78+ stdext::packed_storage<uint8> m_attribs;
79+ TileMap m_tiles;
80+ ItemVector m_doors;
81+ uint32 m_lastDoorId;
82+ stdext::boolean<false> m_isGuildHall;
83+
84+ friend class HouseManager;
85+};
86+
87+class HouseManager {
88+public:
89+ HouseManager();
90+
91+ void addHouse(const HousePtr& house);
92+ void removeHouse(uint32 houseId);
93+ HousePtr getHouse(uint32 houseId);
94+ HousePtr getHouseByName(std::string name);
95+
96+ void load(const std::string& fileName);
97+ void save(const std::string& fileName);
98+
99+ void sort();
100+ void clear() { m_houses.clear(); }
101+ HouseList getHouseList() { return m_houses; }
102+ HouseList filterHouses(uint32 townId);
103+
104+private:
105+ HouseList m_houses;
106+
107+protected:
108+ HouseList::iterator findHouse(uint32 houseId);
109+};
110+
111+extern HouseManager g_houses;
112+
113+#endif
A RD_Client/src/client/item.cpp +450-0 View file
@@ -0,0 +1,450 @@
1+/*
2+ * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
3+ *
4+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5+ * of this software and associated documentation files (the "Software"), to deal
6+ * in the Software without restriction, including without limitation the rights
7+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+ * copies of the Software, and to permit persons to whom the Software is
9+ * furnished to do so, subject to the following conditions:
10+ *
11+ * The above copyright notice and this permission notice shall be included in
12+ * all copies or substantial portions of the Software.
13+ *
14+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+ * THE SOFTWARE.
21+ */
22+
23+#include "item.h"
24+#include "thingtypemanager.h"
25+#include "spritemanager.h"
26+#include "thing.h"
27+#include "tile.h"
28+#include "container.h"
29+#include "map.h"
30+#include "houses.h"
31+#include "game.h"
32+
33+#include <framework/core/clock.h>
34+#include <framework/core/eventdispatcher.h>
35+#include <framework/graphics/graphics.h>
36+#include <framework/core/filestream.h>
37+#include <framework/core/binarytree.h>
38+#include <framework/graphics/shadermanager.h>
39+
40+#include <framework/util/stats.h>
41+
42+Item::Item() :
43+ m_clientId(0),
44+ m_serverId(0),
45+ m_countOrSubType(1),
46+ m_color(Color::alpha),
47+ m_async(true),
48+ m_quickLootFlags(0),
49+ m_phase(0),
50+ m_lastPhase(0)
51+{
52+}
53+
54+ItemPtr Item::create(int id, int countOrSubtype)
55+{
56+ ItemPtr item(new Item);
57+ item->setId(id);
58+ item->setCountOrSubType(countOrSubtype);
59+ return item;
60+}
61+
62+ItemPtr Item::createFromOtb(int id)
63+{
64+ ItemPtr item(new Item);
65+ item->setOtbId(id);
66+ return item;
67+}
68+
69+std::string Item::getName()
70+{
71+ return g_things.findItemTypeByClientId(m_clientId)->getName();
72+}
73+
74+void Item::draw(const Point& dest, bool animate, LightView* lightView)
75+{
76+ if (m_clientId == 0)
77+ return;
78+
79+ // determine animation phase
80+ int animationPhase = calculateAnimationPhase(animate);
81+
82+ // determine x,y,z patterns
83+ int xPattern = 0, yPattern = 0, zPattern = 0;
84+ calculatePatterns(xPattern, yPattern, zPattern);
85+
86+ Color color(Color::white);
87+ if (m_color != Color::alpha)
88+ color = m_color;
89+ size_t drawQueueSize = g_drawQueue->size();
90+ if (!m_shader.empty()) {
91+ rawGetThingType()->drawWithShader(dest, 0, xPattern, yPattern, zPattern, animationPhase, m_shader, color, lightView);
92+ }
93+ else {
94+ rawGetThingType()->draw(dest, 0, xPattern, yPattern, zPattern, animationPhase, color, lightView);
95+ }
96+ if (m_marked) {
97+ g_drawQueue->setMark(drawQueueSize, updatedMarkedColor());
98+ }
99+}
100+
101+void Item::draw(const Rect& dest, bool animate)
102+{
103+ if (m_clientId == 0)
104+ return;
105+
106+ // determine animation phase
107+ int animationPhase = calculateAnimationPhase(animate);
108+
109+ // determine x,y,z patterns
110+ int xPattern = 0, yPattern = 0, zPattern = 0;
111+ calculatePatterns(xPattern, yPattern, zPattern);
112+
113+ Color color(Color::white);
114+ if (m_color != Color::alpha)
115+ color = m_color;
116+
117+ if (!m_shader.empty()) {
118+ rawGetThingType()->drawWithShader(dest, 0, xPattern, yPattern, zPattern, animationPhase, m_shader, color);
119+ }
120+ else {
121+ rawGetThingType()->draw(dest, 0, xPattern, yPattern, zPattern, animationPhase, color);
122+ }
123+}
124+
125+void Item::setId(uint32 id)
126+{
127+ if(!g_things.isValidDatId(id, ThingCategoryItem))
128+ id = 0;
129+ m_serverId = g_things.findItemTypeByClientId(id)->getServerId();
130+ m_clientId = id;
131+}
132+
133+void Item::setOtbId(uint16 id)
134+{
135+ if(!g_things.isValidOtbId(id))
136+ id = 0;
137+ auto itemType = g_things.getItemType(id);
138+ m_serverId = id;
139+
140+ id = itemType->getClientId();
141+ if(!g_things.isValidDatId(id, ThingCategoryItem))
142+ id = 0;
143+ m_clientId = id;
144+}
145+
146+bool Item::isValid()
147+{
148+ return g_things.isValidDatId(m_clientId, ThingCategoryItem);
149+}
150+
151+void Item::unserializeItem(const BinaryTreePtr &in)
152+{
153+ try {
154+ while(in->canRead()) {
155+ int attrib = in->getU8();
156+ if(attrib == 0)
157+ break;
158+
159+ switch(attrib) {
160+ case ATTR_COUNT:
161+ case ATTR_RUNE_CHARGES:
162+ setCount(in->getU8());
163+ break;
164+ case ATTR_CHARGES:
165+ setCount(in->getU16());
166+ break;
167+ case ATTR_HOUSEDOORID:
168+ case ATTR_SCRIPTPROTECTED:
169+ case ATTR_DUALWIELD:
170+ case ATTR_DECAYING_STATE:
171+ m_attribs.set(attrib, in->getU8());
172+ break;
173+ case ATTR_ACTION_ID:
174+ case ATTR_UNIQUE_ID:
175+ case ATTR_DEPOT_ID:
176+ m_attribs.set(attrib, in->getU16());
177+ break;
178+ case ATTR_CONTAINER_ITEMS:
179+ case ATTR_ATTACK:
180+ case ATTR_EXTRAATTACK:
181+ case ATTR_DEFENSE:
182+ case ATTR_EXTRADEFENSE:
183+ case ATTR_ARMOR:
184+ case ATTR_ATTACKSPEED:
185+ case ATTR_HITCHANCE:
186+ case ATTR_DURATION:
187+ case ATTR_WRITTENDATE:
188+ case ATTR_SLEEPERGUID:
189+ case ATTR_SLEEPSTART:
190+ case ATTR_ATTRIBUTE_MAP:
191+ m_attribs.set(attrib, in->getU32());
192+ break;
193+ case ATTR_TELE_DEST: {
194+ Position pos;
195+ pos.x = in->getU16();
196+ pos.y = in->getU16();
197+ pos.z = in->getU8();
198+ m_attribs.set(attrib, pos);
199+ break;
200+ }
201+ case ATTR_NAME:
202+ case ATTR_TEXT:
203+ case ATTR_DESC:
204+ case ATTR_ARTICLE:
205+ case ATTR_WRITTENBY:
206+ m_attribs.set(attrib, in->getString());
207+ break;
208+ default:
209+ stdext::throw_exception(stdext::format("invalid item attribute %d", attrib));
210+ }
211+ }
212+ } catch(stdext::exception& e) {
213+ g_logger.error(stdext::format("Failed to unserialize OTBM item: %s", e.what()));
214+ }
215+}
216+
217+void Item::serializeItem(const OutputBinaryTreePtr& out)
218+{
219+ out->startNode(OTBM_ITEM);
220+ out->addU16(getServerId());
221+
222+ out->addU8(ATTR_COUNT);
223+ out->addU8(getCount());
224+
225+ out->addU8(ATTR_CHARGES);
226+ out->addU16(getCountOrSubType());
227+
228+ Position dest = m_attribs.get<Position>(ATTR_TELE_DEST);
229+ if(dest.isValid()) {
230+ out->addU8(ATTR_TELE_DEST);
231+ out->addPos(dest.x, dest.y, dest.z);
232+ }
233+
234+ if(isDepot()) {
235+ out->addU8(ATTR_DEPOT_ID);
236+ out->addU16(getDepotId());
237+ }
238+
239+ if(isHouseDoor()) {
240+ out->addU8(ATTR_HOUSEDOORID);
241+ out->addU8(getDoorId());
242+ }
243+
244+ uint16 aid = m_attribs.get<uint16>(ATTR_ACTION_ID);
245+ uint16 uid = m_attribs.get<uint16>(ATTR_UNIQUE_ID);
246+ if(aid) {
247+ out->addU8(ATTR_ACTION_ID);
248+ out->addU16(aid);
249+ }
250+
251+ if(uid) {
252+ out->addU8(ATTR_UNIQUE_ID);
253+ out->addU16(uid);
254+ }
255+
256+ std::string text = getText();
257+ if(g_things.getItemType(m_serverId)->isWritable() && !text.empty()) {
258+ out->addU8(ATTR_TEXT);
259+ out->addString(text);
260+ }
261+ std::string desc = getDescription();
262+ if(!desc.empty()) {
263+ out->addU8(ATTR_DESC);
264+ out->addString(desc);
265+ }
266+
267+ out->endNode();
268+ for(auto i : m_containerItems)
269+ i->serializeItem(out);
270+}
271+
272+int Item::getSubType()
273+{
274+ if(isSplash() || isFluidContainer())
275+ return m_countOrSubType;
276+ if(g_game.getClientVersion() >= 860)
277+ return 0;
278+ return 1;
279+}
280+
281+int Item::getCount()
282+{
283+ if(isStackable())
284+ return m_countOrSubType;
285+ return 1;
286+}
287+
288+bool Item::isMoveable()
289+{
290+ return !rawGetThingType()->isNotMoveable();
291+}
292+
293+bool Item::isGround()
294+{
295+ return rawGetThingType()->isGround();
296+}
297+
298+ItemPtr Item::clone()
299+{
300+ ItemPtr item = ItemPtr(new Item);
301+ *(item.get()) = *this;
302+ return item;
303+}
304+
305+void Item::calculatePatterns(int& xPattern, int& yPattern, int& zPattern)
306+{
307+ // Avoid crashes with invalid items
308+ if(!isValid())
309+ return;
310+
311+ if(isStackable() && getNumPatternX() == 4 && getNumPatternY() == 2) {
312+ if(m_countOrSubType <= 0) {
313+ xPattern = 0;
314+ yPattern = 0;
315+ } else if(m_countOrSubType < 5) {
316+ xPattern = m_countOrSubType-1;
317+ yPattern = 0;
318+ } else if(m_countOrSubType < 10) {
319+ xPattern = 0;
320+ yPattern = 1;
321+ } else if(m_countOrSubType < 25) {
322+ xPattern = 1;
323+ yPattern = 1;
324+ } else if(m_countOrSubType < 50) {
325+ xPattern = 2;
326+ yPattern = 1;
327+ } else {
328+ xPattern = 3;
329+ yPattern = 1;
330+ }
331+ } else if(isHangable()) {
332+ const TilePtr& tile = getTile();
333+ if(tile) {
334+ if(tile->mustHookSouth())
335+ xPattern = getNumPatternX() >= 2 ? 1 : 0;
336+ else if(tile->mustHookEast())
337+ xPattern = getNumPatternX() >= 3 ? 2 : 0;
338+ }
339+ } else if(isSplash() || isFluidContainer()) {
340+ int color = Otc::FluidTransparent;
341+ if(g_game.getFeature(Otc::GameNewFluids)) {
342+ switch(m_countOrSubType) {
343+ case Otc::FluidNone:
344+ color = Otc::FluidTransparent;
345+ break;
346+ case Otc::FluidWater:
347+ color = Otc::FluidBlue;
348+ break;
349+ case Otc::FluidMana:
350+ color = Otc::FluidPurple;
351+ break;
352+ case Otc::FluidBeer:
353+ color = Otc::FluidBrown;
354+ break;
355+ case Otc::FluidOil:
356+ color = Otc::FluidBrown;
357+ break;
358+ case Otc::FluidBlood:
359+ color = Otc::FluidRed;
360+ break;
361+ case Otc::FluidSlime:
362+ color = Otc::FluidGreen;
363+ break;
364+ case Otc::FluidMud:
365+ color = Otc::FluidBrown;
366+ break;
367+ case Otc::FluidLemonade:
368+ color = Otc::FluidYellow;
369+ break;
370+ case Otc::FluidMilk:
371+ color = Otc::FluidWhite;
372+ break;
373+ case Otc::FluidWine:
374+ color = Otc::FluidPurple;
375+ break;
376+ case Otc::FluidHealth:
377+ color = Otc::FluidRed;
378+ break;
379+ case Otc::FluidUrine:
380+ color = Otc::FluidYellow;
381+ break;
382+ case Otc::FluidRum:
383+ color = Otc::FluidBrown;
384+ break;
385+ case Otc::FluidFruidJuice:
386+ color = Otc::FluidYellow;
387+ break;
388+ case Otc::FluidCoconutMilk:
389+ color = Otc::FluidWhite;
390+ break;
391+ case Otc::FluidTea:
392+ color = Otc::FluidBrown;
393+ break;
394+ case Otc::FluidMead:
395+ color = Otc::FluidBrown;
396+ break;
397+ default:
398+ color = Otc::FluidTransparent;
399+ break;
400+ }
401+ } else
402+ color = m_countOrSubType;
403+
404+ xPattern = (color % 4) % getNumPatternX();
405+ yPattern = (color / 4) % getNumPatternY();
406+ } else {
407+ xPattern = m_position.x % std::max<int>(1, getNumPatternX());
408+ yPattern = m_position.y % std::max<int>(1, getNumPatternY());
409+ zPattern = m_position.z % std::max<int>(1, getNumPatternZ());
410+ }
411+}
412+
413+int Item::calculateAnimationPhase(bool animate)
414+{
415+ if(getAnimationPhases() > 1) {
416+ if(animate) {
417+ if(getAnimator() != nullptr)
418+ return getAnimator()->getPhase();
419+
420+ if(m_async)
421+ return (g_clock.millis() % ((g_game.getFeature(Otc::GameEnhancedAnimations) ? Otc::ITEM_TICKS_PER_FRAME_FAST : Otc::ITEM_TICKS_PER_FRAME) * getAnimationPhases())) / Otc::ITEM_TICKS_PER_FRAME;
422+ else {
423+ if(g_clock.millis() - m_lastPhase >= (g_game.getFeature(Otc::GameEnhancedAnimations) ? Otc::ITEM_TICKS_PER_FRAME_FAST : Otc::ITEM_TICKS_PER_FRAME)) {
424+ m_phase = (m_phase + 1) % getAnimationPhases();
425+ m_lastPhase = g_clock.millis();
426+ }
427+ return m_phase;
428+ }
429+ } else
430+ return getAnimationPhases()-1;
431+ }
432+ return 0;
433+}
434+
435+int Item::getExactSize(int layer, int xPattern, int yPattern, int zPattern, int animationPhase)
436+{
437+ calculatePatterns(xPattern, yPattern, zPattern);
438+ animationPhase = calculateAnimationPhase(true);
439+ return Thing::getExactSize(layer, xPattern, yPattern, zPattern, animationPhase);
440+}
441+
442+const ThingTypePtr& Item::getThingType()
443+{
444+ return g_things.getThingType(m_clientId, ThingCategoryItem);
445+}
446+
447+ThingType* Item::rawGetThingType()
448+{
449+ return g_things.rawGetThingType(m_clientId, ThingCategoryItem);
450+}
A RD_Client/src/client/item.h +187-0 View file
@@ -0,0 +1,187 @@
1+/*
2+ * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
3+ *
4+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5+ * of this software and associated documentation files (the "Software"), to deal
6+ * in the Software without restriction, including without limitation the rights
7+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+ * copies of the Software, and to permit persons to whom the Software is
9+ * furnished to do so, subject to the following conditions:
10+ *
11+ * The above copyright notice and this permission notice shall be included in
12+ * all copies or substantial portions of the Software.
13+ *
14+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+ * THE SOFTWARE.
21+ */
22+
23+#ifndef ITEM_H
24+#define ITEM_H
25+
26+#include <framework/global.h>
27+
28+#include "thing.h"
29+#include "effect.h"
30+#include "itemtype.h"
31+
32+enum ItemAttr : uint8
33+{
34+ ATTR_END = 0,
35+ //ATTR_DESCRIPTION = 1,
36+ //ATTR_EXT_FILE = 2,
37+ ATTR_TILE_FLAGS = 3,
38+ ATTR_ACTION_ID = 4,
39+ ATTR_UNIQUE_ID = 5,
40+ ATTR_TEXT = 6,
41+ ATTR_DESC = 7,
42+ ATTR_TELE_DEST = 8,
43+ ATTR_ITEM = 9,
44+ ATTR_DEPOT_ID = 10,
45+ //ATTR_EXT_SPAWN_FILE = 11,
46+ ATTR_RUNE_CHARGES = 12,
47+ //ATTR_EXT_HOUSE_FILE = 13,
48+ ATTR_HOUSEDOORID = 14,
49+ ATTR_COUNT = 15,
50+ ATTR_DURATION = 16,
51+ ATTR_DECAYING_STATE = 17,
52+ ATTR_WRITTENDATE = 18,
53+ ATTR_WRITTENBY = 19,
54+ ATTR_SLEEPERGUID = 20,
55+ ATTR_SLEEPSTART = 21,
56+ ATTR_CHARGES = 22,
57+ ATTR_CONTAINER_ITEMS = 23,
58+ ATTR_NAME = 30,
59+ ATTR_PLURALNAME = 31,
60+ ATTR_ATTACK = 33,
61+ ATTR_EXTRAATTACK = 34,
62+ ATTR_DEFENSE = 35,
63+ ATTR_EXTRADEFENSE = 36,
64+ ATTR_ARMOR = 37,
65+ ATTR_ATTACKSPEED = 38,
66+ ATTR_HITCHANCE = 39,
67+ ATTR_SHOOTRANGE = 40,
68+ ATTR_ARTICLE = 41,
69+ ATTR_SCRIPTPROTECTED = 42,
70+ ATTR_DUALWIELD = 43,
71+ ATTR_ATTRIBUTE_MAP = 128
72+};
73+
74+// @bindclass
75+#pragma pack(push,1) // disable memory alignment
76+class Item : public Thing
77+{
78+public:
79+ Item();
80+ virtual ~Item() { }
81+
82+ static ItemPtr create(int id, int countOrSubtype = 1);
83+ static ItemPtr createFromOtb(int id);
84+
85+ void draw(const Point& dest, bool animate = true, LightView* lightView = nullptr);
86+ void draw(const Rect& dest, bool animate = true);
87+
88+ void setId(uint32 id);
89+ void setOtbId(uint16 id);
90+ void setCountOrSubType(int value) { m_countOrSubType = value; }
91+ void setCount(int count) { m_countOrSubType = count; }
92+ void setSubType(int subType) { m_countOrSubType = subType; }
93+ void setColor(const Color& c) { m_color = c; }
94+ void setTooltip(const std::string& str) { m_tooltip = str; }
95+ void setQuickLootFlags(uint32 flags) { m_quickLootFlags = flags; }
96+ void setShader(const std::string& str) { m_shader = str; }
97+
98+ int getCountOrSubType() { return m_countOrSubType; }
99+ int getSubType();
100+ int getCount();
101+ uint32 getId() { return m_clientId; }
102+ uint16 getClientId() { return m_clientId; }
103+ uint16 getServerId() { return m_serverId; }
104+ std::string getName();
105+ bool isValid();
106+ std::string getTooltip() { return m_tooltip; }
107+ uint32 getQuickLootFlags() { return m_quickLootFlags; }
108+ std::string getShader() { return m_shader; }
109+
110+ void unserializeItem(const BinaryTreePtr& in);
111+ void serializeItem(const OutputBinaryTreePtr& out);
112+
113+ void setDepotId(uint16 depotId) { m_attribs.set(ATTR_DEPOT_ID, depotId); }
114+ uint16 getDepotId() { return m_attribs.get<uint16>(ATTR_DEPOT_ID); }
115+
116+ void setDoorId(uint8 doorId) { m_attribs.set(ATTR_HOUSEDOORID, doorId); }
117+ uint8 getDoorId() { return m_attribs.get<uint8>(ATTR_HOUSEDOORID); }
118+
119+ uint16 getUniqueId() { return m_attribs.get<uint16>(ATTR_UNIQUE_ID); }
120+ uint16 getActionId() { return m_attribs.get<uint16>(ATTR_ACTION_ID); }
121+ void setActionId(uint16 actionId) { m_attribs.set(ATTR_ACTION_ID, actionId); }
122+ void setUniqueId(uint16 uniqueId) { m_attribs.set(ATTR_UNIQUE_ID, uniqueId); }
123+
124+ std::string getText() { return m_attribs.get<std::string>(ATTR_TEXT); }
125+ std::string getDescription() { return m_attribs.get<std::string>(ATTR_DESC); }
126+ void setDescription(std::string desc) { m_attribs.set(ATTR_DESC, desc); }
127+ void setText(std::string txt) { m_attribs.set(ATTR_TEXT, txt); }
128+
129+ Position getTeleportDestination() { return m_attribs.get<Position>(ATTR_TELE_DEST); }
130+ void setTeleportDestination(const Position& pos) { m_attribs.set(ATTR_TELE_DEST, pos); }
131+
132+ void setAsync(bool enable) { m_async = enable; }
133+
134+ bool isHouseDoor() { return m_attribs.has(ATTR_HOUSEDOORID); }
135+ bool isDepot() { return m_attribs.has(ATTR_DEPOT_ID); }
136+ bool isContainer() { return m_attribs.has(ATTR_CONTAINER_ITEMS); }
137+ bool isDoor() { return m_attribs.has(ATTR_HOUSEDOORID); }
138+ bool isTeleport() { return m_attribs.has(ATTR_TELE_DEST); }
139+ bool isMoveable();
140+ bool isGround();
141+
142+ ItemPtr clone();
143+ ItemPtr asItem() { return static_self_cast<Item>(); }
144+ bool isItem() { return true; }
145+
146+ ItemVector getContainerItems() { return m_containerItems; }
147+ ItemPtr getContainerItem(int slot) { return m_containerItems[slot]; }
148+ void addContainerItemIndexed(const ItemPtr& i, int slot) { m_containerItems[slot] = i; }
149+ void addContainerItem(const ItemPtr& i) { m_containerItems.push_back(i); }
150+ void removeContainerItem(int slot) { m_containerItems[slot] = nullptr; }
151+ void clearContainerItems() { m_containerItems.clear(); }
152+
153+ void calculatePatterns(int& xPattern, int& yPattern, int& zPattern);
154+ int calculateAnimationPhase(bool animate);
155+ int getExactSize(int layer = 0, int xPattern = 0, int yPattern = 0, int zPattern = 0, int animationPhase = 0);
156+
157+ const ThingTypePtr& getThingType();
158+ ThingType *rawGetThingType();
159+
160+ void setCustomAttribute(uint16 key, uint64 value) {
161+ m_customAttribs.set(key, value);
162+ }
163+ uint64 getCustomAttribute(uint16 key) {
164+ return m_customAttribs.get<uint64>(key);
165+ }
166+
167+private:
168+ uint16 m_clientId;
169+ uint16 m_serverId;
170+ uint16 m_countOrSubType;
171+ stdext::packed_storage<uint8> m_attribs;
172+ ItemVector m_containerItems;
173+ Color m_color;
174+ bool m_async;
175+ std::string m_tooltip;
176+ std::string m_shader;
177+
178+ uint32 m_quickLootFlags;
179+ uint8 m_phase;
180+ ticks_t m_lastPhase;
181+
182+ stdext::packed_storage<uint16> m_customAttribs;
183+};
184+
185+#pragma pack(pop)
186+
187+#endif
A RD_Client/src/client/itemtype.cpp +93-0 View file
@@ -0,0 +1,93 @@
1+/*
2+ * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
3+ *
4+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5+ * of this software and associated documentation files (the "Software"), to deal
6+ * in the Software without restriction, including without limitation the rights
7+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+ * copies of the Software, and to permit persons to whom the Software is
9+ * furnished to do so, subject to the following conditions:
10+ *
11+ * The above copyright notice and this permission notice shall be included in
12+ * all copies or substantial portions of the Software.
13+ *
14+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+ * THE SOFTWARE.
21+ */
22+
23+
24+#include "thingtypemanager.h"
25+#include "thingtype.h"
26+#include "game.h"
27+
28+#include <framework/core/filestream.h>
29+#include <framework/core/binarytree.h>
30+
31+ItemType::ItemType()
32+{
33+ m_category = ItemCategoryInvalid;
34+}
35+
36+void ItemType::unserialize(const BinaryTreePtr& node)
37+{
38+ m_null = false;
39+
40+ m_category = (ItemCategory)node->getU8();
41+
42+ node->getU32(); // flags
43+
44+ static uint16 lastId = 99;
45+ while(node->canRead()) {
46+ uint8 attr = node->getU8();
47+ if(attr == 0 || attr == 0xFF)
48+ break;
49+
50+ uint16 len = node->getU16();
51+ switch(attr) {
52+ case ItemTypeAttrServerId: {
53+ uint16 serverId = node->getU16();
54+ if(g_game.getClientVersion() < 960) {
55+ if(serverId > 20000 && serverId < 20100) {
56+ serverId -= 20000;
57+ } else if(lastId > 99 && lastId != serverId - 1) {
58+ while(lastId != serverId - 1) {
59+ ItemTypePtr tmp(new ItemType);
60+ tmp->setServerId(lastId++);
61+ g_things.addItemType(tmp);
62+ }
63+ }
64+ } else {
65+ if(serverId > 30000 && serverId < 30100) {
66+ serverId -= 30000;
67+ } else if(lastId > 99 && lastId != serverId - 1) {
68+ while(lastId != serverId - 1) {
69+ ItemTypePtr tmp(new ItemType);
70+ tmp->setServerId(lastId++);
71+ g_things.addItemType(tmp);
72+ }
73+ }
74+ }
75+ setServerId(serverId);
76+ lastId = serverId;
77+ break;
78+ }
79+ case ItemTypeAttrClientId:
80+ setClientId(node->getU16());
81+ break;
82+ case ItemTypeAttrName:
83+ setName(node->getString(len));
84+ break;
85+ case ItemTypeAttrWritable:
86+ m_attribs.set(ItemTypeAttrWritable, true);
87+ break;
88+ default:
89+ node->skip(len); // skip attribute
90+ break;
91+ }
92+ }
93+}
A RD_Client/src/client/itemtype.h +162-0 View file
@@ -0,0 +1,162 @@
1+/*
2+ * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
3+ *
4+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5+ * of this software and associated documentation files (the "Software"), to deal
6+ * in the Software without restriction, including without limitation the rights
7+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+ * copies of the Software, and to permit persons to whom the Software is
9+ * furnished to do so, subject to the following conditions:
10+ *
11+ * The above copyright notice and this permission notice shall be included in
12+ * all copies or substantial portions of the Software.
13+ *
14+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+ * THE SOFTWARE.
21+ */
22+
23+
24+#ifndef ITEMTYPE_H
25+#define ITEMTYPE_H
26+
27+#include <framework/core/declarations.h>
28+#include <framework/luaengine/luaobject.h>
29+#include <framework/xml/tinyxml.h>
30+
31+enum ItemCategory : uint8 {
32+ ItemCategoryInvalid = 0,
33+ ItemCategoryGround = 1,
34+ ItemCategoryContainer = 2,
35+ ItemCategoryWeapon = 3,
36+ ItemCategoryAmmunition = 4,
37+ ItemCategoryArmor = 5,
38+ ItemCategoryCharges = 6,
39+ ItemCategoryTeleport = 7,
40+ ItemCategoryMagicField = 8,
41+ ItemCategoryWritable = 9,
42+ ItemCategoryKey = 10,
43+ ItemCategorySplash = 11,
44+ ItemCategoryFluid = 12,
45+ ItemCategoryDoor = 13,
46+ ItemCategoryDeprecated = 14,
47+ ItemCategoryLast = 15
48+};
49+
50+enum ItemTypeAttr : uint8 {
51+ ItemTypeAttrServerId = 16,
52+ ItemTypeAttrClientId = 17,
53+ ItemTypeAttrName = 18, // deprecated
54+ ItemTypeAttrDesc = 19, // deprecated
55+ ItemTypeAttrSpeed = 20,
56+ ItemTypeAttrSlot = 21, // deprecated
57+ ItemTypeAttrMaxItems = 22, // deprecated
58+ ItemTypeAttrWeight = 23, // deprecated
59+ ItemTypeAttrWeapon = 24, // deprecated
60+ ItemTypeAttrAmmunition = 25, // deprecated
61+ ItemTypeAttrArmor = 26, // deprecated
62+ ItemTypeAttrMagicLevel = 27, // deprecated
63+ ItemTypeAttrMagicField = 28, // deprecated
64+ ItemTypeAttrWritable = 29, // deprecated
65+ ItemTypeAttrRotateTo = 30, // deprecated
66+ ItemTypeAttrDecay = 31, // deprecated
67+ ItemTypeAttrSpriteHash = 32,
68+ ItemTypeAttrMinimapColor = 33,
69+ ItemTypeAttr07 = 34,
70+ ItemTypeAttr08 = 35,
71+ ItemTypeAttrLight = 36,
72+ ItemTypeAttrDecay2 = 37, // deprecated
73+ ItemTypeAttrWeapon2 = 38, // deprecated
74+ ItemTypeAttrAmmunition2 = 39, // deprecated
75+ ItemTypeAttrArmor2 = 40, // deprecated
76+ ItemTypeAttrWritable2 = 41, // deprecated
77+ ItemTypeAttrLight2 = 42,
78+ ItemTypeAttrTopOrder = 43,
79+ ItemTypeAttrWrtiable3 = 44, // deprecated
80+ ItemTypeAttrWareId = 45,
81+ ItemTypeAttrLast = 46
82+};
83+
84+enum ClientVersion
85+{
86+ ClientVersion750 = 1,
87+ ClientVersion755 = 2,
88+ ClientVersion760 = 3,
89+ ClientVersion770 = 3,
90+ ClientVersion780 = 4,
91+ ClientVersion790 = 5,
92+ ClientVersion792 = 6,
93+ ClientVersion800 = 7,
94+ ClientVersion810 = 8,
95+ ClientVersion811 = 9,
96+ ClientVersion820 = 10,
97+ ClientVersion830 = 11,
98+ ClientVersion840 = 12,
99+ ClientVersion841 = 13,
100+ ClientVersion842 = 14,
101+ ClientVersion850 = 15,
102+ ClientVersion854_OLD = 16,
103+ ClientVersion854 = 17,
104+ ClientVersion855 = 18,
105+ ClientVersion860_OLD = 19,
106+ ClientVersion860 = 20,
107+ ClientVersion861 = 21,
108+ ClientVersion862 = 22,
109+ ClientVersion870 = 23,
110+ ClientVersion871 = 24,
111+ ClientVersion872 = 25,
112+ ClientVersion873 = 26,
113+ ClientVersion900 = 27,
114+ ClientVersion910 = 28,
115+ ClientVersion920 = 29,
116+ ClientVersion940 = 30,
117+ ClientVersion944_V1 = 31,
118+ ClientVersion944_V2 = 32,
119+ ClientVersion944_V3 = 33,
120+ ClientVersion944_V4 = 34,
121+ ClientVersion946 = 35,
122+ ClientVersion950 = 36,
123+ ClientVersion952 = 37,
124+ ClientVersion953 = 38,
125+ ClientVersion954 = 39,
126+ ClientVersion960 = 40,
127+ ClientVersion961 = 41
128+};
129+
130+class ItemType : public LuaObject
131+{
132+public:
133+ ItemType();
134+
135+ void unserialize(const BinaryTreePtr& node);
136+
137+ void setServerId(uint16 serverId) { m_attribs.set(ItemTypeAttrServerId, serverId); }
138+ uint16 getServerId() { return m_attribs.get<uint16>(ItemTypeAttrServerId); }
139+
140+ void setClientId(uint16 clientId) { m_attribs.set(ItemTypeAttrClientId, clientId); }
141+ uint16 getClientId() { return m_attribs.get<uint16>(ItemTypeAttrClientId); }
142+
143+ void setCategory(ItemCategory category) { m_category = category; }
144+ ItemCategory getCategory() { return m_category; }
145+
146+ void setName(const std::string& name) { m_attribs.set(ItemTypeAttrName, name); }
147+ std::string getName() { return m_attribs.get<std::string>(ItemTypeAttrName); }
148+
149+ void setDesc(const std::string& desc) { m_attribs.set(ItemTypeAttrDesc, desc); }
150+ std::string getDesc() { return m_attribs.get<std::string>(ItemTypeAttrDesc); }
151+
152+ bool isNull() { return m_null; }
153+ bool isWritable() { return m_attribs.get<bool>(ItemTypeAttrWritable); }
154+
155+private:
156+ ItemCategory m_category;
157+ stdext::boolean<true> m_null;
158+
159+ stdext::dynamic_storage<uint8> m_attribs;
160+};
161+
162+#endif
A RD_Client/src/client/lightview.cpp +200-0 View file
@@ -0,0 +1,200 @@
1+/*
2+ * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
3+ *
4+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5+ * of this software and associated documentation files (the "Software"), to deal
6+ * in the Software without restriction, including without limitation the rights
7+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+ * copies of the Software, and to permit persons to whom the Software is
9+ * furnished to do so, subject to the following conditions:
10+ *
11+ * The above copyright notice and this permission notice shall be included in
12+ * all copies or substantial portions of the Software.
13+ *
14+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+ * THE SOFTWARE.
21+ */
22+
23+#include "lightview.h"
24+#include "spritemanager.h"
25+#include <cmath>
26+#include <framework/graphics/painter.h>
27+
28+// ─────────────────────────────────────────────────────────────────────────────
29+// Miembros estáticos
30+// ─────────────────────────────────────────────────────────────────────────────
31+uint32_t LightView::s_frame = 0;
32+
33+// PRNG rápido basado en posición de tile
34+static inline uint32_t hashPos(int tx, int ty) {
35+ uint32_t h = (uint32_t)(tx * 2654435761u ^ ty * 2246822519u);
36+ h ^= h >> 15;
37+ h *= 2246822519u;
38+ h ^= h >> 13;
39+ return h;
40+}
41+
42+// ─────────────────────────────────────────────────────────────────────────────
43+void LightView::addLight(const Point &pos, uint8_t color, uint8_t intensity) {
44+ if (!m_lights.empty()) {
45+ Light &prev = m_lights.back();
46+ if (prev.pos == pos && prev.color == color) {
47+ prev.intensity = std::max(prev.intensity, intensity);
48+ return;
49+ }
50+ }
51+ m_lights.push_back(Light{pos, color, intensity});
52+}
53+
54+void LightView::setFieldBrightness(const Point &pos, size_t start,
55+ uint8_t color) {
56+ const int spriteSize = g_sprites.spriteSize();
57+ size_t index =
58+ (pos.y / spriteSize) * m_mapSize.width() + (pos.x / spriteSize);
59+ if (index >= m_tiles.size())
60+ return;
61+ m_tiles[index].start = start;
62+ m_tiles[index].color = color;
63+}
64+
65+// ─────────────────────────────────────────────────────────────────────────────
66+// DRAW
67+//
68+// El flicker usa tiempo global (s_frame) + offset de fase por posición de tile.
69+// Esto no requiere ningún estado persistente por luz, por lo que funciona
70+// correctamente sin importar cuánto se mueva la cámara.
71+//
72+// Cada antorcha tiene su propia frecuencia y fase derivadas de hashPos.
73+// Al caminar, la misma antorcha mundial cambia de posición de pantalla,
74+// pero como el hash varía SUAVEMENTE entre tiles vecinos, el flicker
75+// simplemente tiene una fase ligeramente diferente (no "reset" visible).
76+// ─────────────────────────────────────────────────────────────────────────────
77+void LightView::draw() {
78+ static std::vector<uint8_t> buffer;
79+
80+ const int mapW = m_mapSize.width();
81+ const int mapH = m_mapSize.height();
82+ const size_t needed = 4u * (size_t)mapW * (size_t)mapH;
83+
84+ if (buffer.size() != needed)
85+ buffer.resize(needed, 0);
86+
87+ const int spriteSize = g_sprites.spriteSize();
88+ s_frame++;
89+
90+ // Tiempo global en segundos (fluye continuamente, sin reset)
91+ const float t = (float)s_frame / 60.f;
92+
93+ // Límite de luces activas
94+ const size_t MAX_LIGHTS = 512;
95+ size_t lightStart =
96+ m_lights.size() > MAX_LIGHTS ? m_lights.size() - MAX_LIGHTS : 0;
97+
98+ // Pre-calcular flicker de cada luz (una sola vez por frame por luz)
99+ // NO se almacena en caché — se calcula directo del tiempo + hash.
100+ struct LightCalc {
101+ float flicker;
102+ };
103+ std::vector<LightCalc> calcs(m_lights.size());
104+
105+ for (size_t i = lightStart; i < m_lights.size(); ++i) {
106+ // Convertir posición de PANTALLA a posición MUNDIAL (tile coords)
107+ // m_worldOffsetX = cameraX - virtualCenterOffset.x
108+ // screenTileX = light.pos.x / spriteSize (0..mapW)
109+ // worldTileX = cameraX + (screenTileX - virtualCenterOffset.x) =
110+ // m_worldOffsetX + screenTileX
111+ int worldTX = m_worldOffsetX + (m_lights[i].pos.x / spriteSize);
112+ int worldTY = m_worldOffsetY + (m_lights[i].pos.y / spriteSize);
113+ uint32_t h = hashPos(worldTX, worldTY);
114+
115+ float phOffset = (float)(h & 0xFFFF) / 65535.f * 6.2832f;
116+ float speed = 1.5f + (float)((h >> 16) & 0xFF) / 255.f * 2.5f;
117+ float amp = 0.06f + (float)((h >> 8) & 0xFF) / 255.f * 0.12f;
118+
119+ float phase = t * speed + phOffset;
120+ float wave = std::sin(phase) + 0.35f * std::sin(phase * 2.3f + 0.8f);
121+ float fk = 1.0f + amp * wave;
122+ if (fk < 0.75f)
123+ fk = 0.75f;
124+ if (fk > 1.25f)
125+ fk = 1.25f;
126+
127+ calcs[i].flicker = fk;
128+ }
129+
130+ // Loop principal: calcular contribución de luz por pixel
131+ for (int y = 0; y < mapH; ++y) {
132+ for (int x = 0; x < mapW; ++x) {
133+ const int px = x * spriteSize + spriteSize / 2;
134+ const int py = y * spriteSize + spriteSize / 2;
135+
136+ const int tileIndex = y * mapW + x;
137+ const int colorIndex = tileIndex * 4;
138+
139+ float r = (float)m_globalLight.r();
140+ float g = (float)m_globalLight.g();
141+ float b = (float)m_globalLight.b();
142+
143+ size_t loopStart = std::max(m_tiles[tileIndex].start, lightStart);
144+ for (size_t i = loopStart; i < m_lights.size(); ++i) {
145+ Light &light = m_lights[i];
146+
147+ const float maxR = (float)light.intensity * spriteSize;
148+ const float dx = (float)(px - light.pos.x);
149+ const float dy = (float)(py - light.pos.y);
150+ const float dist2 = dx * dx + dy * dy;
151+ if (dist2 > maxR * maxR)
152+ continue;
153+
154+ const float dist = std::sqrt(dist2) / (float)spriteSize;
155+ float intensity = (-dist + (float)light.intensity) * 0.2f;
156+ if (intensity < 0.01f)
157+ continue;
158+ if (intensity > 1.0f)
159+ intensity = 1.0f;
160+
161+ // FIX: clamp intensity*flicker a ≤1.0 para evitar overflow uint8
162+ // (importante con admins/GM que tienen luz máxima)
163+ float finalI = intensity * calcs[i].flicker;
164+ if (finalI > 1.0f)
165+ finalI = 1.0f;
166+
167+ Color lc = Color::from8bit(light.color) * finalI;
168+ r = std::max(r, (float)lc.r());
169+ g = std::max(g, (float)lc.g());
170+ b = std::max(b, (float)lc.b());
171+ }
172+
173+ buffer[colorIndex] = (uint8_t)std::min(r, 255.f);
174+ buffer[colorIndex + 1] = (uint8_t)std::min(g, 255.f);
175+ buffer[colorIndex + 2] = (uint8_t)std::min(b, 255.f);
176+ buffer[colorIndex + 3] = 255;
177+ }
178+ }
179+
180+ // Upload a GPU
181+ m_lightTexture->update();
182+ glBindTexture(GL_TEXTURE_2D, m_lightTexture->getId());
183+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, mapW, mapH, 0, GL_RGBA,
184+ GL_UNSIGNED_BYTE, buffer.data());
185+
186+ // Render
187+ Point offset = m_src.topLeft();
188+ Size size = m_src.size();
189+ CoordsBuffer coords;
190+ coords.addRect(
191+ RectF(m_dest.left(), m_dest.top(), m_dest.width(), m_dest.height()),
192+ RectF((float)offset.x / spriteSize, (float)offset.y / spriteSize,
193+ (float)size.width() / spriteSize,
194+ (float)size.height() / spriteSize));
195+
196+ g_painter->resetColor();
197+ g_painter->setCompositionMode(Painter::CompositionMode_Multiply);
198+ g_painter->drawTextureCoords(coords, m_lightTexture);
199+ g_painter->resetCompositionMode();
200+}
A RD_Client/src/client/lightview.h +80-0 View file
@@ -0,0 +1,80 @@
1+/*
2+ * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
3+ *
4+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5+ * of this software and associated documentation files (the "Software"), to deal
6+ * in the Software without restriction, including without limitation the rights
7+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+ * copies of the Software, and to permit persons to whom the Software is
9+ * furnished to do so, subject to the following conditions:
10+ *
11+ * The above copyright notice and this permission notice shall be included in
12+ * all copies or substantial portions of the Software.
13+ *
14+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+ * THE SOFTWARE.
21+ */
22+
23+#ifndef LIGHTVIEW_H
24+#define LIGHTVIEW_H
25+
26+#include "declarations.h"
27+#include "thingtype.h"
28+#include <cmath>
29+#include <framework/graphics/declarations.h>
30+#include <framework/graphics/drawqueue.h>
31+#include <set>
32+#include <unordered_map>
33+
34+struct TileLight {
35+ size_t start;
36+ uint8_t color;
37+};
38+
39+// Flicker state por cada fuente de luz (persistente entre frames)
40+struct LightFlicker {
41+ float phase; // fase actual de la onda seno (0..2π)
42+ float speed; // velocidad de oscilación (varía por antorcha)
43+ float amplitude; // qué tanto varía la intensidad
44+};
45+
46+class LightView : public DrawQueueItem {
47+public:
48+ LightView(TexturePtr &lightTexture, const Size &mapSize, const Rect &dest,
49+ const Rect &src, uint8_t color, uint8_t intensity,
50+ int worldOffsetX = 0, int worldOffsetY = 0)
51+ : DrawQueueItem(nullptr), m_lightTexture(lightTexture),
52+ m_mapSize(mapSize), m_dest(dest), m_src(src),
53+ m_worldOffsetX(worldOffsetX), m_worldOffsetY(worldOffsetY) {
54+ m_globalLight = Color::from8bit(color) * ((float)intensity / 255.f);
55+ m_tiles.resize(m_mapSize.area(), TileLight{0, 0});
56+ }
57+
58+ inline void addLight(const Point &pos, const Light &light) {
59+ return addLight(pos, light.color, light.intensity);
60+ }
61+ void addLight(const Point &pos, uint8_t color, uint8_t intensity);
62+ void setFieldBrightness(const Point &pos, size_t start, uint8_t color);
63+ size_t size() { return m_lights.size(); }
64+
65+ void draw() override;
66+
67+private:
68+ TexturePtr m_lightTexture;
69+ Size m_mapSize;
70+ Rect m_dest, m_src;
71+ Color m_globalLight;
72+ std::vector<Light> m_lights;
73+ std::vector<TileLight> m_tiles;
74+ int m_worldOffsetX = 0; // cameraPos.x - virtualCenterOffset.x (tile coords)
75+ int m_worldOffsetY = 0; // cameraPos.y - virtualCenterOffset.y (tile coords)
76+
77+ static uint32_t s_frame;
78+};
79+
80+#endif
A RD_Client/src/client/localplayer.h +205-0 View file
@@ -0,0 +1,205 @@
1+/*
2+ * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
3+ *
4+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5+ * of this software and associated documentation files (the "Software"), to deal
6+ * in the Software without restriction, including without limitation the rights
7+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+ * copies of the Software, and to permit persons to whom the Software is
9+ * furnished to do so, subject to the following conditions:
10+ *
11+ * The above copyright notice and this permission notice shall be included in
12+ * all copies or substantial portions of the Software.
13+ *
14+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+ * THE SOFTWARE.
21+ */
22+
23+#ifndef LOCALPLAYER_H
24+#define LOCALPLAYER_H
25+
26+#include "player.h"
27+#include "walkmatrix.h"
28+
29+// @bindclass
30+class LocalPlayer : public Player
31+{
32+ enum {
33+ PREWALK_TIMEOUT = 1000
34+ };
35+
36+public:
37+ LocalPlayer();
38+
39+ void draw(const Point& dest, bool animate = true, LightView* lightView = nullptr) override;
40+
41+ void unlockWalk() { m_walkLockExpiration = 0; }
42+ void lockWalk(int millis = 200);
43+ void stopAutoWalk();
44+ bool autoWalk(Position destination, bool retry = false);
45+ bool canWalk(Otc::Direction direction, bool ignoreLock = false);
46+ bool isWalkLocked() {
47+ return (m_walkLockExpiration != 0 && g_clock.millis() < m_walkLockExpiration);
48+ }
49+ void turn(Otc::Direction) override;
50+
51+ void setStates(int states);
52+ void setSkill(uint8_t skill, int level, int levelPercent);
53+ void setBaseSkill(uint8_t skill, int baseLevel);
54+ void setHealth(double health, double maxHealth);
55+ void setFreeCapacity(double freeCapacity);
56+ void setTotalCapacity(double totalCapacity);
57+ void setExperience(double experience);
58+ void setLevel(double level, double levelPercent);
59+ void setMana(double mana, double maxMana);
60+ void setMagicLevel(double magicLevel, double magicLevelPercent);
61+ void setBaseMagicLevel(double baseMagicLevel);
62+ void setSoul(double soul);
63+ void setStamina(double stamina);
64+ void setKnown(bool known) { m_known = known; }
65+ void setPendingGame(bool pending) { m_pending = pending; }
66+ void setInventoryItem(Otc::InventorySlot inventory, const ItemPtr& item);
67+ void setVocation(int vocation);
68+ void setPremium(bool premium);
69+ void setRegenerationTime(double regenerationTime);
70+ void setOfflineTrainingTime(double offlineTrainingTime);
71+ void setSpells(const std::vector<int>& spells);
72+ void setBlessings(int blessings);
73+
74+ int getStates() { return m_states; }
75+ int getSkillLevel(uint8_t skill) { return skill < m_skillsLevel.size() ? m_skillsLevel[skill] : 0; }
76+ int getSkillBaseLevel(uint8_t skill) { return skill < m_skillsBaseLevel.size() ? m_skillsBaseLevel[skill] : 0; }
77+ int getSkillLevelPercent(uint8_t skill) { return skill < m_skillsLevelPercent.size() ? m_skillsLevelPercent[skill] : 0; }
78+ int getVocation() { return m_vocation; }
79+ double getHealth() { return m_health; }
80+ double getMaxHealth() { return m_maxHealth; }
81+ double getFreeCapacity() { return m_freeCapacity; }
82+ double getTotalCapacity() { return m_totalCapacity; }
83+ double getExperience() { return m_experience; }
84+ double getLevel() { return m_level; }
85+ double getLevelPercent() { return m_levelPercent; }
86+ double getMana() { return m_mana; }
87+ double getMaxMana() { return std::max<double>(m_mana, m_maxMana); }
88+ double getMagicLevel() { return m_magicLevel; }
89+ double getMagicLevelPercent() { return m_magicLevelPercent; }
90+ double getBaseMagicLevel() { return m_baseMagicLevel; }
91+ double getSoul() { return m_soul; }
92+ double getStamina() { return m_stamina; }
93+ double getRegenerationTime() { return m_regenerationTime; }
94+ double getOfflineTrainingTime() { return m_offlineTrainingTime; }
95+ std::vector<int> getSpells() { return m_spells; }
96+ ItemPtr getInventoryItem(Otc::InventorySlot inventory) { return m_inventoryItems[inventory]; }
97+ int getBlessings() { return m_blessings; }
98+
99+ bool hasSight(const Position& pos);
100+ bool isKnown() { return m_known; }
101+ bool isAutoWalking() { return m_autoWalkDestination.isValid(); }
102+ bool isServerWalking() override { return m_serverWalking; }
103+ bool isPremium() { return m_premium; }
104+ bool isPendingGame() { return m_pending; }
105+
106+ LocalPlayerPtr asLocalPlayer() { return static_self_cast<LocalPlayer>(); }
107+ bool isLocalPlayer() override { return true; }
108+
109+ void onAppear() override;
110+ void onPositionChange(const Position& newPos, const Position& oldPos) override;
111+
112+ // pre walking
113+ void preWalk(Otc::Direction direction);
114+ bool isPreWalking() override { return !m_preWalking.empty(); }
115+ Position getPrewalkingPosition(bool beforePrewalk = false) override {
116+ if(m_preWalking.empty())
117+ return m_position;
118+ else if (!beforePrewalk && m_preWalking.size() == 1)
119+ return m_position;
120+ auto ret = m_preWalking.rbegin();
121+ if(!beforePrewalk)
122+ ret++;
123+ return *ret;
124+ }
125+
126+ uint32_t getWalkPrediction(const Position& pos)
127+ {
128+ return m_walkMatrix.get(pos);
129+ };
130+
131+ std::string dumpWalkMatrix()
132+ {
133+ return m_walkMatrix.dump();
134+ }
135+
136+ void startServerWalking() { m_serverWalking = true; }
137+ void finishServerWalking() { m_serverWalking = false; }
138+
139+protected:
140+ void walk(const Position& oldPos, const Position& newPos) override;
141+ void cancelWalk(Otc::Direction direction = Otc::InvalidDirection);
142+
143+ void cancelNewWalk(Otc::Direction dir);
144+ bool predictiveCancelWalk(const Position& pos, uint32_t predictionId, Otc::Direction dir);
145+
146+ bool retryAutoWalk();
147+ void stopWalk() override;
148+
149+ friend class Game;
150+
151+protected:
152+ void updateWalkOffset(uint8 totalPixelsWalked, bool inNextFrame = false) override;
153+ void updateWalk() override;
154+ void terminateWalk() override;
155+
156+private:
157+ // walk related
158+ Position m_autoWalkDestination;
159+ Position m_lastAutoWalkPosition;
160+ int m_lastAutoWalkRetries = 0;
161+ ScheduledEventPtr m_serverWalkEndEvent;
162+ ScheduledEventPtr m_autoWalkContinueEvent;
163+ ticks_t m_walkLockExpiration;
164+
165+ // walking and pre walking
166+ std::list<Position> m_preWalking;
167+ bool m_serverWalking = false;
168+ bool m_lastPrewalkDone = false;
169+ WalkMatrix m_walkMatrix;
170+
171+ bool m_premium = false;
172+ bool m_known = false;
173+ bool m_pending = false;
174+
175+ ItemPtr m_inventoryItems[Otc::LastInventorySlot];
176+ Timer m_idleTimer;
177+
178+ std::vector<int> m_skillsLevel;
179+ std::vector<int> m_skillsBaseLevel;
180+ std::vector<int> m_skillsLevelPercent;
181+ std::vector<int> m_spells;
182+
183+ int m_states;
184+ int m_vocation;
185+ int m_blessings;
186+
187+ double m_health;
188+ double m_maxHealth;
189+ double m_freeCapacity;
190+ double m_totalCapacity;
191+ double m_experience;
192+ double m_level;
193+ double m_levelPercent;
194+ double m_mana;
195+ double m_maxMana;
196+ double m_magicLevel;
197+ double m_magicLevelPercent;
198+ double m_baseMagicLevel;
199+ double m_soul;
200+ double m_stamina;
201+ double m_regenerationTime;
202+ double m_offlineTrainingTime;
203+};
204+
205+#endif
Top