summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/macro.cc
diff options
context:
space:
mode:
authorzelgadis <zelgadis@c06c8d41-db1a-0410-9941-cceddc491573>2007-09-19 01:19:56 +0000
committerzelgadis <zelgadis@c06c8d41-db1a-0410-9941-cceddc491573>2007-09-19 01:19:56 +0000
commit725cb5b4d5a3ade5c5e7b04a6210cedc839c2bdd (patch)
treed2644ce5f13e7ab649b27b49f7bdcde18802a6b1 /crawl-ref/source/macro.cc
parent1a36197574afe860feff7208cd883770a5d28946 (diff)
downloadcrawl-ref-725cb5b4d5a3ade5c5e7b04a6210cedc839c2bdd.tar.gz
crawl-ref-725cb5b4d5a3ade5c5e7b04a6210cedc839c2bdd.zip
Added new commands "re-do previous command" (bound to `) and "repeat
next command" (bound to 0). Though this is just an interface change, it changes code in the core input processing function (input() in acr.cc), and also messes around with the input buffer, so it could probably do with more testing before merging it into the 0.3 branch. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@2137 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref/source/macro.cc')
-rw-r--r--crawl-ref/source/macro.cc193
1 files changed, 184 insertions, 9 deletions
diff --git a/crawl-ref/source/macro.cc b/crawl-ref/source/macro.cc
index 219a43943e..803252ad7e 100644
--- a/crawl-ref/source/macro.cc
+++ b/crawl-ref/source/macro.cc
@@ -45,14 +45,15 @@
#include <cstdlib>
#include "cio.h"
+#include "delay.h"
#include "externs.h"
#include "message.h"
+#include "state.h"
#include "stuff.h"
// for trim_string:
#include "initfile.h"
-typedef std::deque<int> keyseq;
typedef std::deque<int> keybuf;
typedef std::map<keyseq,keyseq> macromap;
@@ -73,6 +74,8 @@ static keybuf Buffer;
#define USERFUNCBASE -10000
static std::vector<std::string> userfunctions;
+static std::vector<key_recorder*> recorders;
+
inline int userfunc_index(int key)
{
int index = (key <= USERFUNCBASE? USERFUNCBASE - key : -1);
@@ -406,7 +409,7 @@ static void macro_del( macromap &mapref, keyseq key )
* Adds keypresses from a sequence into the internal keybuffer. Ignores
* macros.
*/
-static void macro_buf_add( const keyseq &actions, bool reverse = false )
+void macro_buf_add( const keyseq &actions, bool reverse)
{
keyseq act;
bool need_more_reset = false;
@@ -426,14 +429,33 @@ static void macro_buf_add( const keyseq &actions, bool reverse = false )
Buffer.insert( reverse? Buffer.begin() : Buffer.end(),
act.begin(), act.end() );
-}
+
+ if (reverse)
+ {
+ for (int i = 0, size_i = recorders.size(); i < size_i; i++)
+ for (int j = act.size() - 1 ; j >= 0; j--)
+ recorders[i]->add_key(act[j], reverse);
+ }
+ else
+ {
+ for (int i = 0, size_i = recorders.size(); i < size_i; i++)
+ for (int j = 0, size_j = act.size(); j < size_j ; j++)
+ recorders[i]->add_key(act[j]);
+ }
+}
/*
* Adds a single keypress into the internal keybuffer.
*/
-void macro_buf_add( int key )
+void macro_buf_add( int key, bool reverse )
{
- Buffer.push_back( key );
+ if (reverse)
+ Buffer.push_front( key );
+ else
+ Buffer.push_back( key );
+
+ for (int i = 0, size = recorders.size(); i < size; i++)
+ recorders[i]->add_key(key, reverse);
}
@@ -491,6 +513,13 @@ static void macro_buf_add_long( keyseq actions,
}
}
+static int macro_keys_left = -1;
+
+bool is_processing_macro()
+{
+ return (macro_keys_left >= 0);
+}
+
/*
* Command macros are only applied from the immediate front of the
* buffer, and only when the game is expecting a command.
@@ -506,11 +535,23 @@ static void macro_buf_apply_command_macro( void )
if (result.size() > 0)
{
+ for (int i = 0, size_i = recorders.size(); i < size_i; i++)
+ recorders[i]->remove_trigger_keys(tmp.size());
+
// Found macro, remove match from front:
for (unsigned int i = 0; i < tmp.size(); i++)
+ {
Buffer.pop_front();
+ if (macro_keys_left >= 0)
+ macro_keys_left--;
+ }
+
+ if (macro_keys_left == -1)
+ macro_keys_left = 0;
+ macro_keys_left += result.size();
macro_buf_add(result, true);
+
break;
}
@@ -519,17 +560,27 @@ static void macro_buf_apply_command_macro( void )
}
/*
- * Removes the earlies keypress from the keybuffer, and returns its
+ * Removes the earliest keypress from the keybuffer, and returns its
* value. If buffer was empty, returns -1;
*/
static int macro_buf_get( void )
{
if (Buffer.size() == 0)
+ {
+ // If we're trying to fetch a new keystroke, then the processing
+ // of the previous keystroke is complete.
+ if (macro_keys_left == 0)
+ macro_keys_left = -1;
+
return (-1);
+ }
int key = Buffer.front();
Buffer.pop_front();
-
+
+ if (macro_keys_left >= 0)
+ macro_keys_left--;
+
return (key);
}
@@ -577,8 +628,17 @@ void macro_save( void )
static keyseq getch_mul( int (*rgetch)() = NULL )
{
keyseq keys;
- int a;
+ int a;
+ // Something's gone wrong with replaying keys if crawl needs to
+ // get new keys from the user.
+ if (crawl_state.is_replaying_keys())
+ {
+ mpr("(Key replay ran out of keys)");
+ crawl_state.cancel_cmd_repeat();
+ crawl_state.cancel_cmd_again();
+ }
+
if (!rgetch)
rgetch = m_getch;
@@ -644,7 +704,26 @@ int getch_with_command_macros( void )
*/
void flush_input_buffer( int reason )
{
- if (Options.flush_input[ reason ])
+ ASSERT(reason != FLUSH_KEY_REPLAY_CANCEL ||
+ crawl_state.is_replaying_keys());
+
+ ASSERT(reason != FLUSH_ABORT_MACRO || is_processing_macro());
+
+ // Any attempt to flush means that the processing of the previously
+ // fetched keystroke is complete.
+ if (macro_keys_left == 0)
+ macro_keys_left = -1;
+
+ if (crawl_state.is_replaying_keys() && reason != FLUSH_ABORT_MACRO
+ && reason != FLUSH_KEY_REPLAY_CANCEL &&
+ reason != FLUSH_REPLAY_SETUP_FAILURE)
+ {
+ return;
+ }
+
+ if (Options.flush_input[ reason ] || reason == FLUSH_ABORT_MACRO
+ || reason == FLUSH_KEY_REPLAY_CANCEL
+ || reason == FLUSH_REPLAY_SETUP_FAILURE)
{
while (!Buffer.empty())
{
@@ -653,6 +732,7 @@ void flush_input_buffer( int reason )
if (key == KEY_MACRO_ENABLE_MORE)
Options.show_more_prompt = true;
}
+ macro_keys_left = -1;
}
}
@@ -822,8 +902,103 @@ bool is_synthetic_key(int key)
case KEY_MACRO_ENABLE_MORE:
case KEY_MACRO_DISABLE_MORE:
case KEY_MACRO_MORE_PROTECT:
+ case KEY_REPEAT_KEYS:
return (true);
default:
return (false);
}
}
+
+key_recorder::key_recorder(key_recorder_callback cb, void* cb_data)
+ : paused(false), call_back(cb), call_back_data(cb_data)
+{
+ keys.clear();
+ macro_trigger_keys.clear();
+}
+
+void key_recorder::add_key(int key, bool reverse)
+{
+ if (paused)
+ return;
+
+ if (call_back)
+ {
+ // Don't record key if true
+ if ((*call_back)(this, key, reverse))
+ return;
+ }
+
+ if (reverse)
+ keys.push_front(key);
+ else
+ keys.push_back(key);
+}
+
+void key_recorder::remove_trigger_keys(int num_keys)
+{
+ ASSERT(num_keys >= 1);
+
+ if (paused)
+ return;
+
+ for (int i = 0; i < num_keys; i++)
+ {
+ ASSERT(keys.size() >= 1);
+
+ int key = keys[keys.size() - 1];
+
+ if (call_back)
+ {
+ // Key wasn't recorded in the first place, so no need to remove
+ // it
+ if ((*call_back)(this, key, true))
+ continue;
+ }
+
+ macro_trigger_keys.push_front(key);
+ keys.pop_back();
+ }
+}
+
+void key_recorder::clear()
+{
+ keys.clear();
+ macro_trigger_keys.clear();
+}
+
+void add_key_recorder(key_recorder* recorder)
+{
+ for (int i = 0, size = recorders.size(); i < size; i++)
+ ASSERT(recorders[i] != recorder);
+
+ recorders.push_back(recorder);
+}
+
+void remove_key_recorder(key_recorder* recorder)
+{
+ std::vector<key_recorder*>::iterator i;
+
+ for(i = recorders.begin(); i != recorders.end(); i++)
+ if (*i == recorder)
+ {
+ recorders.erase(i);
+ return;
+ }
+
+ end(1, true, "remove_key_recorder(): recorder not found\n");
+}
+
+// Add macro trigger keys to beginning of the buffer, then expand
+// them.
+void insert_macro_into_buff(const keyseq& keys)
+{
+ for (int i = (int) keys.size() - 1; i >= 0; i--)
+ macro_buf_add(keys[i], true);
+
+ macro_buf_apply_command_macro();
+}
+
+int get_macro_buf_size()
+{
+ return (Buffer.size());
+}