/// <summary> /// Callback sub-method for all units (player, npc, mob, pet, homu, merc) /// </summary> /// <param name="obj"></param> /// <param name="args"></param> private static void Callback_GetAreaCharUnit(WorldObject obj, object[] args) { Character src = (Character)args[0]; if (src == null || obj == null) { return; } WorldObjectViewData vd = WorldObject.GetViewData(obj); if (vd == null /* || vd.Class == INVISIBLE_CLASS)*/) { return; } // Unit is walking? if ((obj is WorldObjectUnit) && (obj as WorldObjectUnit).WalkTimer != null) { World.Send(new WorldSendUnitWalking(obj), src, ESendTarget.Self); } else { World.Send(new WorldSendUnitIdle(obj, false), src, ESendTarget.Self); } if (vd.ClothesColor > 0) { //clif_refreshlook(&sd->bl,bl->id,LOOK_CLOTHES_COLOR,vd->cloth_color,SELF); } switch (obj.Type) { case EDatabaseType.Char: //clif_getareachar_pc // Special states // Battleground emblem break; case EDatabaseType.Mob: // Special states/sizes break; case EDatabaseType.Mercenary: // Devotion effect break; case EDatabaseType.Npc: // Chat over head // Special states/sizes break; case EDatabaseType.Pet: // Head bottom (Pet equip) break; } }
public WorldSendUnitWalking(WorldObject obj) : base(0) { WorldObjectStatusChangeList sc = WorldObject.GetStatusChange(obj); WorldObjectViewData vd = WorldObject.GetViewData(obj); string name = WorldObject.GetName(obj); ushort speed = WorldObject.GetSpeed(obj); Writer.Position = 0; Write((short)0x7f7); Write((short)(69 + name.Length)); Write((byte)obj.GetPacketType()); Write((uint)(obj is Character ? (obj as Character).Account.ID : obj.ID)); // For Character, send accountID as unique ID Write((ushort)speed); // status_get_speed(bl); Write((short)(sc != null ? sc.Option1 : 0)); // (sc) ? sc->opt1 : 0; Write((short)(sc != null ? sc.Option2 : 0)); // (sc) ? sc->opt2 : 0; Write((int)(sc != null ? sc.Option : 0)); // (sc) ? sc->option : 0; Write((short)vd.Class); // vd->class_; Write((short)vd.HairStlye); // vd->hair_style; Write((short)vd.Weapon); // vd->weapon; Write((short)vd.Shield); // vd->shield; Write((short)vd.HeadBottom); // vd->head_bottom Write((int)Timer.Ticks); Write((short)vd.HeadTop); // vd->head_top; Write((short)vd.HeadMid); // vd->head_mid; Write((short)vd.HairColor); // vd->hair_color; Write((short)vd.ClothesColor); // vd->cloth_color; Write((short)0); // (sd) ? sd->head_dir : 0; Write((int)0); // status_get_guild_id(bl); Write((short)0); // status_get_emblem_id(bl); Write((short)0); // (sd) ? sd->status.manner : 0; Write((int)(sc != null ? sc.Option3 : 0)); // (sc) ? sc->opt3 : 0; Write((byte)0); // (sd) ? sd->status.karma : 0; Write((byte)vd.Sex); // vd->sex; Write((obj as WorldObjectUnit).Location); Write((byte)(obj is Character ? 5 : 0)); // (sd) ? 5 : 0; Write((byte)(obj is Character ? 5 : 0)); // (sd) ? 5 : 0; Write((short)WorldObject.GetLevel(obj)); // clif_setlevel(status_get_lv(bl)); Write((short)0); // sd ? sd->state.user_font : 0; int pos = Writer.Position; Write(name); pos = Writer.Position; }
public MonsterDatabaseData() : base() { // TODO: this is just a hack to let status know that this is mob status // find some other way than a none-existing mob.. Status = new WorldObjectStatus(mEmptyMonster); Drops = new MonsterDropList(); Skills = new MonsterSkillList(); ViewData = new WorldObjectViewData(); SpawnInfo = new List<MonsterSpawnInfo>(); }
public static WorldObjectViewData GetViewData(DatabaseObject obj, int classID) { // Load base values by ID (mob, npc, hom, merc, ..) WorldObjectViewData vd = null; // Fetch base view data if (obj.Serial.Type == EDatabaseType.Mob) { vd = (obj as MonsterDatabaseData).ViewData; } else { vd = new WorldObjectViewData(); } // Set specific values // TODO: why an additional switch for this? Oo .. switch (obj.Serial.Type) { case EDatabaseType.Npc: break; case EDatabaseType.Mob: break; case EDatabaseType.Char: Character c = (Character)World.Objects[EDatabaseType.Char, obj.Serial.ID]; if (Character.CheckID(classID) == true) { if ((c.StatusChange.Option & EStatusOption.Wedding) > 0) { classID = (int)EClientClass.Wedding; } else if ((c.StatusChange.Option & EStatusOption.Summer) > 0) { classID = (int)EClientClass.Summer; } else if ((c.StatusChange.Option & EStatusOption.Xmas) > 0) { classID = (int)EClientClass.Xmas; } else if ((c.StatusChange.Option & EStatusOption.Riding) > 0) { //Adapt class to a Mounted one. switch ((EClientClass)classID) { case EClientClass.Knight: classID = (int)EClientClass.Knight2; break; case EClientClass.Crusader: classID = (int)EClientClass.Crusader2; break; case EClientClass.LordKnight: classID = (int)EClientClass.LordKnight2; break; case EClientClass.Paladin: classID = (int)EClientClass.Paladin2; break; case EClientClass.BabyKnight: classID = (int)EClientClass.BabyKnight2; break; case EClientClass.BabyCrusader: classID = (int)EClientClass.BabyCrusader2; break; } } // TODO: why the hell have they another datatype? vd.Class = (ushort)classID; //clif_get_weapon_view(sd, &sd->vd.weapon, &sd->vd.shield); vd.HeadTop = (ushort)c.Status.HeadTop; vd.HeadMid = (ushort)c.Status.HeadMid; vd.HeadBottom = (ushort)c.Status.HeadBottom; vd.HairStlye = (ushort)c.Status.HairStyle; vd.HairColor = (ushort)c.Status.HairColor; vd.ClothesColor = (ushort)c.Status.ClothColor; vd.Sex = c.Status.Sex; } else { } break; } return(vd); }
/// First packet after selecting a character /// 0x0436 19: <accountID>.L <charID>.L <loginID1>.L <clientTick>.L <sex>.B public static void WantToConnect(NetState state, PacketReader reader) { int accountID = reader.ReadInt32(); int charID = reader.ReadInt32(); int loginID1 = reader.ReadInt32(); int clientTick = reader.ReadInt32(); byte iSex = reader.ReadByte(); EAccountSex sex = (EAccountSex)iSex; state.Account = (Account)World.Objects[EDatabaseType.Account, accountID]; if (state.Account == null || state.Account.AccountState != EAccountState.Char) { ServerConsole.DebugLine("Invalid account or account state: {0}", (state.Account != null ? state.Account.AccountState.ToString() : "null")); state.Disconnect(); return; } if (state.Account.LoginID1 != loginID1 || state.Account.Sex != sex) { ServerConsole.DebugLine("Invalid loginID or sex: {0} != {1}; {2} != {3}", state.Account.LoginID1, loginID1, state.Account.Sex, sex); state.Disconnect(); return; } if (state.Account.ActiveChar == null || state.Account.ActiveChar.ID != charID) { ServerConsole.DebugLine("Invalid active character or charID: {0}", (state.ActiveChar != null ? state.ActiveChar.ID.ToString() : "null")); state.Disconnect(); return; } // Seems to be valid, save the netstate state.Account.Netstate = state; long tick = Timer.Ticks; // Mark as authed state.Account.AccountState = EAccountState.World; // pc_setnew state.ActiveChar.Status.Sex = state.Account.Sex; state.ActiveChar.LoginID1 = loginID1; state.ActiveChar.LoginID2 = 0; state.ActiveChar.ClientTick = clientTick; state.ActiveChar.State.Active = false; //Is set to true after player is fully authed and loaded state.ActiveChar.CanLogTick = tick; // Required to prevent homunculus copuing a base speed of 0 state.ActiveChar.BattleStatus.Speed = (ushort)Global.DEFAULT_WALK_SPEED; // pc_authok if (state.ActiveChar.Status.HP == 0) { state.ActiveChar.SetDead(); } state.ActiveChar.State.ConnectNew = true; state.ActiveChar.FollowTimer = null; state.ActiveChar.InvisibleTimer = null; state.ActiveChar.NpcTimer = null; state.ActiveChar.PvpTimer = null; state.ActiveChar.CanUseItemTick = tick; state.ActiveChar.CanUseCashFoodTick = tick; state.ActiveChar.CanEquipTick = tick; state.ActiveChar.CanTalkTick = tick; state.ActiveChar.CanSendMailTick = tick; state.ActiveChar.SpiritTimer = new List <Timer>(); state.ActiveChar.AutoBonus.Clear(); state.ActiveChar.AutoBonus2.Clear(); state.ActiveChar.AutoBonus3.Clear(); if (Config.ItemAutoGet) { state.ActiveChar.State.Autoloot = 10000; } if (Config.DispExperience) { state.ActiveChar.State.Showexp = true; } if (Config.DispZeny) { state.ActiveChar.State.Showzeny = true; } if ((Config.DisplaySkillFail & 2) > 0) { state.ActiveChar.State.Showdelay = true; } // Check and move equip //pc_setinventorydata(sd); for (int i = 0; i < state.ActiveChar.Status.Inventory.Count; i++) { } //pc_setequipindex(sd); // status_change_init here! // Note: eAthena dosnt realy init the status here, just memset() all to 0 // TODO: why did i set StatusChange.Clear() HERE? confirm this.. state.ActiveChar.StatusChange.Clear(); // TODO: implement player commands (eAthenas @commands) //if ((battle_config.atc_gmonly == 0 || pc_isGM(sd)) && (pc_isGM(sd) >= get_atcommand_level(atcommand_hide))) // sd->status.option &= (OPTION_MASK | OPTION_INVISIBLE); //else state.ActiveChar.Status.Option &= EStatusOption.Mask; state.ActiveChar.StatusChange.Option = state.ActiveChar.Status.Option; // This is the actual option used in battle // Set here because we need the inventory data for weapon sprite parsing state.ActiveChar.ViewData = WorldObjectViewData.GetViewData(state.ActiveChar.Status, (int)state.ActiveChar.Status.Class); // Set base timer for walkable units (from unit_setdata) // TODO: maybe this should be placed in a WorldObjectUnit-method to be used for every walkable unit.. state.ActiveChar.WalkTimer = null; state.ActiveChar.ActiveSkillTimer = null; state.ActiveChar.AttackTimer = null; state.ActiveChar.AttackableTick = state.ActiveChar.CanActTick = state.ActiveChar.CanMoveTick = tick; // clif_authok crap state.ActiveChar.GuildPosition = new Point2D(-1, -1); // Event timer state.ActiveChar.EventTimer = new List <Timer>(); // Rental Timer state.ActiveChar.RentalTimer = null; state.ActiveChar.HateMob = new short[3] { -1, -1, -1 }; // Character enters the map block // TODO: Position checking state.ActiveChar.Location.Map.OnEnter(state.ActiveChar); /* * if ((i = pc_setpos(sd, sd->status.last_point.map, sd->status.last_point.x, sd->status.last_point.y, CLR_OUTSIGHT)) != 0) { * ShowError("Last_point_map %s - id %d not found (error code %d)\n", mapindex_id2name(sd->status.last_point.map), sd->status.last_point.map, i); * * // try warping to a default map instead (church graveyard) * if (pc_setpos(sd, mapindex_name2id(MAP_PRONTERA), 273, 354, CLR_OUTSIGHT) != 0) { * // if we fail again * clif_authfail_fd(sd->fd, 0); * return false; * } * } */ // Let the client know that the authendication was successfull state.Send(new WorldResponseAuthOK(state.Account)); // eA puts the "char logged in" message here.. // TODO: send friend list // TODO: message about expired accounts, night flag // TODO: request registry // or dont need an async load of registry? state.ActiveChar.DieCounter = -1; }
public Character(DatabaseID dbID, bool addToWorld) : base(dbID, addToWorld) { BaseStatus = new WorldObjectStatus(this); BattleStatus = new WorldObjectStatus(this); ViewData = new WorldObjectViewData(); StatusChange = new WorldObjectStatusChangeList(); // TODO: i dont where eAthena initialize them realy.. // they using struct, which cant be null x.x Regen = new WorldObjectRegenerationData(this); HPRegen = new StatusVariationData(); SPRegen = new StatusVariationData(); SRegen = new CharacterRegenerationData(); SSRegen = new CharacterRegenerationData(); }
public WorldSendUnitIdle(WorldObject obj, bool spawn) : base(0) { string name = WorldObject.GetName(obj); WorldObjectStatus status = WorldObject.GetStatusData(obj); WorldObjectViewData vd = WorldObject.GetViewData(obj); WorldObjectStatusChangeList sc = WorldObject.GetStatusChange(obj); ushort speed = WorldObject.GetSpeed(obj); Writer.Position = 0; Write((short)(spawn ? 0x7f8 : 0x7f9)); Write((short)((spawn ? 62 : 63) + name.Length)); Write((byte)obj.GetPacketType()); Write((uint)(obj is Character ? (obj as Character).Account.ID : obj.ID)); // For Character, send accountID as unique ID Write((ushort)speed); // status_get_speed(bl); Write((short)(sc != null ? sc.Option1 : 0)); // (sc) ? sc->opt1 : 0; Write((short)(sc != null ? sc.Option2 : 0)); // (sc) ? sc->opt2 : 0; Write((int)(sc != null ? sc.Option : 0)); // (sc) ? sc->option : 0; Write((short)(obj is NpcScript ? (obj as NpcScript).Class : (short)vd.Class)); // vd->class_; Write((short)(vd != null ? vd.HairStlye : 0)); // vd->hair_style; Write((short)(vd != null ? vd.Weapon : 0)); // vd->weapon; Write((short)(vd != null ? vd.Shield : 0)); // vd->shield; Write((short)(vd != null ? vd.HeadBottom : 0)); // vd->head_bottom Write((short)(vd != null ? vd.HeadTop : 0)); // vd->head_top; Write((short)(vd != null ? vd.HeadMid : 0)); // vd->head_mid; // TODO: implementieren! /* * if (bl->type == BL_NPC && vd->class_ == FLAG_CLASS) { //The hell, why flags work like this? * WBUFL(buf, 22) = status_get_emblem_id(bl); * WBUFL(buf, 26) = status_get_guild_id(bl); * } */ Write((short)(vd != null ? vd.HairColor : 0)); // vd->hair_color; Write((short)(vd != null ? vd.ClothesColor : 0)); // vd->cloth_color; Write((short)0); // (sd) ? sd->head_dir : 0; Write((int)0); // status_get_guild_id(bl); Write((short)0); // status_get_emblem_id(bl); Write((short)0); // (sd) ? sd->status.manner : 0; Write((int)(sc != null ? sc.Option3 : 0)); // (sc) ? sc->opt3 : 0; Write((byte)0); // (sd) ? sd->status.karma : 0; Write((byte)(vd != null ? vd.Sex : 0)); // vd->sex; Write((obj as WorldObjectUnit).Location); Write((byte)(obj is Character ? 5 : 0)); // (sd) ? 5 : 0; Write((byte)(obj is Character ? 5 : 0)); // (sd) ? 5 : 0; if (!spawn) { Write((byte)(vd != null ? vd.DeadSit : 0)); // vd->dead_sit; } Write((short)WorldObject.GetLevel(obj)); // clif_setlevel(status_get_lv(bl)); Write((short)0); // sd ? sd->state.user_font : 0; int pos = Writer.Position; Write(name); pos = Writer.Position; }