mirror of
https://github.com/EQEmu/Server.git
synced 2026-09-05 11:26:35 +00:00
Merge remote-tracking branch 'remotes/origin/master' into blob_conversion
Conflicts: common/database.cpp common/mysql_request_result.h common/shareddb.cpp
This commit is contained in:
@@ -92,6 +92,7 @@ SET(common_sources
|
||||
)
|
||||
|
||||
SET(common_headers
|
||||
any.h
|
||||
base_packet.h
|
||||
base_data.h
|
||||
bodytypes.h
|
||||
|
||||
+190
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Boost Software License - Version 1.0 - August 17th, 2003
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person or organization
|
||||
* obtaining a copy of the software and accompanying documentation covered by
|
||||
* this license (the "Software") to use, reproduce, display, distribute,
|
||||
* execute, and transmit the Software, and to prepare derivative works of the
|
||||
* Software, and to permit third-parties to whom the Software is furnished to
|
||||
* do so, all subject to the following:
|
||||
*
|
||||
* The copyright notices in the Software and this entire statement, including
|
||||
* the above license grant, this restriction and the following disclaimer,
|
||||
* must be included in all copies of the Software, in whole or in part, and
|
||||
* all derivative works of the Software, unless such copies or derivative
|
||||
* works are solely in the form of machine-executable object code generated by
|
||||
* a source language processor.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
* SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
* FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
// EQEmu::Any is a modified version of Boost::Any and as such retains the Boost licensing.
|
||||
|
||||
#ifndef EQEMU_COMMON_ANY_H
|
||||
#define EQEMU_COMMON_ANY_H
|
||||
|
||||
#include <algorithm>
|
||||
#include <typeinfo>
|
||||
|
||||
namespace EQEmu
|
||||
{
|
||||
class Any
|
||||
{
|
||||
public:
|
||||
Any()
|
||||
: content(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename ValueType>
|
||||
Any(const ValueType &value)
|
||||
: content(new Holder<ValueType>(value))
|
||||
{
|
||||
}
|
||||
|
||||
Any(const Any &other)
|
||||
: content(other.content ? other.content->clone() : 0)
|
||||
{
|
||||
}
|
||||
|
||||
~Any()
|
||||
{
|
||||
if(content)
|
||||
delete content;
|
||||
}
|
||||
|
||||
Any& swap(Any &rhs)
|
||||
{
|
||||
std::swap(content, rhs.content);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename ValueType>
|
||||
Any& operator=(const ValueType &rhs)
|
||||
{
|
||||
Any(rhs).swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
Any& operator=(Any rhs)
|
||||
{
|
||||
rhs.swap(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return !content;
|
||||
}
|
||||
|
||||
const std::type_info& type() const
|
||||
{
|
||||
return content ? content->type() : typeid(void);
|
||||
}
|
||||
|
||||
class Placeholder
|
||||
{
|
||||
public:
|
||||
virtual ~Placeholder()
|
||||
{
|
||||
}
|
||||
|
||||
virtual const std::type_info& type() const = 0;
|
||||
virtual Placeholder* clone() const = 0;
|
||||
};
|
||||
|
||||
|
||||
template<typename ValueType>
|
||||
class Holder : public Placeholder
|
||||
{
|
||||
public:
|
||||
Holder(const ValueType &value)
|
||||
: held(value)
|
||||
{
|
||||
}
|
||||
|
||||
virtual const std::type_info& type() const
|
||||
{
|
||||
return typeid(ValueType);
|
||||
}
|
||||
|
||||
virtual Placeholder* clone() const
|
||||
{
|
||||
return new Holder(held);
|
||||
}
|
||||
|
||||
ValueType held;
|
||||
|
||||
private:
|
||||
Holder& operator=(const Holder&);
|
||||
};
|
||||
|
||||
private:
|
||||
template<typename ValueType>
|
||||
friend ValueType* any_cast(Any*);
|
||||
|
||||
template<typename ValueType>
|
||||
friend ValueType* unsafe_any_cast(Any*);
|
||||
|
||||
Placeholder* content;
|
||||
};
|
||||
|
||||
class bad_any_cast : public std::bad_cast
|
||||
{
|
||||
public:
|
||||
virtual const char * what() const throw()
|
||||
{
|
||||
return "DBI::bad_any_cast: failed conversion using DBI::any_cast";
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ValueType>
|
||||
ValueType* any_cast(Any* operand)
|
||||
{
|
||||
return operand &&
|
||||
operand->type() == typeid(ValueType) ? &static_cast<Any::Holder<ValueType>*>(operand->content)->held : nullptr;
|
||||
}
|
||||
|
||||
template<typename ValueType>
|
||||
inline const ValueType* any_cast(const Any* operand)
|
||||
{
|
||||
return any_cast<ValueType>(const_cast<Any*>(operand));
|
||||
}
|
||||
|
||||
template<typename ValueType>
|
||||
ValueType any_cast(Any& operand)
|
||||
{
|
||||
typedef typename std::remove_reference<ValueType>::type nonref;
|
||||
nonref* result = any_cast<nonref>(&operand);
|
||||
if(!result)
|
||||
throw bad_any_cast();
|
||||
return *result;
|
||||
}
|
||||
|
||||
template<typename ValueType>
|
||||
inline ValueType any_cast(const Any& operand)
|
||||
{
|
||||
typedef typename std::remove_reference<ValueType>::type nonref;
|
||||
return any_cast<const nonref&>(const_cast<Any&>(operand));
|
||||
}
|
||||
|
||||
template<typename ValueType>
|
||||
inline ValueType* unsafe_any_cast(Any* operand)
|
||||
{
|
||||
return &static_cast<Any::Holder<ValueType>*>(operand->content)->held;
|
||||
}
|
||||
|
||||
template<typename ValueType>
|
||||
inline const ValueType* unsafe_any_cast(const Any* operand)
|
||||
{
|
||||
return unsafe_any_cast<ValueType>(const_cast<Any*>(operand));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -132,6 +132,9 @@ uint32 Database::CheckLogin(const char* name, const char* password, int16* oStat
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(results.RowCount() == 0)
|
||||
return 0;
|
||||
|
||||
auto row = results.begin();
|
||||
|
||||
uint32 id = atoi(row[0]);
|
||||
|
||||
@@ -540,3 +540,4 @@ N(OP_OpenInventory),
|
||||
N(OP_OpenContainer),
|
||||
N(OP_Marquee),
|
||||
N(OP_ClientTimeStamp),
|
||||
N(OP_GuildPromote),
|
||||
|
||||
@@ -2290,10 +2290,13 @@ struct Stun_Struct { // 4 bytes total
|
||||
};
|
||||
|
||||
struct AugmentItem_Struct {
|
||||
/*00*/ int16 container_slot;
|
||||
/*02*/ char unknown02[2];
|
||||
/*04*/ int32 augment_slot;
|
||||
/*08*/
|
||||
/*00*/ uint32 container_index;
|
||||
/*04*/ int32 container_slot;
|
||||
/*08*/ uint32 augment_index;
|
||||
/*12*/ int32 augment_slot;
|
||||
/*16*/ uint32 dest_inst_id; // The unique serial number for the item instance that is being augmented
|
||||
/*20*/ int32 augment_action; // Guessed - 0 = augment, 1 = remove with distiller, 3 = delete aug
|
||||
/*24*/
|
||||
};
|
||||
|
||||
// OP_Emote
|
||||
@@ -4464,6 +4467,14 @@ struct GuildBankPromote_Struct
|
||||
/*12*/ uint32 Slot2; // Always appears to be the same as Slot for Action code 3
|
||||
};
|
||||
|
||||
struct GuildPromoteStruct {
|
||||
/*000*/ char target[64];
|
||||
/*064*/ char name[64];
|
||||
/*128*/ uint32 rank;
|
||||
/*132*/ uint32 myrank;
|
||||
/*136*/
|
||||
};
|
||||
|
||||
struct GuildBankPermissions_Struct
|
||||
{
|
||||
/*00*/ uint32 Action; // 6
|
||||
|
||||
@@ -534,7 +534,7 @@ void EQStream::FastQueuePacket(EQApplicationPacket **p, bool ack_req)
|
||||
|
||||
uint16 opcode = (*OpMgr)->EmuToEQ(pack->emu_opcode);
|
||||
|
||||
_log(NET__APP_TRACE, "Queueing %sacked packet with opcode 0x%x (%s) and length %d", ack_req?"":"non-", opcode, OpcodeManager::EmuToName(pack->emu_opcode), pack->size);
|
||||
//_log(NET__APP_TRACE, "Queueing %sacked packet with opcode 0x%x (%s) and length %d", ack_req?"":"non-", opcode, OpcodeManager::EmuToName(pack->emu_opcode), pack->size);
|
||||
|
||||
if (!ack_req) {
|
||||
NonSequencedPush(new EQProtocolPacket(opcode, pack->pBuffer, pack->size));
|
||||
|
||||
@@ -474,6 +474,11 @@ bool BaseGuildManager::SetBankerFlag(uint32 charid, bool is_banker) {
|
||||
return(true);
|
||||
}
|
||||
|
||||
bool BaseGuildManager::ForceRankUpdate(uint32 charid) {
|
||||
SendRankUpdate(charid);
|
||||
return(true);
|
||||
}
|
||||
|
||||
bool BaseGuildManager::SetAltFlag(uint32 charid, bool is_alt)
|
||||
{
|
||||
if(!DBSetAltFlag(charid, is_alt))
|
||||
|
||||
@@ -54,6 +54,7 @@ public:
|
||||
bool SetGuild(uint32 charid, uint32 guild_id, uint8 rank);
|
||||
bool SetGuildRank(uint32 charid, uint8 rank);
|
||||
bool SetBankerFlag(uint32 charid, bool is_banker);
|
||||
bool ForceRankUpdate(uint32 charid);
|
||||
bool GetAltFlag(uint32 CharID);
|
||||
bool SetAltFlag(uint32 charid, bool is_alt);
|
||||
bool GetBankerFlag(uint32 CharID);
|
||||
|
||||
+12
-1
@@ -683,6 +683,13 @@ int16 Inventory::FindFreeSlotForTradeItem(const ItemInst* inst) {
|
||||
|
||||
if ((main_inst->GetID() == inst->GetID()) && (main_inst->GetCharges() < main_inst->GetItem()->StackSize))
|
||||
return free_slot;
|
||||
}
|
||||
|
||||
for (int16 free_slot = EmuConstants::GENERAL_BEGIN; free_slot <= EmuConstants::GENERAL_END; ++free_slot) {
|
||||
const ItemInst* main_inst = m_inv[free_slot];
|
||||
|
||||
if (!main_inst)
|
||||
continue;
|
||||
|
||||
if (main_inst->IsType(ItemClassContainer)) { // if item-specific containers already have bad items, we won't fix it here...
|
||||
for (uint8 free_bag_slot = SUB_BEGIN; (free_bag_slot < main_inst->GetItem()->BagSlots) && (free_bag_slot < EmuConstants::ITEM_CONTAINER_SIZE); ++free_bag_slot) {
|
||||
@@ -732,8 +739,12 @@ int16 Inventory::FindFreeSlotForTradeItem(const ItemInst* inst) {
|
||||
|
||||
if (!main_inst)
|
||||
return free_slot;
|
||||
}
|
||||
|
||||
if (main_inst->IsType(ItemClassContainer)) {
|
||||
for (int16 free_slot = EmuConstants::GENERAL_BEGIN; free_slot <= EmuConstants::GENERAL_END; ++free_slot) {
|
||||
const ItemInst* main_inst = m_inv[free_slot];
|
||||
|
||||
if (main_inst && main_inst->IsType(ItemClassContainer)) {
|
||||
if ((main_inst->GetItem()->BagSize < inst->GetItem()->Size) || (main_inst->GetItem()->BagType == BagTypeBandolier) || (main_inst->GetItem()->BagType == BagTypeQuiver))
|
||||
continue;
|
||||
|
||||
|
||||
+3
-3
@@ -92,8 +92,8 @@ extern void log_raw_packet(LogType type, uint16 seq, const BasePacket *p);
|
||||
class Mob;
|
||||
extern void log_message_mob(LogType type, Mob *who, const char *fmt, ...);
|
||||
#define mlog( type, format, ...) \
|
||||
if(IsLoggingEnabled()) \
|
||||
do { \
|
||||
if(IsLoggingEnabled()) \
|
||||
if(log_type_info[ type ].enabled) { \
|
||||
log_message_mob(type, this, format, ##__VA_ARGS__); \
|
||||
} \
|
||||
@@ -150,16 +150,16 @@ extern void log_raw_packet(LogType type, uint16 seq, const BasePacket *p);
|
||||
class Mob;
|
||||
extern void log_hex_mob(LogType type, Mob *who, const char *data, uint32 length);
|
||||
#define mhex( type, data, len) \
|
||||
if(IsLoggingEnabled()) \
|
||||
do { \
|
||||
if(IsLoggingEnabled()) \
|
||||
if(log_type_info[ type ].enabled) { \
|
||||
log_hex_mob(type, this, data, len); \
|
||||
} \
|
||||
} while(false)
|
||||
extern void log_packet_mob(LogType type, Mob *who, const BasePacket *p);
|
||||
#define mpkt( type, packet) \
|
||||
if(IsLoggingEnabled()) \
|
||||
do { \
|
||||
if(IsLoggingEnabled()) \
|
||||
if(log_type_info[ type ].enabled) { \
|
||||
log_packet_mob(type, this, packet); \
|
||||
} \
|
||||
|
||||
@@ -40,7 +40,7 @@ public:
|
||||
MySQLRequestResult& operator=(MySQLRequestResult&& other);
|
||||
|
||||
bool Success() const { return m_Success;}
|
||||
std::string ErrorMessage() const { return m_ErrorBuffer ? std::string(m_ErrorBuffer) : std::string(""); }
|
||||
std::string ErrorMessage() const {return m_ErrorBuffer ? std::string(m_ErrorBuffer) : std::string("");}
|
||||
uint32 ErrorNumber() const {return m_ErrorNumber;}
|
||||
uint32 RowsAffected() const {return m_RowsAffected;}
|
||||
uint32 RowCount() const {return m_RowCount;}
|
||||
|
||||
@@ -64,6 +64,5 @@ bool MySQLRequestRow::operator!=(const MySQLRequestRow& rhs)
|
||||
|
||||
char* MySQLRequestRow::operator[](int index)
|
||||
{
|
||||
|
||||
return m_MySQLRow[index];
|
||||
}
|
||||
|
||||
+32
-7
@@ -1,4 +1,3 @@
|
||||
|
||||
#include "../debug.h"
|
||||
#include "rof.h"
|
||||
#include "../opcodemgr.h"
|
||||
@@ -1974,7 +1973,14 @@ ENCODE(OP_ZoneSpawns)
|
||||
else
|
||||
{
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->guildID);
|
||||
VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->guildrank);
|
||||
|
||||
/* Translate older ranks to new values */
|
||||
switch (emu->guildrank) {
|
||||
case 0: { VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 5); break; } // GUILD_MEMBER 0
|
||||
case 1: { VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 3); break; } // GUILD_OFFICER 1
|
||||
case 2: { VARSTRUCT_ENCODE_TYPE(uint32, Buffer, 1); break; } // GUILD_LEADER 2
|
||||
default: { VARSTRUCT_ENCODE_TYPE(uint32, Buffer, emu->guildrank); break; } //
|
||||
}
|
||||
}
|
||||
|
||||
VARSTRUCT_ENCODE_TYPE(uint8, Buffer, emu->class_);
|
||||
@@ -2406,7 +2412,15 @@ ENCODE(OP_GuildMemberList) {
|
||||
PutFieldN(level);
|
||||
PutFieldN(banker);
|
||||
PutFieldN(class_);
|
||||
PutFieldN(rank);
|
||||
|
||||
/* Translate older ranks to new values */
|
||||
switch (emu_e->rank) {
|
||||
case 0: { e->rank = htonl(5); break; } // GUILD_MEMBER 0
|
||||
case 1: { e->rank = htonl(3); break; } // GUILD_OFFICER 1
|
||||
case 2: { e->rank = htonl(1); break; } // GUILD_LEADER 2
|
||||
default: { e->rank = htonl(emu_e->rank); break; } // GUILD_NONE
|
||||
}
|
||||
|
||||
PutFieldN(time_last_on);
|
||||
PutFieldN(tribute_enable);
|
||||
e->unknown01 = 0;
|
||||
@@ -3330,7 +3344,15 @@ ENCODE(OP_SetGuildRank)
|
||||
ENCODE_LENGTH_EXACT(GuildSetRank_Struct);
|
||||
SETUP_DIRECT_ENCODE(GuildSetRank_Struct, structs::GuildSetRank_Struct);
|
||||
eq->GuildID = emu->Unknown00;
|
||||
OUT(Rank);
|
||||
|
||||
/* Translate older ranks to new values */
|
||||
switch (emu->Rank) {
|
||||
case 0: { eq->Rank = 5; break; } // GUILD_MEMBER 0
|
||||
case 1: { eq->Rank = 3; break; } // GUILD_OFFICER 1
|
||||
case 2: { eq->Rank = 1; break; } // GUILD_LEADER 2
|
||||
default: { eq->Rank = emu->Rank; break; }
|
||||
}
|
||||
|
||||
memcpy(eq->MemberName, emu->MemberName, sizeof(eq->MemberName));
|
||||
OUT(Banker);
|
||||
eq->Unknown76 = 1;
|
||||
@@ -4660,8 +4682,11 @@ DECODE(OP_AugmentItem) {
|
||||
SETUP_DIRECT_DECODE(AugmentItem_Struct, structs::AugmentItem_Struct);
|
||||
|
||||
emu->container_slot = RoFToServerSlot(eq->container_slot);
|
||||
//emu->augment_slot = eq->augment_slot;
|
||||
|
||||
emu->augment_slot = RoFToServerSlot(eq->augment_slot);
|
||||
emu->container_index = eq->container_index;
|
||||
emu->augment_index = eq->augment_index;
|
||||
emu->dest_inst_id = eq->dest_inst_id;
|
||||
emu->augment_action = eq->augment_action;
|
||||
FINISH_DIRECT_DECODE();
|
||||
}
|
||||
|
||||
@@ -5068,7 +5093,7 @@ char* SerializeItem(const ItemInst *inst, int16 slot_id_in, uint32 *length, uint
|
||||
memset(&isbs, 0, sizeof(RoF::structs::ItemSecondaryBodyStruct));
|
||||
|
||||
isbs.augtype = item->AugType;
|
||||
isbs.augdistiller = 0;
|
||||
isbs.augdistiller = 65535;
|
||||
isbs.augrestrict = item->AugRestrict;
|
||||
|
||||
|
||||
|
||||
@@ -2519,10 +2519,10 @@ struct Stun_Struct { // 8 bytes total
|
||||
|
||||
struct AugmentItem_Struct {
|
||||
/*00*/ uint32 dest_inst_id; // The unique serial number for the item instance that is being augmented
|
||||
/*04*/ uint32 unknown04; // Seen 0
|
||||
/*04*/ uint32 container_index; // Seen 0
|
||||
/*08*/ ItemSlotStruct container_slot; // Slot of the item being augmented
|
||||
/*20*/ uint32 unknown20; // Seen 0
|
||||
/*24*/ ItemSlotStruct distiller_slot; // Slot of the distiller to use (if one applies)
|
||||
/*20*/ uint32 augment_index; // Seen 0
|
||||
/*24*/ ItemSlotStruct augment_slot; // Slot of the distiller to use (if one applies)
|
||||
/*36*/ int32 augment_action; // Guessed - 0 = augment, 1 = remove with distiller, 3 = delete aug
|
||||
/*36*/ //int32 augment_slot;
|
||||
/*40*/
|
||||
|
||||
+20
-9
@@ -125,19 +125,22 @@ uint32 SharedDatabase::GetTotalTimeEntitledOnAccount(uint32 AccountID) {
|
||||
|
||||
bool SharedDatabase::SaveCursor(uint32 char_id, std::list<ItemInst*>::const_iterator &start, std::list<ItemInst*>::const_iterator &end)
|
||||
{
|
||||
iter_queue it;
|
||||
int i;
|
||||
bool ret=true;
|
||||
iter_queue it;
|
||||
int i;
|
||||
bool ret = true;
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char* query = 0;
|
||||
// Delete cursor items
|
||||
if ((ret = RunQuery(query, MakeAnyLenString(&query, "DELETE FROM inventory WHERE charid=%i AND ( (slotid >=8000 and slotid<=8999) or slotid=%i or (slotid>=%i and slotid<=%i))", char_id, MainCursor,EmuConstants::CURSOR_BAG_BEGIN,EmuConstants::CURSOR_BAG_END), errbuf))) {
|
||||
for(it=start,i=8000;it!=end;++it,i++) {
|
||||
ItemInst *inst=*it;
|
||||
if (!(ret=SaveInventory(char_id,inst,(i==8000) ? MainCursor : i)))
|
||||
if ((ret = RunQuery(query, MakeAnyLenString(&query, "DELETE FROM inventory WHERE charid = %i AND ((slotid >= 8000 AND slotid <= 8999) OR slotid = %i OR (slotid >= %i AND slotid <= %i))",
|
||||
char_id, MainCursor, EmuConstants::CURSOR_BAG_BEGIN, EmuConstants::CURSOR_BAG_END), errbuf))) {
|
||||
|
||||
for (it = start, i = 8000; it != end; ++it, i++) {
|
||||
ItemInst *inst = *it;
|
||||
if (!(ret = SaveInventory(char_id, inst, (i == 8000) ? MainCursor : i)))
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
std::cout << "Clearing cursor failed: " << errbuf << std::endl;
|
||||
}
|
||||
safe_delete_array(query);
|
||||
@@ -1506,6 +1509,13 @@ void SharedDatabase::LoadSpells(void *data, int max_spells) {
|
||||
|
||||
int tempid = 0;
|
||||
int counter = 0;
|
||||
|
||||
if(result && mysql_field_count(getMySQL()) <= SPELL_LOAD_FIELD_COUNT) {
|
||||
_log(SPELLS__LOAD_ERR, "Fatal error loading spells: Spell field count < SPELL_LOAD_FIELD_COUNT(%u)", SPELL_LOAD_FIELD_COUNT);
|
||||
mysql_free_result(result);
|
||||
return;
|
||||
}
|
||||
|
||||
while (row = mysql_fetch_row(result)) {
|
||||
tempid = atoi(row[0]);
|
||||
if(tempid >= max_spells) {
|
||||
@@ -2027,7 +2037,8 @@ void SharedDatabase::SetBotInspectMessage(uint32 botid, const InspectMessage_Str
|
||||
char errbuf[MYSQL_ERRMSG_SIZE];
|
||||
char *query = 0;
|
||||
|
||||
if (!RunQuery(query, MakeAnyLenString(&query, "UPDATE bots SET BotInspectMessage='%s' WHERE BotID=%i", message->text, botid), errbuf)) {
|
||||
std::string msg = EscapeString(message->text);
|
||||
if (!RunQuery(query, MakeAnyLenString(&query, "UPDATE bots SET BotInspectMessage='%s' WHERE BotID=%i", msg.c_str(), botid), errbuf)) {
|
||||
std::cerr << "Error in SetBotInspectMessage query '" << query << "' " << errbuf << std::endl;
|
||||
}
|
||||
|
||||
|
||||
@@ -621,6 +621,8 @@ typedef enum {
|
||||
// number. note that the id field is counted as 0, this way the numbers
|
||||
// here match the numbers given to sep in the loading function net.cpp
|
||||
//
|
||||
#define SPELL_LOAD_FIELD_COUNT 231
|
||||
|
||||
struct SPDat_Spell_Struct
|
||||
{
|
||||
/* 000 */ int id; // not used
|
||||
|
||||
Reference in New Issue
Block a user