mirror of
https://github.com/Mezeporta/Erupe.git
synced 2026-02-04 09:15:08 +01:00
Merge branch 'main' into feature/discord-login
This commit is contained in:
@@ -5,6 +5,42 @@ INSERT INTO public.shop_items
|
||||
VALUES
|
||||
(5,5,16516,100,1,0,0,1,0,0,0,0),
|
||||
(5,5,16517,100,1,0,0,1,0,0,0,0),
|
||||
(6,5,9958,3,3,1,0,0,0,0,0,0),
|
||||
(6,5,1897,3,1,1,0,0,0,0,0,0),
|
||||
(6,5,8889,3,1,0,0,1,0,0,0,0),
|
||||
(6,5,6176,3,6,1,0,0,0,0,0,0),
|
||||
(6,5,1472,3,10,1,0,0,0,0,0,0),
|
||||
(6,5,7280,3,3,0,0,1,0,0,0,0),
|
||||
(6,5,8027,3,30,1,0,0,0,0,0,0),
|
||||
(6,5,8028,3,30,1,0,0,0,0,0,0),
|
||||
(6,5,8029,3,30,1,0,0,0,0,0,0),
|
||||
(6,5,8026,3,30,1,0,0,0,0,0,0),
|
||||
(6,5,8030,3,30,1,0,0,0,0,0,0),
|
||||
(6,5,4353,3,30,1,0,0,0,0,0,0),
|
||||
(6,5,4354,3,30,1,0,0,0,0,0,0),
|
||||
(6,5,4355,3,30,1,0,0,0,0,0,0),
|
||||
(6,5,4356,3,30,1,0,0,0,0,0,0),
|
||||
(6,5,4357,3,30,1,0,0,0,0,0,0),
|
||||
(6,5,4745,3,30,1,0,0,0,0,0,0),
|
||||
(6,5,4746,3,30,1,0,0,0,0,0,0),
|
||||
(6,5,4747,3,30,1,0,0,0,0,0,0),
|
||||
(6,5,4748,3,30,1,0,0,0,0,0,0),
|
||||
(6,5,4749,3,30,1,0,0,0,0,0,0),
|
||||
(6,5,5122,3,30,1,0,0,0,0,0,0),
|
||||
(6,5,5123,3,30,1,0,0,0,0,0,0),
|
||||
(6,5,5124,3,30,1,0,0,0,0,0,0),
|
||||
(6,5,5125,3,30,1,0,0,0,0,0,0),
|
||||
(6,5,5126,3,30,1,0,0,0,0,0,0),
|
||||
(6,5,5795,3,30,1,0,0,0,0,0,0),
|
||||
(6,5,5796,3,30,1,0,0,0,0,0,0),
|
||||
(6,5,5797,3,30,1,0,0,0,0,0,0),
|
||||
(6,5,5798,3,30,1,0,0,0,0,0,0),
|
||||
(6,5,5799,3,30,1,0,0,0,0,0,0),
|
||||
(6,5,6168,3,30,1,0,0,0,0,0,0),
|
||||
(6,5,6169,3,30,1,0,0,0,0,0,0),
|
||||
(6,5,6170,3,30,1,0,0,0,0,0,0),
|
||||
(6,5,6171,3,30,1,0,0,0,0,0,0),
|
||||
(6,5,6172,3,30,1,0,0,0,0,0,0),
|
||||
(7,0,13190,10,1,0,0,0,0,0,0,0),
|
||||
(7,0,1662,10,1,0,0,0,0,0,0,0),
|
||||
(7,0,10179,100,1,0,0,0,0,0,0,0);
|
||||
|
||||
15
config.json
15
config.json
@@ -14,6 +14,7 @@
|
||||
"ClientMode": "ZZ",
|
||||
"QuestCacheExpiry": 300,
|
||||
"ProxyPort": 0,
|
||||
"CommandPrefix": "!",
|
||||
"DevMode": true,
|
||||
"DevModeOptions": {
|
||||
"AutoCreateAccount": true,
|
||||
@@ -30,7 +31,7 @@
|
||||
"QuestDebugTools": false,
|
||||
"EarthStatusOverride": 0,
|
||||
"EarthIDOverride": 0,
|
||||
"EarthMonsterOverride": 0,
|
||||
"EarthMonsterOverride": [0, 0, 0, 0],
|
||||
"SaveDumps": {
|
||||
"Enabled": true,
|
||||
"OutputDir": "save-backups"
|
||||
@@ -82,32 +83,44 @@
|
||||
},
|
||||
"Commands": [
|
||||
{
|
||||
"Name": "Help",
|
||||
"Enabled": true,
|
||||
"Description": "Show enabled chat commands",
|
||||
"Prefix": "help"
|
||||
}, {
|
||||
"Name": "Rights",
|
||||
"Enabled": false,
|
||||
"Description": "Overwrite the Rights value on your account",
|
||||
"Prefix": "rights"
|
||||
}, {
|
||||
"Name": "Raviente",
|
||||
"Enabled": true,
|
||||
"Description": "Various Raviente siege commands",
|
||||
"Prefix": "ravi"
|
||||
}, {
|
||||
"Name": "Teleport",
|
||||
"Enabled": false,
|
||||
"Description": "Teleport to specified coordinates",
|
||||
"Prefix": "tele"
|
||||
}, {
|
||||
"Name": "Reload",
|
||||
"Enabled": true,
|
||||
"Description": "Reload all players in your Land",
|
||||
"Prefix": "reload"
|
||||
}, {
|
||||
"Name": "KeyQuest",
|
||||
"Enabled": false,
|
||||
"Description": "Overwrite your HR Key Quest progress",
|
||||
"Prefix": "kqf"
|
||||
}, {
|
||||
"Name": "Course",
|
||||
"Enabled": true,
|
||||
"Description": "Toggle Courses on your account",
|
||||
"Prefix": "course"
|
||||
}, {
|
||||
"Name": "PSN",
|
||||
"Enabled": true,
|
||||
"Description": "Link a PlayStation Network ID to your account",
|
||||
"Prefix": "psn"
|
||||
}, {
|
||||
"Name": "Discord",
|
||||
|
||||
@@ -81,6 +81,7 @@ type Config struct {
|
||||
RealClientMode Mode
|
||||
QuestCacheExpiry int // Number of seconds to keep quest data cached
|
||||
ProxyPort uint16 // Forces the game to connect to a channel server proxy
|
||||
CommandPrefix string // The prefix for commands
|
||||
DevMode bool
|
||||
|
||||
DevModeOptions DevModeOptions
|
||||
@@ -111,7 +112,7 @@ type DevModeOptions struct {
|
||||
QuestDebugTools bool // Enable various quest debug logs
|
||||
EarthStatusOverride int32
|
||||
EarthIDOverride int32
|
||||
EarthMonsterOverride int32
|
||||
EarthMonsterOverride []int32
|
||||
SaveDumps SaveDumpOptions
|
||||
}
|
||||
|
||||
@@ -175,6 +176,7 @@ type DiscordRealTime struct {
|
||||
type Command struct {
|
||||
Name string
|
||||
Enabled bool
|
||||
Description string
|
||||
Prefix string
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ type MsgMhfEnumerateShop struct {
|
||||
AckHandle uint32
|
||||
ShopType uint8 // 1 running gachas, 10 normal shop extensions, 8 Diva Defense shop
|
||||
ShopID uint32
|
||||
Unk2 uint16 // 00 80 running gachas, 00 20 normal shop
|
||||
Limit uint16
|
||||
Unk3 uint8
|
||||
Unk4 uint8
|
||||
Unk5 uint32
|
||||
@@ -30,7 +30,7 @@ func (m *MsgMhfEnumerateShop) Parse(bf *byteframe.ByteFrame, ctx *clientctx.Clie
|
||||
m.AckHandle = bf.ReadUint32()
|
||||
m.ShopType = bf.ReadUint8()
|
||||
m.ShopID = bf.ReadUint32()
|
||||
m.Unk2 = bf.ReadUint16()
|
||||
m.Limit = bf.ReadUint16()
|
||||
m.Unk3 = bf.ReadUint8()
|
||||
if _config.ErupeConfig.RealClientMode >= _config.G2 {
|
||||
m.Unk4 = bf.ReadUint8()
|
||||
|
||||
@@ -3,13 +3,22 @@ package mhfpacket
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"erupe-ce/network/clientctx"
|
||||
"erupe-ce/network"
|
||||
"erupe-ce/common/byteframe"
|
||||
"erupe-ce/network"
|
||||
"erupe-ce/network/clientctx"
|
||||
)
|
||||
|
||||
// MsgMhfPostSeibattle represents the MSG_MHF_POST_SEIBATTLE
|
||||
type MsgMhfPostSeibattle struct{}
|
||||
type MsgMhfPostSeibattle struct {
|
||||
AckHandle uint32
|
||||
Unk0 uint8
|
||||
Unk1 uint8
|
||||
Unk2 uint32
|
||||
Unk3 uint8
|
||||
Unk4 uint16
|
||||
Unk5 uint16
|
||||
Unk6 uint8
|
||||
}
|
||||
|
||||
// Opcode returns the ID associated with this packet type.
|
||||
func (m *MsgMhfPostSeibattle) Opcode() network.PacketID {
|
||||
@@ -18,7 +27,15 @@ func (m *MsgMhfPostSeibattle) Opcode() network.PacketID {
|
||||
|
||||
// Parse parses the packet from binary
|
||||
func (m *MsgMhfPostSeibattle) Parse(bf *byteframe.ByteFrame, ctx *clientctx.ClientContext) error {
|
||||
return errors.New("NOT IMPLEMENTED")
|
||||
m.AckHandle = bf.ReadUint32()
|
||||
m.Unk0 = bf.ReadUint8()
|
||||
m.Unk1 = bf.ReadUint8()
|
||||
m.Unk2 = bf.ReadUint32()
|
||||
m.Unk3 = bf.ReadUint8()
|
||||
m.Unk4 = bf.ReadUint16()
|
||||
m.Unk5 = bf.ReadUint16()
|
||||
m.Unk6 = bf.ReadUint8()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Build builds a binary packet from the current data.
|
||||
|
||||
@@ -992,10 +992,17 @@ func handleMsgMhfGetEarthStatus(s *Session, p mhfpacket.MHFPacket) {
|
||||
bf.WriteUint32(uint32(TimeWeekNext().Unix())) // End
|
||||
bf.WriteInt32(s.server.erupeConfig.DevModeOptions.EarthStatusOverride)
|
||||
bf.WriteInt32(s.server.erupeConfig.DevModeOptions.EarthIDOverride)
|
||||
bf.WriteInt32(s.server.erupeConfig.DevModeOptions.EarthMonsterOverride)
|
||||
bf.WriteInt32(0)
|
||||
bf.WriteInt32(0)
|
||||
bf.WriteInt32(0)
|
||||
for i, m := range s.server.erupeConfig.DevModeOptions.EarthMonsterOverride {
|
||||
if _config.ErupeConfig.RealClientMode <= _config.G9 {
|
||||
if i == 3 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if i == 4 {
|
||||
break
|
||||
}
|
||||
bf.WriteInt32(m)
|
||||
}
|
||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||
}
|
||||
|
||||
@@ -1195,7 +1202,10 @@ func handleMsgMhfGetSeibattle(s *Session, p mhfpacket.MHFPacket) {
|
||||
doAckEarthSucceed(s, pkt.AckHandle, data)
|
||||
}
|
||||
|
||||
func handleMsgMhfPostSeibattle(s *Session, p mhfpacket.MHFPacket) {}
|
||||
func handleMsgMhfPostSeibattle(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgMhfPostSeibattle)
|
||||
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||
}
|
||||
|
||||
func handleMsgMhfGetDailyMissionMaster(s *Session, p mhfpacket.MHFPacket) {}
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ func sendServerChatMessage(s *Session, message string) {
|
||||
}
|
||||
|
||||
func parseChatCommand(s *Session, command string) {
|
||||
args := strings.Split(command[1:], " ")
|
||||
args := strings.Split(command[len(s.server.erupeConfig.CommandPrefix):], " ")
|
||||
switch args[0] {
|
||||
case commands["PSN"].Prefix:
|
||||
if commands["PSN"].Enabled {
|
||||
@@ -344,6 +344,15 @@ func parseChatCommand(s *Session, command string) {
|
||||
sendServerChatMessage(s, fmt.Sprintf(s.server.dict["commandDiscordSuccess"], discordToken))
|
||||
} else {
|
||||
sendDisabledCommandMessage(s, commands["Discord"])
|
||||
case commands["Help"].Prefix:
|
||||
if commands["Help"].Enabled {
|
||||
for _, command := range commands {
|
||||
if command.Enabled {
|
||||
sendServerChatMessage(s, fmt.Sprintf("%s%s: %s", s.server.erupeConfig.CommandPrefix, command.Prefix, command.Description))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
sendDisabledCommandMessage(s, commands["Help"])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -418,7 +427,7 @@ func handleMsgSysCastBinary(s *Session, p mhfpacket.MHFPacket) {
|
||||
bf.SetLE()
|
||||
chatMessage := &binpacket.MsgBinChat{}
|
||||
chatMessage.Parse(bf)
|
||||
if strings.HasPrefix(chatMessage.Message, "!") {
|
||||
if strings.HasPrefix(chatMessage.Message, s.server.erupeConfig.CommandPrefix) {
|
||||
parseChatCommand(s, chatMessage.Message)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ func handleMsgMhfGetUdSchedule(s *Session, p mhfpacket.MHFPacket) {
|
||||
var timestamps []uint32
|
||||
if s.server.erupeConfig.DevMode && s.server.erupeConfig.DevModeOptions.DivaEvent >= 0 {
|
||||
if s.server.erupeConfig.DevModeOptions.DivaEvent == 0 {
|
||||
if s.server.erupeConfig.RealClientMode <= _config.Z1 {
|
||||
if s.server.erupeConfig.RealClientMode >= _config.Z2 {
|
||||
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 32))
|
||||
} else {
|
||||
doAckBufSucceed(s, pkt.AckHandle, make([]byte, 36))
|
||||
@@ -84,7 +84,7 @@ func handleMsgMhfGetUdSchedule(s *Session, p mhfpacket.MHFPacket) {
|
||||
timestamps = generateDivaTimestamps(s, start, false)
|
||||
}
|
||||
|
||||
if s.server.erupeConfig.RealClientMode <= _config.Z1 {
|
||||
if s.server.erupeConfig.RealClientMode >= _config.Z2 {
|
||||
bf.WriteUint32(id)
|
||||
}
|
||||
for i := range timestamps {
|
||||
|
||||
@@ -262,66 +262,55 @@ func handleMsgMhfLoadDecoMyset(s *Session, p mhfpacket.MHFPacket) {
|
||||
|
||||
func handleMsgMhfSaveDecoMyset(s *Session, p mhfpacket.MHFPacket) {
|
||||
pkt := p.(*mhfpacket.MsgMhfSaveDecoMyset)
|
||||
// TODO: Backwards compatibility for DecoMyset
|
||||
if s.server.erupeConfig.RealClientMode < _config.ZZ {
|
||||
var temp []byte
|
||||
err := s.server.db.QueryRow("SELECT decomyset FROM characters WHERE id = $1", s.charID).Scan(&temp)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to load decomyset", zap.Error(err))
|
||||
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||
return
|
||||
}
|
||||
// https://gist.github.com/Andoryuuta/9c524da7285e4b5ca7e52e0fc1ca1daf
|
||||
var loadData []byte
|
||||
bf := byteframe.NewByteFrameFromBytes(pkt.RawDataPayload[1:]) // skip first unk byte
|
||||
err := s.server.db.QueryRow("SELECT decomyset FROM characters WHERE id = $1", s.charID).Scan(&loadData)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to load decomyset", zap.Error(err))
|
||||
|
||||
// Version handling
|
||||
bf := byteframe.NewByteFrame()
|
||||
var size uint
|
||||
if s.server.erupeConfig.RealClientMode >= _config.G10 {
|
||||
size = 76
|
||||
bf.WriteUint8(1)
|
||||
} else {
|
||||
numSets := bf.ReadUint8() // sets being written
|
||||
// empty save
|
||||
if len(loadData) == 0 {
|
||||
loadData = []byte{0x01, 0x00}
|
||||
size = 68
|
||||
bf.WriteUint8(0)
|
||||
}
|
||||
|
||||
savedSets := loadData[1] // existing saved sets
|
||||
// no sets, new slice with just first 2 bytes for appends later
|
||||
if savedSets == 0 {
|
||||
loadData = []byte{0x01, 0x00}
|
||||
// Handle nil data
|
||||
if len(temp) == 0 {
|
||||
temp = append(bf.Data(), uint8(0))
|
||||
}
|
||||
for i := 0; i < int(numSets); i++ {
|
||||
writeSet := bf.ReadUint16()
|
||||
dataChunk := bf.ReadBytes(76)
|
||||
setBytes := append([]byte{uint8(writeSet >> 8), uint8(writeSet & 0xff)}, dataChunk...)
|
||||
for x := 0; true; x++ {
|
||||
if x == int(savedSets) {
|
||||
// appending set
|
||||
if loadData[len(loadData)-1] == 0x10 {
|
||||
// sanity check for if there was a messy manual import
|
||||
loadData = append(loadData[:len(loadData)-2], setBytes...)
|
||||
} else {
|
||||
loadData = append(loadData, setBytes...)
|
||||
|
||||
// Build a map of set data
|
||||
sets := make(map[uint16][]byte)
|
||||
oldSets := byteframe.NewByteFrameFromBytes(temp[2:])
|
||||
for i := uint8(0); i < temp[1]; i++ {
|
||||
index := oldSets.ReadUint16()
|
||||
sets[index] = oldSets.ReadBytes(size)
|
||||
}
|
||||
savedSets++
|
||||
break
|
||||
|
||||
// Overwrite existing sets
|
||||
newSets := byteframe.NewByteFrameFromBytes(pkt.RawDataPayload[2:])
|
||||
for i := uint8(0); i < pkt.RawDataPayload[1]; i++ {
|
||||
index := newSets.ReadUint16()
|
||||
sets[index] = newSets.ReadBytes(size)
|
||||
}
|
||||
currentSet := loadData[3+(x*78)]
|
||||
if int(currentSet) == int(writeSet) {
|
||||
// replacing a set
|
||||
loadData = append(loadData[:2+(x*78)], append(setBytes, loadData[2+((x+1)*78):]...)...)
|
||||
break
|
||||
} else if int(currentSet) > int(writeSet) {
|
||||
// inserting before current set
|
||||
loadData = append(loadData[:2+((x)*78)], append(setBytes, loadData[2+((x)*78):]...)...)
|
||||
savedSets++
|
||||
break
|
||||
|
||||
// Serialise the set data
|
||||
bf.WriteUint8(uint8(len(sets)))
|
||||
for u, b := range sets {
|
||||
bf.WriteUint16(u)
|
||||
bf.WriteBytes(b)
|
||||
}
|
||||
}
|
||||
loadData[1] = savedSets // update set count
|
||||
}
|
||||
dumpSaveData(s, loadData, "decomyset")
|
||||
_, err := s.server.db.Exec("UPDATE characters SET decomyset=$1 WHERE id=$2", loadData, s.charID)
|
||||
if err != nil {
|
||||
s.logger.Error("Failed to save decomyset", zap.Error(err))
|
||||
}
|
||||
}
|
||||
doAckSimpleSucceed(s, pkt.AckHandle, []byte{0x00, 0x00, 0x00, 0x00})
|
||||
|
||||
dumpSaveData(s, bf.Data(), "decomyset")
|
||||
s.server.db.Exec("UPDATE characters SET decomyset=$1 WHERE id=$2", bf.Data(), s.charID)
|
||||
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||
}
|
||||
|
||||
type Title struct {
|
||||
|
||||
@@ -10,13 +10,13 @@ import (
|
||||
|
||||
type ShopItem struct {
|
||||
ID uint32 `db:"id"`
|
||||
ItemID uint16 `db:"item_id"`
|
||||
ItemID uint32 `db:"item_id"`
|
||||
Cost uint32 `db:"cost"`
|
||||
Quantity uint16 `db:"quantity"`
|
||||
MinHR uint16 `db:"min_hr"`
|
||||
MinSR uint16 `db:"min_sr"`
|
||||
MinGR uint16 `db:"min_gr"`
|
||||
StoreLevel uint16 `db:"store_level"`
|
||||
StoreLevel uint8 `db:"store_level"`
|
||||
MaxQuantity uint16 `db:"max_quantity"`
|
||||
UsedQuantity uint16 `db:"used_quantity"`
|
||||
RoadFloors uint16 `db:"road_floors"`
|
||||
@@ -61,20 +61,31 @@ func writeShopItems(bf *byteframe.ByteFrame, items []ShopItem) {
|
||||
bf.WriteUint16(uint16(len(items)))
|
||||
bf.WriteUint16(uint16(len(items)))
|
||||
for _, item := range items {
|
||||
if _config.ErupeConfig.RealClientMode >= _config.Z2 {
|
||||
bf.WriteUint32(item.ID)
|
||||
bf.WriteUint16(0)
|
||||
bf.WriteUint16(item.ItemID)
|
||||
}
|
||||
bf.WriteUint32(item.ItemID)
|
||||
bf.WriteUint32(item.Cost)
|
||||
bf.WriteUint16(item.Quantity)
|
||||
bf.WriteUint16(item.MinHR)
|
||||
bf.WriteUint16(item.MinSR)
|
||||
if _config.ErupeConfig.RealClientMode >= _config.Z2 {
|
||||
bf.WriteUint16(item.MinGR)
|
||||
bf.WriteUint16(item.StoreLevel)
|
||||
}
|
||||
bf.WriteUint8(0) // Unk
|
||||
bf.WriteUint8(item.StoreLevel)
|
||||
if _config.ErupeConfig.RealClientMode >= _config.Z2 {
|
||||
bf.WriteUint16(item.MaxQuantity)
|
||||
bf.WriteUint16(item.UsedQuantity)
|
||||
}
|
||||
if _config.ErupeConfig.RealClientMode == _config.Z1 {
|
||||
bf.WriteUint8(uint8(item.RoadFloors))
|
||||
bf.WriteUint8(uint8(item.RoadFatalis))
|
||||
} else if _config.ErupeConfig.RealClientMode >= _config.Z2 {
|
||||
bf.WriteUint16(item.RoadFloors)
|
||||
bf.WriteUint16(item.RoadFatalis)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getShopItems(s *Session, shopType uint8, shopID uint32) []ShopItem {
|
||||
@@ -241,6 +252,9 @@ func handleMsgMhfEnumerateShop(s *Session, p mhfpacket.MHFPacket) {
|
||||
case 10: // Item shop, 0-8
|
||||
bf := byteframe.NewByteFrame()
|
||||
items := getShopItems(s, pkt.ShopType, pkt.ShopID)
|
||||
if len(items) > int(pkt.Limit) {
|
||||
items = items[:pkt.Limit]
|
||||
}
|
||||
writeShopItems(bf, items)
|
||||
doAckBufSucceed(s, pkt.AckHandle, bf.Data())
|
||||
}
|
||||
|
||||
@@ -171,8 +171,8 @@ func handleMsgSysBackStage(s *Session, p mhfpacket.MHFPacket) {
|
||||
|
||||
// Transfer back to the saved stage ID before the previous move or enter.
|
||||
backStage, err := s.stageMoveStack.Pop()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
if backStage == "" || err != nil {
|
||||
backStage = "sl1Ns200p0a0u0"
|
||||
}
|
||||
|
||||
if _, exists := s.stage.reservedClientSlots[s.charID]; exists {
|
||||
|
||||
@@ -126,8 +126,9 @@ func handleMsgMhfPostTowerInfo(s *Session, p mhfpacket.MHFPacket) {
|
||||
skills := "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0"
|
||||
s.server.db.QueryRow(`SELECT skills FROM tower WHERE char_id=$1`, s.charID).Scan(&skills)
|
||||
s.server.db.Exec(`UPDATE tower SET skills=$1, tsp=tsp-$2 WHERE char_id=$3`, stringsupport.CSVSetIndex(skills, int(pkt.Skill), stringsupport.CSVGetIndex(skills, int(pkt.Skill))+1), pkt.Cost, s.charID)
|
||||
case 7:
|
||||
s.server.db.Exec(`UPDATE tower SET tr=$1, trp=trp+$2, block1=block1+$3 WHERE char_id=$4`, pkt.TR, pkt.TRP, pkt.Block1, s.charID)
|
||||
case 1, 7:
|
||||
// This might give too much TSP? No idea what the rate is supposed to be
|
||||
s.server.db.Exec(`UPDATE tower SET tr=$1, trp=COALESCE(trp, 0)+$2, tsp=COALESCE(tsp, 0)+$3, block1=COALESCE(block1, 0)+$4 WHERE char_id=$5`, pkt.TR, pkt.TRP, pkt.Cost, pkt.Block1, s.charID)
|
||||
}
|
||||
doAckSimpleSucceed(s, pkt.AckHandle, make([]byte, 4))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user