1 /***********************************************************************
2  Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License as published by
5    the Free Software Foundation; either version 2, or (at your option)
6    any later version.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 ***********************************************************************/
13 
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
17 
18 #ifdef AI_MODULES
19 #include <ltdl.h>
20 #endif
21 
22 /* utility */
23 #include "support.h"
24 
25 /* common */
26 #include "ai.h"
27 #include "player.h"
28 
29 /* server/advisors */
30 #include "autosettlers.h"
31 
32 /* ai/classic */
33 #include "classicai.h"
34 
35 #include "aiiface.h"
36 
37 #ifdef AI_MOD_STATIC_THREADED
38 bool fc_ai_threaded_setup(struct ai_type *ai);
39 #endif
40 
41 #ifdef AI_MOD_STATIC_STUB
42 bool fc_ai_stub_setup(struct ai_type *ai);
43 #endif
44 
45 static struct ai_type *default_ai = NULL;
46 
47 #ifdef AI_MODULES
48 /**************************************************************************
49   Return string describing module loading error. Never returns NULL.
50 **************************************************************************/
fc_module_error(void)51 static const char *fc_module_error(void)
52 {
53   static char def_err[] = "Unknown error";
54   const char *errtxt = lt_dlerror();
55 
56   if (errtxt == NULL) {
57     return def_err;
58   }
59 
60   return errtxt;
61 }
62 
63 /**************************************************************************
64   Load ai module from file.
65 **************************************************************************/
load_ai_module(const char * modname)66 bool load_ai_module(const char *modname)
67 {
68   struct ai_type *ai = ai_type_alloc();
69   bool setup_success;
70   lt_dlhandle handle;
71   bool (*setup_func)(struct ai_type *ai);
72   const char *(*capstr_func)(void);
73   const char *capstr;
74   char buffer[2048];
75   char filename[1024];
76 
77   if (ai == NULL) {
78     return FALSE;
79   }
80 
81   init_ai(ai);
82 
83   fc_snprintf(filename, sizeof(filename), "fc_ai_%s", modname);
84   fc_snprintf(buffer, sizeof(buffer), "%s", filename);
85   handle = lt_dlopenext(buffer);
86   if (handle == NULL) {
87     log_error(_("Cannot open AI module %s (%s)"), filename, fc_module_error());
88     return FALSE;
89   }
90 
91   fc_snprintf(buffer, sizeof(buffer), "%s_capstr", filename);
92   capstr_func = lt_dlsym(handle, buffer);
93   if (capstr_func == NULL) {
94     log_error(_("Cannot find capstr function from ai module %s (%s)"),
95               filename, fc_module_error());
96     return FALSE;
97   }
98 
99   capstr = capstr_func();
100   if (strcmp(FC_AI_MOD_CAPSTR, capstr)) {
101     log_error(_("Incompatible ai module %s:"), filename);
102     log_error(_("  Module options:    %s"), capstr);
103     log_error(_("  Supported options: %s"), FC_AI_MOD_CAPSTR);
104 
105     return FALSE;
106   }
107 
108   fc_snprintf(buffer, sizeof(buffer), "%s_setup", filename);
109   setup_func = lt_dlsym(handle, buffer);
110   if (setup_func == NULL) {
111     log_error(_("Cannot find setup function from ai module %s (%s)"),
112               filename, fc_module_error());
113     return FALSE;
114   }
115   setup_success = setup_func(ai);
116 
117   if (!setup_success) {
118     log_error(_("Setup of ai module %s failed."), filename);
119     return FALSE;
120   }
121 
122   return TRUE;
123 }
124 #endif /* AI_MODULES */
125 
126 /**************************************************************************
127   Initialize ai stuff
128 **************************************************************************/
ai_init(void)129 void ai_init(void)
130 {
131   bool failure = FALSE;
132 #if !defined(AI_MODULES) || defined(AI_MOD_STATIC_CLASSIC) || defined(AI_MOD_STATIC_THREADED) || defined(AI_MOD_STATIC_STUB)
133   /* First !defined(AI_MODULES) case is for default ai support. */
134   struct ai_type *ai;
135 #endif
136 
137 #ifdef AI_MODULES
138   if (lt_dlinit()) {
139     failure = TRUE;
140   }
141   if (!failure) {
142 
143 #ifdef DEBUG
144     /* First search ai modules under directory ai/<module> under
145        current directory. This allows us to run freeciv without
146        installing it. */
147     const char *moduledirs[] = { "classic", "threaded", "stub", NULL };
148     int i;
149 
150     for (i = 0; moduledirs[i] != NULL ; i++) {
151       char buf[2048];
152 
153       fc_snprintf(buf, sizeof(buf), "ai/%s", moduledirs[i]);
154       lt_dladdsearchdir(buf);
155     }
156 #endif /* DEBUG */
157 
158     /* Then search ai modules from their installation directory. */
159     lt_dladdsearchdir(AI_MODULEDIR);
160   }
161 #endif /* AI_MODULES */
162 
163 #ifdef AI_MOD_STATIC_CLASSIC
164   ai = ai_type_alloc();
165   if (ai != NULL) {
166     init_ai(ai);
167     if (!fc_ai_classic_setup(ai)) {
168       log_error(_("Failed to setup \"%s\" AI module"), "classic");
169       ai_type_dealloc();
170     }
171   }
172 #endif /* AI_MOD_STATIC_CLASSIC */
173 
174 #ifdef AI_MOD_STATIC_THREADED
175   ai = ai_type_alloc();
176   if (ai != NULL) {
177     init_ai(ai);
178     if (!fc_ai_threaded_setup(ai)) {
179       log_error(_("Failed to setup \"%s\" AI module"), "threaded");
180       ai_type_dealloc();
181     }
182   }
183 #endif /* AI_MOD_STATIC_THREADED */
184 
185 #ifdef AI_MOD_STATIC_STUB
186   ai = ai_type_alloc();
187   if (ai != NULL) {
188     init_ai(ai);
189     if (!fc_ai_stub_setup(ai)) {
190       log_error(_("Failed to setup \"%s\" AI module"), "stub");
191       ai_type_dealloc();
192     }
193   }
194 #endif /* AI_MOD_STATIC_STUB */
195 
196   default_ai = ai_type_by_name(AI_MOD_DEFAULT);
197 #ifdef AI_MODULES
198   if (default_ai == NULL) {
199     /* Wasn't among statically linked. Try to load dynamic module. */
200     if (!failure && !load_ai_module(AI_MOD_DEFAULT)) {
201       failure = TRUE;
202     }
203     if (!failure) {
204       default_ai = ai_type_by_name(AI_MOD_DEFAULT);
205     }
206   }
207 #endif /* AI_MODULES */
208   if (default_ai == NULL || failure) {
209     log_error(_("Failed to setup default AI module \"%s\", cannot continue."),
210               AI_MOD_DEFAULT);
211     exit(EXIT_FAILURE);
212   }
213 }
214 
215 /**************************************************************************
216   Call incident function of victim.
217 **************************************************************************/
call_incident(enum incident_type type,struct player * violator,struct player * victim)218 void call_incident(enum incident_type type, struct player *violator,
219                    struct player *victim)
220 {
221   CALL_PLR_AI_FUNC(incident, victim, type, violator, victim);
222 }
223 
224 /****************************************************************************
225   Call ai refresh() callback for all players.
226 ****************************************************************************/
call_ai_refresh(void)227 void call_ai_refresh(void)
228 {
229   players_iterate(pplayer) {
230     CALL_PLR_AI_FUNC(refresh, pplayer, pplayer);
231   } players_iterate_end;
232 }
233 
234 /**************************************************************************
235   Return name of default ai type.
236 **************************************************************************/
default_ai_type_name(void)237 const char *default_ai_type_name(void)
238 {
239   return default_ai->name;
240 }
241