game_sync/worldsrv/shopmgr.go

1253 lines
40 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"encoding/json"
"errors"
"fmt"
"math/rand"
"slices"
"strconv"
"time"
"mongo.games.com/goserver/core/basic"
"mongo.games.com/goserver/core/logger"
"mongo.games.com/goserver/core/module"
"mongo.games.com/goserver/core/task"
"mongo.games.com/goserver/core/timer"
"mongo.games.com/game/common"
"mongo.games.com/game/model"
"mongo.games.com/game/proto"
hall_proto "mongo.games.com/game/protocol/gamehall"
"mongo.games.com/game/protocol/shop"
webapi_proto "mongo.games.com/game/protocol/webapi"
"mongo.games.com/game/srvdata"
"mongo.games.com/game/webapi"
)
const (
BlindBox int32 = iota + 101 //盲盒
FirstPay //首冲
ContinuousPay //连充
Exchange // 兑换商品
ShopTypeStart int32 = 900000 //商品
)
// 消费类型
const (
ShopConsumeCoin = iota + 1 // 金币
ShopConsumeDiamond // 钻石
ShopConsumeMoney // 现金
ExchangeConsumeCash //兑换消耗现金
ShopConsumePhoneScore = 11 //手机积分
)
// page类型
const (
ShopPageCoin = iota + 1 //金币页面
ShopPageDiamond //钻石页面
ShopPageItem //道具页面
ShopPageVip //VIP页面
ShopPagePrivilege //VIP特权礼包
ShopPagePhoneScore = 61 //手机积分商城
ShopPagePhoneScore_google = 62
ShopPageGift = 7 //礼包页面
)
// 商品类型
const (
ShopTypeCoin = iota + 1 // 金币
ShopTypeDiamond // 钻石
ShopTypeItem // 道具
)
// 兑换商品状态
const (
Shop_Status_Keep = iota //0为待审核
Shop_Status_Pass // 1为审核通过
Shop_Status_Send // 2为已发货
Shop_Status_NotSend // 3为审核不通过
Shop_Status_Revoke // 4为撤单
)
const (
VCard int32 = 30001
JCard int32 = 30002 //金券
)
/*
1.兑换成功:兑换成功,请等待审核
2.今日兑换已达上限,请明日再来
3.该物品已被兑换完
*/
const (
Err_ExShopNEnough string = "ExShopNotEnough" // 该物品已被兑换完
Err_ExShopLimit string = "ExShopIsLimit" // 今日兑换已达上限,请明日再来
Err_ExShopData string = "ExShopDataErr" // 收件人地址有误
)
var ShopMgrSington = &ShopMgr{
ConfigMgr: model.NewConfigMgr(),
}
type ShopMgr struct {
*model.ConfigMgr
}
type ExchangeShopInfo struct {
Id int32 //商品ID
Picture string // 图片
Type int32 // 类型 1话费2实物
Name string // 名称
Rule string //规则说明
ExType []*shop.ExchangeType // 获得道具
OrderId string //兑换的订单Id
ExchangeTypeId int32 //兑换类型的id
ExchangeNum int32 //兑换数量
}
func (this *ShopMgr) ModuleName() string {
return "ShopMgr"
}
func (this *ShopMgr) Init() {
}
// UpExShop 更新兑换商品信息
func (this *ShopMgr) UpExShop(cfgs *webapi_proto.ExchangeShopList) {
this.GetConfig(cfgs.Platform).ExchangeShopList = cfgs
}
func (this *ShopMgr) GetShopInfoProto(si *model.ShopInfo, p *Player, vipShopId int32) (shopInfo *shop.ShopInfo) {
if si == nil {
return nil
}
var itemInfo []*shop.ItemInfo
for _, i2 := range si.AddItemInfo {
itemInfo = append(itemInfo, &shop.ItemInfo{
ItemId: i2.ItemId,
ItemNum: i2.ItemNum,
})
}
added := int32(rand.Intn(int(si.AddArea[1])-int(si.AddArea[0])+1) + int(si.AddArea[0]))
consumptionAmount := int32(rand.Intn(int(si.CostArea[1])-int(si.CostArea[0])+1) + int(si.CostArea[0]))
amount := int64(si.Amount)
isBuy := false
if si.Page == ShopPageVip {
shopData := p.GetVipShopData(si.Id, vipShopId)
if shopData == nil {
logger.Logger.Errorf("Vip商城 没有当前物品 snid = %v,shopId = %v", p.SnId, si.Id)
return nil
}
added = shopData.AddArea
consumptionAmount = shopData.CostArea
amount = si.Amount * int64(consumptionAmount)
isBuy = shopData.IsBuy
}
shopInfo = &shop.ShopInfo{
Id: si.Id,
AdLookedNum: si.AdLookedNum,
AdReceiveNum: si.AdReceiveNum,
LastLookTime: si.LastLookTime,
RoleAdded: si.RoleAdded,
PetAdded: si.PetAdded,
ItemId: si.ItemId,
Order: si.Order,
Page: si.Page,
Type: si.Type,
Location: si.Location,
Picture: si.Picture,
Name: si.Name,
Ad: si.Ad,
AdTime: si.AdTime,
RepeatTimes: si.RepeatTimes,
CoolingTime: si.CoolingTime,
Label: si.Label,
Added: added,
Amount: amount,
Consume: si.ConstType,
ConsumptionAmount: consumptionAmount,
AddItemInfo: itemInfo,
VipLevel: si.VipLevel,
EndTime: si.EndTime,
IsBuy: isBuy,
RoleAddedId: si.RoleAddedId,
AmountFinal: this.GetAmountFinal(p, si.Id, vipShopId),
}
return
}
// GetShopInfo 获取玩家某个商品信息(例如玩家看广告领取)
func (this *ShopMgr) GetShopInfo(shopId int32, p *Player) *model.ShopInfo {
if shopId == 0 {
return nil
}
var shopInfo = this.ConfigMgr.GetShopInfo(p.Platform, shopId)
if shopInfo != nil {
// AdLookedNum 已看次数
// AdReceiveNum 已领次数
// remainingTime 商品设置的冷却时长
var AdLookedNum, AdReceiveNum, remainingTime int32
var lastLookTime int64
if shopInfo.Ad > 0 {
shopTotal := p.ShopTotal[shopInfo.Id]
if shopTotal != nil {
AdLookedNum = shopTotal.AdLookedNum
AdReceiveNum = shopTotal.AdReceiveNum
}
lastLookTime = p.ShopLastLookTime[shopInfo.Id]
if AdLookedNum < int32(len(shopInfo.CoolingTime)) {
remainingTime = shopInfo.CoolingTime[AdLookedNum]
}
if lastLookTime >= 0 {
dif := int32(time.Now().Unix() - lastLookTime)
if dif >= remainingTime {
remainingTime = 0
} else {
remainingTime = remainingTime - dif
}
}
}
award, roleId := PetMgrSington.GetShopAward(shopInfo, p)
firstBuy := false
if shopInfo.FirstSwitch {
firstBuy = !slices.Contains(p.ShopID, int(shopInfo.Id))
}
return &model.ShopInfo{
Id: shopInfo.Id,
Ad: shopInfo.Ad,
AdTime: shopInfo.AdTime,
RepeatTimes: shopInfo.RepeatTimes,
CoolingTime: shopInfo.CoolingTime,
AdLookedNum: AdLookedNum,
AdReceiveNum: AdReceiveNum,
RemainingTime: remainingTime,
LastLookTime: int32(lastLookTime),
RoleAdded: award,
ItemId: shopInfo.ItemId,
Order: shopInfo.Order,
Page: shopInfo.Page,
Type: shopInfo.Type,
Location: shopInfo.Location,
Picture: shopInfo.Picture,
Name: shopInfo.Name,
Label: shopInfo.Label,
AddArea: shopInfo.AddArea,
Amount: shopInfo.Amount,
ConstType: shopInfo.ConstType,
CostArea: shopInfo.CostArea,
RoleAddedId: roleId,
AddItemInfo: shopInfo.AddItemInfo,
VipLevel: shopInfo.VipLevel,
EndTime: shopInfo.EndTime,
Ratio: shopInfo.Ratio,
FirstSwitch: firstBuy,
AmountFinal: this.GetAmountFinal(p, shopId, 0),
}
}
return nil
}
// GetShopInfos 获取玩家商品信息给客户端展示
func (this *ShopMgr) GetShopInfos(p *Player, nowLocation int) []*shop.ShopInfo {
if p.ShopTotal == nil {
p.ShopTotal = make(map[int32]*model.ShopTotal)
}
if p.ShopLastLookTime == nil {
p.ShopLastLookTime = make(map[int32]int64)
}
var newShops = make([]*shop.ShopInfo, 0)
if p.VipShopData == nil || len(p.VipShopData) == 0 {
this.UpdateVipShopData(p)
}
shopInfos := this.GetConfig(p.Platform).ShopInfos
for _, shopInfo := range shopInfos {
if nowLocation == -1 || (nowLocation < len(shopInfo.Location) && shopInfo.Location[nowLocation] == 1) {
if shopInfo.Page == ShopPageVip {
continue
}
var AdLookedNum, AdReceiveNum, remainingTime int32
var lastLookTime int64
if shopInfo.Ad > 0 {
shopTotal := p.ShopTotal[shopInfo.Id]
if shopTotal != nil {
AdLookedNum = shopTotal.AdLookedNum
AdReceiveNum = shopTotal.AdReceiveNum
}
lastLookTime = p.ShopLastLookTime[shopInfo.Id]
if AdLookedNum < int32(len(shopInfo.CoolingTime)) {
remainingTime = shopInfo.CoolingTime[AdLookedNum]
}
dif := int32(time.Now().Unix() - lastLookTime)
if dif >= remainingTime {
remainingTime = 0
} else {
remainingTime = remainingTime - dif
}
}
added := int32(rand.Intn(int(shopInfo.AddArea[1])-int(shopInfo.AddArea[0])+1) + int(shopInfo.AddArea[0]))
consumptionAmount := int32(rand.Intn(int(shopInfo.CostArea[1])-int(shopInfo.CostArea[0])+1) + int(shopInfo.CostArea[0]))
var itemInfo []*shop.ItemInfo
for _, i2 := range shopInfo.AddItemInfo {
itemInfo = append(itemInfo, &shop.ItemInfo{
ItemId: i2.ItemId,
ItemNum: i2.ItemNum,
})
}
award, roleId := PetMgrSington.GetShopAward(shopInfo, p)
firstBuy := false
if shopInfo.FirstSwitch {
firstBuy = !slices.Contains(p.ShopID, int(shopInfo.Id))
}
newShops = append(newShops, &shop.ShopInfo{
Id: shopInfo.Id,
AdLookedNum: AdLookedNum,
AdReceiveNum: AdReceiveNum,
LastLookTime: int32(lastLookTime),
RoleAdded: award,
RoleAddedId: roleId,
ItemId: shopInfo.ItemId,
Order: shopInfo.Order,
Page: shopInfo.Page,
Type: shopInfo.Type,
Location: shopInfo.Location,
Picture: shopInfo.Picture,
Name: shopInfo.Name,
Ad: shopInfo.Ad,
AdTime: shopInfo.AdTime,
RepeatTimes: shopInfo.RepeatTimes,
CoolingTime: shopInfo.CoolingTime,
Label: shopInfo.Label,
Added: added,
Amount: int64(shopInfo.Amount),
Consume: shopInfo.ConstType,
ConsumptionAmount: consumptionAmount,
AddItemInfo: itemInfo,
VipLevel: shopInfo.VipLevel,
EndTime: shopInfo.EndTime,
IsBuy: false,
FirstBuy: firstBuy,
AmountFinal: this.GetAmountFinal(p, shopInfo.Id, 0),
})
}
}
//VIP商城数据
if shopInfos == nil {
return newShops
}
for i, data := range p.VipShopData {
shopInfo := shopInfos[data.Id]
if shopInfo == nil {
continue
}
var AdLookedNum, AdReceiveNum, remainingTime int32
var lastLookTime int64
if shopInfo.Ad > 0 {
shopTotal := p.ShopTotal[shopInfo.Id]
if shopTotal != nil {
AdLookedNum = shopTotal.AdLookedNum
AdReceiveNum = shopTotal.AdReceiveNum
}
lastLookTime = p.ShopLastLookTime[shopInfo.Id]
if AdLookedNum < int32(len(shopInfo.CoolingTime)) {
remainingTime = shopInfo.CoolingTime[AdLookedNum]
}
dif := int32(time.Now().Unix() - lastLookTime)
if dif >= remainingTime {
remainingTime = 0
} else {
remainingTime = remainingTime - dif
}
}
var itemInfo []*shop.ItemInfo
for _, i2 := range shopInfo.AddItemInfo {
itemInfo = append(itemInfo, &shop.ItemInfo{
ItemId: i2.ItemId,
ItemNum: i2.ItemNum,
})
}
award, roleId := PetMgrSington.GetShopAward(shopInfo, p)
firstBuy := false
if shopInfo.FirstSwitch {
firstBuy = !slices.Contains(p.ShopID, int(shopInfo.Id))
}
newShops = append(newShops, &shop.ShopInfo{
Id: shopInfo.Id,
AdLookedNum: AdLookedNum,
AdReceiveNum: AdReceiveNum,
LastLookTime: int32(lastLookTime),
RoleAdded: award,
RoleAddedId: roleId,
ItemId: shopInfo.ItemId,
Order: shopInfo.Order,
Page: shopInfo.Page,
Type: shopInfo.Type,
Location: shopInfo.Location,
Picture: shopInfo.Picture,
Name: shopInfo.Name,
Ad: shopInfo.Ad,
AdTime: shopInfo.AdTime,
RepeatTimes: shopInfo.RepeatTimes,
CoolingTime: shopInfo.CoolingTime,
Label: shopInfo.Label,
Added: data.AddArea,
Amount: shopInfo.Amount * int64(data.CostArea),
Consume: shopInfo.ConstType,
ConsumptionAmount: data.CostArea,
AddItemInfo: itemInfo,
VipLevel: shopInfo.VipLevel,
EndTime: shopInfo.EndTime,
IsBuy: data.IsBuy,
VipShopId: i,
FirstBuy: firstBuy,
AmountFinal: this.GetAmountFinal(p, shopInfo.Id, i),
})
}
return newShops
}
// 更新玩家vipShop数据
func (this *ShopMgr) UpdateVipShopData(p *Player) {
if p.VIP == 0 {
return
}
if p.VipShopData == nil {
p.VipShopData = make(map[int32]*model.ShopData)
} else {
//购买过的不刷新
keysToDelete := []int32{}
for id, data := range p.VipShopData {
if !data.IsBuy {
keysToDelete = append(keysToDelete, id)
}
}
// 删除要删除的键
for _, id := range keysToDelete {
delete(p.VipShopData, id)
}
}
//获取vip商品刷新个数
vipConfig := VipMgrSington.GetVIPLevelCfg(p.Platform, p.VIP)
if vipConfig == nil {
return
}
count := int(vipConfig.Privilege3[1])
count -= len(p.VipShopData)
logger.Logger.Trace("VIP商城刷新 刷新商品个数为:", count)
if count <= 0 {
logger.Logger.Error("VIP商城 暂时无法刷新Snid = ", p.SnId)
return
}
//获取对应VIP等级物品列表
vipShopInfoMap := make(map[int32]*model.ShopInfo)
var sumRatio = 0 //权重
for _, shopInfo := range this.GetConfig(p.Platform).ShopInfos {
if shopInfo.Page == ShopPageVip && shopInfo.VipLevel == p.VIP {
vipShopInfoMap[shopInfo.Id] = shopInfo
sumRatio += int(shopInfo.Ratio)
}
}
if len(vipShopInfoMap) == 0 {
return
}
for i := 1; i <= int(vipConfig.Privilege3[1]); i++ {
if p.VipShopData[int32(i)] != nil {
continue
}
//随机vip物品
random := rand.Intn(sumRatio + 1)
logger.Logger.Tracef("Vip商城 随机到的值:%v,总权重:%v", random, sumRatio)
ratio := 0
for id, shopInfo := range vipShopInfoMap {
ratio += int(shopInfo.Ratio)
if random <= ratio {
//判断商品位置
p.VipShopData[int32(i)] = &model.ShopData{
Id: id,
AddArea: int32(rand.Intn(int(shopInfo.AddArea[1]-shopInfo.AddArea[0]+1)) + int(shopInfo.AddArea[0])),
CostArea: int32(rand.Intn(int(shopInfo.CostArea[1]-shopInfo.CostArea[0]+1)) + int(shopInfo.CostArea[0])),
IsBuy: false,
}
logger.Logger.Tracef("Vip商城 随机到的物品id = %v,shopInfo = %v,random = %v,num = %v,商品位置:%v", id, shopInfo, random, ratio, i)
break
}
}
}
}
// LookAdReceive 看广告领取商品,校验领取次数
func (this *ShopMgr) LookAdReceive(shopId int32, p *Player, position int32) shop.OpResultCode {
var shopInfo = this.ConfigMgr.GetShopInfo(p.Platform, shopId)
if shopInfo == nil {
logger.Logger.Errorf("this shop == nil shopId[%v] ", shopId)
return shop.OpResultCode_OPRC_Error
}
//需要观看广告的
if shopInfo.Ad > 0 {
if _, ok1 := p.ShopTotal[shopId]; !ok1 {
p.ShopTotal[shopId] = &model.ShopTotal{}
}
shopTotal := p.ShopTotal[shopId]
if shopTotal.AdReceiveNum < shopInfo.RepeatTimes {
shopTotal.AdReceiveNum++
return this.ReceiveVCPayShop(shopInfo, p, 0, position)
}
}
return shop.OpResultCode_OPRC_Error
}
// ReceiveVCPayShop 领取VC看广告商品
func (this *ShopMgr) ReceiveVCPayShop(shopInfo *model.ShopInfo, p *Player, vipShopId, position int32) shop.OpResultCode {
if shopInfo == nil {
logger.Logger.Errorf("this shop == nil")
return shop.OpResultCode_OPRC_Error
}
//产生订单
this.PayAway(shopInfo, p, vipShopId, position)
return shop.OpResultCode_OPRC_Sucess
}
// PayAway 商城 领取商品
func (this *ShopMgr) PayAway(shopInfo *model.ShopInfo, p *Player, vipShopId, position int32) {
shopName := shopInfo.Name + "|" + strconv.Itoa(int(shopInfo.Id))
costNum := rand.Int31n(shopInfo.CostArea[1]-shopInfo.CostArea[0]+1) + shopInfo.CostArea[0]
if shopInfo.Page == ShopPageVip {
shopData := p.GetVipShopData(shopInfo.Id, vipShopId)
if shopData != nil {
costNum = shopData.CostArea
}
}
if shopInfo.Ad <= 0 { //消耗
logger.Logger.Tracef("AddOrder Consume[%v],shopName[%v]", shopInfo.ConstType, shopName, costNum)
switch shopInfo.ConstType {
case ShopConsumeCoin:
p.AddCoin(int64(-costNum), 0, common.GainWay_Shop_Buy, "sys", shopName)
case ShopConsumeDiamond:
p.AddDiamond(int64(-costNum), 0, common.GainWay_Shop_Buy, "sys", shopName)
case ShopConsumePhoneScore:
p.AddPhoneScore(int64(-costNum), 0, common.GainWay_Shop_Buy, "sys", shopName)
case ShopConsumeMoney:
//task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
// return webapi.API_CreateOrder(common.GetAppId(),"", p.SnId, shopInfo.Id, p.Platform, p.PackageID, p.DeviceOS,
// p.DeviceId, shopInfo.Name, shopInfo.Amount, shopInfo.ConsumptionAmount)
//}), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) {
// if data != nil {
// //失败
// }
//}), "API_CreateOrder").Start()
//p.AddMoneyPayTotal(int64(shopInfo.ConsumptionAmount))
return
}
} else {
TaskSubjectSingleton.Touch(common.TaskTypeAdv, &TaskData{
SnId: p.SnId,
Num: 1,
Position: position,
})
}
amount := [3]int32{} // 获得
if shopInfo.Page == ShopPageVip {
if p.VipShopData[vipShopId] == nil {
return
}
p.VipShopData[vipShopId].IsBuy = true
logger.Logger.Trace("玩家购买VIP商城物品成功,商品Id = ", shopInfo.Id)
}
addTotal := this.GetAmountFinal(p, shopInfo.Id, vipShopId)
logger.Logger.Trace("addTotal ", addTotal, shopInfo.Amount)
switch shopInfo.Type {
case ShopTypeCoin:
amount[shopInfo.Type-1] = int32(addTotal)
p.AddCoin(addTotal, 0, common.GainWay_Shop_Buy, "system", shopName)
if shopInfo.Ad > 0 { //观看广告
if !p.IsRob {
LogChannelSingleton.WriteMQData(model.GenerateSystemFreeGive(p.SnId, p.Name, p.Platform, p.Channel, model.SystemFreeGive_GiveType_ShopAd, model.SystemFreeGive_CoinType_Coin, addTotal))
}
}
// 记录钻石兑换金币的金币数量,个人水池调控使用
if shopInfo.ConstType == ShopConsumeDiamond && shopInfo.Ad <= 0 && costNum > 0 {
p.AddDiamondToCoin(addTotal)
}
if shopInfo.Ad <= 0 && costNum != 0 {
TaskSubjectSingleton.Touch(common.TaskTypeBuyCoin, &TaskData{SnId: p.SnId, Num: 1, Position: position})
}
case ShopTypeDiamond:
//增加钻石
amount[shopInfo.Type-1] = int32(addTotal)
p.AddDiamond(addTotal, 0, common.GainWay_Shop_Buy, "system", shopName)
if shopInfo.Ad > 0 { //观看广告
if !p.IsRob {
LogChannelSingleton.WriteMQData(model.GenerateSystemFreeGive(p.SnId, p.Name, p.Platform, p.Channel, model.SystemFreeGive_GiveType_ShopAd, model.SystemFreeGive_CoinType_Diamond, addTotal))
}
}
case ShopTypeItem:
//增加道具
item := &Item{ItemId: shopInfo.ItemId, ItemNum: addTotal, ObtainTime: time.Now().Unix(), ExpireTime: 0}
BagMgrSingleton.AddJybBagInfo(p, []*Item{item}, 0, common.GainWay_Shop_Buy, "system", shopName)
data := srvdata.PBDB_GameItemMgr.GetData(item.ItemId)
if data != nil {
BagMgrSingleton.RecordItemLog(p.Platform, p.SnId, ItemObtain, shopInfo.ItemId, data.Name, addTotal, "商城购买")
}
PetMgrSington.CheckShowRed(p)
}
this.ShopAddItem(shopInfo, p)
this.CreateVCOrder(shopInfo, p.SnId, costNum, p.Platform, amount)
//抽奖兑换统计
if shopInfo.ConstType == ShopConsumePhoneScore {
items := make([]*Item, 0)
itemId := int32(0)
if shopInfo.Type == ShopTypeCoin {
itemId = common.ItemIDCoin
} else if shopInfo.Type == ShopTypeDiamond {
itemId = common.ItemIDDiamond
} else {
//道具
itemId = shopInfo.ItemId
}
items = append(items, &Item{
ItemId: itemId, // 物品id
ItemNum: addTotal, // 数量
})
jsonData, err := json.Marshal(items)
if err == nil {
LogChannelSingleton.WriteMQData(model.GeneratePhoneLottery(p.SnId, p.Platform, string(jsonData), 2, 0, 0, int(costNum)))
}
}
}
// GetAmountFinal 计算商品实际获得数量
func (this *ShopMgr) GetAmountFinal(p *Player, shopId, vipShopId int32) int64 {
if p == nil {
return 0
}
var shopInfo = this.ConfigMgr.GetShopInfo(p.Platform, shopId)
if shopInfo == nil {
return 0
}
//默认加成
var addTotal = shopInfo.Amount
added := rand.Int31n(shopInfo.AddArea[1]-shopInfo.AddArea[0]+1) + shopInfo.AddArea[0]
if shopInfo.Page == ShopPageVip {
if p.VipShopData[vipShopId] == nil {
return 0
}
addTotal = shopInfo.Amount * int64(p.VipShopData[vipShopId].CostArea)
added = p.VipShopData[vipShopId].AddArea
}
var addNormal int64
if added > 0 {
addNormal = int64(float64(addTotal) * float64(added) / 100.0)
}
vipAdded := int64(0)
if shopInfo.Page == ShopPageDiamond {
//vip加成
vipAdded = int64(VipMgrSington.GetVipDiamondExtra(p.Platform, p.VIP))
logger.Logger.Tracef("商城钻石购买vip加成 vipAdded = %v", vipAdded)
vipAdded = int64(float64(addTotal) * float64(vipAdded) / 100.0)
}
switch shopInfo.Type {
case ShopTypeCoin:
var addCoin int64
award, _ := PetMgrSington.GetShopAward(shopInfo, p)
if award > 0 {
addCoin = int64(float64(addTotal) * float64(award) / 100.0)
}
//增加金币
addTotal += addNormal + addCoin
case ShopTypeDiamond:
addTotal += addNormal + vipAdded
// 首充翻倍
if shopInfo.FirstSwitch {
if !slices.Contains(p.ShopID, int(shopInfo.Id)) {
addTotal *= 2
}
}
}
return addTotal
}
// 商城购买 额外增加道具
func (this *ShopMgr) ShopAddItem(shopInfo *model.ShopInfo, p *Player) {
for _, info := range shopInfo.AddItemInfo {
item := &Item{ItemId: info.ItemId, ItemNum: info.ItemNum, ObtainTime: time.Now().Unix()}
BagMgrSingleton.AddJybBagInfo(p, []*Item{item}, 0, common.GainWay_Shop_Buy, "system", shopInfo.Name)
data := srvdata.PBDB_GameItemMgr.GetData(item.ItemId)
if data != nil {
BagMgrSingleton.RecordItemLog(p.Platform, p.SnId, ItemObtain, info.ItemId, data.Name, info.ItemNum, "商城购买")
}
PetMgrSington.CheckShowRed(p)
}
}
// CreateVCOrder 产生VC订单记录看广告获取商品的订单
func (this *ShopMgr) CreateVCOrder(shopInfo *model.ShopInfo, snid, costNum int32, platform string, amount [3]int32) {
task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
//获得类型
if shopInfo.Type < ShopTypeCoin && shopInfo.Type > ShopTypeItem {
return errors.New("error type")
}
//道具
var item []model.ItemInfo
if shopInfo.Type == ShopTypeItem {
item = append(item, model.ItemInfo{ItemId: shopInfo.ItemId, ItemNum: shopInfo.Amount})
if shopInfo.AddItemInfo != nil {
for _, info := range shopInfo.AddItemInfo {
item = append(item, model.ItemInfo{ItemId: info.ItemId, ItemNum: int64(info.ItemNum)})
}
}
}
dbShop := model.NewDbShop(platform, shopInfo.Page, amount[:], "sys", 0, shopInfo.ConstType, costNum,
common.GainWay_ShopBuy, item, shopInfo.Id, shopInfo.Name, snid, 1, "shop_goods", []int32{})
return model.InsertDbShopLog(dbShop)
}), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) {
if data != nil {
logger.Logger.Errorf("err:", data.(error))
}
}), "CreateVCOrder").Start()
}
func (this *ShopMgr) GetExchangeData(platform string, id int32) *ExchangeShopInfo {
if exShops := this.GetConfig(platform).ExchangeShopList; exShops != nil {
for _, data := range exShops.List {
if data.Id == id {
var exType []*shop.ExchangeType
for _, info := range data.ExType {
exType = append(exType, &shop.ExchangeType{
Price: info.Price,
JPrice: info.JPrice,
Cash: info.Cash,
Id: info.Id,
})
}
return &ExchangeShopInfo{
Id: data.Id,
Picture: data.Picture,
Type: data.Type,
Name: data.Name,
Rule: data.Content,
ExType: exType,
}
}
}
}
return nil
}
// 兑换操作
// Exchange 生成兑换订单v卡 id 兑换方式 0~2
func (this *ShopMgr) Exchange(p *Player, goodsId int32, username, mobile, comment string, id int32, num int32) (ret bool) {
ret = true
cdata := this.GetExchangeData(p.Platform, goodsId)
pack := &shop.SCShopExchange{
RetCode: shop.OpResultCode_OPRC_VCoinNotEnough,
}
if cdata == nil {
pack.RetCode = shop.OpResultCode_OPRC_ExchangeSoldOut
p.SendToClient(int(shop.SPacketID_PACKET_SC_SHOP_EXCHANGE), pack)
return false
}
var info *shop.ExchangeType
for _, value := range cdata.ExType {
if value.Id == id {
info = value
break
}
}
if info == nil || (info.Price == 0 && info.JPrice == 0 && info.Cash == 0) {
return false
}
var itemInfo []model.ItemInfo
// TODO 服务器处理 减劵 成功后调后台生成订单
// 判断p.VCoin是否足够 不足返回错误 足够扣掉 另外需从后台操作回执成功生成扣除V卡的订单 回执失败
//扣除V卡
if info.Price > 0 {
if isF := BagMgrSingleton.SaleItem(p, VCard, int64(info.Price*num)); !isF { // 扣掉V卡
p.SendToClient(int(shop.SPacketID_PACKET_SC_SHOP_EXCHANGE), pack)
return false
}
itemInfo = append(itemInfo, model.ItemInfo{
ItemId: VCard,
ItemNum: int64(info.Price * num),
})
}
//扣除金券
if info.JPrice > 0 {
if isF := BagMgrSingleton.SaleItem(p, JCard, int64(info.JPrice*num)); !isF { // 扣掉金券
pack.RetCode = shop.OpResultCode_OPRC_JCoinNotEnough
p.SendToClient(int(shop.SPacketID_PACKET_SC_SHOP_EXCHANGE), pack)
return false
}
itemInfo = append(itemInfo, model.ItemInfo{
ItemId: JCard,
ItemNum: int64(info.JPrice * num),
})
}
task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
pack := &webapi_proto.ASCreateExchangeOrder{
Snid: p.SnId,
Platform: p.Platform,
Type: cdata.Type,
GoodsId: cdata.Id,
VCard: info.Price * num,
GoodsName: cdata.Name,
UserName: username,
Mobile: mobile,
Comment: comment,
JPrice: info.JPrice * num,
Cash: info.Cash * num,
Amount: num,
ExchangeType: id,
}
buff, err := webapi.API_CreateExchange(common.GetAppId(), pack)
if err != nil {
logger.Logger.Error("API_CreateExchange error:", err)
}
as := &webapi_proto.SACreateExchangeOrder{}
if err := proto.Unmarshal(buff, as); err != nil {
logger.Logger.Errorf("API_CreateExchange err: %v %v", err, as.Tag)
}
var amount [ShopTypeItem]int32
//保存db
dbShop := this.NewDbShop(p, 0, amount[:], ExchangeConsumeCash, info.Cash*num,
common.GainWay_ShopBuy, itemInfo, cdata.Id, cdata.Name, 0, "", []int32{})
err = model.InsertDbShopLog(dbShop)
if err != nil {
logger.Logger.Errorf("model.InsertDbShopLog err:", err)
return nil
}
return as
}), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) {
pack := &shop.SCShopExchange{
RetCode: shop.OpResultCode_OPRC_Error,
}
as := data.(*webapi_proto.SACreateExchangeOrder) // 必不为空
//dbShop
if as.Tag == webapi_proto.TagCode_SUCCESS {
pack.RetCode = shop.OpResultCode_OPRC_Sucess
//p.SendVCoinDiffData() // 强推
if info.Price > 0 {
name := "V卡"
if item := BagMgrSingleton.GetItem(p.SnId, VCard); item != nil && item.Name != "" {
name = item.Name
} else {
logger.Logger.Errorf("ExchangeList name err snid %v item %v ", p.SnId, VCard)
}
BagMgrSingleton.RecordItemLog(p.Platform, p.SnId, ItemConsume, VCard, name, int64(info.Price*num), fmt.Sprintf("兑换订单 %v-%v", cdata.Id, cdata.Name))
}
if info.JPrice > 0 {
name := "金券"
if item := BagMgrSingleton.GetItem(p.SnId, JCard); item != nil && item.Name != "" {
name = item.Name
} else {
logger.Logger.Errorf("ExchangeList name err snid %v item %v ", p.SnId, JCard)
}
BagMgrSingleton.RecordItemLog(p.Platform, p.SnId, ItemConsume, JCard, name, int64(info.JPrice*num), fmt.Sprintf("兑换订单 %v-%v", cdata.Id, cdata.Name))
}
} else {
if as.GetReturnCPO() != nil {
switch as.ReturnCPO.Err {
case Err_ExShopNEnough:
pack.RetCode = shop.OpResultCode_OPRC_ExchangeNotEnough
case Err_ExShopLimit:
pack.RetCode = shop.OpResultCode_OPRC_ExchangeLimit
case Err_ExShopData:
pack.RetCode = shop.OpResultCode_OPRC_ExchangeDataRtt
default:
pack.RetCode = shop.OpResultCode_OPRC_ExchangeSoldOut
}
}
logger.Logger.Trace("API_CreateExchange: ", as.Tag, as.GetReturnCPO())
var items = []*Item{}
//返回V卡
if info.Price > 0 {
item1 := &Item{
ItemId: VCard, // 物品id
ItemNum: int64(info.Price * num), // 数量
}
items = append(items, item1)
}
//返回金券
if info.JPrice > 0 {
item := &Item{
ItemId: JCard,
ItemNum: int64(info.JPrice * num),
}
items = append(items, item)
}
if len(items) > 0 {
BagMgrSingleton.AddJybBagInfo(p, items, 0, common.GainWay_Exchange, "system", "返还物品") // 后台订单创建失败 返回物品
}
}
p.SendToClient(int(shop.SPacketID_PACKET_SC_SHOP_EXCHANGE), pack)
}), "CreateExchange").Start()
return
}
// 兑换列表
func (this *ShopMgr) ExchangeList(p *Player) (ret bool) {
ret = true
task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
pack := &webapi_proto.ASGetExchangeShop{
Snid: p.SnId,
Platform: p.Platform,
}
buff, err := webapi.API_ExchangeList(common.GetAppId(), pack)
// spack := &shop.SCShopExchangeRecord{}
as := &webapi_proto.SAGetExchangeShop{}
logger.Logger.Trace("SCShopOrder:", pack)
if err != nil {
logger.Logger.Error("API_ExchangeList error:", err)
return nil
} else if err := proto.Unmarshal(buff, as); err != nil { // 有订单
logger.Logger.Errorf("ExchangeRecord: %v", err)
return nil
}
return as
}), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) {
pack := &shop.SCShopExchangeList{
RetCode: shop.OpResultCode_OPRC_Sucess,
}
if data != nil {
if as := data.(*webapi_proto.SAGetExchangeShop); as != nil {
for _, v := range as.List {
var exChangeType []*shop.ExchangeType
for _, info := range v.ExType {
exChangeType = append(exChangeType, &shop.ExchangeType{
Price: info.Price,
JPrice: info.JPrice,
Id: info.Id,
Cash: info.Cash,
})
}
pack.Infos = append(pack.Infos, &shop.ShopExchangeInfo{
Type: v.Type,
Picture: v.Picture,
Name: v.Name,
Rule: v.Content,
GoodsId: v.Id,
ShopLimit: v.ShopLimit,
DayMaxLimit: v.DayMaxLimit,
DayPlayLimit: v.DayPlayLimit,
ExType: exChangeType,
TelCharge: v.TelCharge,
})
}
}
} else {
pack.RetCode = shop.OpResultCode_OPRC_Error
}
p.SendToClient(int(shop.SPacketID_PACKET_SC_SHOP_EXCHANGELIST), pack)
}), "ExchangeList").Start()
return
}
// 获取兑换记录
func (this *ShopMgr) GetExchangeRecord(p *Player, pageNo int32) {
task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
pack := &webapi_proto.ASGetExchangeOrder{
Snid: p.SnId,
Platform: p.Platform,
Page: pageNo,
}
buff, err := webapi.API_ExchangeRecord(common.GetAppId(), pack)
// spack := &shop.SCShopExchangeRecord{}
as := &webapi_proto.SAGetExchangeOrder{}
logger.Logger.Trace("SCShopOrder:", pack)
if err != nil {
logger.Logger.Error("API_ExchangeRecord error:", err)
return nil
} else if err := proto.Unmarshal(buff, as); err != nil { // 有订单
logger.Logger.Errorf("ExchangeRecord: %v", err)
return nil
}
return as
}), task.CompleteNotifyWrapper(func(data interface{}, t task.Task) {
pack := &shop.SCShopExchangeRecord{}
if data != nil {
if as := data.(*webapi_proto.SAGetExchangeOrder); as != nil {
pack.PageNo = as.CurPage
pack.PageSize = as.PageLimit
pack.PageSum = as.PageTotal
for _, v := range as.OrderList {
record := &shop.ShopExchangeRecord{
CreateTs: v.CreateTime,
OrderId: fmt.Sprintf("%v", v.Id),
State: v.Status,
Name: v.Name,
Remark: v.Remark,
PayState: v.PayStatus,
ExchangeNum: v.ExchangeNum,
EXchangeType: v.EXchangeType,
GoodsId: v.GoodsId,
}
// remark
pack.Infos = append(pack.Infos, record)
}
}
}
p.SendToClient(int(shop.SPacketID_PACKET_SC_SHOP_EXCHANGERECORD), pack)
}), "ExchangeRecord").Start()
}
// ShopCheckShowRed 商城红点通知
func (this *ShopMgr) ShopCheckShowRed(p *Player) {
if p == nil {
return
}
for i := 0; i < 3; i++ {
var isShow bool
for _, shopInfo := range this.GetConfig(p.Platform).ShopInfos {
if shopInfo == nil {
continue
}
var AdLookedNum, remainingTime int32
var lastLookTime int64
if shopInfo.Ad > 0 && (i == -1 || (i < len(shopInfo.Location) && shopInfo.Location[i] == 1)) {
shopTotal := p.ShopTotal[shopInfo.Id]
if shopTotal != nil {
AdLookedNum = shopTotal.AdLookedNum
}
lastLookTime = p.ShopLastLookTime[shopInfo.Id]
if AdLookedNum < int32(len(shopInfo.CoolingTime)) {
remainingTime = shopInfo.CoolingTime[AdLookedNum]
} else {
continue
}
dif := int32(time.Now().Unix() - lastLookTime)
if dif >= remainingTime {
remainingTime = 0
if i+1 <= len(shopInfo.Location) {
isShow = true
p.SendShowRed(hall_proto.ShowRedCode_Shop, int32(i+1), 1)
}
}
}
}
if !isShow {
p.SendShowRed(hall_proto.ShowRedCode_Shop, int32(i+1), 0)
}
}
}
// 现金订单
func (this *ShopMgr) NewDbShop(p *Player, pageId int32, amount []int32, consume, consumeNum, gainWay int32,
itemInfo []model.ItemInfo, shopId int32, shopName string, state int32, remark string, other []int32) (dbShop *model.DbShop) {
ct, cr := PlatformMgrSingleton.GetCurrencyByPackageTag(p.PackageID)
dbShop = model.NewDbShop(p.Platform, pageId, amount[:], ct, consumeNum*cr, consume, consumeNum,
gainWay, itemInfo, shopId, shopName, p.SnId, state, remark, other)
return
}
// SendAPICreateOrder 创建订单
func (this *ShopMgr) SendAPICreateOrder(p *Player, ConfigPayId int32, data any, remark string) {
//三方购买
task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} {
var amount [ShopTypeItem]int32
var dbShop *model.DbShop
if shopInfo, ok := data.(*model.ShopInfo); ok {
// 目前现金只能买钻石
var addTotal = int64(shopInfo.Amount)
added := rand.Int31n(shopInfo.AddArea[1]-shopInfo.AddArea[0]+1) + shopInfo.AddArea[0]
costNum := rand.Int31n(shopInfo.CostArea[1]-shopInfo.CostArea[0]+1) + shopInfo.CostArea[0]
/* if shopInfo.Page == ShopPageVip {
//暂时这样修改 VIP礼包没有现金支付
shopData := p.GetVipShopData(shopInfo.Id, 0)
if shopData != nil {
added = shopData.AddArea
costNum = shopData.CostArea
}
}*/
vipAdded := int32(0)
if shopInfo.Page == ShopPageDiamond {
//vip加成
vipAdded = VipMgrSington.GetVipDiamondExtra(p.Platform, p.VIP)
logger.Logger.Tracef("商城钻石购买vip加成 vipAdded = %v", vipAdded)
}
if added > 0 || vipAdded > 0 {
addTotal = shopInfo.Amount + int64((float64(shopInfo.Amount)*float64(added+vipAdded))/100.0)
}
// 首充翻倍
if shopInfo.FirstSwitch {
if !slices.Contains(p.ShopID, int(shopInfo.Id)) {
addTotal *= 2
}
}
amount[ShopTypeDiamond-1] = int32(addTotal)
var itemInfo []model.ItemInfo
var webItemInfo []*webapi_proto.ItemInfo
if shopInfo.AddItemInfo != nil {
for _, info := range shopInfo.AddItemInfo {
itemInfo = append(itemInfo, model.ItemInfo{
ItemId: info.ItemId,
ItemNum: int64(info.ItemNum),
})
webItemInfo = append(webItemInfo, &webapi_proto.ItemInfo{
ItemId: info.ItemId,
ItemNum: info.ItemNum,
})
}
}
dbShop = this.NewDbShop(p, shopInfo.Page, amount[:], ShopConsumeMoney, costNum,
common.GainWay_ShopBuy, itemInfo, shopInfo.Id, shopInfo.Name, 0, remark, []int32{})
err := model.InsertDbShopLog(dbShop)
if err != nil {
logger.Logger.Errorf("model.InsertDbShopLog err:", err)
return nil
}
return webapi.API_CreateOrder(common.GetAppId(), dbShop.LogId.Hex(), ConfigPayId, p.SnId, shopInfo.Id, p.Platform, p.PackageID, p.DeviceOS,
p.DeviceId, shopInfo.Name, [ShopTypeItem]int32{0, int32(addTotal), 0}, costNum, webItemInfo, "", p.Channel)
} else if cdata, ok := data.(*ExchangeShopInfo); ok {
var info *shop.ExchangeType
for _, value := range cdata.ExType {
if value.Id == cdata.ExchangeTypeId {
info = value
break
}
}
if info.Cash <= 0 {
return nil
}
//保存到db
dbShop = this.NewDbShop(p, 0, amount[:], ExchangeConsumeCash, info.Cash*cdata.ExchangeNum,
common.GainWay_ShopBuy, nil, cdata.Id, cdata.Name, 0, remark, []int32{})
err := model.InsertDbShopLog(dbShop)
if err != nil {
logger.Logger.Errorf("model.InsertDbShopLog err:", err)
return nil
}
orderId := cdata.OrderId
//兑换 充值订单
logger.Logger.Infof("客户端请求兑换 创建支付订单AppId = %v,SnId = %v,Id = %v,dbShop.LogId.Hex() = %v,cash = %v", common.GetAppId(), p.SnId, cdata.Id, dbShop.LogId.Hex(), info.Cash*cdata.ExchangeNum)
return webapi.API_CreateOrder(common.GetAppId(), dbShop.LogId.Hex(), ConfigPayId, p.SnId, cdata.Id, p.Platform, p.PackageID, p.DeviceOS,
p.DeviceId, cdata.Name, [ShopTypeItem]int32{0, 0, 0}, info.Cash*cdata.ExchangeNum, nil, orderId, p.Channel)
} else if bbd, ok := data.(*webapi_proto.BlindBoxData); ok {
if bbd.Type == 1 {
//金币
amount[0] = bbd.Grade
} else if bbd.Type == 2 {
//钻石
amount[1] = bbd.Grade
}
dbShop = this.NewDbShop(p, 0, amount[:], ShopConsumeMoney, int32(bbd.Price2), common.GainWay_ActBlindBox, nil, 0, "", 0, remark, []int32{bbd.Id})
err := model.InsertDbShopLog(dbShop)
if err != nil {
logger.Logger.Errorf("model.InsertDbShopLog err:", err)
return nil
}
return webapi.API_CreateOrder(common.GetAppId(), dbShop.LogId.Hex(), ConfigPayId, p.SnId, 0, p.Platform, p.PackageID, p.DeviceOS,
p.DeviceId, bbd.Name, amount, int32(bbd.Price2), nil, "", p.Channel)
} else if wfs, ok := data.(*webapi_proto.WelfareSpree); ok {
for _, it := range wfs.Item {
if it.Type == 1 {
amount[0] = it.Grade
} else if it.Type == 2 {
amount[1] = it.Grade
}
}
var gainWay int32 = common.GainWay_ActFirstPay
if remark == "ContinuousPay" {
gainWay = common.GainWay_ActContinuousPay
}
dbShop = this.NewDbShop(p, 0, amount[:], ShopConsumeMoney, int32(wfs.Price2), gainWay, nil, 0, "", 0, remark, []int32{wfs.Day})
err := model.InsertDbShopLog(dbShop)
if err != nil {
logger.Logger.Errorf("model.InsertDbShopLog err:", err)
return nil
}
return webapi.API_CreateOrder(common.GetAppId(), dbShop.LogId.Hex(), ConfigPayId, p.SnId, 0, p.Platform, p.PackageID, p.DeviceOS,
p.DeviceId, "FirstRecharge", amount, int32(wfs.Price2), nil, "", p.Channel)
}
return nil
}), task.CompleteNotifyWrapper(func(retdata interface{}, t task.Task) {
logger.Logger.Trace("API_CreateOrder:", retdata)
pack := &shop.SCPayInfo{
RetCode: shop.OpResultCode_OPRC_Error,
}
if retdata == nil {
p.SendToClient(int(shop.SPacketID_PACKET_SCPAYINFO), pack)
return
}
info := retdata.(*webapi_proto.ASCreateOrder)
if info == nil || info.Tag != 0 {
logger.Logger.Errorf("SCPayInfo:Tag[%v] Msg[%v] Url[%v]", info.Tag, info.Msg, info.Url)
//失败
p.SendToClient(int(shop.SPacketID_PACKET_SCPAYINFO), pack)
} else {
pack.RetCode = shop.OpResultCode_OPRC_Sucess
pack.Url = info.Url
logger.Logger.Trace("SCPayInfo:", pack)
p.SendToClient(int(shop.SPacketID_PACKET_SCPAYINFO), pack)
}
}), "API_CreateOrder").Start()
}
func (this *ShopMgr) StartTimer(SnId int32, afterTs int32) {
timer.StartTimer(timer.TimerActionWrapper(func(h timer.TimerHandle, ud interface{}) bool {
p := PlayerMgrSington.GetPlayerBySnId(SnId)
if p == nil || !p.IsOnLine() {
return true
}
this.ShopCheckShowRed(p)
return true
}), nil, time.Duration(afterTs)*time.Second, 1)
}
func (this *ShopMgr) Update() {
}
func (this *ShopMgr) Shutdown() {
module.UnregisteModule(this)
}
func init() {
module.RegisteModule(ShopMgrSington, time.Second, 0)
}