1 // -*- Mode: C++; tab-width:2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 // vi:tw=80:et:ts=2:sts=2
3 //
4 // -----------------------------------------------------------------------
5 //
6 // This file is part of RLVM, a RealLive virtual machine clone.
7 //
8 // -----------------------------------------------------------------------
9 //
10 // Copyright (C) 2010 Elliot Glaysher
11 //
12 // This program is free software; you can redistribute it and/or modify
13 // it under the terms of the GNU General Public License as published by
14 // the Free Software Foundation; either version 3 of the License, or
15 // (at your option) any later version.
16 //
17 // This program is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 // GNU General Public License for more details.
21 //
22 // You should have received a copy of the GNU General Public License
23 // along with this program; if not, write to the Free Software
24 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
25 // -----------------------------------------------------------------------
26 
27 #include "systems/base/little_busters_ef00dll.h"
28 
29 #include <iostream>
30 #include <string>
31 
32 #include "machine/rlmachine.h"
33 #include "utilities/exception.h"
34 #include "libreallive/intmemref.h"
35 
36 using libreallive::IntMemRef;
37 
38 namespace {
39 
40 static int random_dirtable[] = {0, 2, 1, 3, 0, 2, 1, 3, 1, 3, 2, 0, 1, 3, 2, 0,
41                                 0, 0, 0, 0, 3, 1, 2, 0, 3, 1, 3, 1, 0, 2, 3, 1};
42 
43 }  // namespace
44 
CallDLL(RLMachine & machine,int func,int arg1,int arg2,int arg3,int arg4)45 int LittleBustersEF00DLL::CallDLL(RLMachine& machine,
46                                   int func,
47                                   int arg1,
48                                   int arg2,
49                                   int arg3,
50                                   int arg4) {
51   switch (func) {
52     case 0:
53       ConfigureEffect(arg1, arg2, arg3, arg4);
54       break;
55     case 1:
56       PerformCalculations(machine, arg1);
57       break;
58     default:
59       std::cerr << "LittleBustersEF00DLL::callDLL(): Invalid function: " << func
60                 << std::endl;
61       return -1;
62   }
63   return 0;
64 }
65 
ConfigureEffect(int arg1,int arg2,int arg3,int arg4)66 void LittleBustersEF00DLL::ConfigureEffect(int arg1,
67                                            int arg2,
68                                            int arg3,
69                                            int arg4) {
70   if (!lb_ef_param)
71     lb_ef_param.reset(new double[sizeof(double) * 0x60 * 8]);
72 
73   int param_top, param_size;
74   if (arg1 == 1) {
75     param_top = 0;
76     param_size = 0x20;
77   } else {
78     param_top = arg2;
79     param_size = arg3;
80     if (param_top < 0)
81       param_top = 0;
82     if (param_top > 0x20)
83       param_top = 0x20;
84     if (param_size + param_top > 0x20)
85       param_size = 0x20 - param_top;
86   }
87   for (int i = 0; i < 8; i++) {
88     double* param = lb_ef_param.get() + i * 0x60 + param_top * 3;
89     for (int j = 0; j < param_size; j++) {
90       *param++ = random() % 800 - 400;
91       *param++ = random() % 600 - 300;
92       *param++ = random() % 700 - 350;
93     }
94   }
95   if (arg4 != 1)
96     return;
97   int* dir = &random_dirtable[(random() & 3) * 8];
98   for (int i = 0; i < 8; i++) {
99     double* param = lb_ef_param.get() + i * 0x60;
100     double x = random() % 600 - 300;
101     double y = random() % 480 - 240;
102     if (x < 0)
103       x -= 80;
104     else
105       x += 80;
106     if (y < 0)
107       y -= 80;
108     else
109       y += 80;
110 
111     switch (*dir++) {
112       case 0:
113         if (x < 0)
114           x = -x;
115         if (y < 0)
116           y = -y;
117         break;
118       case 1:
119         if (x > 0)
120           x = -x;
121         if (y < 0)
122           y = -y;
123         break;
124       case 2:
125         if (x < 0)
126           x = -x;
127         if (y > 0)
128           y = -y;
129         break;
130       case 4:
131         if (x > 0)
132           x = -x;
133         if (y > 0)
134           y = -y;
135         break;
136     }
137     param[9] = x * 1.2;
138     param[10] = y * 1.2;
139     param[11] *= 1.2;
140     param[12] *= -0.08;
141     param[13] *= -0.08;
142     param[14] *= -0.08;
143     param[15] = -param[9];
144     param[16] = -param[10];
145     param[17] = -param[11];
146   }
147 }
148 
PerformCalculations(RLMachine & machine,int index)149 void LittleBustersEF00DLL::PerformCalculations(RLMachine& machine, int index) {
150   if (!lb_ef_param) {
151     throw rlvm::Exception("Effect calculation was called before setting");
152   }
153 
154   int v5_1154 =
155       machine.GetIntValue(IntMemRef(libreallive::INTF_LOCATION, 1154 + index));
156   int j = ((v5_1154) & 0x1f) + index * 0x20;
157   int k = ((v5_1154 + 1) & 0x1f) + index * 0x20;
158   int l = ((v5_1154 + 2) & 0x1f) + index * 0x20;
159   int m = ((v5_1154 + 3) & 0x1f) + index * 0x20;
160   j *= 3;
161   k *= 3;
162   l *= 3;
163   m *= 3;
164 
165   // 0 < x < 1
166   // va - vd は 0-1 の範囲で対称性を持つ3次関数
167   double x = double(machine.GetIntValue(
168                  IntMemRef(libreallive::INTF_LOCATION, 1162 + index))) *
169              0.001;
170   double va = (x * x * x) / 6;
171   double vb = (-x * x * x + 3 * x * x - 3 * x + 1) / 6;
172   double vc = (3 * x * x * x - 6 * x * x + 4) / 6;
173   double vd = (-3 * x * x * x + 3 * x * x + 3 * x + 1) / 6;
174 
175   double r1 = va * lb_ef_param[m + 3] + vd * lb_ef_param[l + 3] +
176               vc * lb_ef_param[k + 3] + vb * lb_ef_param[j + 3];
177   double r2 = va * lb_ef_param[m + 2] + vd * lb_ef_param[l + 2] +
178               vc * lb_ef_param[k + 2] + vb * lb_ef_param[j + 2];
179   double r3 = va * lb_ef_param[m + 1] + vd * lb_ef_param[l + 1] +
180               vc * lb_ef_param[k + 1] + vb * lb_ef_param[j + 1];
181   if (r1 != 400) {
182     r2 = r2 * 800 / (400 - r1);
183     r3 = r3 * 700 / (400 - r1);
184   }
185 
186   machine.SetIntValue(IntMemRef(libreallive::INTF_LOCATION, 1151), r2);
187   machine.SetIntValue(IntMemRef(libreallive::INTF_LOCATION, 1152), r3);
188   machine.SetIntValue(IntMemRef(libreallive::INTF_LOCATION, 1153), r1);
189 }
190 
GetDLLName() const191 const std::string& LittleBustersEF00DLL::GetDLLName() const {
192   static std::string n("EF00");
193   return n;
194 }
195