I'm extremely biased on the subject, as I have been tinkering with something like this for a bit. Also, language features is one of those topics that can generate very heated discussions, so be warned
This is just my opinion on the subject and isn't any more correct or more wrong than any other opinion on the topic.
I wouldn't choose OOP as main paradigm, but rather split data and functions that operate on that data apart. It's easy to build a hierarchies and topologies of different type of data, but as soon as behaviour enters the picture it starts to get trickier. Having functions that operate on the data separate also helps in organizing the code and reduces amount of 'doers', 'managers' and 'utilityclassxes'. It also helps to answer the question "if I want to read a scroll, who has the method? character, scroll, some manager?". Multiple dispatch would be really nice, with :before, :after and :around semantics like in CLOS, so one can check if preconditions of a function (like attack for example) are fulfilled, before calling the function. Compile time type checking with inferred typing would be my preference, but my preference on that tends to fluctuate a bit. I like syntax of lisp quite a bit, so I think I would take that as a base.
Having ability to model the basic constructs like state machines is very good idea. Syntax I chose for my current project is somewhat like:
(defstatemachine <statemachine name> [<interface>]
(--init-- [<init parameters>] <init code>)
(<state> <initial-state>
(on-activate <activation code>)
(active <code that is run while state is active>)
(transitions [<check> <new state>]
[<another check> <another state>]))
<more states>)
This creates a state machine, which can then be instantiated and called like it were a function with parameters defined in <interface>. <init parameters> and <init code> are for initialization of the finite state machine. Each state is then defined in a block that starts with name of the state (on being marked as initial state, which is the state the state machine starts in). on-activate block is executed when state activates, active is run when finite state machine is given signal to process and transitions define when and how the machine switches to different state.
Ability to do random stuff, without having to resort to random numbers and comparing them to some range is nice. So instead of:
(if (> (.next random 1 100) 90) (something-bad-happens player-character))
I want to write:
(rarely (something-bad-happens player-character))
Another option I would like to have is relational or logic programming. Instead of describing an algorithm, I would describe problem domain and relations of things within it and let the computer to solve the problem. For example, if a AI character would like to figure out what kind of items it needs to bypass a trap and if they already have them, it could be done with a program like (this one doesn't take account possible skills or perks of the character, only their inventory):
(defn item-for-safe-passage [inventory trap]
(run 10 [q]
(fresh [item trigger safe-method]
(triggerᵒ trap trigger)
(safe-movement-methodᵒ trigger safe-method)
(memberᵒ item inventory)
(effectᵒ item safe-method)
(nameᵒ item q))))
Code would output at most names of 10 items that let character to bypass the trap. Neat thing about this approach is that the goals can work all directions. For example in:
(safe-movement-methodᵒ trigger safe-method)
If triggering method is know, this will produce safe method of crossing the trap. If safe-method is know, this will tell what kinds of triggers can be avoided with that. If both are known, the code will check if the trap is sprung or not. Since this language can be wrapped into a function, it is transparently callable from regular code. Having AI and game logic share the same routines helps to make sure that if rules of the game are updated, AI is updated too.
Since designing language is hard and designer will never get it right for every user, I would like to have ability to modify and extend the language. It could be done in macro system similar to what lisp has, or it could work with some other system. But since ability to do symbolic programming is something I really like, lisp macros would be my preferred method of extending the language.
I think something like that would be my start.