/// This shows how to apply a concept to a collection of entities. void check_entity_collection_example() { std::vector<entity> elist = { /* ... lots of entities ... */ }; /// Check is elist contains AT LEAST one entity that satisfys /// the concept bool result = IsMonster().contains(elist); /// Try and find the first entity in a list that satisfys the concept. /// Return an iterator at the position of the entity /// (or end() if none is found) std::vector<entity>::iterator pos = IsHero().find(elist); /// Try and find the first entity that satisfys the concept. /// return a reference to that entity. Throw if not found. entity & hero = IsHero().get(elist); /// Create a "filtered_view" of a list of entities that contains /// only the entities that satisfy the concept. /// NOTE: filtered_view only provides iterators over the filtered view /// NO COPYS ARE MADE. auto view = IsMonster().filter(elist); /// Views can be used to iterator over matching entities for (auto & monster : view) { // this never fires REQUIRE_CONCEPT(monster, IsMonster); } /// Same as above, but iterators it reverse order auto rview = IsMonster().rfilter(elist); /// "apply" a filter to a given list. DO NOT modify the list. /// instead return a vector of reference's to entities that match. /// This is useful when you want to sort the matching entities. std::vector<std::reference<entity>> matching_entities = IsMonster().apply_filter(elist); }
// do buff skill bool CCharacter::BuffSkill( CCharacter* Target, CSkills* skill ) { Position->destiny = Position->current; //if(Battle->castTime == 0) //{ BEGINPACKET( pak, 0x7bb ); ADDWORD ( pak, clientid ); GServer->SendToVisible( &pak, (CCharacter*)this ); // Battle->castTime = clock(); // return true; //} //else //{ // clock_t etime = clock() - Battle->castTime; // if(etime < SKILL_DELAY) // return true; //} //Battle->castTime = 0; //Log(MSG_DEBUG,"applied buff skill %i",skill->id); UseBuffSkill( Target, skill ); Stats->MP -= (skill->mp - (skill->mp * Stats->MPReduction / 100)); if(Stats->MP < 0) Stats->MP = 0; GServer->DoSkillScript( this, skill ); //summons a monster. Why do we do this for all skills? if(!IsMonster()) { ClearBattle( Battle ); // clear battle for players when they use buff skills //Battle->bufftarget = 0; //Battle->skilltarget = 0; //Battle->skillid = 0; //Battle->atktype = NORMAL_ATTACK; } else //Monsters need to be reset to normal attack and clear skill attacks. { //Battle->atktarget = Battle->target; //Battle->bufftarget = 0; //Battle->skilltarget = 0; //Battle->skillid = 0; //Battle->atktype = NORMAL_ATTACK; //StartAction(Target, NORMAL_ATTACK); } Battle->lastAtkTime = clock( ); Battle->iscasting = 1; return true; }
const std::string& Ship::PublicName(int empire_id) const { // Disclose real ship name only to fleet owners. Rationale: a player who // doesn't know the design for a particular ship can easily guess it if the // ship's name is "Scout" // An exception is made for unowned monsters. if (GetUniverse().AllObjectsVisible() || empire_id == ALL_EMPIRES || OwnedBy(empire_id) || (IsMonster() && Owner() == ALL_EMPIRES)) return Name(); const ShipDesign* design = Design(); if (design) return design->Name(); else if (IsMonster()) return UserString("SM_MONSTER"); else if (!Unowned()) return UserString("FW_FOREIGN_SHIP"); else if (Unowned() && GetVisibility(empire_id) > VIS_NO_VISIBILITY) return UserString("FW_ROGUE_SHIP"); else return UserString("OBJ_SHIP"); }
// update position void CCharacter::UpdatePosition( ) { if(IsOnBattle( ) && Battle->target!=0) { CCharacter* Target = GetCharTarget( ); if(Target!=NULL) { if(IsMonster()) { float distance = GServer->distance( Position->current, Position->source ); if(distance>50)//AI should take care of this { OnFar( ); } //else Position->destiny = Target->Position->current; } //else Position->destiny = Target->Position->current; } else ClearBattle( Battle ); } if(!IsMoving()){ /* if(IsPlayer()) */ Position->lastMoveTime = clock(); return; } float dx = Position->destiny.x - Position->current.x; float dy = Position->destiny.y - Position->current.y; float distance = sqrt( (dx*dx) + (dy*dy) ); float ntime = ( distance / (float(Stats->Move_Speed)/100.f)) * CLOCKS_PER_SEC;// * 100000; clock_t etime = clock() - Position->lastMoveTime; if (ntime<=etime || distance==0) { Position->current.x = Position->destiny.x; Position->current.y = Position->destiny.y; } else { Position->current.x = dx*(etime/ntime) + Position->current.x; Position->current.y = dy*(etime/ntime) + Position->current.y; } Position->lastMoveTime = clock(); }
// update position void CCharacter::UpdatePosition( bool monster_stay_still ) { /* old version if(IsOnBattle( ) && Battle->target!=0) { CCharacter* Target = GetCharTarget( ); if(Target!=NULL) { if(IsMonster()) { float distance = GServer->distance( Position->current, Position->source ); if(distance>30) { if(Position->Map==8) Log(MSG_INFO,"Update Position, OnFar"); OnFar( ); } else { if (!monster_stay_still) Position->destiny = Target->Position->current; //MOBS ONLY else Log(MSG_INFO,"This one stays still"); if(Position->Map==8) Log(MSG_INFO,"Update Position, destiny=Target->Position->current (%2.f:%.2f)",Position->destiny.x,Position->destiny.y); } } else { if(Position->Map==8) Log(MSG_INFO,"Update Position Player, destiny=Target->Position->current (%2.f:%.2f)",Position->destiny.x,Position->destiny.y); Position->destiny = Target->Position->current; //ONLY IF NO TARGET ON BATTLE } } else { if(Position->Map==8) Log(MSG_INFO,"Update Position,no target, clear battle"); ClearBattle( Battle ); } } */ //LMA: osprose. if(IsOnBattle( ) && Battle->target!=0) { CCharacter* Target = GetCharTarget( ); if(Target == NULL) { ClearBattle( Battle ); } else { Position->destiny=Target->Position->current; } } //osprose end. if(Position->Map==8) { float tempdist = GServer->distance(Position->current,Position->destiny); if(IsPlayer()) { Log(MSG_INFO,"Player HP %I64i, (%.2f:%.2f)->(%.2f:%.2f)=%.2f speed %u",Stats->HP,Position->current.x,Position->current.y,Position->destiny.x,Position->destiny.y,tempdist,Stats->Move_Speed); } else { //Log(MSG_INFO,"Monster HP %I64i, (%.2f:%.2f)->(%.2f:%.2f)=%.2f speed %u",Stats->HP,Position->current.x,Position->current.y,Position->destiny.x,Position->destiny.y,tempdist,Stats->Move_Speed); //Log(MSG_LOAD,"Monster (%.2f:%.2f)->(%.2f:%.2f)",Position->current.x,Position->current.y,Position->destiny.x,Position->destiny.y); } } //LMA maps: special case (arrive in Game) //and he changed map (GM or scroll or teleporter or boat?) //2do: other cases too, all in fact... bool is_done=false; if (IsPlayer( )&&((last_map==-1&&last_coords==-1)||(last_map!=Position->Map))) { //updating player's grid int new_coords=0; int new_map=0; int grid_id=0; //deleting previous presence... if (last_map!=-1&&last_coords!=-1) { grid_id=GServer->allmaps[last_map].grid_id; if (grid_id!=-1&&!GServer->allmaps[last_map].always_on&&GServer->gridmaps[grid_id].coords[last_coords]>0) GServer->gridmaps[grid_id].coords[last_coords]--; } //New coordinates new_map=Position->Map; grid_id=GServer->allmaps[new_map].grid_id; new_coords=GServer->GetGridNumber(new_map,(UINT) floor(Position->current.x),(UINT) floor(Position->current.y)); last_map=new_map; last_coords=new_coords; if (grid_id!=-1||!GServer->allmaps[new_map].always_on) GServer->gridmaps[grid_id].coords[new_coords]++; is_done=true; } if(!IsMoving()) { //osprose if(IsPlayer())Position->lastMoveTime = clock(); //osprose end return; } float dx = Position->destiny.x - Position->current.x; float dy = Position->destiny.y - Position->current.y; float distance = sqrt( (dx*dx) + (dy*dy) ); float ntime = ( distance / Stats->Move_Speed * GServer->MOVE_SPEED_MODIF ); clock_t etime = clock() - Position->lastMoveTime; //LMA: bad, that's bad... //if (ntime<=etime || distance<1.0 ) if (ntime<=etime || distance<0.01 ) { // if (IsPlayer()) printf("Arrived! X: %i, Y: %i\n", (int)Position->current.x, (int)Position->current.y); if(Position->Map==8&&IsMonster()) Log(MSG_INFO," Monster Arrived, J (%.2f:%.2f)->(%.2f:%.2f)",Position->current.x,Position->current.y,Position->destiny.x,Position->destiny.y); Position->current.x = Position->destiny.x; Position->current.y = Position->destiny.y; } else { Position->current.x += dx*(etime/ntime); Position->current.y += dy*(etime/ntime); } Position->lastMoveTime = clock( ); //LMA: maps (for player) if(!IsPlayer()||is_done) return; //updating player's grid int new_coords=0; int new_map=0; int grid_id=0; new_map=Position->Map; grid_id=GServer->allmaps[new_map].grid_id; new_coords=GServer->GetGridNumber(new_map,(UINT) floor(Position->current.x),(UINT) floor(Position->current.y)); //changed? if (last_map==new_map&&new_coords==last_coords) return; //Let's update. if (grid_id!=-1||!GServer->allmaps[new_map].always_on) GServer->gridmaps[grid_id].coords[new_coords]++; //deleting player from his previous map grid_id=GServer->allmaps[last_map].grid_id; if (grid_id!=-1&&!GServer->allmaps[last_map].always_on&&GServer->gridmaps[grid_id].coords[last_coords]>0) GServer->gridmaps[grid_id].coords[last_coords]--; //Log(MSG_INFO,"Now[%i,%i],Was[%i,%i]",new_map,new_coords,last_map,last_coords); last_map=new_map; last_coords=new_coords; }
//arnold // do AoE skill bool CCharacter::AoeSkill( CSkills* skill, CCharacter* Enemy ) { Position->destiny = Position->current; //Log(MSG_INFO,"Doing AOE Skill"); //if(Battle->castTime == 0) //{ BEGINPACKET( pak, 0x7bb ); ADDWORD ( pak, clientid ); GServer->SendToVisible( &pak, (CCharacter*)this ); // Battle->castTime = clock(); // return true; //} //else //{ // clock_t etime = clock() - Battle->castTime; // if(etime < SKILL_DELAY) // return true; //} //Battle->castTime = 0; CMap* map = GServer->MapList.Index[Position->Map]; //PY replacement code if(IsPlayer() || IsSummon()) { for(UINT i=0;i<map->MonsterList.size();i++) { CMonster* monster = map->MonsterList.at(i); if(monster == NULL) continue; if(monster->clientid == clientid) continue; if(monster->IsSummon( ) && (map->allowpvp == 0 || monster->owner == clientid)) continue; if(GServer->IsMonInCircle( Position->skilltargetpos, monster->Position->current,(float)skill->aoeradius + 1)) UseAtkSkill( (CCharacter*) monster, skill ); } } if(IsMonster() && !IsSummon()) { for(UINT i=0;i<map->PlayerList.size();i++) { CPlayer* player = map->PlayerList.at(i); if(player == NULL)continue; if(player->clientid == clientid) continue; if(GServer->IsMonInCircle( Position->skilltargetpos,player->Position->current,(float)skill->aoeradius+1)) UseAtkSkill( (CCharacter*) player, skill ); } } //PY end // this code appears to me to be completely wrong replaced with code above /* for(UINT i=0;i<map->MonsterList.size();i++) { CMonster* monster = map->MonsterList.at(i); if(monster->clientid == clientid) continue; if(IsSummon( ) || IsPlayer( )) { if(monster->IsSummon( ) && (map->allowpvp==0 || monster->owner == clientid)) continue; } else { if(!monster->IsSummon( )) continue; } if(GServer->IsMonInCircle( Position->skilltargetpos, monster->Position->current,(float)skill->aoeradius + 1)) UseAtkSkill( (CCharacter*) monster, skill ); } if(map->allowpvp!=0 || (IsMonster( ) && !IsSummon( ))) { for(UINT i=0;i<map->PlayerList.size();i++) { CPlayer* player = map->PlayerList.at(i); if(player->clientid==clientid) continue; if(GServer->IsMonInCircle( Position->skilltargetpos,player->Position->current,(float)skill->aoeradius+1)) UseAtkSkill( (CCharacter*) player, skill ); } }*/ Battle->iscasting = 1; //Log(MSG_DEBUG,"Cast a skill. Iscasting set to true"); if(Enemy != NULL) { if(Enemy->IsDead( )) ClearBattle( Battle ); } else ClearBattle( Battle ); Stats->MP -= (skill->mp - (skill->mp * Stats->MPReduction / 100)); if(Stats->MP < 0) Stats->MP = 0; Battle->lastAtkTime = clock( ); return true; }
// do normal attack void CCharacter::NormalAttack( CCharacter* Enemy ) { Enemy->OnBeAttacked( this ); Position->destiny = Position->current; // new formula float levelmult = (float) Stats->Level / Enemy->Stats->Level; if(levelmult > 2)levelmult = 2; float atkdefmult = 0; float attack = 0; float constant = 4; if(Stats->magicattack == 1) { atkdefmult = (float) Stats->Attack_Power / Enemy->Stats->Magic_Defense; } else { atkdefmult = (float) Stats->Attack_Power / Enemy->Stats->Defense; } attack = Stats->Attack_Power * levelmult * atkdefmult / constant; if(attack < 5) attack = 5; float d_attack = attack / 100; float mod = GServer->RandNumber( 0, 10 ) * d_attack; attack += mod; long int hitpower = (long int)floor(attack); if(IsPlayer( )) //temp fix to find balance btw monster and player { hitpower = (long int)floor(attack * (GServer->Config.PlayerDmg/100.00)); hitpower+=((hitpower*(Stats->ExtraDamage))/100); } if(IsSummon( )) //temp fix to find balance btw monster and player { hitpower = (long int)floor(attack * (GServer->Config.PlayerDmg/100.00)); Log(MSG_DEBUG,"Summon hitpower = %i",hitpower); } if(IsMonster( )) //temp fix to find balance btw monster and player hitpower = (long int)floor(attack * (GServer->Config.MonsterDmg/100.00)); bool critical = false; if(hitpower <= 5) { hitpower = 5; } else { if(GServer->RandNumber(0,300)<Stats->Critical) { hitpower = (long int)floor(hitpower * 1.5); critical = true; } } // dodge unsigned int hitvalue = (unsigned int)floor((double)(Stats->Accury * 40 / Enemy->Stats->Dodge)); if(hitvalue > 100) hitvalue = 100; if(GServer->RandNumber( 0, 100 ) > hitvalue) hitpower = 0; // dodged if (hitpower > 0x7ff)//2047 packet size limit. { hitpower = 0x7ff; } Battle->atktarget = Battle->target; if(IsMonster()) { //Log(MSG_INFO,"Monster hits player for %i damage. Attack target = %i",hitpower,Battle->atktarget); } //Log( MSG_INFO, "hitpower %i. Attack %f ", hitpower,attack ); if(!Enemy->IsSummon( ) && Enemy->IsMonster( )) { Enemy->AddDamage( this, hitpower ); Enemy->damagecounter += hitpower;// is for AI } Enemy->Stats->HP -= hitpower; BEGINPACKET( pak, 0x799 ); ADDWORD ( pak, clientid ); ADDWORD ( pak, Battle->atktarget ); if(Enemy->IsDead()) { CDrop* thisdrop = NULL; ADDWORD ( pak, (hitpower | ( critical?0xb000:0x8000 ) )); if(!Enemy->IsSummon( ) && !Enemy->IsPlayer( )) { thisdrop = Enemy->GetDrop( ); if(thisdrop != NULL) { //ADDFLOAT ( pak, thisdrop->pos.x*100 ); //ADDFLOAT ( pak, thisdrop->pos.y*100 ); //if(thisdrop->type == 1) //{ // ADDWORD( pak, 0xccdf ); // ADDDWORD( pak, thisdrop->amount ); //} //else //{ // ADDWORD ( pak, GServer->BuildItemHead( thisdrop->item ) ); // ADDDWORD ( pak, GServer->BuildItemData( thisdrop->item ) ); //} //ADDWORD ( pak, thisdrop->clientid ); //ADDWORD ( pak, thisdrop->owner ); CMap* map = GServer->MapList.Index[thisdrop->posMap]; map->AddDrop( thisdrop ); } } GServer->SendToVisible( &pak, Enemy ); //, thisdrop ); OnEnemyDie( Enemy ); } else { ADDWORD ( pak, (hitpower|(hitpower>0?(critical?0x4000:0):0))); GServer->SendToVisible( &pak, Enemy ); } ReduceABC( ); Battle->lastAtkTime = clock( ); }
void CCharacter::UpdatePosition( bool monster_stay_still ) { //LMA: osprose. if(IsOnBattle( ) && Battle->target!=0) { CCharacter* Target = GetCharTarget( ); if(Target == NULL) { ClearBattle( Battle ); } else { //LMA: Don't need to move if the target is reached. //Bad idea since the monster can go away and it seems //player goes automatically after him client side... /* if (Battle->atktype==NORMAL_ATTACK) { if(!IsTargetReached( Target )) { Position->destiny=Target->Position->current; } } else { Position->destiny=Target->Position->current; } */ //So let's go back to the old way. //LMA: done in DoAttack... //Can be "dangerous" since it checks range for normal attack //and if we're with skills the range isn't the same so player changes //its destiny all the time from skill range to weapon range. /*if(!IsTargetReached( Target )) { Position->destiny=Target->Position->current; }*/ } } //osprose end. //LMA: position in map 8 /*if(Position->Map==8) { float tempdist = GServer->distance(Position->current,Position->destiny); if(IsPlayer()) { Log(MSG_INFO,"Player HP %I64i, (%.2f:%.2f)->(%.2f:%.2f)=%.2f speed %u",Stats->HP,Position->current.x,Position->current.y,Position->destiny.x,Position->destiny.y,tempdist,Stats->Move_Speed); } else { Log(MSG_INFO,"Monster HP %I64i, (%.2f:%.2f)->(%.2f:%.2f)=%.2f speed %u",Stats->HP,Position->current.x,Position->current.y,Position->destiny.x,Position->destiny.y,tempdist,Stats->Move_Speed); //Log(MSG_LOAD,"Monster (%.2f:%.2f)->(%.2f:%.2f)",Position->current.x,Position->current.y,Position->destiny.x,Position->destiny.y); } }*/ //LMA maps: special case (arrive in Game) //and he changed map (GM or scroll or teleporter or boat?) //2do: other cases too, all in fact... bool is_done=false; if (IsPlayer( )&&((last_map==-1&&last_coords==-1)||(last_map!=Position->Map))) { //updating player's grid int new_coords=0; int new_map=0; int grid_id=0; //deleting previous presence... if (last_map!=-1&&last_coords!=-1) { grid_id=GServer->allmaps[last_map].grid_id; if (grid_id!=-1&&!GServer->allmaps[last_map].always_on&&GServer->gridmaps[grid_id].coords[last_coords]>0) GServer->gridmaps[grid_id].coords[last_coords]--; } //New coordinates new_map=Position->Map; grid_id=GServer->allmaps[new_map].grid_id; if (grid_id==-1) { Log(MSG_WARNING,"It seems you forgot to declare map %i in map_grid.csv",new_map); } new_coords=GServer->GetGridNumber(new_map,(UINT) floor(Position->current.x),(UINT) floor(Position->current.y)); last_map=new_map; last_coords=new_coords; //if (grid_id!=-1||!GServer->allmaps[new_map].always_on) if (grid_id!=-1&&!GServer->allmaps[new_map].always_on) GServer->gridmaps[grid_id].coords[new_coords]++; is_done=true; } if(!IsMoving()) { //osprose if(IsPlayer()) { Position->current.x = Position->destiny.x; Position->current.y = Position->destiny.y; Position->lastMoveTime = clock(); } //osprose end return; } float dx = Position->destiny.x - Position->current.x; float dy = Position->destiny.y - Position->current.y; float distance = sqrt( (dx*dx) + (dy*dy) ); float ntime = ( distance / (float(Stats->Move_Speed)/100)) * CLOCKS_PER_SEC; clock_t etime = clock() - Position->lastMoveTime; //LMA: bad, that's bad... //if (ntime<=etime || distance<1.0 ) if (ntime<=etime || distance<0.01 ) { // if (IsPlayer()) printf("Arrived! X: %i, Y: %i\n", (int)Position->current.x, (int)Position->current.y); if(Position->Map==8&&IsMonster()) { Log(MSG_INFO," Monster Arrived, J (%.2f:%.2f)->(%.2f:%.2f)",Position->current.x,Position->current.y,Position->destiny.x,Position->destiny.y); } Position->current.x = Position->destiny.x; Position->current.y = Position->destiny.y; } else { Position->current.x = dx*(etime/ntime) + Position->current.x; Position->current.y = dy*(etime/ntime) + Position->current.y; } Position->lastMoveTime = clock( ); //LMA: maps (for player) if(!IsPlayer()||is_done) return; //updating player's grid int new_coords=0; int new_map=0; int grid_id=0; new_map=Position->Map; grid_id=GServer->allmaps[new_map].grid_id; if (grid_id==-1) { Log(MSG_WARNING,"It seems you forgot to declare map %i in map_grid.csv",new_map); } new_coords=GServer->GetGridNumber(new_map,(UINT) floor(Position->current.x),(UINT) floor(Position->current.y)); //changed? if (last_map==new_map&&new_coords==last_coords) return; //Let's update. //if (grid_id!=-1||!GServer->allmaps[new_map].always_on) if (grid_id!=-1&&!GServer->allmaps[new_map].always_on) GServer->gridmaps[grid_id].coords[new_coords]++; //deleting player from his previous map grid_id=GServer->allmaps[last_map].grid_id; if (grid_id!=-1&&!GServer->allmaps[last_map].always_on&&GServer->gridmaps[grid_id].coords[last_coords]>0) GServer->gridmaps[grid_id].coords[last_coords]--; //Log(MSG_INFO,"Now[%i,%i],Was[%i,%i]",new_map,new_coords,last_map,last_coords); last_map=new_map; last_coords=new_coords; }