diff --git a/source/source/content/mob/bridge.cpp b/source/source/content/mob/bridge.cpp index 878ffc360..c9e749468 100644 --- a/source/source/content/mob/bridge.cpp +++ b/source/source/content/mob/bridge.cpp @@ -209,7 +209,7 @@ bool Bridge::checkHealth() { for(size_t m = 0; m < newMobs.size(); m++) { Mob* mPtr = newMobs[m]; enableFlag(mPtr->flags, MOB_FLAG_CAN_MOVE_MIDAIR); - mPtr->links.push_back(this); + mPtr->push_anonymous_link(this); } //Move the bridge object proper to the farthest point of the bridge. @@ -233,7 +233,7 @@ bool Bridge::checkHealth() { * @param m Bridge component mob. */ void Bridge::drawComponent(Mob* m) { - if(m->links.empty() || !m->links[0]) return; + if(m->link_anon_size==0 || !m->links["0"]) return; BitmapEffect eff; m->getSpriteBitmapEffects( @@ -241,7 +241,7 @@ void Bridge::drawComponent(Mob* m) { SPRITE_BMP_EFFECT_FLAG_SECTOR_BRIGHTNESS ); - Bridge* briPtr = (Bridge*) m->links[0]; + Bridge* briPtr = (Bridge*) m->links["0"]; string side = m->vars["side"]; ALLEGRO_BITMAP* texture = side == "left" ? @@ -346,10 +346,10 @@ void Bridge::readScriptVars(const ScriptVarReader &svr) { * like its linked destination object. */ void Bridge::setup() { - if(!links.empty() && links[0]) { - totalLength = Distance(pos, links[0]->pos).toFloat(); - face(getAngle(pos, links[0]->pos), nullptr, true); - deltaZ = links[0]->z - z; + if(!link_anon_size == 0 && links["0"]) { + totalLength = Distance(pos, links["0"]->pos).toFloat(); + face(getAngle(pos, links["0"]->pos), nullptr, true); + deltaZ = links["0"]->z - z; totalChunksNeeded = std::max( totalChunksNeeded, diff --git a/source/source/content/mob/mob.cpp b/source/source/content/mob/mob.cpp index 272417deb..e9656bdd0 100644 --- a/source/source/content/mob/mob.cpp +++ b/source/source/content/mob/mob.cpp @@ -252,6 +252,13 @@ void Mob::addToGroup(Mob* newMember) { } } +/** + * @brief counts the number of non identified links + */ +void Mob::push_anonymous_link(Mob* linkPtr) { + links[i2s(link_anon_size)]= linkPtr; + link_anon_size +=1; +} /** * @brief Applies the damage caused by an attack from another mob to this one. @@ -451,18 +458,21 @@ void Mob::arachnorbHeadTurnLogic() { float angleDeviationAvg = 0; size_t nFeet = 0; - for(size_t l = 0; l < links.size(); l++) { - if(!links[l]) { + for (const auto& [identifier, link] : links) { + if (!isNumber(identifier)){ + continue; + } + if(!link) { continue; } - if(!links[l]->parent) { + if(!link->parent) { continue; } - if(links[l]->parent->m != this) { + if(link->parent->m != this) { continue; } - if(links[l]->parent->limbParentBodyPart == INVALID) { + if(link->parent->limbParentBodyPart == INVALID) { continue; } @@ -472,11 +482,11 @@ void Mob::arachnorbHeadTurnLogic() { getAngle( Point(), getHitbox( - links[l]->parent->limbParentBodyPart + link->parent->limbParentBodyPart )->pos ); float curAngle = - getAngle(pos, links[l]->pos) - angle; + getAngle(pos, link->pos) - angle; float angleDeviation = getAngleCwDiff(defaultAngle, curAngle); if(angleDeviation > M_PI) { @@ -664,12 +674,14 @@ bool Mob::calculateCarryingDestination( //If it's towards a linked mob, just go to the closest one. Mob* closestLink = nullptr; Distance closestLinkDist; - - for(size_t s = 0; s < links.size(); s++) { - Distance d(pos, links[s]->pos); + for (const auto& [identifier, link] : links) { + if (!isNumber(identifier)){ + continue; + } + Distance d(pos, link->pos); if(!closestLink || d < closestLinkDist) { - closestLink = links[s]; + closestLink = link; closestLinkDist = d; } } @@ -692,12 +704,15 @@ bool Mob::calculateCarryingDestination( } unordered_set availableTypes; - vector > mobsPerType; + vector > mobsPerType; - for(size_t l = 0; l < links.size(); l++) { - if(!links[l]) continue; + for (const auto& [identifier, link] : links) { + if (!isNumber(identifier)){ + continue; + } + if(!link) continue; string typeName = - links[l]->vars["carry_destination_type"]; + link->vars["carry_destination_type"]; MobType* pikType = game.mobCategories.get(MOB_CATEGORY_PIKMIN)-> getType(typeName); @@ -707,7 +722,7 @@ bool Mob::calculateCarryingDestination( (PikminType*) pikType ); mobsPerType.push_back( - std::make_pair(links[l], (PikminType*) pikType) + std::make_pair(identifier,(PikminType*) pikType) ); } @@ -720,21 +735,21 @@ bool Mob::calculateCarryingDestination( decideCarryPikminType(availableTypes, added, removed); //Figure out which linked mob matches the decided type. - size_t closestTargetIdx = INVALID; + string closestTargetKey = ""; Distance closestTargetDist; for(size_t m = 0; m < mobsPerType.size(); m++) { if(mobsPerType[m].second != decidedType) continue; - Distance d(pos, mobsPerType[m].first->pos); - if(closestTargetIdx == INVALID || d < closestTargetDist) { + Distance d(pos, links.at(mobsPerType[m].first)->pos); + if(closestTargetKey.empty() || d < closestTargetDist) { closestTargetDist = d; - closestTargetIdx = m; + closestTargetKey = mobsPerType[m].first; } } //Finally, set the destination data. *targetType = decidedType; - *targetMob = links[closestTargetIdx]; + *targetMob = links.at(closestTargetKey); *targetPoint = (*targetMob)->pos; return true; @@ -1591,6 +1606,7 @@ void Mob::focusOnMob(Mob* m2) { } + /** * @brief Makes the mob start following a path. This populates the pathInfo * class member, and calculates a path to take. @@ -3296,10 +3312,10 @@ Mob* Mob::spawn(const MobType::SpawnInfo* info, MobType* typePtr) { } if(info->linkObjectToSpawn) { - links.push_back(newMob); + push_anonymous_link(newMob); } if(info->linkSpawnToObject) { - newMob->links.push_back(this); + newMob->push_anonymous_link(this); } if(info->momentum != 0) { float a = game.rng.f(0, TAU); diff --git a/source/source/content/mob/mob.h b/source/source/content/mob/mob.h index bcb1f8fd4..dd8b9e88c 100644 --- a/source/source/content/mob/mob.h +++ b/source/source/content/mob/mob.h @@ -255,8 +255,11 @@ class Mob { //-Interactions with other mobs- //Mobs it is linked to. - vector links; + map links; + //How many Anonymous Links there are + size_t link_anon_size=0; + //If it's being held by another mob, the information is kept here. HoldInfo holder; @@ -375,6 +378,7 @@ class Mob { void becomeCarriable(const CARRY_DESTINATION destination); void becomeUncarriable(); + void push_anonymous_link(Mob* linkPtr); void applyAttackDamage( Mob* attacker, Hitbox* attackH, Hitbox* victimH, float damage ); diff --git a/source/source/content/mob/mob_utils.cpp b/source/source/content/mob/mob_utils.cpp index b4a012c8b..61b0ba246 100644 --- a/source/source/content/mob/mob_utils.cpp +++ b/source/source/content/mob/mob_utils.cpp @@ -1272,9 +1272,9 @@ void deleteMob(Mob* mPtr, bool completeDestruction) { m2Ptr->chompingMobs[c] = nullptr; } } - for(size_t l = 0; l < m2Ptr->links.size(); l++) { - if(m2Ptr->links[l] == mPtr) { - m2Ptr->links[l] = nullptr; + for (const auto& [identifier, link] : m2Ptr->links) { + if(link == mPtr) { + m2Ptr->links[identifier] = nullptr; } } if(m2Ptr->storedInsideAnother == mPtr) { diff --git a/source/source/content/mob/pikmin.cpp b/source/source/content/mob/pikmin.cpp index 1da687ae7..f1be90017 100644 --- a/source/source/content/mob/pikmin.cpp +++ b/source/source/content/mob/pikmin.cpp @@ -587,8 +587,8 @@ void Pikmin::tickClassSpecifics(float deltaT) { bumpLock = std::max(bumpLock - deltaT, 0.0f); //Forcefully follow another mob as a leader. - if(mustFollowLinkAsLeader && !links.empty()) { - Mob* leader = links[0]; + if(mustFollowLinkAsLeader && !link_anon_size == 0 && links["0"]) { + Mob* leader = links["0"]; fsm.runEvent( MOB_EV_TOUCHED_ACTIVE_LEADER, (void*) (leader), diff --git a/source/source/content/mob_script/bouncer_fsm.cpp b/source/source/content/mob_script/bouncer_fsm.cpp index f1660e648..14f02e338 100644 --- a/source/source/content/mob_script/bouncer_fsm.cpp +++ b/source/source/content/mob_script/bouncer_fsm.cpp @@ -71,8 +71,8 @@ void BouncerFsm::handleMob(Mob* m, void* info1, void* info2) { Mob* toucher = (Mob*) info1; Mob* targetMob = nullptr; - if(!bouPtr->links.empty()) { - targetMob = bouPtr->links[0]; + if(!bouPtr->link_anon_size ==0 && bouPtr->links["0"]) { + targetMob = bouPtr->links["0"]; } if(!targetMob) { diff --git a/source/source/content/other/mob_script_action.cpp b/source/source/content/other/mob_script_action.cpp index 8880fea60..72a6d9783 100644 --- a/source/source/content/other/mob_script_action.cpp +++ b/source/source/content/other/mob_script_action.cpp @@ -440,9 +440,12 @@ bool MobActionLoaders::loadMobTargetType( call.args[argIdx] = i2s(MOB_ACTION_MOB_TARGET_TYPE_FOCUS); } else if(call.args[argIdx] == "trigger") { call.args[argIdx] = i2s(MOB_ACTION_MOB_TARGET_TYPE_TRIGGER); - } else if(call.args[argIdx] == "link") { + } else if(call.args[argIdx].find("link")==0) { + call.args.resize(17,""); + call.args[16]= call.args[argIdx].substr(4); call.args[argIdx] = i2s(MOB_ACTION_MOB_TARGET_TYPE_LINK); - } else if(call.args[argIdx] == "parent") { + } + else if(call.args[argIdx] == "parent") { call.args[argIdx] = i2s(MOB_ACTION_MOB_TARGET_TYPE_PARENT); } else { reportEnumError(call, argIdx); @@ -1349,8 +1352,12 @@ Mob* getTargetMob( return getTriggerMob(data); break; } case MOB_ACTION_MOB_TARGET_TYPE_LINK: { - if(!data.m->links.empty() && data.m->links[0]) { - return data.m->links[0]; + + if(data.args[16] == "" && !data.m->link_anon_size ==0 && data.m->links.find("0")!= data.m->links.end() && data.m->links["0"]) { + return data.m->links["0"]; + } + if(data.args[16] != "" && data.m->links.find(data.args[16]) != data.m->links.end()){ + return data.m->links[data.args[16]]; } break; } case MOB_ACTION_MOB_TARGET_TYPE_PARENT: { @@ -1441,14 +1448,17 @@ void MobActionRunners::linkWithFocus(MobActionRunData &data) { return; } - for(size_t l = 0; l < data.m->links.size(); l++) { - if(data.m->links[l] == data.m->focusedMob) { + for (const auto& [identifier, link] : data.m->links) { + if(link == data.m->focusedMob) { //Already linked. return; } } - - data.m->links.push_back(data.m->focusedMob); + if (data.args.size() <= 0){ + data.m->push_anonymous_link(data.m->focusedMob); + }else{ + data.m->links[data.args[0]] = data.m->focusedMob; + } } @@ -1543,9 +1553,9 @@ void MobActionRunners::moveToTarget(MobActionRunData &data) { } Point des; - for(size_t l = 0; l < data.m->links.size(); l++) { - if(!data.m->links[l]) continue; - des += data.m->links[l]->pos; + for (const auto& [identifier, link] : data.m->links) { + if(!link) continue; + des += link->pos; } des = des / data.m->links.size(); @@ -1671,10 +1681,12 @@ void MobActionRunners::sendMessageToFocus(MobActionRunData &data) { * @param data Data about the action call. */ void MobActionRunners::sendMessageToLinks(MobActionRunData &data) { - for(size_t l = 0; l < data.m->links.size(); l++) { - if(data.m->links[l] == data.m) continue; - if(!data.m->links[l]) continue; - data.m->sendScriptMessage(data.m->links[l], data.args[0]); + string receipient = data.args.size() > 1? data.args[1] : "0"; + for (const auto& [identifier, link] : data.m->links) { + if(link == data.m) continue; + if(!link) continue; + if(receipient != "0" && identifier != receipient) continue; + data.m->sendScriptMessage(link, data.args[0]); } } @@ -2002,28 +2014,28 @@ void MobActionRunners::spawn(MobActionRunData &data) { * @param data Data about the action call. */ void MobActionRunners::stabilizeZ(MobActionRunData &data) { - if(data.m->links.empty() || !data.m->links[0]) { + if(data.m->links.empty() || !data.m->links.begin()->second) { return; } - float bestMatchZ = data.m->links[0]->z; + float bestMatchZ = data.m->links.begin()->second->z; MOB_ACTION_STABILIZE_Z_TYPE t = (MOB_ACTION_STABILIZE_Z_TYPE) s2i(data.args[0]); - for(size_t l = 1; l < data.m->links.size(); l++) { + for (const auto& [identifier, link] : data.m->links) { - if(!data.m->links[l]) continue; + if(!link) continue; switch(t) { case MOB_ACTION_STABILIZE_Z_TYPE_HIGHEST: { - if(data.m->links[l]->z > bestMatchZ) { - bestMatchZ = data.m->links[l]->z; + if(link->z > bestMatchZ) { + bestMatchZ = link->z; } break; } case MOB_ACTION_STABILIZE_Z_TYPE_LOWEST: { - if(data.m->links[l]->z < bestMatchZ) { - bestMatchZ = data.m->links[l]->z; + if(link->z < bestMatchZ) { + bestMatchZ = link->z; } break; diff --git a/source/source/core/init.cpp b/source/source/core/init.cpp index 2fc19a195..5b9b27de3 100644 --- a/source/source/core/init.cpp +++ b/source/source/core/init.cpp @@ -1298,6 +1298,7 @@ void initMobActions() { nullptr ); + regParam("identifier", MOB_ACTION_PARAM_STRING, false, true); regAction( MOB_ACTION_LINK_WITH_FOCUS, "link_with_focused_mob", @@ -1414,6 +1415,7 @@ void initMobActions() { ); regParam("message", MOB_ACTION_PARAM_STRING, false, false); + regParam("identifier", MOB_ACTION_PARAM_STRING, false, true); regAction( MOB_ACTION_SEND_MESSAGE_TO_LINKS, "send_message_to_links", diff --git a/source/source/game_state/gameplay/gameplay.cpp b/source/source/game_state/gameplay/gameplay.cpp index c8cd166bc..7599e5754 100644 --- a/source/source/game_state/gameplay/gameplay.cpp +++ b/source/source/game_state/gameplay/gameplay.cpp @@ -929,7 +929,7 @@ void GameplayState::load() { for(size_t l = 0; l < genPtr->linkIdxs.size(); l++) { size_t linkTargetGenIdx = genPtr->linkIdxs[l]; Mob* linkTargetMobPtr = mobsPerGen[linkTargetGenIdx]; - mobPtr->links.push_back(linkTargetMobPtr); + mobPtr->push_anonymous_link(linkTargetMobPtr); } }