Tackling the if web problem you can create a rule engine where each specific rule is coded independently. A further refinement for this would be to create a domain specific language (DSL) to create the rules, however a DSL alone only displaces the problem from one code base (main) to another (DSL). Without structure the DSL will not fare any better than native language (Java, C# etc), so we'll come back to it after we find an improved structural approach.

The fundamental issue is that you are having a modelization problem. Whenever you encounter combinatorial situations like this it is a clear sign that your model abstraction that describes the situation is too coarse. You are most likely combining elements that should belong to different models in a single entity.

If you keep breaking down your model you will eventually completely dissolve this combinatorial effect. However when taking this path it is easy to get lost in your design creating an even bigger mess, perfectionism here is not necessarily your friend.

Finite state machines and rule engines are just an example of how this problem can be broken down and made more manageable. The main idea here is that a good way to rid of a combinatorial problem such as this is often to create a design and repeat it ad-nauseam in nested levels of abstraction until your system performs satisfactorily. Akin to how fractals are used to create intricate patterns. The rules remain the same no matter if you look at your system with a microscope or from a high birds eye view.

Example of applying this to your domain.

You are trying to model how cows are moving through a terrain. Though your question lacks details I would guess that your large amount of ifs include decision fragment such as if cow.isStanding then cow.canRun = true but you get bogged down as you add details of terrain for example. So for every action you want to take you have to check every aspects you can think of and repeat these verifications for the next possible action.

First we need our repeatable design, which in this case will be a FSM to model the changing states of the simulation. So the first thing I would do is implement a reference FSM, defining a state interface, a transition interface, and perhaps a transition context that can contains shared information to be made available to the other two. A basic FSM implementation will switch from one transition to another regardless of the context, this is where a rule engine comes in. The rule engine cleanly encapsulates the conditions that must be met if the transition is to take place. A rule engine here can be as simple as a list of rules each having an evaluate function returning a boolean. To check if a transition should take we place, iterate the list of rules and if any of them evaluate to false, the transition does not take place. The transition itself will contain the behavioural code to modify the current state of the FSM (and other possible tasks).

Now, if I start to implement the simulation as a single large FSM at the GOD level I end up with a LOT of possible states, transitions etc. The if-else mess looks like it's fixed but it's actually just spread around: each IF is now a rule that performs a test against a specific information of the context (which at this point pretty much contain everything) and each IF body is somewhere in the transition code.

Enter the fractals breakdown: the first step would be to create a FSM for each cow where the states are the cow's own internal states (standing, running, walking, grazing etc) and transitions between them would be affected by the environment. It's possible that the graph is not complete, for example grazing is only accessible from the standing state, any other transition is dissalowed because simply absent from the model. Here you effectively separate the data in two different models, the cow and the terrain. Each with it's own properties set. This breakdown will allow you to simplify your overall engine design. Now instead of having a single rule engine that decides all you have multiple, simpler rule engines (one for each transitions) that decide on very specific details. Many games company are using finite state machines such as this to decide on such aspects.

Because I am re-using the same code for the FSM this is basically a configuration of the FSM. Remember when we mentioned DSL's earlier? This is where the DSL can do a lot of good if you have a lot of rules & transitions to write.

Going deeper

Now GOD no longer has to deal with all the complexity on managing the cow's internal states, but we can push it further. There is still a lot of complexity involved in managing the terrain for example. This is where you decide where the breakdown is enough. If for example in your GOD you end up managing terrain dynamics (long grass, mud, dry mud, short grass etc) we can repeat the same pattern. There is nothing preventing you from embedding such logic in the terrain itself by extracting all the terrain states (long grass, short grass, muddy, dry, etc) into a new terrain FSM with transitions between the states and perhaps simple rules. For example to get to the muddy state the rule engine should check the context to find liquids, otherwise it is not possible. Now GOD got simpler still.

You can complete the system of FSM by making them autonomous and give them each a thread. This last step is not necessary but it allows you to change the system's interaction dynamically by adjusting how you delegate your decision making (launching a specialized FSM or just return a pre-determined state).

Remember how we mentioned that transitions could also do "other possible tasks"? Let's explore that by adding the possibility for different models (FSM) to communicate with each-other. You can define a set of events and allow each FSM to register listener to these events. Thus, if, for example a cow enters a terrain hex the hex can register listeners for transition changes. Here it gets a bit tricky because each FSM is implemented at very high level without any knowledge of the specific domain it harbours. However you can achieve this by having the cow publish a list of events and the cell can register if it sees events to which it can react. A good hierarchy of event family here is a good investment. Thus if the cow starts grazing the patch of terrain can record the grazing time and after some time can transition from long grass to short grass thus signalling the cow there is nothing left to eat here.

You can push deeper still by modeling the nutrient levels and growth cycle of grass, with... you guessed it... a grass FSM embedded in the terrain patch's own model.

If you push the idea far enough GOD has very little to do as all the aspects are pretty much self managed, freeing up time to spend on more godly things.

Recap

As stated above the FSM here is not the solution, just a means to illustrate that the solution to such a problem is not found in code per say but how you model your problem. There are most likely other solutions that are possible and most likely much better than my FSM proposition. However the "fractals" approach remains a good way to manage this difficulty. If done correctly you can dynamically allocate deeper levels where it matters while giving simpler models where it matters less. You can queue changes and apply them when resources become more available. In an action sequence it may not be all that important to calculate the nutrient transfer from cow to grass patch. You can however record these transitions and apply the changes at a later time or just approximate with an educated guess by simply replacing the rule engines or perhaps replacing the FSM implementation altogether with a simpler naive version for the elements that are not in the direct field of interest (that cow at the other end of the field) to allow more detailed interactions to get the focus and a larger share of resources. All this without ever revisiting the system as a whole; since each part is well isolated it becomes easier to create a drop-in replacement limiting or extending the depth of your model. By using a standard design you can build on that and maximize investments made in ad-hoc tools such as a DSL to define rules or a standard vocabulary for events, again starting at very high level and adding refinements as needed.

I would provide a code example but this is all I can afford to do right now.