You can. There is only a small piece of code needed where combat classes are managed. Era can be made implicit "combat class" or more logical would be, if it would be just a value you can refer to from promotions and other places. But I would need to see an example, how you would like to refer to eras from XMLs to conclude, how it should be done.But what I cannot as easily do is establish that as a Combat Class.
Combat Classes can be designators that can qualify or disqualify promotions and equipments, can be qualifiers or disqualifiers for combat modifiers, and many more subtle game functions.
But are you sure, you want to make things like this. I know it is an easy-to-do approach, but it is not very logical. Era do not determine any feature of units, that could be used to fight against them. +10% vs short-range archers, +10% vs long-range archers, +10% vs heavy armored infantry, +10% fast mounted units, this everything looks ok for me. But +10% vs ancient era units?For example: +10% vs Ancient Era Units becomes a use of a pre-existing CC tag for combat modifiers vs a particular CC rather than having to make a new tag for combat modifier vs a unit's era definition.
I have a challenge.
In BuildingInfos
This is a Prehistoric Building that requires Consumerism.
Would it be possible for this buiding to be autofilled have FreeStartEra be ANCIENT.
This would be based on the ERA of the PrereqTech
Prehistoric Buidings will have FreeStartEra be ANCIENT
Ancient Buildings will have it be CLASSICAL
Classical Buildings will have MEDIEVAL
and so on.
The code would be:
See PrereqTech in BuildInfos
Find Tech in TechInfos
Find <Era></Era> in Techinfos
Make a trigger rename list.
If TECH is PREHISTORIC put ANCIENT inside <PrereqTech><PrereqTech> of said building.
If TECH is ANCIENT put CLASSICAL inside <PrereqTech><PrereqTech> of said building.
Then we modders can edit select buildings to have NONE instead but the majority will be autofilled in.
This will allow us to really start at any Era.
This + what MrAzure wanted can be probably done now and it will cost me ~20 minutes so I can do it. But are you sure you want it?- no building that requires a population of more than 3 can ever be free
Perhaps originally it would've been more logical but it is not now considering how many functions and features work off of combat class that to simply plug in an era cc would enable.You can. There is only a small piece of code needed where combat classes are managed. Era can be made implicit "combat class" or more logical would be, if it would be just a value you can refer to from promotions and other places. But I would need to see an example, how you would like to refer to eras from XMLs to conclude, how it should be done.
You're thinking too hard. This was an overly basic example since basic is easier to express. I want to include these because they can be a useful tool for compound evaluations, filters, and perhaps modifiers.But are you sure, you want to make things like this. I know it is an easy-to-do approach, but it is not very logical. Era do not determine any feature of units, that could be used to fight against them. +10% vs short-range archers, +10% vs long-range archers, +10% vs heavy armored infantry, +10% fast mounted units, this everything looks ok for me. But +10% vs ancient era units?![]()
This is the worst attitude a programmer can have. Conceptual work and design is the most important part of software creating. Most of projects end up in a trash bin because of not doing this part properly. And no, it is not my opinion. I've seen statistics during my studies.And yes, we could work out something in the coding that auto-includes the era CC even on the base of the unit but it'd be a bit more processing delay than would be necessary as NO delay should be acceptable from such a minor issue. Much easier to auto-assign it to the unit when the unit is manifested into the game.
Ok ok. This one I can somehow buy.Consider this: A set of Leader traits that represents the leader fully embracing everything about a given era. It's the era he's born in or from or it's the era he's most drawn to and he naturally fits with that era. His people are thus more empowered by his efforts during this era and his troops are better trained. Thus, perhaps units OF that era gain a free promotion that states +10% Combat Modifier (to state something very basic) when owned by a Leader with that Era's trait.
It would be very easy to do in CvUnit. It would be a little better for the pedia if it was done in CvUnitInfo. I'm a little worried it might be a bit difficult to plug in this extra add-on CC to the vector without potential bugs... it'd be on the fringe of my ability anyhow. I certainly wouldn't mind if it was auto assigned to the base unit definition there after all modules have been loaded but before the end of the mod load sequence- I'm just not sure where and how exactly to add it. CvUnit, when initializing the unit, would be the easiest for me. So if you can pinpoint how to best add to the base unit definition that would be appreciated.This is the worst attitude a programmer can have. Conceptual work and design is the most important part of software creating. Most of projects end up in a trash bin because of not doing this part properly. And no, it is not my opinion. I've seen statistics during my studies.
But ok, we will see. Maybe you have a good idea, but can't say it precisely. So where are you planing to put this "auto-assigned" era information? In CvUnitInfo or in CvUnit? -- I assume "auto-assigned" does not mean assigned from an XML tag, but somehow evaluated in the dll and then assigned.
I do debate as if I already know what the proper conclusions are but largely that's due to having put a lot of thought into things already and trying to remap that fragmented thought process for others can be a bit frustrating. That said, I don't doubt your knowledge of coding. I've been reading what you've been discussing with Koshling and I usually can't follow the first bit of it, which would lend me to assume you do have 'serious knowledge'. Furthermore, I figured I was simply answering your questions as best I could. I'm not closed minded to new approaches but I'll explain why I didn't want to use a particular approach if you present one and I've given it previous consideration - this is not to say I refuse to see some rational that would overpower the 'cons' I bring up.Btw, perhaps you should try to reduce your cocksureness a little bit, when you are talking with someone more experienced then you? I am not talking here, because I do not have anything to do, but because I have some serious knowledge about how to do thing properly, which you probably don't.
This is what I was afraid of. If you will add it to CvUnit each unit object in game will grow. Then think about what happens if you fatten unit objects each time you need some minor thing. According to Koshling the objects are already insanely big and you have quite plenty of them in the game. People do not have infinite RAM. -- This should be stored in CvUnitInfo.It would be very easy to do in CvUnit. It would be a little better for the pedia if it was done in CvUnitInfo. I'm a little worried it might be a bit difficult to plug in this extra add-on CC to the vector without potential bugs... it'd be on the fringe of my ability anyhow. I certainly wouldn't mind if it was auto assigned to the base unit definition there after all modules have been loaded but before the end of the mod load sequence- I'm just not sure where and how exactly to add it. CvUnit, when initializing the unit, would be the easiest for me. So if you can pinpoint how to best add to the base unit definition that would be appreciated.
Recall the situation with this additional column in your gdocs. You do not put enough attention to what you are reading and it often ends like you have a bad picture of things. So maybe precise reading and asking for more explanations before criticism would be a good idea?I do debate as if I already know what the proper conclusions are but largely that's due to having put a lot of thought into things already and trying to remap that fragmented thought process for others can be a bit frustrating. That said, I don't doubt your knowledge of coding. I've been reading what you've been discussing with Koshling and I usually can't follow the first bit of it, which would lend me to assume you do have 'serious knowledge'. Furthermore, I figured I was simply answering your questions as best I could. I'm not closed minded to new approaches but I'll explain why I didn't want to use a particular approach if you present one and I've given it previous consideration - this is not to say I refuse to see some rational that would overpower the 'cons' I bring up.
You're going to tell me this is a bit of a mess at the moment and to some extent it is but it's due to evolving methods here and trying to keep compatibility with older methods that overcomplicated this a bit.Say me how do you store combat classes and how do you check if a unit has one. -- Names of classes, fields and methods, please.
int getSubCombatType(int i) const;
int getNumSubCombatTypes() const;
bool isSubCombatType(int i);
bool hasUnitCombat(UnitCombatTypes eUnitCombat) const;
std::vector<int> m_aiSubCombatTypes;
int CvUnitInfo::getSubCombatType(int i) const
{
return m_aiSubCombatTypes[i];
}
int CvUnitInfo::getNumSubCombatTypes() const
{
return (int)m_aiSubCombatTypes.size();
}
bool CvUnitInfo::isSubCombatType(int i)
{
FAssert (i > -1 && i < GC.getNumUnitCombatInfos());
if (find(m_aiSubCombatTypes.begin(), m_aiSubCombatTypes.end(), i) == m_aiSubCombatTypes.end())
{
return false;
}
return true;
}
stream->Read(&iNumElements);
m_aiSubCombatTypes.clear();
for(int i=0; i<iNumElements;i++)
{
stream->Read(&iElement);
m_aiSubCombatTypes.push_back(iElement);
}
stream->Write(m_aiSubCombatTypes.size());
for (std::vector<int>::iterator it = m_aiSubCombatTypes.begin(); it != m_aiSubCombatTypes.end(); ++it)
{
stream->Write(*it);
}
CheckSumC(iSum, m_aiSubCombatTypes);
if (GETXML->SetToChildByTagName(pXML->GetXML(),"SubCombatTypes"))
{
if (pXML->SkipToNextVal())
{
int iNumSibs = GETXML->GetNumChildren(pXML->GetXML());
m_aiSubCombatTypes.clear();
if (0 < iNumSibs)
{
if (pXML->GetChildXmlVal(szTextVal))
{
for (int j = 0; j < iNumSibs; j++)
{
m_aiSubCombatTypes.push_back(pXML->FindInInfoClass(szTextVal));
if (!pXML->GetNextXmlVal(szTextVal))
{
break;
}
}
GETXML->SetToParent(pXML->GetXML());
}
}
}
GETXML->SetToParent(pXML->GetXML());
}
if (getNumSubCombatTypes() == 0)
{
m_aiSubCombatTypes.clear();
for ( int i = 0; i < pClassInfo->getNumSubCombatTypes(); i++)
{
m_aiSubCombatTypes.push_back(pClassInfo->getSubCombatType(i));
}
}
bool CvUnitInfo::hasUnitCombat(UnitCombatTypes eUnitCombat) const
{
FAssert(0 <= eUnitCombat && eUnitCombat < GC.getNumUnitCombatInfos());
if ( m_abHasCombatType == NULL )
{
m_abHasCombatType = new bool[GC.getNumUnitCombatInfos()];
memset(m_abHasCombatType, 0, GC.getNumUnitCombatInfos());
for(int iI = 0; iI < GC.getNumUnitCombatInfos(); iI++)
{
if (getUnitCombatType() == iI)
{
m_abHasCombatType[iI] = true;
continue;
}
//TB SubCombat Mod Begin
for (int iJ = 0; iJ < getNumSubCombatTypes(); iJ++)
{
if (getSubCombatType(iJ) == iI)
{
m_abHasCombatType[iI] = true;
break;
}
}
}
}
return m_abHasCombatType[eUnitCombat];
}
int getSubCombatChangeType(int i) const;
int getNumSubCombatChangeTypes() const;
bool isSubCombatChangeType(int i);
int getRemovesUnitCombatType(int i) const;
int getNumRemovesUnitCombatTypes() const;
bool isRemovesUnitCombatType(int i);
bool CvUnit::hasCombatType(UnitCombatTypes eCombatType) const
{
if (((getUnitCombatType() == eCombatType) || hasExtraSubCombatType(eCombatType)) && !hasRemovesUnitCombatType(eCombatType))
{
return true;
}
// AIAndy: That loop could be removed if the unit type sub combat types get added to the extra sub combat type counts
for (int iI = 0; iI < m_pUnitInfo->getNumSubCombatTypes(); iI++)
{
if (m_pUnitInfo->getSubCombatType(iI) == ((int)eCombatType))
{
return true;
}
}
return false;
}
bool CvUnit::hasSubCombatType(UnitCombatTypes eCombatType) const
{
int iI;
bool bSubCombat = false;
for (iI = 0; iI < m_pUnitInfo->getNumSubCombatTypes(); iI++)
{
if (m_pUnitInfo->getSubCombatType(iI) == ((int)eCombatType))
{
bSubCombat = true;
}
}
if ((((bSubCombat) || hasExtraSubCombatType(eCombatType)) && (m_pUnitInfo->getUnitCombatType() != eCombatType)) && !hasRemovesUnitCombatType(eCombatType))
{
return true;
}
return false;
}
int CvUnit::getSubCombatTypeCount(UnitCombatTypes eCombatType) const
{
FAssertMsg(eCombatType >= 0, "eIndex is expected to be non-negative (invalid Index)");
FAssertMsg(eCombatType < GC.getNumUnitCombatInfos(), "eIndex is expected to be within maximum bounds (invalid Index)");
const UnitCombatKeyedInfo* info = findUnitCombatKeyedInfo(eCombatType);
return info == NULL ? 0 : info->m_iSubCombatTypeCount;
}
bool CvUnit::hasExtraSubCombatType(UnitCombatTypes eCombatType) const
{
FAssertMsg(eCombatType >= 0, "eIndex is expected to be non-negative (invalid Index)");
FAssertMsg(eCombatType < GC.getNumUnitCombatInfos(), "eIndex is expected to be within maximum bounds (invalid Index)");
return (getSubCombatTypeCount(eCombatType) > 0);
}
void CvUnit::changeSubCombatTypeCount(UnitCombatTypes eCombatType, int iChange)
{
FAssertMsg(eCombatType >= 0, "eIndex is expected to be non-negative (invalid Index)");
FAssertMsg(eCombatType < GC.getNumUnitCombatInfos(), "eIndex is expected to be within maximum bounds (invalid Index)");
UnitCombatKeyedInfo* info = findOrCreateUnitCombatKeyedInfo(eCombatType);
info->m_iSubCombatTypeCount += iChange;
FAssert(info->m_iSubCombatTypeCount >= 0);
}
int CvUnit::getRemovesUnitCombatTypeCount(UnitCombatTypes eCombatType) const
{
FAssertMsg(eCombatType >= 0, "eIndex is expected to be non-negative (invalid Index)");
FAssertMsg(eCombatType < GC.getNumUnitCombatInfos(), "eIndex is expected to be within maximum bounds (invalid Index)");
const UnitCombatKeyedInfo* info = findUnitCombatKeyedInfo(eCombatType);
return info == NULL ? 0 : info->m_iRemovesUnitCombatTypeCount;
}
bool CvUnit::hasRemovesUnitCombatType(UnitCombatTypes eCombatType) const
{
FAssertMsg(eCombatType >= 0, "eIndex is expected to be non-negative (invalid Index)");
FAssertMsg(eCombatType < GC.getNumUnitCombatInfos(), "eIndex is expected to be within maximum bounds (invalid Index)");
return (getRemovesUnitCombatTypeCount(eCombatType) > 0);
}
void CvUnit::changeRemovesUnitCombatTypeCount(UnitCombatTypes eCombatType, int iChange)
{
FAssertMsg(eCombatType >= 0, "eIndex is expected to be non-negative (invalid Index)");
FAssertMsg(eCombatType < GC.getNumUnitCombatInfos(), "eIndex is expected to be within maximum bounds (invalid Index)");
UnitCombatKeyedInfo* info = findOrCreateUnitCombatKeyedInfo(eCombatType);
info->m_iRemovesUnitCombatTypeCount += iChange;
FAssert(info->m_iRemovesUnitCombatTypeCount >= 0);
}
for (iI = 0; iI < kPromotion.getNumSubCombatChangeTypes(); iI++)
{
setHasUnitCombat(((UnitCombatTypes)kPromotion.getSubCombatChangeType(iI)), iChange);
}
for (iI = 0; iI < kPromotion.getNumRemovesUnitCombatTypes(); iI++)
{
setHasUnitCombat(((UnitCombatTypes)kPromotion.getRemovesUnitCombatType(iI)), -iChange);
}
void CvUnit::doSetUnitCombats()
{
if (getUnitCombatType() != NO_UNITCOMBAT)
{
setHasUnitCombat(getUnitCombatType(),true);
for (int iI = 0; iI < m_pUnitInfo->getNumSubCombatTypes(); iI++)
{
setHasUnitCombat((UnitCombatTypes)m_pUnitInfo->getSubCombatType(iI),true);
}
}
}
bool CvUnit::isHasUnitCombat(UnitCombatTypes eIndex) const
{
FAssertMsg(eIndex >= 0 || eIndex == NO_UNITCOMBAT, "eIndex is expected to be non-negative (invalid Index)");
FAssertMsg(eIndex < GC.getNumUnitCombatInfos(), "eIndex is expected to be within maximum bounds (invalid Index)");
const UnitCombatKeyedInfo* info = findUnitCombatKeyedInfo(eIndex);
return (info != NULL && info->m_bHasUnitCombat);
}
Yeah that second part, copyNonDefaults becomes the problem for the method as you mention it. I mean, I get what you're saying to do but copyNonDefaults sorta throws a monkeywrench into the deal. I'll have to further consider the implications but I think something like it could be done - may just need another update after any Module potentially changes the era. That's what copyNonDefaults is for - it implements the modular edits we were talking about earlier.TB, in short, add the methods getEraInfo() and setEraSubCombat() to CvUnitInfo, use the first for the second and call the second in CvUnitInfo::read(CvXMLLoadUtility* pXML) after reading tech pre-requirements. If the code you posted is after the tech reading, I would put the call immediately after it.
Do not know how about CvUnitInfo::copyNonDefaults(CvUnitInfo* pClassInfo, CvXMLLoadUtility* pXML) . I would need to know when and for what it is called.
Yeah I don't think we'd need to touch anything there for this. I concur.Rather do not need to touch CvUnitInfo::read(FDataStreamBase* stream). If it would be used to deserialize something from another game run, it can case errors anyway. At least at first glance.
isHasUnitCombat was named as such to help differentiate any potential confusion with the old hasCombatType call. setHasUnitCombat does have meaning over setUnitCombat. The first infers that any unit combat is possible on a unit and thus any number of unit combats may be added to the unit while the second infers that there's only one possible UnitCombat. Very minor and subtle difference and there's not much of a streamlined naming standard between both but I also tried to mirror what was already established for Promotions to make things easier for coders who follow. I mean, I get your point on both so I figured I'd share the rational that went into the naming choices as they are.And btw I would consider CvUnit::isHasUnitCombat -> CvUnit::hasUnitCombat, CvUnit::setHasUnitCombat -> CvUnit::setUnitCombat name change.
Yeah, I hate when that happens too!I really deeply hate most of programmers. They are total morons. I've written a big post and lost it, because those idiots from this forum script did not think about storing post's body, when there is some session mismatch after submitting. I am rather an opponent of death penalty, but for bad programmers who provide commonly used code I would make an exception.
Add setEraSubCombat() call after this code in copyNonDefaults.Yeah that second part, copyNonDefaults becomes the problem for the method as you mention it. I mean, I get what you're saying to do but copyNonDefaults sorta throws a monkeywrench into the deal. I'll have to further consider the implications but I think something like it could be done - may just need another update after any Module potentially changes the era. That's what copyNonDefaults is for - it implements the modular edits we were talking about earlier
for ( int i = 0; i < GC.getNUM_UNIT_AND_TECH_PREREQS(); i++)
{
if ( getPrereqAndTechs(i) == NO_TECH && pClassInfo->getPrereqAndTechs(i) != NO_TECH)
{
if ( NULL == m_piPrereqAndTechs )
{
CvXMLLoadUtility::InitList(&m_piPrereqAndTechs,GC.getNUM_UNIT_AND_TECH_PREREQS(),(int)NO_TECH);
}
m_piPrereqAndTechs[i] = pClassInfo->getPrereqAndTechs(i);
}
}
Probably yes, you should.I figured out I should use this same method for Religion and Culture CCs too. Those, in particular, will have some ability to change or be assigned in CvUnit eventually depending on the greater influence of the Religion or Culture in the city that generates the unit. But for those units that have a PREREQ of a given Religion or Culture this would be the appropriate place and would also let the system know that the unit when initialized cannot have it's Religion or Culture CC adjusted on initializing - it'll keep the CvUnitInfo derived definition.
Doesn't it do semantically the same? The only difference is there can be more classes?isHasUnitCombat was named as such to help differentiate any potential confusion with the old hasCombatType call
It is common to use such naming. It is like setting flags. You mostly can have many flags, but you sill say you set them. The type of this function also suggest, there are more combat classes that can be set at once.setHasUnitCombat does have meaning over setUnitCombat. The first infers that any unit combat is possible on a unit and thus any number of unit combats may be added to the unit while the second infers that there's only one possible UnitCombat. Very minor and subtle difference and there's not much of a streamlined naming standard between both but I also tried to mirror what was already established for Promotions to make things easier for coders who follow.
I understand, but I rather haven't seen such naming even in such cases. It is not terribly awful, but less convenient then hasUnitCombat and setUnitCombat, I think.I mean, I get your point on both so I figured I'd share the rational that went into the naming choices as they are.
Yeah, I figured I'd do something along those lines. Then I would NOT put it in the initial read sequence right?Add setEraSubCombat() call after this code in copyNonDefaults.
Code:for ( int i = 0; i < GC.getNUM_UNIT_AND_TECH_PREREQS(); i++) { if ( getPrereqAndTechs(i) == NO_TECH && pClassInfo->getPrereqAndTechs(i) != NO_TECH) { if ( NULL == m_piPrereqAndTechs ) { CvXMLLoadUtility::InitList(&m_piPrereqAndTechs,GC.getNUM_UNIT_AND_TECH_PREREQS(),(int)NO_TECH); } m_piPrereqAndTechs[i] = pClassInfo->getPrereqAndTechs(i); } }
I don't know all that much about the WoC Modular loading beyond this but I can tell you that you are right... values are not capable of enabling editing a tag back to a null or zero with a modularized edit. This is so that the edits can ignore most of the tags on the object without that being interpreted as an attempt to set those tags to null.But his method looks wrong. Especially for boolean values. If it is used for loading a module, it disallows to switch such values to false by the module. Do you know where is the code responsible for a module loading, where this method is called? I would take a look at it.
I'm not saying it doesn't. I just wanted to avoid any possible ongoing confusing myself between hasCombatType and hasUnitCombat - the isHasUnitCombat helped to put it a step further away from that potential confusion. You're working with a guy in ADD recovery here! lolDoesn't it do semantically the same? The only difference is there can be more classes?
I would think inferring there were more that could be set at once would be setUnitCombats or setHasUnitCombats. Anyhow, setHasPromotion was the name of the mirrored function so I went with what was already established. Why change names once set unless it's really a very compelling reason to do so?It is common to use such naming. It is like setting flags. You mostly can have many flags, but you sill say you set them. The type of this function also suggest, there are more combat classes that can be set at once.
Yeah, I asked Sargon to do this a while back and he did so... can't recall where the google doc list he made is but he got it done and yes it now just needs updated. And more. I need to get the generic category system in place so that we can assign categories to those buildings in the xml. Still, it's a good idea to update the list and put the buildings' <Type> tags in a column.Yes it will.
It will also be good to have list of buildings categories and apply category to every building. I believe someone has already done building categorizations but now it needs to be updated.
SargontheGreat2 had it in his sigline. The list is here.If anyone has the most recent list of buildings, please post it and I will update it.
You mean CvUnitInfo::read(CvXMLLoadUtility* pXML)? Do you mean you want to there would be no era cc, if your module is not loaded? No it will not work correctly then. If any other module will call CvUnitInfo::copyNonDefaults, then this cc will be added. It seems this design of modules loading is against more complex modules. I need to see the code responsible for this module loading to be sure how to do it. -- I though ccs are not intended to be a module.Yeah, I figured I'd do something along those lines. Then I would NOT put it in the initial read sequence right?
Modular loading is a heavy thing. A proper solution would even be able to require rewriting big part of the dll. *sigh* More I know about the dll code, more it looks like a piece of junk. Ok, we will see what can be done. But I need to find this loading code first.We do have an alternative method of replacing an object's definitions however, that AIAndy developed at my request (ok I may have helped a little here and there to flesh it out some but I don't want to take much credit because he's the one who infused the magik there...) The replacement mechanism we worked out allows for a complete replacement of the game object with the new definition predicated on any possible trigger gamestate (usually a game option.) THAT is pretty cool stuff. It's currently in use on our alternative trait set that ls612 established. However, we're trying to get it to work for an alternative gamespeed set and it doesn't seem to be working quite as intended which is a bug I've been meaning to investigate for some time now.
What a bullsh*t. Psychiatrists say to half to half of people they come to them they have ADD now. This is just putting money to the pharmaceutical corporations not a serious health care.You're working with a guy in ADD recovery here! lol
A language problem. I meant, that an object can be in a state, there are many combat classes set at same time. (Still am not sure isn't it ambiguous...)I would think inferring there were more that could be set at once would be setUnitCombats or setHasUnitCombats.