diff options
-rw-r--r-- | Changelog-SVN.txt | 7 | ||||
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | npc/other/eliza.txt | 702 | ||||
-rw-r--r-- | src/map/Makefile | 6 | ||||
-rw-r--r-- | src/map/clif.c | 4 | ||||
-rw-r--r-- | src/map/map.h | 2 | ||||
-rw-r--r-- | src/map/npc.c | 4 | ||||
-rw-r--r-- | src/map/npc.h | 2 | ||||
-rw-r--r-- | src/map/npc_chat.c | 502 | ||||
-rw-r--r-- | src/map/script.c | 26 | ||||
-rw-r--r-- | src/map/script.h | 4 |
11 files changed, 1253 insertions, 8 deletions
diff --git a/Changelog-SVN.txt b/Changelog-SVN.txt index 84b0bb6fb..7e5d7258d 100644 --- a/Changelog-SVN.txt +++ b/Changelog-SVN.txt @@ -1,5 +1,10 @@ Date Added +02/22 + * Added perl regular expression support.. look at src/map/npc_chat.c + for all the dirt on the new features. To build it, you have + to enable the PCRE_SUPPORT #define and you also have to + build/install the pcre library. [SVN 1157: MouseJstr] 02/21 * Added actual item_db.sql into sql-files. [Lupus] * Added actual mob_db.sql into sql-files. If you use SQL Mob DB then update it [Lupus] @@ -2000,4 +2005,4 @@ Date Added router or a firewall since there is no way of determining the external IP address. On the other hand, we should be able to eliminate the lan_conf file since we know our IP addresses as well - as our netmask.
\ No newline at end of file + as our netmask. @@ -1,11 +1,13 @@ CC = gcc -pipe +# CC = gcc -pipe -DPCRE_SUPPORT # CC = g++ # CC = gcc -pipe -DGCOLLECT # CC = gcc -pipe -DDMALLOC -DDMALLOC_FUNC_CHECK # CC = /usr/local/bin/gcc -fbounds-checking -pipe -DBCHECK # GCLIB = -lgc +# GCLIB = -L/usr/local/lib -lpcre GCLIB = # GCLIB = -ldmalloc diff --git a/npc/other/eliza.txt b/npc/other/eliza.txt new file mode 100644 index 000000000..d5c3c0765 --- /dev/null +++ b/npc/other/eliza.txt @@ -0,0 +1,702 @@ +prontera.gat,152,181,5 script MouseJstr 763,{ + +// hello +Lquote0: + npctalk "How do you do. Please state your problem."; + break; +// computer +Lquote1: + set $foo,rand(4); + if($foo == 0) goto Lquote1a; + if($foo == 1) goto Lquote1b; + if($foo == 2) goto Lquote1c; + if($foo == 3) goto Lquote1d; +Lquote1a: + npctalk "Do computers worry you?"; + break; +Lquote1b: + npctalk "What do you think about machines?"; + break; +Lquote1c: + npctalk "Why do you mention computers?"; + break; +Lquote1d: + npctalk "What do you think machines have to do with your problem?"; + break; +// name +Lquote2: + npctalk "I am not interested in names"; + break; +// sorry +Lquote3: + set $foo,rand(3); + if($foo == 0) goto Lquote3a; + if($foo == 1) goto Lquote3b; + if($foo == 2) goto Lquote3c; + +Lquote3a: + npctalk "Please don't apologize"; + break; + +Lquote3b: + npctalk "Apologies are not necessary"; + break; + +Lquote3c: + npctalk "What feelings do you have when you apologize"; + break; + +// I remember $p2$ +Lquote4: + set $foo,rand(6); + if($foo == 0) goto Lquote4a; + if($foo == 1) goto Lquote4b; + if($foo == 2) goto Lquote4c; + if($foo == 3) goto Lquote4d; + if($foo == 4) goto Lquote4e; + if($foo == 5) goto Lquote4f; + +Lquote4a: + npctalk "Do you often think of "+$p2$+"?"; + break; + +Lquote4b: + npctalk "Does thinking of "+$p2$+" bring anything else to mind?"; + break; + +Lquote4c: + npctalk "What else do you remember?"; + break; + +Lquote4d: + npctalk "Why do you recall "+$p2$+" right now?"; + break; + +Lquote4e: + npctalk "What in the present situation reminds you of "+$p2$+"?"; + break; + +Lquote4f: + npctalk "What is the connection between me and "+$p2$+"?"; + break; + +// do you remember +Lquote5: + set $foo,rand(4); + if($foo == 0) goto Lquote5a; + if($foo == 1) goto Lquote5b; + if($foo == 2) goto Lquote5c; + if($foo == 3) goto Lquote5d; +Lquote5a: + npctalk "Did you think I would forget "+$p2$+" ?"; + break; + +Lquote5b: + npctalk "Why do you think I should recall "+$p2$+" now"; + break; + +Lquote5c: + npctalk "What about "+$p2$+""; + break; + +Lquote5d: + npctalk "You mentioned "+$p2$+""; + break; + +// if +Lquote6: + set $foo,rand(4); + if($foo == 0) goto Lquote6a; + if($foo == 1) goto Lquote6b; + if($foo == 2) goto Lquote6c; + if($foo == 3) goto Lquote6d; +Lquote6a: + npctalk "Do you really think its likely that "+$p2$+""; + break; + +Lquote6b: + npctalk "Do you wish that "+$p2$+"?"; + break; + +Lquote6c: + npctalk "What do you think about "+$p2$+"?"; + break; + +Lquote6d: + npctalk "Really-- if "+$p2$+"?"; + break; + +// i dreamt +Lquote7: + set $foo,rand(3); + if($foo == 0) goto Lquote7a; + if($foo == 1) goto Lquote7b; + if($foo == 2) goto Lquote7c; +Lquote7a: + npctalk "Really-- "+$p2$+""; + break; + +Lquote7b: + npctalk "Have you ever fantasized "+$p2$+" while you were awake?"; + break; + +Lquote7c: + npctalk "Have you dreamt "+$p2$+" before?"; + break; + +// dream about + +Lquote8: + npctalk "How do you feel about "+$p2$+" in reality?"; + break; + +// dream +Lquote9: + set $foo,rand(4); + if($foo == 0) goto Lquote9a; + if($foo == 1) goto Lquote9b; + if($foo == 2) goto Lquote9c; + if($foo == 3) goto Lquote9d; +Lquote9a: + npctalk "What does this dream suggest to you?"; + break; + +Lquote9b: + npctalk "Do you dream often?"; + break; + +Lquote9c: + npctalk "What persons appear in your dreams?"; + break; + +Lquote9d: + npctalk "Don't you believe that dream has to do with your problem?"; + break; + +// my mother +Lquote10: + set $foo,rand(2); + if($foo == 0) goto Lquote10a; + if($foo == 1) goto Lquote10b; +Lquote10a: + npctalk "Who else in your family "+$p2$+""; + break; + +Lquote10b: + npctalk "Tell me more about your family"; + break; + +// my father +Lquote11: + set $foo,rand(3); + if($foo == 0) goto Lquote11a; + if($foo == 1) goto Lquote11b; + if($foo == 2) goto Lquote11c; +Lquote11a: + npctalk "Your father"; + break; + +Lquote11b: + npctalk "Does he influence you strongly?"; + break; + +Lquote11c: + npctalk "What else comes to mind when you think of your father?"; + break; + +// I want +Lquote12: + set $foo,rand(3); + if($foo == 0) goto Lquote12a; + if($foo == 1) goto Lquote12b; + if($foo == 2) goto Lquote12c; +Lquote12a: + npctalk "What would it mean if you got "+$p2$+""; + break; + +Lquote12b: + npctalk "Why do you want "+$p2$+""; + break; + +Lquote12c: + npctalk "Suppose you got "+$p2$+" soon"; + break; + +// I am glad +Lquote13: + set $foo,rand(3); + if($foo == 0) goto Lquote13a; + if($foo == 1) goto Lquote13b; + if($foo == 2) goto Lquote13c; +Lquote13a: + npctalk "How have I helped you to be "+$p2$+""; + break; + +Lquote13b: + npctalk "What makes you happy just now"; + break; + +Lquote13c: + npctalk "Can you explain why you are suddenly "+$p2$+""; + break; + +// I am sad +Lquote14: + set $foo,rand(2); + if($foo == 0) goto Lquote14a; + if($foo == 1) goto Lquote14b; +Lquote14a: + npctalk "I am sorry to hear you are depressed"; + break; + +Lquote14b: + npctalk "I'm sure its not pleasant to be sad"; + break; + +// $p2 are like "+$p3$+" +Lquote15: + npctalk "What resemblance do you see between "+$p2$+" and "+$p3$+""; + break; + +// "+$p2$+" is like "+$p3$+" +Lquote16: + set $foo,rand(4); + if($foo == 0) goto Lquote16a; + if($foo == 1) goto Lquote16b; + if($foo == 2) goto Lquote16c; + if($foo == 3) goto Lquote16d; +Lquote16a: + npctalk "In what way is it that "+$p2$+" is like "+$p3$+""; + break; + +Lquote16b: + npctalk "What resemblance do you see?"; + break; + +Lquote16c: + npctalk "Could there really be some connection?"; + break; + +Lquote16d: + npctalk "How?"; + break; +// alike +Lquote17: + set $foo,rand(2); + if($foo == 0) goto Lquote17a; + if($foo == 1) goto Lquote17b; +Lquote17a: + npctalk "In what way?"; + break; + +Lquote17b: + npctalk "What similarities are there?"; + break; +// same +Lquote18: + npctalk "What other connections do you see?"; + break; + +// I was "+$p2$+" +Lquote19: + set $foo,rand(3); + if($foo == 0) goto Lquote19a; + if($foo == 1) goto Lquote19b; + if($foo == 2) goto Lquote19c; +Lquote19a: + npctalk "Were you really?"; + break; + +Lquote19b: + npctalk "Perhaps I already knew you were "+$p2$+""; + break; + +Lquote19c: + npctalk "Why do you tell me you were "+$p2$+" now?"; + break; + +// was I +Lquote20: + set $foo,rand(3); + if($foo == 0) goto Lquote20a; + if($foo == 1) goto Lquote20b; + if($foo == 2) goto Lquote20c; +Lquote20a: + npctalk "What if you were "+$p2$+" ?"; + break; + +Lquote20b: + npctalk "Do you thin you were "+$p2$+""; + break; + +Lquote20c: + npctalk "What would it mean if you were "+$p2$+""; + break; + +// I am +Lquote21: + set $foo,rand(2); + if($foo == 0) goto Lquote21a; + if($foo == 1) goto Lquote21b; +Lquote21a: + npctalk "In what way are you "+$p2$+""; + break; + +Lquote21b: + npctalk "Do you want to be "+$p2$+" ?"; + break; + +// am I +Lquote22: + set $foo,rand(4); + if($foo == 0) goto Lquote22a; + if($foo == 1) goto Lquote22b; + if($foo == 2) goto Lquote22c; + if($foo == 3) goto Lquote22d; +Lquote22a: + npctalk "Do you believe you are "+$p2$+""; + break; + +Lquote22b: + npctalk "Would you want to be "+$p2$+""; + break; + +Lquote22c: + npctalk "You wish I would tell you you are "+$p2$+""; + break; + +Lquote22d: + npctalk "What would it mean if you were "+$p2$+""; + break; + +// am +Lquote23: + set $foo,rand(2); + if($foo == 0) goto Lquote23a; + if($foo == 1) goto Lquote23b; + +Lquote23a: + npctalk "Why do you say AM?"; + break; + +Lquote23b: + npctalk "I don't understand that"; + break; + +// are you +Lquote24: + set $foo,rand(3); + if($foo == 0) goto Lquote24a; + if($foo == 1) goto Lquote24b; + if($foo == 2) goto Lquote24c; +Lquote24a: + npctalk "Why are you interested in whether I am "+$p2$+" or not?"; + break; + +Lquote24b: + npctalk "Would you prefer if I weren't "+$p2$+""; + break; + +Lquote24c: + npctalk "Perhaps I am "+$p2$+" in your fantasies"; + break; + +// you are +Lquote25: + npctalk "What makes you think I am "+$p2$+" ?"; + break; + +// because +Lquote26: + set $foo,rand(3); + if($foo == 0) goto Lquote26a; + if($foo == 1) goto Lquote26b; + if($foo == 2) goto Lquote26c; +Lquote26a: + npctalk "Is that the real reason?"; + break; + +Lquote26b: + npctalk "What other reasons might there be?"; + break; + +Lquote26c: + npctalk "Does that reason seem to explain anything else?"; + break; + +// were you +Lquote27: + set $foo,rand(3); + if($foo == 0) goto Lquote27a; + if($foo == 1) goto Lquote27b; + if($foo == 2) goto Lquote27c; +Lquote27a: + npctalk "Perhaps I was "+$p2$+""; + break; + +Lquote27b: + npctalk "What do you think?"; + break; + +Lquote27c: + npctalk "What if I had been "+$p2$+""; + break; + +// I can't +Lquote28: + set $foo,rand(2); + if($foo == 0) goto Lquote28a; + if($foo == 1) goto Lquote28b; +Lquote28a: + npctalk "Maybe you could "+$p2$+" now"; + break; + +Lquote28b: + npctalk "What if you could "+$p2$+" ?"; + break; + +// I feel +Lquote29: + npctalk "Do you often feel "+$p2$+" ?"; + break; + +// I felt +Lquote30: + npctalk "What other feelings do you have?"; + break; + +// $p1$ I $p2$ you $p3$ +Lquote31: + npctalk "Perhaps in your fantasy we "+$p3$+" each other?"; + break; + +// why don't you +Lquote32: + set $foo,rand(3); + if($foo == 0) goto Lquote32a; + if($foo == 1) goto Lquote32b; + if($foo == 2) goto Lquote32c; +Lquote32a: + npctalk "Should you "+$p2$+" yourself?"; + break; + +Lquote32b: + npctalk "Do you believe I don't "+$p2$+""; + break; + +Lquote32c: + npctalk "Perhaps I will "+$p2$+" in good time"; + break; + +// yes +Lquote33: + set $foo,rand(3); + if($foo == 0) goto Lquote33a; + if($foo == 1) goto Lquote33b; + if($foo == 2) goto Lquote33c; +Lquote33a: + npctalk "You seem quite positive"; + break; + +Lquote33b: + npctalk "You are sure?"; + break; + +Lquote33c: + npctalk "I understand"; + break; + +// no +Lquote34: + set $foo,rand(3); + if($foo == 0) goto Lquote34a; + if($foo == 1) goto Lquote34b; + if($foo == 2) goto Lquote34c; +Lquote34a: + npctalk "Why not?"; + break; + +Lquote34b: + npctalk "You are being a bit negative"; + break; + +Lquote34c: + npctalk "Are you saying NO just to be negative?"; + break; + +// someone +Lquote35: + npctalk "Can you be more specific?"; + break; + +// everyone +Lquote36: + set $foo,rand(4); + if($foo == 0) goto Lquote36a; + if($foo == 1) goto Lquote36b; + if($foo == 2) goto Lquote36c; + if($foo == 3) goto Lquote36d; +Lquote36a: + npctalk "surely not everyone"; + break; + +Lquote36b: + npctalk "Can you think of anyone in particular?"; + break; + +Lquote36c: + npctalk "Who for example?"; + break; + +Lquote36d: + npctalk "You are thinking of a special person?"; + break; + +// always +Lquote37: + set $foo,rand(4); + if($foo == 0) goto Lquote37a; + if($foo == 1) goto Lquote37b; + if($foo == 2) goto Lquote37c; + if($foo == 3) goto Lquote37d; +Lquote37a: + npctalk "Can you think of a specific example?"; + break; + +Lquote37b: + npctalk "When?"; + break; + +Lquote37c: + npctalk "What incident are you thinking of?"; + break; + +Lquote37d: + npctalk "Really-- always?"; + break; + +// what +Lquote38: + set $foo,rand(5); + if($foo == 0) goto Lquote38a; + if($foo == 1) goto Lquote38b; + if($foo == 2) goto Lquote38c; + if($foo == 3) goto Lquote38d; + if($foo == 4) goto Lquote38e; +Lquote38a: + npctalk "Why do you ask?"; + break; + +Lquote38b: + npctalk "Does that question interest you?"; + break; + +Lquote38c: + npctalk "What is it you really want to know?"; + break; + +Lquote38d: + npctalk "What do you think?"; + break; + +Lquote38e: + npctalk "What comes to your mind when you ask that?"; + break; + +// perhaps +Lquote39: + npctalk "You do not seem quite certain"; + break; + +// are +Lquote40: + set $foo,rand(2); + if($foo == 0) goto Lquote40a; + if($foo == 1) goto Lquote40b; +Lquote40a: + npctalk "Did you think they might not be "+$p2$+""; + break; + +Lquote40b: + npctalk "Possibly they are "+$p2$; + break; + +// default +Lquote41: + set $foo,rand(6); + if($foo == 0) goto Lquote41a; + if($foo == 1) goto Lquote41b; + if($foo == 2) goto Lquote41c; + if($foo == 3) goto Lquote41d; + if($foo == 4) goto Lquote41e; + if($foo == 5) goto Lquote41f; +Lquote41a: + npctalk "Very interesting"; + break; + +Lquote41b: + npctalk "I am not sure I understand you fully"; + break; + +Lquote41c: + npctalk "What does that suggest to you?"; + break; + +Lquote41d: + npctalk "Please continue"; + break; + +Lquote41e: + npctalk "Go on"; + break; + +Lquote41f: + npctalk "Do you feel strongly about discussing such things?"; + break; +OnInit: + defpattern 1, "([^:]+):.*\\shello.*", "Lquote0"; + defpattern 1, "([^:]+):.*\\scomputer.*", "Lquote1"; + defpattern 1, "([^:]+):.*\\sname.*", "Lquote2"; + defpattern 1, "([^:]+):.*\\ssorry.*", "Lquote3"; + defpattern 1, "([^:]+):.*\\si\\s+remember\\s+(.*)", "Lquote4"; + defpattern 1, "([^:]+):.*\\sdo\\s+you\\s+remember\\s+(.*)", "Lquote5"; + defpattern 1, "([^:]+):.*\\sif\\s+(.*)", "Lquote6"; + defpattern 1, "([^:]+):.*\\si\\s+dreamt\\s+(.*)", "Lquote7"; + defpattern 1, "([^:]+):.*\\sdream\\s+about\\s+(.*)", "Lquote8"; + defpattern 1, "([^:]+):.*\\sdream\\s+(.*)", "Lquote9"; + defpattern 1, "([^:]+):.*\\smy\\s+mother\\s+(.*)", "Lquote10"; + defpattern 1, "([^:]+):.*\\smy\\s+father\\s+(.*)", "Lquote11"; + defpattern 1, "([^:]+):.*\\si\\s+want\\s+(.*)", "Lquote12"; + defpattern 1, "([^:]+):.*\\si\\s+am\\s+glad\\s+(.*)", "Lquote13"; + defpattern 1, "([^:]+):\\s+(.*)\\s+i\\s+am\\s+sad\\s+(.*)", "Lquote14"; + defpattern 1, "([^:]+):\\s+(.*)\\s+are\\s+like\\s+(.*)", "Lquote15"; + defpattern 1, "([^:]+):\\s+(.*)\\s+is\\s+like\\s+(.*)", "Lquote16"; + defpattern 1, "([^:]+):.*\\salike\\s+(.*)", "Lquote17"; + defpattern 1, "([^:]+):.*\\ssame\\s+(.*)", "Lquote18"; + defpattern 1, "([^:]+):.*\\si\\s+was\\s+(.*)", "Lquote19"; + defpattern 1, "([^:]+):.*\\swas\\s+i\\s+(.*)", "Lquote20"; + defpattern 1, "([^:]+):.*\\si\\s+am\\s+(.*)", "Lquote21"; + defpattern 1, "([^:]+):.*\\sam\\s+i\\s+(.*)", "Lquote22"; + defpattern 1, "([^:]+):.*\\sam\\s+(.*)", "Lquote23"; + defpattern 1, "([^:]+):.*\\sare\\s+you\\s+(.*)", "Lquote24"; + defpattern 1, "([^:]+):.*\\syou\\s+are\\s+(.*)", "Lquote25"; + defpattern 1, "([^:]+):.*\\sbecause\\s+(.*)", "Lquote26"; + defpattern 1, "([^:]+):.*\\swere\\s+you\\s+(.*)", "Lquote27"; + defpattern 1, "([^:]+):.*\\si\\s+(cant|can't|cannot)\\s+(.*)", "Lquote28"; + defpattern 1, "([^:]+):.*\\si\\s+feel\\s+(.*)", "Lquote29"; + defpattern 1, "([^:]+):.*\\si\\s+felt\\s+(.*)", "Lquote30"; + defpattern 1, "([^:]+):.*\\si\\s+(.*)\\s+you\\s+(.*)", "Lquote31"; + defpattern 1, "([^:]+):.*\\swhy\\s+(don't|dont)\\s+you\\s+(.*)", "Lquote32"; + defpattern 1, "([^:]+):.*\\syes\\s+(.*)", "Lquote33"; + defpattern 1, "([^:]+):.*\\sno\\s+(.*)", "Lquote34"; + defpattern 1, "([^:]+):.*\\ssomeone\\s+(.*)", "Lquote35"; + defpattern 1, "([^:]+):.*\\severyone\\s+(.*)", "Lquote36"; + defpattern 1, "([^:]+):.*\\salways\\s+(.*)", "Lquote37"; + defpattern 1, "([^:]+):.*\\swhat\\s+(.*)", "Lquote38"; + defpattern 1, "([^:]+):.*\\sperhaps\\s+(.*)", "Lquote39"; + defpattern 1, "([^:]+):.*\\sare\\s+(.*)", "Lquote40"; + defpattern 1, "([^:]+):(.*)", "Lquote41"; + + activatepset 1; + break; +} diff --git a/src/map/Makefile b/src/map/Makefile index 3a05cd7a8..884e8b902 100644 --- a/src/map/Makefile +++ b/src/map/Makefile @@ -13,10 +13,10 @@ sqlobj: COMMON_OBJ = ../common/core.o ../common/socket.o ../common/timer.o ../common/grfio.o ../common/db.o ../common/lock.o ../common/nullpo.o ../common/malloc.o ../common/showmsg.o ../common/utils.o ../common/strlib.o LIBS = -lz -lm -map-server: txtobj/map.o txtobj/chrif.o txtobj/clif.o txtobj/pc.o txtobj/status.o txtobj/npc.o txtobj/chat.o txtobj/path.o txtobj/itemdb.o txtobj/mob.o txtobj/script.o txtobj/storage.o txtobj/skill.o txtobj/atcommand.o txtobj/charcommand.o txtobj/battle.o txtobj/intif.o txtobj/trade.o txtobj/party.o txtobj/vending.o txtobj/guild.o txtobj/pet.o txtobj/log.o $(COMMON_OBJ) +map-server: txtobj/map.o txtobj/chrif.o txtobj/clif.o txtobj/pc.o txtobj/status.o txtobj/npc.o txtobj/npc_chat.o txtobj/chat.o txtobj/path.o txtobj/itemdb.o txtobj/mob.o txtobj/script.o txtobj/storage.o txtobj/skill.o txtobj/atcommand.o txtobj/charcommand.o txtobj/battle.o txtobj/intif.o txtobj/trade.o txtobj/party.o txtobj/vending.o txtobj/guild.o txtobj/pet.o txtobj/log.o $(COMMON_OBJ) $(CC) -o ../../$@ $> $(LIBS) $(LIB_S) -map-server_sql: sqlobj/map.o sqlobj/chrif.o sqlobj/clif.o sqlobj/pc.o sqlobj/status.o sqlobj/npc.o sqlobj/chat.o sqlobj/path.o sqlobj/itemdb.o sqlobj/mob.o sqlobj/script.o sqlobj/storage.o sqlobj/skill.o sqlobj/atcommand.o sqlobj/charcommand.o sqlobj/battle.o sqlobj/intif.o sqlobj/trade.o sqlobj/party.o sqlobj/vending.o sqlobj/guild.o sqlobj/pet.o sqlobj/mail.o sqlobj/log.o $(COMMON_OBJ) +map-server_sql: sqlobj/map.o sqlobj/chrif.o sqlobj/clif.o sqlobj/pc.o sqlobj/status.o sqlobj/npc.o sqlobj/npc_chat.o sqlobj/chat.o sqlobj/path.o sqlobj/itemdb.o sqlobj/mob.o sqlobj/script.o sqlobj/storage.o sqlobj/skill.o sqlobj/atcommand.o sqlobj/charcommand.o sqlobj/battle.o sqlobj/intif.o sqlobj/trade.o sqlobj/party.o sqlobj/vending.o sqlobj/guild.o sqlobj/pet.o sqlobj/mail.o sqlobj/log.o $(COMMON_OBJ) $(CC) -o ../../$@ $> $(LIB_S) txtobj/%.o: %.c @@ -31,6 +31,7 @@ txtobj/clif.o: clif.c map.h chrif.h clif.h mob.h intif.h pc.h npc.h itemdb.h cha txtobj/pc.o: pc.c map.h clif.h intif.h pc.h npc.h mob.h itemdb.h battle.h skill.h script.h party.h guild.h pet.h trade.h storage.h chat.h vending.h ../common/timer.h ../common/mmo.h ../common/db.h ../common/showmsg.h txtobj/status.o: status.c pc.h map.h clif.h status.h mob.h itemdb.h battle.h skill.h script.h pet.h guild.h ../common/timer.h ../common/mmo.h ../common/db.h ../common/showmsg.h txtobj/npc.o: npc.c map.h npc.h clif.h pc.h script.h mob.h itemdb.h battle.h ../common/db.h ../common/timer.h ../common/mmo.h ../common/showmsg.h +txtobj/npc_chat.o: npc_chat.c map.h npc.h clif.h pc.h script.h mob.h itemdb.h battle.h ../common/db.h ../common/timer.h ../common/mmo.h ../common/showmsg.h txtobj/chat.o: chat.c map.h clif.h pc.h chat.h ../common/db.h ../common/mmo.h ../common/showmsg.h txtobj/path.o: path.c map.h battle.h ../common/mmo.h ../common/showmsg.h txtobj/itemdb.o: itemdb.c map.h battle.h itemdb.h ../common/db.h ../common/grfio.h ../common/mmo.h ../common/showmsg.h @@ -55,6 +56,7 @@ sqlobj/clif.o: clif.c map.h chrif.h clif.h mob.h intif.h pc.h npc.h itemdb.h cha sqlobj/pc.o: pc.c map.h clif.h intif.h pc.h npc.h mob.h itemdb.h battle.h skill.h script.h party.h guild.h pet.h trade.h storage.h chat.h vending.h log.h ../common/timer.h ../common/mmo.h ../common/db.h ../common/showmsg.h sqlobj/status.o: status.c pc.h map.h clif.h status.h mob.h itemdb.h battle.h skill.h script.h pet.h guild.h ../common/timer.h ../common/mmo.h ../common/db.h ../common/showmsg.h sqlobj/npc.o: npc.c map.h npc.h clif.h pc.h script.h mob.h itemdb.h battle.h ../common/db.h ../common/timer.h ../common/mmo.h ../common/showmsg.h +sqlobj/npc_chat.o: npc_chat.c map.h npc.h clif.h pc.h script.h mob.h itemdb.h battle.h ../common/db.h ../common/timer.h ../common/mmo.h ../common/showmsg.h sqlobj/chat.o: chat.c map.h clif.h pc.h chat.h ../common/db.h ../common/mmo.h ../common/showmsg.h sqlobj/path.o: path.c map.h battle.h ../common/mmo.h ../common/showmsg.h sqlobj/itemdb.o: itemdb.c map.h battle.h itemdb.h ../common/db.h ../common/grfio.h ../common/mmo.h ../common/showmsg.h diff --git a/src/map/clif.c b/src/map/clif.c index 0a0db934a..67c925f75 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -7964,6 +7964,10 @@ void clif_parse_GlobalMessage(int fd, struct map_session_data *sd) { // S 008c < WFIFOW(fd,0) = 0x8e; WFIFOSET(fd, WFIFOW(fd,2)); +#ifdef PCRE_SUPPORT + map_foreachinarea(npc_chat_sub, sd->bl.m, sd->bl.x-AREA_SIZE, sd->bl.y-AREA_SIZE, sd->bl.x+AREA_SIZE, sd->bl.y+AREA_SIZE, BL_NPC, RFIFOP(fd,4), strlen(RFIFOP(fd,4)), &sd->bl); +#endif + // Celest if (pc_calc_base_job2 (sd->status.class_) == 23 ) { int next = pc_nextbaseexp(sd)>0 ? pc_nextbaseexp(sd) : sd->status.base_exp; diff --git a/src/map/map.h b/src/map/map.h index 92c334806..2963a316e 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -411,6 +411,8 @@ struct npc_data { char eventqueue[MAX_EVENTQUEUE][50]; int eventtimer[MAX_EVENTTIMER]; short arenaflag; + + void *chatdb; }; struct mob_data { struct block_list bl; diff --git a/src/map/npc.c b/src/map/npc.c index 1ba55699f..54a35c51c 100644 --- a/src/map/npc.c +++ b/src/map/npc.c @@ -153,6 +153,10 @@ int npc_delete(struct npc_data *nd) if(nd->bl.prev == NULL) return 1; +#ifdef PCRE_SUPPORT + npc_chat_finalize(nd); +#endif + clif_clearchar_area(&nd->bl,1); map_delblock(&nd->bl); return 0; diff --git a/src/map/npc.h b/src/map/npc.h index a68cc8e54..dbb351fa0 100644 --- a/src/map/npc.h +++ b/src/map/npc.h @@ -8,6 +8,8 @@ #define WARP_DEBUG_CLASS 722 #define INVISIBLE_CLASS 32767 +void npc_chat_finalize(struct npc_data *nd); +int npc_chat_sub(struct block_list *bl, va_list ap); int npc_event_dequeue(struct map_session_data *sd); int npc_event_timer(int tid,unsigned int tick,int id,int data); int npc_event(struct map_session_data *sd,const char *npcname,int); diff --git a/src/map/npc_chat.c b/src/map/npc_chat.c new file mode 100644 index 000000000..5ec8540ae --- /dev/null +++ b/src/map/npc_chat.c @@ -0,0 +1,502 @@ +#ifdef PCRE_SUPPORT + +#include <stdio.h> +#include <ctype.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#ifdef __WIN32 +#define __USE_W32_SOCKETS +#include <windows.h> +#else +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#endif +#include <time.h> + +#include "../common/timer.h" +#include "../common/malloc.h" +#include "../common/version.h" +#include "../common/nullpo.h" +#include "../common/showmsg.h" + +#include "map.h" +#include "status.h" +#include "npc.h" +#include "chat.h" +#include "script.h" +#include "battle.h" + +#include "pcre.h" + +/** + * Written by MouseJstr in a vision... (2/21/2005) + * + * This allows you to make npc listen for spoken text (global + * messages) and pattern match against that spoken text using perl + * regular expressions. + * + * Please feel free to copy this code into your own personal ragnarok + * servers or distributions but please leave my name. Also, please + * wait until I've put it into the main eA branch which means I + * believe it is ready for distribution. + * + * So, how do people use this? + * + * The first and most important function is defpattern + * + * defpattern 1, "[^:]+: (.*) loves (.*)", "label"; + * + * this defines a new pattern in set 1 using perl syntax + * (http://www.troubleshooters.com/codecorn/littperl/perlreg.htm) + * and tells it to jump to the supplied label when the pattern + * is matched. + * + * each of the matched Groups will result in a variable being + * set ($p1$ through $p9$ with $p0$ being the entire string) + * before the script gets executed. + * + * activatepset 1; + * + * This activates a set of patterns.. You can have many pattern + * sets defined and many active all at once. This feature allows + * you to set up "conversations" and ever changing expectations of + * the pattern matcher + * + * deactivatepset 1; + * + * turns off a pattern set; + * + * deactivatepset -1; + * + * turns off ALL pattern sets; + * + * deletepset 1; + * + * deletes a pset + */ + +/* Structure containing all info associated with a single pattern + block */ + +struct pcrematch_entry { + struct pcrematch_entry *next_; + char *pattern_; + pcre *pcre_; + pcre_extra *pcre_extra_; + char *label_; +}; + +/* A set of patterns that can be activated and deactived with a single + command */ + +struct pcrematch_set { + struct pcrematch_set *next_, *prev_; + struct pcrematch_entry *head_; + int setid_; +}; + +/* + * Entire data structure hung off a NPC + * + * The reason I have done it this way (a void * in npc_data and then + * this) was to reduce the number of patches that needed to be applied + * to a ragnarok distribution to bring this code online. I + * also wanted people to be able to grab this one file to get updates + * without having to do a large number of changes. + */ + +struct npc_parse { + struct pcrematch_set *active_; + struct pcrematch_set *inactive_; +}; + + +/** + * delete everythign associated with a entry + * + * This does NOT do the list management + */ + +void finalize_pcrematch_entry(struct pcrematch_entry *e) { + free(e->pcre_); + free(e->pcre_extra_); + aFree(e->pattern_); + aFree(e->label_); +} + +/** + * Lookup (and possibly create) a new set of patterns by the set id + */ +static struct pcrematch_set * lookup_pcreset(struct npc_data *nd,int setid) +{ + struct pcrematch_set *pcreset; + struct npc_parse *npcParse = (struct npc_parse *) nd->chatdb; + if (npcParse == NULL) + nd->chatdb = npcParse = (struct npc_parse *) + aCalloc(sizeof(struct npc_parse), 1); + + pcreset = npcParse->active_; + + while (pcreset != NULL) { + if (pcreset->setid_ == setid) + break; + pcreset = pcreset->next_; + } + if (pcreset == NULL) + pcreset = npcParse->inactive_; + + while (pcreset != NULL) { + if (pcreset->setid_ == setid) + break; + pcreset = pcreset->next_; + } + + if (pcreset == NULL) { + pcreset = (struct pcrematch_set *) + aCalloc(sizeof(struct pcrematch_set), 1); + pcreset->next_ = npcParse->inactive_; + if (pcreset->next_ != NULL) + pcreset->next_->prev_ = pcreset; + pcreset->prev_ = 0; + npcParse->inactive_ = pcreset; + pcreset->setid_ = setid; + } + + return pcreset; +} + +/** + * activate a set of patterns. + * + * if the setid does not exist, this will silently return + */ + +static void activate_pcreset(struct npc_data *nd,int setid) { + struct pcrematch_set *pcreset; + struct npc_parse *npcParse = (struct npc_parse *) nd->chatdb; + if (npcParse == NULL) + return; // Nothing to activate... + pcreset = npcParse->inactive_; + while (pcreset != NULL) { + if (pcreset->setid_ == setid) + break; + pcreset = pcreset->next_; + } + if (pcreset == NULL) + return; // not in inactive list + if (pcreset->next_ != NULL) + pcreset->next_->prev_ = pcreset->prev_; + if (pcreset->prev_ != NULL) + pcreset->prev_->next_ = pcreset->next_; + else + npcParse->inactive_ = pcreset->next_; + + pcreset->prev_ = NULL; + pcreset->next_ = npcParse->active_; + if (pcreset->next_ != NULL) + pcreset->next_->prev_ = pcreset; + npcParse->active_ = pcreset; +} + +/** + * deactivate a set of patterns. + * + * if the setid does not exist, this will silently return + */ + +static void deactivate_pcreset(struct npc_data *nd,int setid) { + struct pcrematch_set *pcreset; + struct npc_parse *npcParse = (struct npc_parse *) nd->chatdb; + if (npcParse == NULL) + return; // Nothing to deactivate... + if (setid == -1) { + while(npcParse->active_ != NULL) + deactivate_pcreset(nd, npcParse->active_->setid_); + return; + } + pcreset = npcParse->active_; + while (pcreset != NULL) { + if (pcreset->setid_ == setid) + break; + pcreset = pcreset->next_; + } + if (pcreset == NULL) + return; // not in active list + if (pcreset->next_ != NULL) + pcreset->next_->prev_ = pcreset->prev_; + if (pcreset->prev_ != NULL) + pcreset->prev_->next_ = pcreset->next_; + else + npcParse->active_ = pcreset->next_; + + pcreset->prev_ = NULL; + pcreset->next_ = npcParse->inactive_; + if (pcreset->next_ != NULL) + pcreset->next_->prev_ = pcreset; + npcParse->inactive_ = pcreset; +} + +/** + * delete a set of patterns. + */ +static void delete_pcreset(struct npc_data *nd,int setid) { + int active = 1; + struct pcrematch_set *pcreset; + struct npc_parse *npcParse = (struct npc_parse *) nd->chatdb; + if (npcParse == NULL) + return; // Nothing to deactivate... + pcreset = npcParse->active_; + while (pcreset != NULL) { + if (pcreset->setid_ == setid) + break; + pcreset = pcreset->next_; + } + if (pcreset == NULL) { + active = 0; + pcreset = npcParse->inactive_; + while (pcreset != NULL) { + if (pcreset->setid_ == setid) + break; + pcreset = pcreset->next_; + } + } + if (pcreset == NULL) + return; + + if (pcreset->next_ != NULL) + pcreset->next_->prev_ = pcreset->prev_; + if (pcreset->prev_ != NULL) + pcreset->prev_->next_ = pcreset->next_; + else if(active == 1) + npcParse->active_ = pcreset->next_; + else + npcParse->inactive_ = pcreset->next_; + + pcreset->prev_ = NULL; + pcreset->next_ = NULL; + + while (pcreset->head_) { + struct pcrematch_entry *n = pcreset->head_->next_;; + finalize_pcrematch_entry(pcreset->head_); + pcreset->head_ = n; + } + + aFree(pcreset); +} + +/** + * create a new pattern entry + */ +static struct pcrematch_entry *create_pcrematch_entry(struct pcrematch_set * set) { + struct pcrematch_entry * e = (struct pcrematch_entry *) + aCalloc(sizeof(struct pcrematch_entry), 1); + struct pcrematch_entry * last = set->head_; + + // Normally we would have just stuck it at the end of the list but + // this doesn't sink up with peoples usage pattern. They wanted + // the items defined first to have a higher priority then the + // items defined later.. as a result, we have to do some work up + // front.. + + /* if we are the first pattern, stick us at the end */ + if (last == NULL) { + set->head_ = e; + return e; + } + + /* Look for the last entry */ + while (last->next_ != NULL) + last = last->next_; + + last->next_ = e; + e->next_ = NULL; + + return e; +} + +/** + * define/compile a new pattern + */ + +void npc_chat_def_pattern(struct npc_data *nd, int setid, + const char *pattern, const char *label) +{ + const char *err; + int erroff; + + struct pcrematch_set * s = lookup_pcreset(nd, setid); + struct pcrematch_entry *e = create_pcrematch_entry(s); + e->pattern_ = aStrdup(pattern); + e->label_ = aStrdup(label); + e->pcre_ = pcre_compile(pattern, PCRE_CASELESS, &err, &erroff, NULL); + e->pcre_extra_ = pcre_study(e->pcre_, 0, &err); +} + +/** + * Delete everything associated with a NPC concerning the pattern + * matching code + * + * this could be more efficent but.. how often do you do this? + */ +void npc_chat_finalize(struct npc_data *nd) +{ + struct npc_parse *npcParse = (struct npc_parse *) nd->chatdb; + if (npcParse == NULL) + return; + + while(npcParse->active_) + delete_pcreset(nd, npcParse->active_->setid_); + + while(npcParse->inactive_) + delete_pcreset(nd, npcParse->inactive_->setid_); +} + +/** + * Handler called whenever a global message is spoken in a NPC's area + */ +int npc_chat_sub(struct block_list *bl, va_list ap) +{ + struct npc_data *nd = (struct npc_data *)bl; + struct npc_parse *npcParse = (struct npc_parse *) nd->chatdb; + unsigned char *msg; + int len, pos, i; + struct map_session_data *sd; + struct npc_label_list *lst; + struct pcrematch_set *pcreset; + + // Not interested in anything you might have to say... + if (npcParse == NULL || npcParse->active_ == NULL) + return 0; + + msg = va_arg(ap,unsigned char*); + len = va_arg(ap,int); + sd = va_arg(ap,struct map_session_data *); + + // grab the active list + pcreset = npcParse->active_; + + // interate across all active sets + while (pcreset != NULL) { + struct pcrematch_entry *e = pcreset->head_; + // interate across all patterns in that set + while (e != NULL) { + int offsets[20]; + char buf[255]; + // perform pattern match + int r = pcre_exec(e->pcre_, e->pcre_extra_, msg, len, 0, + 0, offsets, sizeof(offsets) / sizeof(offsets[0])); + if (r >= 0) { + // save out the matched strings + switch (r) { + case 10: + memcpy(buf, &msg[offsets[18]], offsets[19]); + buf[offsets[19]] = '\0'; + set_var(sd, "$p9$", buf); + case 9: + memcpy(buf, &msg[offsets[16]], offsets[17]); + buf[offsets[17]] = '\0'; + set_var(sd, "$p8$", buf); + case 8: + memcpy(buf, &msg[offsets[14]], offsets[15]); + buf[offsets[15]] = '\0'; + set_var(sd, "$p7$", buf); + case 7: + memcpy(buf, &msg[offsets[12]], offsets[13]); + buf[offsets[13]] = '\0'; + set_var(sd, "$p6$", buf); + case 6: + memcpy(buf, &msg[offsets[10]], offsets[11]); + buf[offsets[11]] = '\0'; + set_var(sd, "$p5$", buf); + case 5: + memcpy(buf, &msg[offsets[8]], offsets[9]); + buf[offsets[9]] = '\0'; + set_var(sd, "$p4$", buf); + case 4: + memcpy(buf, &msg[offsets[6]], offsets[7]); + buf[offsets[7]] = '\0'; + set_var(sd, "$p3$", buf); + case 3: + memcpy(buf, &msg[offsets[4]], offsets[5]); + buf[offsets[5]] = '\0'; + set_var(sd, "$p2$", buf); + case 2: + memcpy(buf, &msg[offsets[2]], offsets[3]); + buf[offsets[3]] = '\0'; + set_var(sd, "$p1$", buf); + case 1: + memcpy(buf, &msg[offsets[0]], offsets[1]); + buf[offsets[1]] = '\0'; + set_var(sd, "$p0$", buf); + } + + // find the target label.. this sucks.. + lst=nd->u.scr.label_list; + pos = -1; + for (i = 0; i < nd->u.scr.label_list_num; i++) { + if (strncmp(lst[i].name, e->label_, sizeof(lst[i].name)) == 0) { + pos = lst[i].pos; + break; + } + } + if (pos == -1) { + printf("Unable to find label: %s", e->label_); + // unable to find label... do something.. + return 0; + } + // run the npc script + run_script(nd->u.scr.script,pos,sd->bl.id,nd->bl.id); + return 0; + } + e = e->next_; + } + pcreset = pcreset->next_; + } + + return 0; +} + +// Various script builtins used to support these functions + +int buildin_defpattern(struct script_state *st) { + int setid=conv_num(st,& (st->stack->stack_data[st->start+2])); + char *pattern=conv_str(st,& (st->stack->stack_data[st->start+3])); + char *label=conv_str(st,& (st->stack->stack_data[st->start+4])); + struct npc_data *nd=(struct npc_data *)map_id2bl(st->oid); + + npc_chat_def_pattern(nd, setid, pattern, label); + + return 0; +} + +int buildin_activatepset(struct script_state *st) { + int setid=conv_num(st,& (st->stack->stack_data[st->start+2])); + struct npc_data *nd=(struct npc_data *)map_id2bl(st->oid); + + activate_pcreset(nd, setid); + + return 0; +} +int buildin_deactivatepset(struct script_state *st) { + int setid=conv_num(st,& (st->stack->stack_data[st->start+2])); + struct npc_data *nd=(struct npc_data *)map_id2bl(st->oid); + + deactivate_pcreset(nd, setid); + + return 0; +} +int buildin_deletepset(struct script_state *st) { + int setid=conv_num(st,& (st->stack->stack_data[st->start+2])); + struct npc_data *nd=(struct npc_data *)map_id2bl(st->oid); + + delete_pcreset(nd, setid); + + return 0; +} + + +#endif diff --git a/src/map/script.c b/src/map/script.c index 92ecd8690..24195b698 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -253,9 +253,9 @@ int buildin_failedremovecards(struct script_state *st); int buildin_marriage(struct script_state *st); int buildin_wedding_effect(struct script_state *st); int buildin_divorce(struct script_state *st); -int buildin_ispartneron(struct script_state *st); -int buildin_getpartnerid(struct script_state *st); -int buildin_warppartner(struct script_state *st); +int buildin_ispartneron(struct script_state *st); // MouseJstr +int buildin_getpartnerid(struct script_state *st); // MouseJstr +int buildin_warppartner(struct script_state *st); // MouseJstr int buildin_getitemname(struct script_state *st); int buildin_makepet(struct script_state *st); int buildin_getexp(struct script_state *st); @@ -315,6 +315,13 @@ int run_func(struct script_state *st); int mapreg_setreg(int num,int val); int mapreg_setregstr(int num,const char *str); +#ifdef PCRE_SUPPORT +int buildin_defpattern(struct script_state *st); // MouseJstr +int buildin_activatepset(struct script_state *st); // MouseJstr +int buildin_deactivatepset(struct script_state *st); // MouseJstr +int buildin_deletepset(struct script_state *st); // MouseJstr +#endif + struct { int (*func)(struct script_state *); char *name; @@ -537,10 +544,14 @@ struct { {buildin_isday,"isday",""}, // check whether it is day time [Celest] {buildin_isequipped,"isequipped","i*"}, // check whether another item/card has been equipped [Celest] {buildin_isequippedcnt,"isequippedcnt","i*"}, // check how many items/cards are being equipped [Celest] +#ifdef PCRE_SUPPORT + {buildin_defpattern, "defpattern", "iss"}, // Define pattern to listen for [MouseJstr] + {buildin_activatepset, "activatepset", "i"}, // Activate a pattern set [MouseJstr] + {buildin_deactivatepset, "deactivatepset", "i"}, // Deactive a pattern set [MouseJstr] + {buildin_deletepset, "deletepset", "i"}, // Delete a pattern set [MouseJstr] +#endif {NULL,NULL,NULL}, }; -int buildin_message(struct script_state *st); // [MouseJstr] - enum { C_NOP,C_POS,C_INT,C_PARAM,C_FUNC,C_STR,C_CONSTSTR,C_ARG, @@ -1403,6 +1414,11 @@ static int set_reg(struct map_session_data *sd,int num,char *name,void *v) return 0; } +int set_var(struct map_session_data *sd, char *name, void *val) +{ + return set_reg(sd, add_str(name), name, val); +} + /*========================================== * 文字列への変換 *------------------------------------------ diff --git a/src/map/script.h b/src/map/script.h index 759013e95..b30201a67 100644 --- a/src/map/script.h +++ b/src/map/script.h @@ -42,6 +42,10 @@ struct script_state { char * parse_script(unsigned char *,int); int run_script(char *,int,int,int); +int set_var(struct map_session_data *sd, char *name, void *val); +int conv_num(struct script_state *st,struct script_data *data); +char* conv_str(struct script_state *st,struct script_data *data); + struct dbt* script_get_label_db(); struct dbt* script_get_userfunc_db(); |