/** * @function GUI_ObjSetFocused * @brief set the flag <Focused> of a generic object * @param const g_obj_st *obj: generic object * @param bool p: new flag value * @return none */ void GUI_ObjSetFocused(g_obj_st /*@null@*/ *obj, bool p) { g_obj_st *ptr; if(obj == NULL) obj = lastAddedObj; if(obj != NULL) { /*if focus == true, we shall check that the given object can receive focus */ if(p == true) { if(GUI_ObjIsFocusable(obj) && GUI_ObjIsDisabled(obj) == false && GUI_ObjIsFocused(obj) == false) { /*find & clear previously focused object*/ ptr = GetObjectList(); while(ptr != NULL) { if(GUI_ObjIsFocused(ptr)) { StateSet(ptr, OBJ_S_FOCUSED, false); GUI_ObjSetNeedRefresh(ptr, true); } ptr = ptr->next; } /*give focus to object*/ StateSet(obj, OBJ_S_FOCUSED, true); GUI_ObjSetNeedRefresh(obj, true); } } else { if(GUI_ObjIsFocused(obj)) { StateSet(obj, OBJ_S_FOCUSED, false); GUI_ObjSetNeedRefresh(obj, true); } } } }
/** * @function GUI_GroupRefresh * @brief force refresh o group of object * @param group_t g: selected group * @param bool p * @return none */ void GUI_GroupRefresh(group_t g, bool p) { g_obj_st *ptr = GetObjectList(); while(ptr != NULL) { if(ptr->group == g) GUI_ObjSetNeedRefresh(ptr, p); ptr = ptr->next; } }
/** * @function GUI_GroupNotify * @brief notify or not a group of object * @param group_t g: selected group * @param bool p: notified / not notified * @return none */ void GUI_GroupNotify(group_t g, bool p) { g_obj_st *ptr = GetObjectList(); while(ptr != NULL) { if(ptr->group == g) GUI_ObjSetNotified(ptr, p); ptr = ptr->next; } }
bool Model::ImportUVCoords (Model* other, IProgressCtl &progctl) { vector <MdlObject*> objects=GetObjectList (); MdlObject *srcobj = other->root; vector <Vector3> pverts; int numPl = 0, curPl=0; for (int a=0;a<objects.size();a++) numPl += objects[a]->poly.size(); for (int a=0;a<objects.size();a++) { MdlObject *obj = objects[a]; Matrix objTransform; obj->GetFullTransform(objTransform); // give each polygon an independent set of vertices, this will be optimized back to normal later vector <Vertex> nverts; for (int b=0;b<obj->poly.size();b++) { Poly *pl = obj->poly[b]; for (int v=0;v<pl->verts.size();v++) { nverts.push_back (obj->verts[pl->verts[v]]); pl->verts[v]=nverts.size()-1; } } obj->verts=nverts; // match our polygons with the ones of the other model for (int b=0;b<obj->poly.size();b++) { Poly *pl = obj->poly[b]; pverts.clear(); for (int pv=0;pv<pl->verts.size();pv++) { Vector3 tpos; objTransform.apply (&obj->verts [pl->verts[pv]].pos, &tpos); pverts.push_back (tpos); } int startVertex; int bestpl = MatchPolygon (srcobj,pverts,startVertex); if (bestpl >= 0) { // copy texture coordinates from rt->poly[bestpl] to pl Poly *src = srcobj->poly [bestpl]; for (int v=0;v<src->verts.size();v++) { Vertex &dstvrt = obj->verts[pl->verts[(v + startVertex)%pl->verts.size()]]; dstvrt.tc[0] = srcobj->verts[src->verts[v]].tc[0]; } } progctl.Update ((float)(curPl++) / numPl); } obj->Optimize (); obj->InvalidateRenderData(); } return true; }
// Vtable functions // Creates: A single Game Object via the Factory GameObject *Object2Create ( void ) { List *GameObjectList = GetObjectList( ); Node *node = InsertBackRaw( GameObjectList, sizeof( Object2 ) ); GameObject *obj = &NODE_DATA( node, GameObject ); obj->id = ID_Object2; return obj; }
void Model::CalculateRadius () { vector<MdlObject*> objs = GetObjectList(); radius=0.0f; for (int o=0;o<objs.size();o++) { MdlObject *obj = objs[o]; Matrix objTransform; obj->GetFullTransform(objTransform); for(int v=0;v<obj->verts.size();v++){ Vector3 tpos; objTransform.apply(&obj->verts[v].pos,&tpos); float r= (tpos-mid).length(); if (radius < r) radius=r; } } }
// Set target for client void _Battle::ClientSetTarget(const _Item *Item, int Side, _Object *InitialTarget) { ClientPlayer->Character->Targets.clear(); // Can't change self targets if(Item->TargetID == TargetType::SELF) { ClientPlayer->Character->Targets.push_back(ClientPlayer); return; } // Get list of objects on each side std::list<_Object *> ObjectList; GetObjectList(Side, ObjectList); auto Iterator = ObjectList.begin(); // Get iterator to last target _Object *LastTarget = InitialTarget; if(ObjectList.size() && LastTarget && Item->CanTarget(ClientPlayer, LastTarget)) Iterator = std::find(ObjectList.begin(), ObjectList.end(), LastTarget); // Set up targets int TargetCount = Item->GetTargetCount(); for(size_t i = 0; i < ObjectList.size(); i++) { // Check for valid target _Object *Target = *Iterator; if(Item->CanTarget(ClientPlayer, Target)) { // Add object to list of targets ClientPlayer->Character->Targets.push_back(Target); // Update count TargetCount--; if(TargetCount <= 0) break; } // Update target ++Iterator; if(Iterator == ObjectList.end()) Iterator = ObjectList.begin(); } }
// End battle and give rewards void _Battle::ServerEndBattle() { // Get statistics for each side _BattleResult SideStats[2]; std::list<_Object *> SideObjects[2]; for(int Side = 0; Side < 2; Side++) { // Get a list of objects that are still in the battle GetObjectList(Side, SideObjects[Side]); // Loop through objects for(auto &Object : SideObjects[Side]) { // Keep track of players if(!Object->IsMonster()) SideStats[Side].PlayerCount++; else SideStats[Side].MonsterCount++; if(Object->Fighter->JoinedBattle) SideStats[Side].JoinedCount++; // Tally alive objects if(Object->Character->IsAlive()) { SideStats[Side].AliveCount++; SideStats[Side].Dead = false; } // Sum experience and gold SideStats[Side].TotalExperienceGiven += Object->Monster->ExperienceGiven; // Calculate gold based on monster or player if(Object->IsMonster()) SideStats[Side].TotalGoldGiven += Object->Monster->GoldGiven + Object->Fighter->GoldStolen; else SideStats[Side].TotalGoldGiven += Object->Character->Bounty + Object->Fighter->GoldStolen + (int)(Object->Character->Gold * BountyEarned + 0.5f); } SideStats[Side].TotalExperienceGiven = (int)std::ceil(SideStats[Side].TotalExperienceGiven * Difficulty[Side]); SideStats[Side].TotalGoldGiven = (int)std::ceil(SideStats[Side].TotalGoldGiven * Difficulty[Side]); } // Get winning side int WinningSide; if(SideStats[0].Dead && SideStats[1].Dead) WinningSide = -1; else if(SideStats[0].Dead) WinningSide = 1; else WinningSide = 0; // Check for a winning side if(WinningSide != -1 && SideObjects[WinningSide].size()) { // Divide up rewards for(int Side = 0; Side < 2; Side++) { int OtherSide = !Side; int DivideCount = SideStats[Side].AliveCount; if(DivideCount <= 0) continue; // Divide experience up if(SideStats[OtherSide].TotalExperienceGiven > 0) { SideStats[Side].ExperiencePerCharacter = SideStats[OtherSide].TotalExperienceGiven / DivideCount; if(SideStats[Side].ExperiencePerCharacter <= 0) SideStats[Side].ExperiencePerCharacter = 1; } // Divide gold up if(SideStats[OtherSide].TotalGoldGiven > 0) { SideStats[Side].GoldPerCharacter = SideStats[OtherSide].TotalGoldGiven / DivideCount; if(SideStats[Side].GoldPerCharacter <= 0) SideStats[Side].GoldPerCharacter = 1; } } // Get list of objects that get rewards std::list<_Object *> RewardObjects; int DropRate = 0; for(auto &Object : SideObjects[WinningSide]) { if(Object->Character->IsAlive()) { DropRate += Object->Character->DropRate; RewardObjects.push_back(Object); } } // Check for reward recipients if(RewardObjects.size() && !PVP) { // Convert winning side list to array std::vector<_Object *> ObjectArray { std::begin(RewardObjects), std::end(RewardObjects) }; // Generate items drops std::list<uint32_t> ItemDrops; for(auto &Object : SideObjects[!WinningSide]) { if(Object->IsMonster()) Stats->GenerateItemDrops(Object->Monster->DatabaseID, 1, DropRate, ItemDrops); } // Boss drops aren't divided up if(Boss) { for(auto &ItemID : ItemDrops) { for(auto &Object : RewardObjects) { Object->Fighter->ItemDropsReceived.push_back(ItemID); } } } // Give out drops randomly else { for(auto &ItemID : ItemDrops) { std::shuffle(ObjectArray.begin(), ObjectArray.end(), ae::RandomGenerator); _Object *Object = ObjectArray[0]; Object->Fighter->ItemDropsReceived.push_back(ItemID); } } } } // Send data for(auto &Object : Objects) { Object->Controller->InputStates.clear(); Object->Fighter->PotentialAction.Unset(); Object->Character->Action.Unset(); // Get rewards int ExperienceEarned = 0; int GoldEarned = 0; if(!Object->Character->IsAlive()) { if(PVP) Object->ApplyDeathPenalty(BountyEarned, Object->Character->Bounty); else Object->ApplyDeathPenalty(PLAYER_DEATH_GOLD_PENALTY, 0); } else { ExperienceEarned = SideStats[WinningSide].ExperiencePerCharacter; GoldEarned = SideStats[WinningSide].GoldPerCharacter; Object->Character->PlayerKills += SideStats[!WinningSide].PlayerCount; Object->Character->MonsterKills += SideStats[!WinningSide].MonsterCount; if(PVP && Object->Fighter->BattleSide == BATTLE_PVP_ATTACKER_SIDE) { if(BountyEarned) { Object->Character->Bounty += GoldEarned; if(Object->Character->Bounty) { std::string BountyMessage = "Player " + Object->Name + " now has a bounty of " + std::to_string(Object->Character->Bounty) + " gold!"; Server->BroadcastMessage(nullptr, BountyMessage, "cyan"); Server->Log << "[BOUNTY] " << BountyMessage << std::endl; } } } } // Start cooldown timer if(Object->Character->IsAlive() && Cooldown > 0.0 && Zone) Object->Character->BattleCooldown[Zone] = Cooldown; // Update stats int CurrentLevel = Object->Character->Level; Object->Character->UpdateExperience(ExperienceEarned); Object->Character->UpdateGold(GoldEarned); Object->Character->CalculateStats(); int NewLevel = Object->Character->Level; if(NewLevel > CurrentLevel) { if(Object->Peer) Server->SendMessage(Object->Peer, std::string("You are now level " + std::to_string(NewLevel) + "!"), "gold"); Object->Character->Health = Object->Character->MaxHealth; Object->Character->Mana = Object->Character->MaxMana; } // Write results ae::_Buffer Packet; Packet.Write<PacketType>(PacketType::BATTLE_END); Packet.Write<int>(Object->Character->PlayerKills); Packet.Write<int>(Object->Character->MonsterKills); Packet.Write<int>(Object->Character->GoldLost); Packet.Write<int>(Object->Character->Bounty); Packet.Write<int>(ExperienceEarned); Packet.Write<int>(GoldEarned); // Sort item drops std::unordered_map<uint32_t, int> SortedItems; for(auto &ItemID : Object->Fighter->ItemDropsReceived) { SortedItems[ItemID]++; } Object->Fighter->ItemDropsReceived.clear(); // Write item count size_t ItemCount = SortedItems.size(); Packet.Write<uint8_t>((uint8_t)ItemCount); // Write items for(auto &Iterator : SortedItems) { Packet.Write<uint32_t>(Iterator.first); Packet.Write<uint8_t>(0); Packet.Write<uint8_t>((uint8_t)Iterator.second); Object->Inventory->AddItem(Stats->Items.at(Iterator.first), 0, Iterator.second); } // Update bot goal if(Object->Character->Bot) { if(Scripting->StartMethodCall("Bot_Server", "DetermineNextGoal")) { Scripting->PushObject(Object); Scripting->MethodCall(1, 0); Scripting->FinishMethodCall(); } } // Send info else if(Object->Peer) { Server->Network->SendPacket(Packet, Object->Peer); Server->SendHUD(Object->Peer); } } Deleted = true; }
// Changes targets void _Battle::ChangeTarget(int Direction, bool ChangeSides) { if(!ClientNetwork || !ClientPlayer->Fighter->PotentialAction.IsSet() || !ClientPlayer->Character->IsAlive() || !ClientPlayer->Character->Targets.size()) return; // Can't change self targetting actions const _Item *Item = ClientPlayer->Fighter->PotentialAction.Item; if(Item->TargetID == TargetType::SELF) return; // Get current target side int BattleTargetSide = ClientPlayer->Character->Targets.front()->Fighter->BattleSide; // Change sides if(Item->TargetID == TargetType::ANY && ChangeSides) BattleTargetSide = !BattleTargetSide; // Get list of objects on target side std::list<_Object *> ObjectList; GetObjectList(BattleTargetSide, ObjectList); // Get iterator to current target auto Iterator = ObjectList.begin(); if(ObjectList.size()) Iterator = std::find(ObjectList.begin(), ObjectList.end(), ClientPlayer->Character->Targets.front()); // Get target count size_t TargetCount = ClientPlayer->Character->Targets.size(); ClientPlayer->Character->Targets.clear(); // Get max available targets size_t MaxTargets = 0; for(auto &Target : ObjectList) { if(Item->CanTarget(ClientPlayer, Target)) MaxTargets++; } // Cap target count TargetCount = std::min(TargetCount, MaxTargets); // Search for valid target _Object *NewTarget = nullptr; while(TargetCount) { // Wrap around if(Iterator == ObjectList.end()) Iterator = ObjectList.begin(); // Update target if(Direction > 0) { ++Iterator; if(Iterator == ObjectList.end()) Iterator = ObjectList.begin(); NewTarget = *Iterator; } else if(Direction < 0) { if(Iterator == ObjectList.begin()) { Iterator = ObjectList.end(); --Iterator; } else { --Iterator; } NewTarget = *Iterator; } else NewTarget = *Iterator; // Check break condition if(Item->CanTarget(ClientPlayer, NewTarget)) { ClientPlayer->Character->Targets.push_back(NewTarget); // Update count TargetCount--; // Start moving down after first target found Direction = 1; } else if(ChangeSides) Direction = 1; } }
/** * @function GUI_DrawObjects * @brief handle all object (user event, refresh) * @param none * @return none */ void GUI_DrawObjects(void) { g_obj_st *ptr = NULL; coord_t newX, newY; /*reset signal & read touch screen; only once for all object*/ signal = 0; TouchScreenRead(&newX, &newY); /*small hysteresis to compensate touchscreen noise*/ #define TOUCH_THRES_HYS 2 if(newX < 0 || newY < 0) { x = y = -1; } else { if(x < 0 || y < 0) { x = newX; y = newY; } else if(P2D_Abs(newX - x) > TOUCH_THRES_HYS || P2D_Abs(newY - y) > TOUCH_THRES_HYS) { x = newX; y = newY; } } /*get the object list, according to the active layer*/ ptr = GetObjectList(); /*process notification blink*/ if(IsTimerElapsed(tmrBlink)) { bBlink = !bBlink; tmrBlink = GetPeriodicTimeout(500); while(ptr != NULL) { GUI_ObjSetBlink(ptr, bBlink); ptr = ptr->next; } } /*process each generic object of the current layer*/ while(ptr != NULL) { /*handle user interaction*/ HandleTouchEvent(x, y, ptr); /*handle object signals*/ HandleSignal(ptr); if(ptr->obj != NULL) { /*launch the object task, if any*/ if(ptr->task != NULL) ptr->task(ptr, ptr->obj); /*redraw the object, only if needed*/ if(GUI_ObjIsNeedRefresh(ptr) && ptr->draw != NULL) { P2D_SetClip(&(ptr->rec)); ptr->draw(ptr, ptr->obj); GUI_ObjSetNeedRefresh(ptr, false); } } /*next object*/ ptr = ptr->next; } /** * execute, if any, the top layer task * pInternalTask may close the top layer and return a signal; * when closing the top layer, pInternalTask becomes NULL * this signal will be given to the user at end of GUI_DrawObjects() */ if(pInternalTask != NULL) signal = pInternalTask(signal); /** * Save the last non null signal (for slave remote) */ if(signal != 0 && pInternalTask == NULL) { lastSignal = signal; } /** * execute the user task, if no internal task is running * DO NOT concate this condition with the previous one in a if/else statement ! */ if(pInternalTask == NULL) { if(pUserTask != NULL) pUserTask(signal); } }