public void Enter(NecClient client, MapPosition mapPosition = null) { if (client.map != null) { client.map.Leave(client); } client.map = this; _Logger.Info(client, $"Entering Map: {id}:{fullName}"); // If position is passed in use it and set character position, if null then use map default coords // If this isn't set here, the wrong coords are in character until send_movement_info updates it. if (mapPosition != null) { client.character.x = mapPosition.x; client.character.y = mapPosition.y; client.character.z = mapPosition.z; client.character.heading = mapPosition.heading; } //set character coords to default map entry coords If arriving form another map. else if (client.character.mapId != id) { client.character.x = x; client.character.y = y; client.character.z = z; client.character.heading = orientation; } client.character.mapId = id; client.character.mapChange = false; clientLookup.Add(client); _Logger.Debug($"Client Lookup count is now : {clientLookup.GetAll().Count} for map {id} "); _Logger.Debug($"Character State for character {client.character.name} is {client.character.state}"); //Send your character data to the other living or dead players on the map. //on successful map entry, update the client database position if (!_server.database.UpdateCharacter(client.character)) { _Logger.Error("Could not update the database with current known player position"); } if (!_server.database.UpdateSoul(client.soul)) { _Logger.Error("Could not update the database with soul details "); } //ToDo move all this rendering logic to Send_Map_Entry. We dont need a copy of this logic on every map instance. RecvDataNotifyCharaData myCharacterData = new RecvDataNotifyCharaData(client.character, client.soul.name); //dead //you are dead here. only getting soul form characters. sorry bro. if (client.character.state.HasFlag(CharacterState.SoulForm)) { foreach (NecClient otherClient in clientLookup.GetAll()) { if (otherClient == client) { continue; } if (otherClient.character.state.HasFlag(CharacterState.SoulForm)) { _server.router.Send(myCharacterData, otherClient); } } } else //Bro, you alive! You gon see living characters! { foreach (NecClient otherClient in clientLookup.GetAll()) { if (otherClient == client) { continue; } if (otherClient.character.state.HasFlag(CharacterState.SoulForm)) { continue; } _server.router.Send(myCharacterData, otherClient); } } if (client.union != null) { RecvDataNotifyUnionData myUnionData = new RecvDataNotifyUnionData(client.character, client.union.name); _server.router.Send(this, myUnionData, client); } Task.Delay(TimeSpan.FromSeconds(10)).ContinueWith (t1 => { foreach (MonsterSpawn monsterSpawn in monsterSpawns.Values) { if (monsterSpawn.active) { monsterSpawn.spawnActive = true; if (!monsterSpawn.taskActive) { MonsterTask monsterTask = new MonsterTask(_server, monsterSpawn); if (monsterSpawn.defaultCoords) { monsterTask.monsterHome = monsterSpawn.monsterCoords[0]; } else { monsterTask.monsterHome = monsterSpawn.monsterCoords.Find(x => x.coordIdx == 64); } monsterTask.Start(); } else { if (monsterSpawn.monsterVisible) { _Logger.Debug($"MonsterTask already running for [{monsterSpawn.name}]"); RecvDataNotifyMonsterData monsterData = new RecvDataNotifyMonsterData(monsterSpawn); _server.router.Send(monsterData, client); if (!monsterSpawn.GetAgro()) { monsterSpawn.MonsterMove(_server, client, monsterSpawn.monsterWalkVelocity, 2, 0); } } } } } } ); }
private void AttackObjectsInRange(NecClient client, int damage) { float perHp = 100.0f; //Damage Players in range foreach (NecClient targetClient in client.map.clientLookup.GetAll()) { if (targetClient == client) { continue; //skip damaging yourself } if (targetClient.character.partyId == client.character.partyId && client.character.partyId != 0) { continue; //skip damaging party members } //if (targetClient.Soul.CriminalLevel == 0 && client.CriminalOnlyDamage == true) continue; //skip attacking non criminal players. TODO double distanceToCharacter = Distance(targetClient.character.x, targetClient.character.y, client.character.x, client.character.y); _Logger.Debug( $"target Character name [{targetClient.character.name}] distanceToCharacter [{distanceToCharacter}] Radius { /*[{monsterSpawn.Radius}]*/" 125 "} {targetClient.character.name}"); if (distanceToCharacter > /*targetClient.Character.Radius +*/ 125) { continue; } if (targetClient.character.hp.depleted) { continue; } damage -= targetClient.character.battleParam.plusPhysicalDefence; if (damage < 0) { damage = 1; //pity damage } targetClient.character.hp.Modify(-damage, client.character.instanceId); perHp = (float)targetClient.character.hp.current / targetClient.character.hp.max * 100; _Logger.Debug( $"CurrentHp [{targetClient.character.hp.current}] MaxHp[{targetClient.character.hp.max}] perHp[{perHp}]"); RecvCharaUpdateHp cHpUpdate = new RecvCharaUpdateHp(targetClient.character.hp.current); _server.router.Send(targetClient, cHpUpdate.ToPacket()); //logic to turn characters to criminals on criminal actions. possibly should move to character task. client.character.criminalState += 1; if ((client.character.criminalState == 1) | (client.character.criminalState == 2) | (client.character.criminalState == 3)) { IBuffer res40 = BufferProvider.Provide(); res40.WriteUInt32(client.character.instanceId); res40.WriteByte(client.character.criminalState); _Logger.Debug($"Setting crime level for Character {client.character.name} to {client.character.criminalState}"); router.Send(client.map, (ushort)AreaPacketId.recv_chara_update_notify_crime_lv, res40, ServerType.Area); //Router.Send(client.Map, (ushort) AreaPacketId.recv_charabody_notify_crime_lv, res40, ServerType.Area, client); } if (client.character.criminalState > 255) { client.character.criminalState = 255; } DamageTheObject(client, targetClient.character.instanceId, damage, perHp); } //Damage Monsters in range foreach (MonsterSpawn monsterSpawn in client.map.monsterSpawns.Values) { double distanceToObject = Distance(monsterSpawn.x, monsterSpawn.y, client.character.x, client.character.y); //_Logger.Debug($"target Monster name [{monsterSpawn.name}] distanceToObject [{distanceToObject}] Radius [{monsterSpawn.radius}] {monsterSpawn.name}"); if (distanceToObject > monsterSpawn.radius * 5 ) //increased hitbox for monsters by a factor of 5. Beetle radius is 40 { continue; } if (monsterSpawn.hp.depleted) { continue; } monsterSpawn.hp.Modify(-damage, client.character.instanceId); perHp = (float)monsterSpawn.hp.current / monsterSpawn.hp.max * 100; _Logger.Debug($"CurrentHp [{monsterSpawn.hp.current}] MaxHp[{monsterSpawn.hp.max}] perHp[{perHp}]"); //just for fun. turn on inactive monsters if (monsterSpawn.active == false) { monsterSpawn.active = true; monsterSpawn.spawnActive = true; if (!monsterSpawn.taskActive) { MonsterTask monsterTask = new MonsterTask(_server, monsterSpawn); if (monsterSpawn.defaultCoords) { monsterTask.monsterHome = monsterSpawn.monsterCoords[0]; } else { monsterTask.monsterHome = monsterSpawn.monsterCoords.Find(x => x.coordIdx == 64); } monsterTask.Start(); } } DamageTheObject(client, monsterSpawn.instanceId, damage, perHp); } //Damage NPCs in range foreach (NpcSpawn npcSpawn in client.map.npcSpawns.Values) { double distanceToObject = Distance(npcSpawn.x, npcSpawn.y, client.character.x, client.character.y); // _Logger.Debug($"target NPC name [{npcSpawn.name}] distanceToObject [{distanceToObject}] Radius [{npcSpawn.radius}] {npcSpawn.name}"); if (distanceToObject > npcSpawn.radius) { continue; } //attacking an NPC is a misdimeanor crime for non-criminals. if ((client.character.criminalState == 0)) { client.character.criminalState += 1; IBuffer res40 = BufferProvider.Provide(); res40.WriteUInt32(client.character.instanceId); res40.WriteByte(client.character.criminalState); router.Send(client.map, (ushort)AreaPacketId.recv_chara_update_notify_crime_lv, res40, ServerType.Area); } DamageTheObject(client, npcSpawn.instanceId, damage, perHp); } }
public void Enter(NecClient client, MapPosition mapPosition = null) { if (client.Map != null) { client.Map.Leave(client); } Logger.Info(client, $"Entering Map: {Id}:{FullName}"); // If position is passed in use it and set character position, if null then use map default coords // If this isn't set here, the wrong coords are in character until send_movement_info updates it. if (mapPosition != null) { client.Character.X = mapPosition.X; client.Character.Y = mapPosition.Y; client.Character.Z = mapPosition.Z; client.Character.Heading = mapPosition.Heading; } else { client.Character.X = this.X; client.Character.Y = this.Y; client.Character.Z = this.Z; client.Character.Heading = this.Orientation; } client.Map = this; client.Character.MapId = Id; client.Character.mapChange = false; ClientLookup.Add(client); Logger.Debug($"Client Lookup count is now : {ClientLookup.GetAll().Count} for map {this.Id} "); RecvDataNotifyCharaData myCharacterData = new RecvDataNotifyCharaData(client.Character, client.Soul.Name); _server.Router.Send(this, myCharacterData, client); if (client.Union != null) { RecvDataNotifyUnionData myUnionData = new RecvDataNotifyUnionData(client.Character, client.Union.Name); _server.Router.Send(this, myUnionData, client); } foreach (MonsterSpawn monsterSpawn in this.MonsterSpawns.Values) { if (monsterSpawn.Active == true) { monsterSpawn.SpawnActive = true; if (!monsterSpawn.TaskActive) { MonsterTask monsterTask = new MonsterTask(_server, monsterSpawn); if (monsterSpawn.defaultCoords) { monsterTask.monsterHome = monsterSpawn.monsterCoords[0]; } else { monsterTask.monsterHome = monsterSpawn.monsterCoords.Find(x => x.CoordIdx == 64); } monsterTask.Start(); } else { if (monsterSpawn.MonsterVisible) { Logger.Debug($"MonsterTask already running for [{monsterSpawn.Name}]"); RecvDataNotifyMonsterData monsterData = new RecvDataNotifyMonsterData(monsterSpawn); _server.Router.Send(monsterData, client); if (!monsterSpawn.GetAgro()) { monsterSpawn.MonsterMove(_server, client, monsterSpawn.MonsterWalkVelocity, (byte)2, (byte)0); } } } } } //on successful map entry, update the client database position if (!_server.Database.UpdateCharacter(client.Character)) { Logger.Error("Could not update the database with current known player position"); } }