func CGSkillToTileHandler(pkt packet.Packet, agent *Agent) { if agent.PlayerStatus != GPS_NORMAL { return } // 检查变身狼状态一些技能不可用 // if slayer, ok := agent.PlayerCreature.(Ouster); ok { // // } skillPacket := pkt.(*packet.CGSkillToTilePacket) skillHandler, ok := skillTable[skillPacket.SkillType] if !ok { log.Errorln("尚未实现的skill", skillPacket.SkillType) return } handler, ok := skillHandler.(SkillToTileInterface) if !ok { log.Errorln(skillPacket.SkillType, "没有实现SkillToTile接口") return } handler.ExecuteToTile(skillPacket, agent) }
func InitPlayer(player *Player, conn net.Conn) { player.PlayerStatus = GPS_BEGIN_SESSION player.conn = conn read := make(chan packet.Packet, 1) write := make(chan packet.Packet, 1) player.send = write player.client = read go func() { reader := packet.NewReader() player.packetReader = reader for { data, err := reader.Read(player.conn) if err != nil { if _, ok := err.(packet.NotImplementError); ok { log.Errorln("读到一个未实现的包:", data.PacketID()) } else { if err == io.EOF { log.Infoln("后台gouroutine读客户端失败了:", err) player.conn.Close() // 关闭读channel会使得agent的goroutine退出,回收资源 close(read) return } else { log.Errorln("这是一个严重的错误:", err) return } } } log.Debugln("读到了一个packet:", data) read <- data } }() go func() { writer := packet.NewWriter() player.packetWriter = writer for { pkt, ok := <-write if !ok { // 关闭使读goroutine退出 player.conn.Close() return } log.Debugf("write channel get a pkt: %#v\n", pkt) err := writer.Write(player.conn, pkt) if err != nil { log.Errorln(err) continue } } }() }
func (agent *Agent) handleClientMessage(pkt packet.Packet) { if pkt == nil { log.Errorln("不应该呀 怎么可能返回一个空") } handler, ok := packetHandlers[pkt.PacketID()] if !ok { log.Errorln("packet的handler未实现:", pkt.PacketID()) return } handler(pkt, agent) }
func (vampire *Vampire) computeDamage(creature CreatureInterface, bCritical bool) Damage_t { minDamage := vampire.Damage[ATTR_CURRENT] maxDamage := vampire.Damage[ATTR_MAX] // timeband := getZoneTimeband(vampire->getZone()) // TODO timeband := 0 // pItem := vampire.getWearItem(Vampire_WEAR_RIGHTHAND) // // if pItem != nil { // MinDamage += pItem.getMinDamage() // MaxDamage += pItem.getMaxDamage() // } realDamage := max(1, int(minDamage)+rand.Intn(int(maxDamage-minDamage))) realDamage = getPercentValue(realDamage, VampireTimebandFactor[timeband]) var protection Protection_t switch creature.(type) { case *Vampire: protection = creature.(*Vampire).Protection[ATTR_CURRENT] protection = Protection_t(getPercentValue(int(protection), VampireTimebandFactor[timeband])) case *Monster: protection = creature.(*Monster).Protection protection = Protection_t(getPercentValue(int(protection), VampireTimebandFactor[timeband])) case *Slayer: protection = creature.(*Slayer).Protection[ATTR_CURRENT] case *Ouster: protection = creature.(*Ouster).Protection[ATTR_CURRENT] default: log.Errorln("输入的参数不对") } finalDamage := Damage_t(computeFinalDamage(minDamage, maxDamage, Damage_t(realDamage), protection, bCritical)) return finalDamage }
// 这个函数只能在scene的goroutine中调用 // 被攻击者是怪物,直接减血 // 被攻击者是玩家,发到agent的goroutine中去计算 func (m *Scene) setDamage(target CreatureInterface, agent *Agent, damage Damage_t) { var status packet.GCStatusCurrentHP switch target.(type) { case *Agent: // TODO case *Monster: monster := target.(*Monster) if monster.HP[ATTR_CURRENT] < HP_t(damage) { // 这里只是设置dead标志,在MonsterManager的heartbeat中kill monster.HP[ATTR_CURRENT] = 0 monster.LastKiller = agent.ObjectInstance().ObjectID } else { monster.HP[ATTR_CURRENT] -= HP_t(damage) status = packet.GCStatusCurrentHP{ ObjectID: monster.ObjectID, CurrentHP: monster.HP[ATTR_CURRENT], } } default: log.Errorln("参数不对") } pc := agent.CreatureInstance() // // 广播给所有玩家,攻击成功,怪物状态变化 // ok3 := packet.GCAttackMeleeOK3{ // ObjectID: pc.ObjectID, // TargetObjectID: target.CreatureInstance().ObjectID, // } // m.broadcastPacket(pc.X, pc.Y, ok3, agent) m.broadcastPacket(pc.X, pc.Y, status, nil) }
func loadSlayer(decoder *json.Decoder) (slayer *Slayer, zoneID ZoneID_t, err error) { var pcInfo data.PCSlayerInfo err = decoder.Decode(&pcInfo) if err != nil { log.Errorln("decode pcinfo failed") return } slayer = new(Slayer) slayer.Init() slayer.Name = pcInfo.Name slayer.HairColor = pcInfo.HairColor slayer.MasterEffectColor = pcInfo.MasterEffectColor slayer.Alignment = pcInfo.Alignment slayer.STR = pcInfo.STR slayer.DEX = pcInfo.DEX slayer.INI = pcInfo.INI slayer.HP[ATTR_MAX] = pcInfo.HP[ATTR_MAX] slayer.HP[ATTR_CURRENT] = pcInfo.HP[ATTR_CURRENT] slayer.MP[ATTR_MAX] = pcInfo.MP[ATTR_MAX] slayer.MP[ATTR_CURRENT] = pcInfo.MP[ATTR_CURRENT] slayer.Rank = pcInfo.Rank slayer.RankExp = pcInfo.RankExp slayer.Fame = pcInfo.Fame slayer.Sight = pcInfo.Sight slayer.Competence = pcInfo.Competence slayer.GuildMemberRank = pcInfo.GuildMemberRank slayer.AdvancementLevel = pcInfo.AdvancementLevel for i := 0; i < 6; i++ { slayer.DomainLevels[i] = pcInfo.DomainLevels[i] slayer.DomainExps[i] = pcInfo.DomainExps[i] } zoneID = pcInfo.ZoneID slayer.X = ZoneCoord_t(pcInfo.ZoneX) slayer.Y = ZoneCoord_t(pcInfo.ZoneY) // var skillInfo packet.OusterSkillInfo // err = decoder.Decode(&skillInfo) // if err != nil { // return // } // // slayer.SkillSlot = make(map[SkillType_t]*OusterSkillSlot) // for _, v := range skillInfo.SubOusterSkillInfoList { // skillslot := &OusterSkillSlot{ // // Name string // SkillType: v.SkillType, // ExpLevel: v.ExpLevel, // Interval: time.Duration(v.Interval) * time.Millisecond, // CastingTime: time.Duration(v.CastingTime) * time.Millisecond, // // RunTime time.Time // } // slayer.SkillSlot[v.SkillType] = skillslot // } return }
func loadOuster(decoder *json.Decoder) (ouster *Ouster, zoneID ZoneID_t, err error) { var pcInfo data.PCOusterInfo err = decoder.Decode(&pcInfo) if err != nil { log.Errorln("decode pcinfo failed") return } ouster = new(Ouster) ouster.Init() ouster.Name = pcInfo.Name ouster.Level = pcInfo.Level ouster.HairColor = pcInfo.HairColor ouster.MasterEffectColor = pcInfo.MasterEffectColor ouster.Alignment = pcInfo.Alignment ouster.STR = pcInfo.STR ouster.DEX = pcInfo.DEX ouster.INI = pcInfo.INI ouster.HP[ATTR_MAX] = pcInfo.HP[ATTR_MAX] ouster.HP[ATTR_CURRENT] = pcInfo.HP[ATTR_CURRENT] ouster.MP[ATTR_MAX] = pcInfo.MP[ATTR_MAX] ouster.MP[ATTR_CURRENT] = pcInfo.MP[ATTR_CURRENT] ouster.Rank = pcInfo.Rank ouster.RankExp = pcInfo.RankExp ouster.Exp = pcInfo.Exp ouster.Fame = pcInfo.Fame ouster.Sight = pcInfo.Sight ouster.Bonus = pcInfo.Bonus ouster.Competence = pcInfo.Competence ouster.GuildMemberRank = pcInfo.GuildMemberRank ouster.AdvancementLevel = pcInfo.AdvancementLevel zoneID = pcInfo.ZoneID ouster.X = pcInfo.ZoneX ouster.Y = pcInfo.ZoneY var skillInfo data.OusterSkillInfo err = decoder.Decode(&skillInfo) if err != nil { return } ouster.SkillSlot = make(map[SkillType_t]*OusterSkillSlot) for _, v := range skillInfo.SubOusterSkillInfoList { skillslot := &OusterSkillSlot{ // Name string SkillType: v.SkillType, ExpLevel: v.ExpLevel, Interval: time.Duration(v.Interval) * time.Millisecond, CastingTime: time.Duration(v.CastingTime) * time.Millisecond, // RunTime time.Time } ouster.SkillSlot[v.SkillType] = skillslot } return }
func (vampire *Vampire) PCInfo() data.PCInfo { if vampire == nil || vampire.Scene == nil { log.Errorln("f**k...Scene为空谁让你调这个函数了?") return nil } ret := &data.PCVampireInfo{ ObjectID: vampire.ObjectID, Name: vampire.Name, Level: vampire.Level, Sex: vampire.Sex, BatColor: vampire.BatColor, SkinColor: vampire.SkinColor, Alignment: vampire.Alignment, Rank: vampire.Rank, RankExp: vampire.RankExp, Exp: vampire.Exp, Fame: vampire.Fame, Gold: vampire.Gold, Sight: vampire.Sight, Bonus: vampire.Bonus, // HotKey: vampire.HotKey, SilverDamage: vampire.SilverDamage, Competence: vampire.Competence, GuildID: vampire.GuildID, GuildMemberRank: vampire.GuildMemberRank, UnionID: vampire.UnionID, AdvancementLevel: vampire.AdvancementLevel, AdvancementGoalExp: vampire.AdvancementGoalExp, ZoneID: vampire.Scene.ZoneID, ZoneX: Coord_t(vampire.X), ZoneY: Coord_t(vampire.Y), } log.Debugln("run here.......") ret.STR[ATTR_CURRENT] = vampire.STR[ATTR_CURRENT] ret.STR[ATTR_MAX] = vampire.STR[ATTR_MAX] ret.DEX[ATTR_CURRENT] = vampire.DEX[ATTR_CURRENT] ret.DEX[ATTR_MAX] = vampire.DEX[ATTR_MAX] ret.INI[ATTR_CURRENT] = vampire.INI[ATTR_CURRENT] ret.INI[ATTR_MAX] = vampire.INI[ATTR_MAX] ret.HP[ATTR_CURRENT] = vampire.HP[ATTR_CURRENT] ret.HP[ATTR_MAX] = vampire.HP[ATTR_MAX] return ret }
func CGSkillToObjectHandler(pkt packet.Packet, agent *Agent) { skillPacket := pkt.(*packet.CGSkillToObjectPacket) skillHandler, ok := skillTable[skillPacket.SkillType] if !ok { log.Errorln("尚未实现的skill", skillPacket.SkillType) return } handler, ok := skillHandler.(SkillToObjectInterface) if !ok { log.Errorln(skillPacket.SkillType, "没有实现SkillToObject接口") return } // type GCSkillFailed1Packet struct { // SkillType SkillType_t // Grade uint8 // ModifyInfo // } // fail := packet.GCSkillToTileFail{ // SkillType: SKILL_ATTACK_MELEE, // } pc := agent.PlayerCreatureInstance() obj, ok := pc.Scene.objects[skillPacket.TargetObjectID] if !ok { // TODO 发送失败包 // agent.sendPacket() return } target, ok := obj.(CreatureInterface) if !ok { log.Error("不能对非creature的东西放技能") return } handler.ExecuteToObject(agent, target) }
func (ouster *Ouster) computeDamage(creature CreatureInterface, bCritical bool) Damage_t { minDamage := ouster.Damage[ATTR_CURRENT] maxDamage := ouster.Damage[ATTR_MAX] // timeband := getZoneTimeband(pVampire->getZone()) // TODO timeband := 0 // TODO // pItem := ouster.getWearItem(OUSTER_WEAR_RIGHTHAND) // // if pItem != nil { // MinDamage += pItem.getMinDamage() // MaxDamage += pItem.getMaxDamage() // } // scope := int(maxDamage - minDamage) if scope < 1 { scope = 1 } realDamage := max(1, int(minDamage)+rand.Intn(scope)) var protection Protection_t if creature != nil { again: switch creature.(type) { case *Vampire: protection = creature.(*Vampire).Protection[ATTR_CURRENT] protection = Protection_t(getPercentValue(int(realDamage), VampireTimebandFactor[timeband])) case *Monster: protection = creature.(*Monster).Protection protection = Protection_t(getPercentValue(int(realDamage), VampireTimebandFactor[timeband])) case *Slayer: protection = creature.(*Slayer).Protection[ATTR_CURRENT] case *Ouster: protection = creature.(*Ouster).Protection[ATTR_CURRENT] case *Agent: creature = creature.(*Agent).PlayerCreatureInterface goto again default: log.Errorln("输入的参数不对") } } finalDamage := computeFinalDamage(minDamage, maxDamage, Damage_t(realDamage), protection, bCritical) return finalDamage }
func main() { ln, err := net.Listen("tcp", config.LoginServerPort) if err != nil { panic(err) } log.Infoln("loginserver started") for { conn, err := ln.Accept() if err != nil { log.Errorln("accept err:", err) continue } log.Infoln("receive a connect request") go serve(conn) } }
func (ai *MonsterAI) useSkill(pEnemy CreatureInterface, SkillType SkillType_t, ratio int) int { // enemy := pEnemy.CreatureInstance() // ex := enemy.X // ey := enemy.Y // dist := ai.Body.getDistance(ex, ey) if rand.Intn(100) >= ratio { // return SKILL_FAILED_RATIO return -1 } if ai.Body.isFlag(EFFECT_CLASS_HIDE) { SkillType = SKILL_UN_BURROW } else if ai.Body.isFlag(EFFECT_CLASS_TRANSFORM_TO_BAT) { SkillType = SKILL_UN_TRANSFORM } else if ai.Body.isFlag(EFFECT_CLASS_INVISIBILITY) { SkillType = SKILL_UN_INVISIBILITY } skill, ok := skillTable[SkillType] if !ok { log.Errorf("技能%d的handler没有实现!!", SkillType) return 0 } switch handler := skill.(type) { case SkillToObjectInterface: // 移动计算,以闭包形式发到agent的goroutine中运行 if agent, ok := pEnemy.(*Agent); ok { closure := func() { handler.ExecuteToObject(ai.Body, pEnemy) } agent.computation <- closure } else { log.Errorln("怪物打怪物还没实现") } ai.LastAction = LAST_ACTION_SKILL default: log.Warnln("skill handler没有实现", SkillType) } return 0 }
func serve(conn net.Conn) { defer conn.Close() reader := packet.NewReader() writer := packet.NewWriter() for { pkt, err := reader.Read(conn) if err != nil { if _, ok := err.(packet.NotImplementError); !ok { log.Errorln("read packet error in loginserver's serve:", err) return } } log.Debugln("read a packet: ", pkt.PacketID()) switch pkt.PacketID() { case packet.PACKET_CL_GET_WORLD_LIST: writer.Write(conn, packet.LCWorldListPacket{}) case packet.PACKET_CL_LOGIN: writer.Write(conn, packet.LCLoginOKPacket{}) case packet.PACKET_CL_SELECT_SERVER: writer.Write(conn, &packet.LCPCListPacket{}) case packet.PACKET_CL_SELECT_WORLD: writer.Write(conn, &packet.LCServerListPacket{}) case packet.PACKET_CL_VERSION_CHECK: writer.Write(conn, packet.LCVersionCheckOKPacket{}) case packet.PACKET_CL_SELECT_PC: reconnect := &packet.LCReconnectPacket{ Ip: config.GameServerIP, Port: 9998, Key: 82180, } writer.Write(conn, reconnect) return default: log.Errorf("get a unknow packet: %d\n", pkt.PacketID()) } } }
func (m *MonsterManager) findPosition(zone *Zone, monsterType MonsterType_t) (x ZoneCoord_t, y ZoneCoord_t) { info, ok := data.MonsterInfoTable[monsterType] if !ok { log.Error("不对,找不到monster信息") return } for i := 0; i < 300; i++ { pt := zone.getRandomMonsterRegenPosition() tile := zone.Tile(int(pt.X), int(pt.Y)) if !tile.isBlocked(info.MoveMode) && !tile.hasPortal() && (*zone.Level(int(pt.X), int(pt.Y))&ZoneLevel_t(SAFE_ZONE)) == 0 { x = ZoneCoord_t(pt.X) y = ZoneCoord_t(pt.Y) return } } log.Errorln("地图中找不到可以放怪物的点了...不科学!") return }
func CGReadyHandler(pkt packet.Packet, agent *Agent) { pc := agent.PlayerCreatureInstance() if agent.PlayerStatus != GPS_WAITING_FOR_CG_READY { } // scene := GetScene(pc.ZoneID) // scene.agent <- AgentMsg{} // var save chan<- AgentMsg // 地图切换 if agent.ZoneID != 0 { // save = agent.send } agent.sendPacket(&packet.GCSetPositionPacket{ X: uint8(pc.X), Y: uint8(pc.Y), Dir: uint8(pc.Dir), }) var skillInfo packet.GCSkillInfoPacket switch agent.PlayerCreatureInterface.(type) { case *Vampire: skillInfo.PCType = packet.PC_VAMPIRE case *Ouster: skillInfo.PCType = packet.PC_OUSTER case *Slayer: skillInfo.PCType = packet.PC_SLAYER default: log.Errorln("不应该运行到这里") } // skillInfo.PCSkillInfoList = []packet.SkillInfo{ // agent.SkillInfo(), // } // log.Debugf("发送技能信息%#v\n", skillInfo) // agent.sendPacket(&skillInfo) agent.PlayerStatus = GPS_NORMAL }
func (tile *Tile) deleteCreature(id ObjectID_t) { var object ObjectInterface object, ok := tile.Objects[id] if !ok { log.Warnf("object not exist in tile! id=%d tile=%#v\n", id, tile) return } delete(tile.Objects, id) var creature *Creature switch raw := object.(type) { case *Agent: creature = raw.CreatureInstance() case *Monster: creature = raw.CreatureInstance() default: log.Errorln(raw) panic("不对") } tile.Flags &^= (1 << (TILE_WALKING_CREATURE + creature.MoveMode)) tile.Flags &^= (1 << (TILE_GROUND_BLOCKED + creature.MoveMode)) }
// 注意:需要在agent的goroutine中执行的 func (melee AttackMelee) ExecuteToObject(sender CreatureInterface, target CreatureInterface) { rangeCheck := verifyDistance(sender, target) hitRoll := HitRoll(sender, target, 0) if rangeCheck && hitRoll { if agent, ok := sender.(*Agent); ok { damage := agent.computeDamage(target, false) // 这个伤害是要广播给地图周围玩家知道的 agent.scene <- DamageMessage{ Agent: agent, target: target, damage: damage, critical: false, } // 发给攻击者,告诉他攻击成功了 ok1 := packet.GCAttackMeleeOK1{ ObjectID: target.CreatureInstance().ObjectID, } agent.sendPacket(ok1) if slayer, ok := agent.PlayerCreatureInterface.(*Slayer); ok { weapon := slayer.getWearItem(SLAYER_WEAR_RIGHTHAND) switch weapon.ItemClass() { case ITEM_CLASS_BLADE: // increaseDomainExp(slayer, SKILL_DOMAIN_BLADE, 1, packet.GCAttackMeleeOK1{}, targetCreature.CreatureInstance().Level) case ITEM_CLASS_SWORD: // increaseDomainExp(slayer, SKILL_DOMAIN_BLADE, 1, packet.GCAttackMeleeOK1{}, targetCreature.CreatureInstance().Level) case ITEM_CLASS_CROSS: // increaseDomainExp(slayer, SKILL_DOMAIN_BLADE, 1, packet.GCAttackMeleeOK1{}, targetCreature.CreatureInstance().Level) case ITEM_CLASS_MACE: // increaseDomainExp(slayer, SKILL_DOMAIN_BLADE, 1, packet.GCAttackMeleeOK1{}, targetCreature.CreatureInstance().Level) default: log.Errorln("武器不对!") } } } if monster, ok := sender.(*Monster); ok { damage := monster.computeDamage(target, false) if agent, ok := target.(*Agent); ok { pc := agent.PlayerCreatureInstance() if pc.HP[ATTR_CURRENT] < HP_t(damage) { // 玩家被打死了 log.Debugln("玩家被打死还没实现") } else { pc.HP[ATTR_CURRENT] -= HP_t(damage) log.Debugln("怪物攻击玩家,广播状态信息的攻击成功") // 广播给所有玩家,攻击成功 ok3 := packet.GCAttackMeleeOK3{ ObjectID: sender.CreatureInstance().ObjectID, TargetObjectID: target.CreatureInstance().ObjectID, } pc.Scene.broadcastPacket(pc.X, pc.Y, ok3, agent) // 广播给所有玩家,状态变化 status := packet.GCStatusCurrentHP{ ObjectID: pc.ObjectID, CurrentHP: pc.HP[ATTR_CURRENT], } pc.Scene.broadcastPacket(pc.X, pc.Y, status, nil) } } else { log.Errorln("参数不对") } } switch agent := target.(type) { case *Agent: agent.sendPacket(packet.GCAttackMeleeOK2{ ObjectID: sender.CreatureInstance().ObjectID, }) case *Monster: // monster := target.(*Monster) // monster.addEnemy(agent) } } }
func HitRoll(pAttacker CreatureInterface, pDefender CreatureInterface, bonus int) bool { if pDefender.CreatureInstance().isFlag(EFFECT_CLASS_NO_DAMAGE) { return false } var ( tohit ToHit_t defense Defense_t ) //TODO // timeband = pZone->getTimeband(); timeband := 0 again1: switch pAttacker.(type) { case *Slayer: tohit = pAttacker.(*Slayer).ToHit[ATTR_CURRENT] case *Ouster: tohit = pAttacker.(*Ouster).ToHit[ATTR_CURRENT] case *Vampire: tohit = pAttacker.(*Vampire).ToHit[ATTR_CURRENT] tohit = ToHit_t(getPercentValue(int(tohit), VampireTimebandFactor[timeband])) case *Monster: tohit = pAttacker.(*Monster).ToHit tohit = ToHit_t(getPercentValue(int(tohit), VampireTimebandFactor[timeband])) case *Agent: pAttacker = pAttacker.(*Agent).PlayerCreatureInterface goto again1 default: log.Errorln("参数不对") } again2: switch pDefender.(type) { case *Slayer: defense = pDefender.(*Slayer).Defense[ATTR_CURRENT] case *Ouster: defense = pDefender.(*Ouster).Defense[ATTR_CURRENT] case *Vampire: defense = pDefender.(*Vampire).Defense[ATTR_CURRENT] defense = Defense_t(getPercentValue(int(defense), VampireTimebandFactor[timeband])) case *Monster: defense = pDefender.(*Monster).Defense defense = Defense_t(getPercentValue(int(defense), VampireTimebandFactor[timeband])) case *Agent: pDefender = pDefender.(*Agent).PlayerCreatureInterface goto again2 } randValue := rand.Intn(100) var result int if int(tohit) >= int(defense) { result = min(90, int(int((float64(int(tohit)-int(defense))/1.5))+60)+bonus) } else { if _, ok := pAttacker.(*Monster); ok { result = max(10, (int)(60-int((float64(defense)-float64(tohit))/1.5)+bonus)) } else { result = max(20, (int)(60-int((float64(defense)-float64(tohit))/1.5)+bonus)) } } if randValue <= result { return true } return false }
func CGAttackHandler(pkt packet.Packet, agent *Agent) { fail := packet.GCSkillFailed1Packet{ SkillType: SKILL_ATTACK_MELEE, } if agent.PlayerStatus != GPS_NORMAL { agent.sendPacket(&fail) return } pc := agent.PlayerCreatureInstance() zoneLevel := pc.Scene.getZoneLevel(pc.X, pc.Y) if (zoneLevel&ZoneLevel_t(COMPLETE_SAFE_ZONE)) != 0 || pc.isFlag(EFFECT_CLASS_PARALYZE) || pc.isFlag(EFFECT_CLASS_CAUSE_CRITICAL_WOUNDS) || pc.isFlag(EFFECT_CLASS_EXPLOSION_WATER) || pc.isFlag(EFFECT_CLASS_COMA) { agent.sendPacket(&fail) return } attack := pkt.(*packet.CGAttackPacket) target, ok := pc.Scene.objects[attack.ObjectID] if !ok { agent.sendPacket(&fail) return } if target.ObjectClass() != OBJECT_CLASS_CREATURE { agent.sendPacket(&fail) return } targetCreature := target.(CreatureInterface) // ok3 := packet.GCAttackMeleeOK3{} // skillslot = agent.hasSkill(SKILL_ATTACK_MELEE) // timeCheck := verifyRunTime(skillslot) rangeCheck := verifyDistance(agent, targetCreature) hitRoll := HitRoll(agent.PlayerCreatureInterface, targetCreature, 0) if rangeCheck && hitRoll { damage := agent.PlayerCreatureInterface.computeDamage(targetCreature, false) // 这个伤害是要广播给地图周围玩家知道的 agent.scene <- DamageMessage{ Agent: agent, target: targetCreature, damage: damage, critical: false, } if slayer, ok := agent.PlayerCreatureInterface.(*Slayer); ok { weapon := slayer.getWearItem(SLAYER_WEAR_RIGHTHAND) switch weapon.ItemClass() { case ITEM_CLASS_BLADE: increaseDomainExp(slayer, SKILL_DOMAIN_BLADE, 1, &packet.GCAttackMeleeOK1{}, targetCreature.CreatureInstance().Level) case ITEM_CLASS_SWORD: increaseDomainExp(slayer, SKILL_DOMAIN_BLADE, 1, &packet.GCAttackMeleeOK1{}, targetCreature.CreatureInstance().Level) case ITEM_CLASS_CROSS: increaseDomainExp(slayer, SKILL_DOMAIN_BLADE, 1, &packet.GCAttackMeleeOK1{}, targetCreature.CreatureInstance().Level) case ITEM_CLASS_MACE: increaseDomainExp(slayer, SKILL_DOMAIN_BLADE, 1, &packet.GCAttackMeleeOK1{}, targetCreature.CreatureInstance().Level) default: log.Errorln("武器不对!") } } switch target.(type) { case *Agent: targetAgent := target.(*Agent) targetAgent.sendPacket(packet.GCAttackMeleeOK2{ ObjectID: agent.ObjectInstance().ObjectID, }) case *Monster: monster := target.(*Monster) monster.addEnemy(agent) } // skillslot.setRunTime() } else { // 执行失败处理 } // agent.setLastTarget(target.ObjectID) // if monster, ok := target.(*Monster); ok { // hit := HitTest(player.ToHit, monster.Defense) // if hit { // player.send <- packet.GCAttackMeleeOK1{ // ObjectID: monster.Id(), // } // // damage := 1 // if player.Damage > monster.Protection { // damage = int(player.Damage - monster.Protection) // } // // log.Println("send attack SkillOutput to scene..........") // player.Scene.agent <- AgentMessage{ // Player: player, // Msg: SkillOutput{ // MonsterID: attack.ObjectID, // Damage: damage, // }, // } // } else { // player.send <- &packet.GCSkillFailed1Packet{} // } // } }
func (info *GCUpdateInfoPacket) Write(buf io.Writer, code uint8) error { var PCType byte switch info.PCInfo.(type) { case *data.PCOusterInfo: PCType = 'O' case *data.PCSlayerInfo: PCType = 'S' case *data.PCVampireInfo: PCType = 'V' default: log.Errorln("unknown PCInfo in GCUpdateInfoPacket") } binary.Write(buf, binary.LittleEndian, PCType) info.PCInfo.Write(buf) info.InventoryInfo.Write(buf) info.GearInfo.Write(buf) info.ExtraInfo.Write(buf) info.EffectInfo.Write(buf) if info.hasMotorcycle { binary.Write(buf, binary.LittleEndian, uint8(1)) info.RideMotorcycleInfo.Dump(buf) } else { binary.Write(buf, binary.LittleEndian, uint8(0)) } binary.Write(buf, binary.LittleEndian, info.ZoneID) binary.Write(buf, binary.LittleEndian, info.ZoneX) binary.Write(buf, binary.LittleEndian, info.ZoneY) info.GameTime.Dump(buf) binary.Write(buf, binary.LittleEndian, info.Weather) binary.Write(buf, binary.LittleEndian, info.WeatherLevel) binary.Write(buf, binary.LittleEndian, info.DarkLevel) binary.Write(buf, binary.LittleEndian, info.LightLevel) binary.Write(buf, binary.LittleEndian, uint8(len(info.NPCTypes))) for i := 0; i < len(info.NPCTypes); i++ { binary.Write(buf, binary.LittleEndian, info.NPCTypes[i]) } binary.Write(buf, binary.LittleEndian, uint8(len(info.MonsterTypes))) for i := 0; i < len(info.MonsterTypes); i++ { binary.Write(buf, binary.LittleEndian, info.MonsterTypes[i]) } binary.Write(buf, binary.LittleEndian, uint8(len(info.NPCInfos))) for i := 0; i < len(info.NPCInfos); i++ { info.NPCInfos[i].Write(buf) } binary.Write(buf, binary.LittleEndian, info.ServerStat) binary.Write(buf, binary.LittleEndian, info.Premium) binary.Write(buf, binary.LittleEndian, info.SMSCharge) info.NicknameInfo.Write(buf) if info.NonPK { binary.Write(buf, binary.LittleEndian, uint8(1)) } else { binary.Write(buf, binary.LittleEndian, uint8(0)) } binary.Write(buf, binary.LittleEndian, info.GuildUnionID) binary.Write(buf, binary.LittleEndian, info.GuildUnionUserType) info.BloodBibleSignInfo.Write(buf) binary.Write(buf, binary.LittleEndian, info.PowerPoint) return nil // return // buf.Write([]byte{190, 7, // 3, // 19, // 16, // 10, // 40, // // 0, Weather // 0, WeatherLevel // 13, DarkLevel // 2, LightLevel // // 0, nNPCS // // 5, nMonsters // 9, 0, monsterTypes // 61, 0, // 62, 0, // 64, 0, // 163, 0, // // 0, NPCInfoCount // 0, ServerStat // 17, Premium // 0, 0, 0, 0, SMSCharge // NickNameInfo // 24, 125, 0, // // 0, NonPK // 0, 0, 0, 0, GuildUnionID // 2, GuildUnionUserType // 1, 0, 0, 0, 0, // 0, 0, 0, 0}) PowerPoint // return nil // return []byte{86, 117, 48, 0, 0, 4, 183, 232, 191, 241, 150, 0, 0, 0, 164, 1, 0, 76, 29, 0, 0, // 20, 0, 20, 0, 20, 0, 20, 0, 20, 0, 20, 0, 20, 0, 20, 0, 20, 0, 216, 1, 216, 1, 50, 204, 41, 0, 0, 125, 0, 0, // 0, 0, 0, 0, 0, 26, 1, 0, 0, 13, 15, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 4, 0, 0, // 0, 0, 100, 0, 0, 0, 0, 6, 118, 48, 0, 0, 30, 0, 0, 0, 232, 3, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 119, // 48, 0, 0, 44, 0, 0, 2, 16, 1, 136, 19, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 120, 48, 0, 0, 34, 5, 0, 0, // 1, 0, 0, 0, 0, 0, 255, 255, 255, 255, 0, 8, 0, 0, 0, 0, 1, 121, 48, 0, 0, 32, 0, 0, 2, 53, 43, 232, 3, 0, 0, // 0, 0, 4, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 122, 48, 0, 0, 32, 1, 0, 0, 232, 3, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1, 0, 0, 0, 0, 3, 123, 48, 0, // 0, 44, 0, 0, 2, 58, 38, 32, 28, 0, 0, 0, 0, 4, 0, 0, 0, 0, 1, 0, 0, 0, 0, 4, 0, 0, 2, 146, 1, 54, 66, 109, 0, 246, 224, 0, 21, 0, 145, 237, 190, 7, 3, 19, 16, // 10, 40, 0, 0, 13, 2, 0, 5, 9, 0, 61, 0, 62, 0, 64, 0, 163, 0, 0, 0, 17, 0, 0, 0, 0, 24, 125, 0, 0, 0, 0, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0}, // nil }
func CGConnectHandler(pkt packet.Packet, agent *Agent) { raw := pkt.(*packet.CGConnectPacket) pcItf, zid, err := LoadPlayerCreature(raw.PCName, packet.PCType(raw.PCType)) if err != nil { log.Errorln("LoadPlayerCreature失败了:", err) } agent.PlayerCreatureInterface = pcItf scene, ok := g_Scenes[zid] if !ok { log.Errorln("加载的agent所在的scene不存在:", zid) agent.ErrorClose() return } agent.scene = scene.agent msg := LoginMessage{ Agent: agent, wg: &sync.WaitGroup{}, } // 向scene发消息并等待其返回 msg.wg.Add(1) agent.scene <- msg msg.wg.Wait() // log.Debugln("坐标:", agent.CreatureInstance().X, // agent.CreatureInstance().Y) info := &packet.GCUpdateInfoPacket{ PCInfo: agent.PCInfo(), ZoneID: zid, ZoneX: Coord_t(agent.CreatureInstance().X), ZoneY: Coord_t(agent.CreatureInstance().Y), GameTime: packet.GameTimeType{ Year: 1983, Month: 8, Day: 19, Hour: 12, Minute: 28, Second: 16, }, DarkLevel: 13, LightLevel: 6, MonsterTypes: []MonsterType_t{5, 6, 7, 8}, Premium: 17, NicknameInfo: data.NicknameInfo{ NicknameID: 32560, }, GuildUnionUserType: 2, } code := Encrypt(uint16(agent.CreatureInstance().Scene.ZoneID), 1) agent.packetReader.Code = code agent.packetWriter.Code = code if _, ok := info.PCInfo.(*data.PCOusterInfo); ok { info.GearInfo = data.GearInfo{ GearSlotInfoList: []data.GearSlotInfo{ data.GearSlotInfo{ PCItemInfo: data.PCItemInfo{ ObjectID: 12494, IClass: 59, ItemType: 14, Durability: 6700, Grade: 4, ItemNum: 1, }, SlotID: 3, }, }, } } agent.sendPacket(info) agent.sendPacket(&packet.GCPetInfoPacket{}) agent.PlayerStatus = GPS_WAITING_FOR_CG_READY }