import statuses; import saving; tidy class Statuses : Component_Statuses, Savable { array statuses; array instances; int nextInstanceId = 1; bool delta = false; void save(SaveFile& file) { file << nextInstanceId; uint cnt = statuses.length; file << cnt; for(uint i = 0; i < cnt; ++i) file << statuses[i]; cnt = instances.length; file << cnt; for(uint i = 0; i < cnt; ++i) { file << statuses.find(instances[i].status); file << instances[i]; } } void load(SaveFile& file) { if(file < SV_0013) return; file >> nextInstanceId; uint cnt = 0; file >> cnt; statuses.length = cnt; for(uint i = 0; i < cnt; ++i) { @statuses[i] = Status(); file >> statuses[i]; } file >> cnt; instances.length = cnt; for(uint i = 0; i < cnt; ++i) { @instances[i] = StatusInstance(); int index = 0; file >> index; @instances[i].status = statuses[index]; file >> instances[i]; } } void getStatusEffects(Player& pl, Object& obj) { Empire@ plEmp = pl.emp; for(uint i = 0, cnt = statuses.length; i < cnt; ++i) { if(!statuses[i].isVisibleTo(obj, plEmp)) continue; yield(statuses[i]); } } uint get_statusEffectCount() { return statuses.length; } uint get_statusEffectType(uint index) { if(index >= statuses.length) return uint(-1); return statuses[index].type.id; } uint get_statusEffectStacks(uint index) { if(index >= statuses.length) return 0; return statuses[index].stacks; } Object@ get_statusEffectOriginObject(uint index) { if(index >= statuses.length) return null; return statuses[index].originObject; } Empire@ get_statusEffectOriginEmpire(uint index) { if(index >= statuses.length) return null; return statuses[index].originEmpire; } uint getStatusStackCountAny(uint typeId) { uint count = 0; for(uint i = 0, cnt = statuses.length; i < cnt; ++i) { if(statuses[i].type.id == typeId) count += statuses[i].stacks; } return count; } uint getStatusStackCount(uint typeId, Object@ originObject = null, Empire@ originEmpire = null) { uint count = 0; for(uint i = 0, cnt = statuses.length; i < cnt; ++i) { if(statuses[i].type.id == typeId && statuses[i].originObject is originObject && statuses[i].originEmpire is originEmpire) count += statuses[i].stacks; } return count; } uint get_statusInstanceCount() { return instances.length; } uint get_statusInstanceType(uint index) { if(index >= instances.length) return uint(-1); return instances[index].status.type.id; } int get_statusInstanceId(uint index) { if(index >= instances.length) return -1; return instances[index].id; } bool hasStatusEffect(uint typeId) { for(uint i = 0, cnt = statuses.length; i < cnt; ++i) { if(statuses[i].type.id == typeId) return true; } return false; } int addStatus(Object& obj, double timer, uint typeId, Empire@ boundEmpire = null, Region@ boundRegion = null, Empire@ originEmpire = null, Object@ originObject = null) { const StatusType@ type = getStatusType(typeId); if(type is null) return -1; Status@ status; if(type.collapses) { for(uint i = 0, cnt = statuses.length; i < cnt; ++i) { auto@ cur = statuses[i]; if(cur.type is type && originEmpire is cur.originEmpire && originObject is cur.originObject) { @status = cur; break; } } } if(status is null) { @status = Status(type); @status.originEmpire = originEmpire; @status.originObject = originObject; status.create(obj); statuses.insertLast(status); } auto@ instance = status.instance(obj); instance.id = nextInstanceId++; instance.timer = timer; @instance.boundEmpire = boundEmpire; @instance.boundRegion = boundRegion; instances.insertLast(instance); delta = true; return instance.id; } void addStatus(Object& obj, uint typeId, double timer = -1.0, Empire@ boundEmpire = null, Region@ boundRegion = null, Empire@ originEmpire = null, Object@ originObject = null) { addStatus(obj, timer, typeId, boundEmpire, boundRegion, originEmpire, originObject); } void addRandomCondition(Object& obj) { if(!obj.isPlanet) return; auto@ type = getRandomCondition(cast(obj)); if(type !is null) addStatus(obj, type.id); } void removeStatus(Object& obj, int id) { StatusInstance@ instance; for(uint i = 0, cnt = instances.length; i < cnt; ++i) { if(instances[i].id == id) { @instance = instances[i]; instances.removeAt(i); break; } } if(instance is null) return; instance.remove(obj); if(instance.status.stacks <= 0) { statuses.remove(instance.status); instance.status.destroy(obj); } delta = true; } bool isStatusInstanceActive(int id) { for(uint i = 0, cnt = instances.length; i < cnt; ++i) { if(instances[i].id == id) return true; } return false; } void removeStatusInstanceOfType(Object& obj, uint typeId) { StatusInstance@ instance; for(uint i = 0, cnt = instances.length; i < cnt; ++i) { auto@ inst = instances[i]; if(inst.boundEmpire !is null) continue; if(inst.boundRegion !is null) continue; if(inst.timer >= 0) continue; if(inst.status.type.id == typeId) { @instance = inst; instances.removeAt(i); break; } } if(instance is null) return; instance.remove(obj); if(instance.status.stacks <= 0) { statuses.remove(instance.status); instance.status.destroy(obj); } delta = true; } void removeStatusType(Object& obj, uint typeId) { uint index = uint(-1); for(uint i = 0, cnt = statuses.length; i < cnt; ++i) { auto@ cur = statuses[i]; if(cur.type.id == typeId) { index = i; break; } } if(index == uint(-1)) return; removeStatusTypeByIndex(obj, index); } void removeStatusTypeByIndex(Object& obj, uint index) { Status@ status; if(index < statuses.length) @status = statuses[index]; if(status is null) return; for(int j = instances.length - 1; j >= 0; --j) { if(instances[j].status is status) { status.remove(obj, instances[j]); instances.removeAt(j); } } statuses.removeAt(index); status.destroy(obj); delta = true; } void changeStatusOwner(Object& obj, Empire@ prevOwner, Empire@ newOwner) { for(int i = instances.length - 1; i >= 0; --i) { auto@ instance = instances[i]; if(instance.boundEmpire !is null && instance.boundEmpire is prevOwner) { instance.remove(obj); instances.removeAt(i); } } for(int i = statuses.length - 1; i >= 0; --i) { auto@ status = statuses[i]; if(status.stacks <= 0 || !status.ownerChange(obj, prevOwner, newOwner)) removeStatusTypeByIndex(obj, i); } } void changeStatusRegion(Object& obj, Region@ prevRegion, Region@ newRegion) { for(int i = instances.length - 1; i >= 0; --i) { auto@ instance = instances[i]; if(instance.boundRegion !is null && instance.boundRegion is prevRegion) { instance.remove(obj); instances.removeAt(i); } } for(int i = statuses.length - 1; i >= 0; --i) { auto@ status = statuses[i]; if(status.stacks <= 0 || !status.regionChange(obj, prevRegion, newRegion)) removeStatusTypeByIndex(obj, i); } } void removeRegionBoundStatus(Object& obj, Region@ region, uint typeId, double timer = -1.0) { for(int i = instances.length - 1; i >= 0; --i) { auto@ instance = instances[i]; if(instance.boundRegion is region && instance.status.type.id == typeId && abs(instance.timer - timer) < 0.9) { instances.removeAt(i); instance.remove(obj); for(int j = statuses.length - 1; j >= 0; --j) { auto@ status = statuses[j]; if(status.stacks <= 0) removeStatusTypeByIndex(obj, j); } break; } } } void statusTick(Object& obj, double time) { for(int i = instances.length - 1; i >= 0; --i) { auto@ instance = instances[i]; if(!instance.tick(obj, time)) instances.removeAt(i); } for(int i = statuses.length - 1; i >= 0; --i) { auto@ status = statuses[i]; if(status.stacks <= 0 || !status.tick(obj, time)) removeStatusTypeByIndex(obj, i); } } void destroyStatus(Object& obj) { for(int i = statuses.length - 1; i >= 0; --i) { auto@ status = statuses[i]; status.objectDestroy(obj); } for(uint i = 0; i < instances.length; ++i) { auto@ instance = instances[i]; instance.remove(obj); if(instance.status.stacks <= 0) { statuses.remove(instance.status); instance.status.destroy(obj); } } statuses.length = 0; instances.length = 0; } void writeStatuses(Message& msg) const { uint cnt = statuses.length; msg.writeSmall(cnt); for(uint i = 0; i < cnt; ++i) msg << statuses[i]; } bool writeStatusDelta(Message& msg) { if(delta) { delta = false; msg.write1(); writeStatuses(msg); return true; } return false; } };